ec/kontron/it8516e: Add it8516e EC driver

This driver communicates with the IT8516e on the Kontron KTQM77.
Since we don't know if the firmware and protocol are standard for
the chip or customized to the board, call it kontron/it8516e.

Change-Id: I7382172c6d865d60106c929124444821a07a5184
Signed-off-by: Nico Huber <nico.huber@secunet.com>
Reviewed-on: http://review.coreboot.org/3390
Tested-by: build bot (Jenkins)
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
diff --git a/src/ec/Kconfig b/src/ec/Kconfig
index d3ac471..98aeb9c 100644
--- a/src/ec/Kconfig
+++ b/src/ec/Kconfig
@@ -1,6 +1,7 @@
 source src/ec/acpi/Kconfig
 source src/ec/compal/Kconfig
 source src/ec/google/Kconfig
+source src/ec/kontron/Kconfig
 source src/ec/lenovo/Kconfig
 source src/ec/smsc/Kconfig
 source src/ec/quanta/Kconfig
diff --git a/src/ec/Makefile.inc b/src/ec/Makefile.inc
index b363016..be3da45 100644
--- a/src/ec/Makefile.inc
+++ b/src/ec/Makefile.inc
@@ -1,2 +1,2 @@
 subdirs-$(CONFIG_EC_ACPI) += acpi
-subdirs-y += compal google lenovo smsc quanta
+subdirs-y += compal google kontron lenovo smsc quanta
diff --git a/src/ec/kontron/Kconfig b/src/ec/kontron/Kconfig
new file mode 100644
index 0000000..747a667
--- /dev/null
+++ b/src/ec/kontron/Kconfig
@@ -0,0 +1 @@
+source src/ec/kontron/it8516e/Kconfig
diff --git a/src/ec/kontron/Makefile.inc b/src/ec/kontron/Makefile.inc
new file mode 100644
index 0000000..8c3b7c7
--- /dev/null
+++ b/src/ec/kontron/Makefile.inc
@@ -0,0 +1 @@
+subdirs-$(CONFIG_EC_KONTRON_IT8516E) += it8516e
diff --git a/src/ec/kontron/it8516e/Kconfig b/src/ec/kontron/it8516e/Kconfig
new file mode 100644
index 0000000..2da473e
--- /dev/null
+++ b/src/ec/kontron/it8516e/Kconfig
@@ -0,0 +1,9 @@
+config EC_KONTRON_IT8516E
+	select EC_ACPI
+	bool
+	help
+	  Kontron uses an ITE IT8516E on the KTQM77. It's firmware might
+	  come from Fintek (mentioned as Finte*c* somewhere in their Linux
+	  driver).
+	  The KTQM77 is an embedded board and the IT8516E seems to be
+	  only used for fan control and GPIO.
diff --git a/src/ec/kontron/it8516e/Makefile.inc b/src/ec/kontron/it8516e/Makefile.inc
new file mode 100644
index 0000000..1275cf3
--- /dev/null
+++ b/src/ec/kontron/it8516e/Makefile.inc
@@ -0,0 +1 @@
+ramstage-y += ec.c
diff --git a/src/ec/kontron/it8516e/acpi/ec.asl b/src/ec/kontron/it8516e/acpi/ec.asl
new file mode 100644
index 0000000..bdae967
--- /dev/null
+++ b/src/ec/kontron/it8516e/acpi/ec.asl
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 secunet Security Networks 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 this file into a mainboard's DSDT _SB device tree and it will
+ * expose the IT8516E in the configuration used by Kontron:
+ *   2xUART,
+ *   PS/2 Mouse, Keyboard
+ *   Two PM Channels
+ *
+ * It allows the change of IO ports, IRQs and DMA settings on the devices
+ * and disabling and reenabling logical devices.
+ *
+ * Controlled by the following preprocessor defines:
+ * IT8516E_EC_DEV	Device identifier for this EC (e.g. EC0)
+ * SUPERIO_PNP_BASE	I/o address of the first PnP configuration register
+ * IT8516E_FIRST_DATA	I/o address of the EC_DATA register on the first
+ *			pm channel
+ * IT8516E_FIRST_SC	I/o address of the EC_SC register on the first
+ *			pm channel
+ * IT8516E_SECOND_DATA	I/o address of the EC_DATA register on the second
+ *			pm channel
+ * IT8516E_SECOND_SC	I/o address of the EC_SC register on the second
+ *			pm channel
+ */
+
+#undef SUPERIO_CHIP_NAME
+#define SUPERIO_CHIP_NAME IT8516E
+#include <superio/acpi/pnp.asl>
+
+Device(IT8516E_EC_DEV) {
+	Name (_HID, EisaId("PNP0A05"))
+	Name (_STR, Unicode("Kontron IT8516E Embedded Controller"))
+	Name (_UID, SUPERIO_UID(IT8516E_EC_DEV,))
+
+	/* SuperIO configuration ports */
+	OperationRegion (CREG, SystemIO, SUPERIO_PNP_BASE, 0x02)
+	Field (CREG, ByteAcc, NoLock, Preserve)
+	{
+		ADDR,   8,
+		DATA,   8
+	}
+	IndexField (ADDR, DATA, ByteAcc, NoLock, Preserve)
+	{
+		Offset (0x07),
+		PNP_LOGICAL_DEVICE,	8, /* Logical device selector */
+
+		Offset (0x30),
+		PNP_DEVICE_ACTIVE,	1, /* Logical device activation */
+
+		Offset (0x60),
+		PNP_IO0_HIGH_BYTE,	8, /* First I/O port base - high byte */
+		PNP_IO0_LOW_BYTE,	8, /* First I/O port base - low byte */
+		PNP_IO1_HIGH_BYTE,	8, /* Second I/O port base - high byte */
+		PNP_IO1_LOW_BYTE,	8, /* Second I/O port base - low byte */
+
+		Offset (0x70),
+		PNP_IRQ0,		8, /* First IRQ */
+	}
+
+	Method (_CRS)
+	{
+		/* Announce the used i/o ports to the OS */
+		Return (ResourceTemplate () {
+			IO (Decode16, SUPERIO_PNP_BASE, SUPERIO_PNP_BASE, 0x01, 0x02)
+		})
+	}
+
+	#undef PNP_ENTER_MAGIC_1ST
+	#undef PNP_ENTER_MAGIC_2ND
+	#undef PNP_ENTER_MAGIC_3RD
+	#undef PNP_EXIT_MAGIC_1ST
+	#include <superio/acpi/pnp_config.asl>
+
+	Method (_PSC)
+	{
+		/* No PM: always in C0 */
+		Return (0)
+	}
+
+	#undef SUPERIO_UART_LDN
+	#undef SUPERIO_UART_DDN
+	#undef SUPERIO_UART_PM_REG
+	#define SUPERIO_UART_LDN 1
+	#include <superio/acpi/pnp_uart.asl>
+
+	#undef SUPERIO_UART_LDN
+	#define SUPERIO_UART_LDN 2
+	#include <superio/acpi/pnp_uart.asl>
+
+	#undef SUPERIO_KBC_LDN
+	#undef SUPERIO_KBC_PS2M
+	#undef SUPERIO_KBC_PS2LDN
+	#define SUPERIO_KBC_LDN 6
+	#define SUPERIO_KBC_PS2LDN 5
+	#include <superio/acpi/pnp_kbc.asl>
+
+	#include "pm_channels.asl"
+}
diff --git a/src/ec/kontron/it8516e/acpi/pm_channels.asl b/src/ec/kontron/it8516e/acpi/pm_channels.asl
new file mode 100644
index 0000000..f18ac36
--- /dev/null
+++ b/src/ec/kontron/it8516e/acpi/pm_channels.asl
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 secunet Security Networks 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
+ */
+
+#ifdef IT8516E_FIRST_DATA
+Device (PM1) {
+	Name (_HID, EisaId("PNP0C02"))
+	Name (_STR, Unicode("IT8516E PM Channel 1"))
+	Name (_UID, SUPERIO_UID(PM, 1))
+
+	/*
+	 * The EC firmware exposes CPU temperature through ec ram
+	 * on the first PM channel.
+	 */
+
+	#undef EC_DATA_IO
+	#define EC_DATA_IO IT8516E_FIRST_DATA
+	#undef EC_SC_IO
+	#define EC_SC_IO IT8516E_FIRST_SC
+	#include <ec/acpi/ec.asl>
+
+	Method (_CRS)
+	{
+		/* Announce the used i/o ports to the OS */
+		Return (ResourceTemplate () {
+			IO (Decode16, IT8516E_FIRST_DATA, IT8516E_FIRST_DATA, 0x01, 0x01)
+			IO (Decode16, IT8516E_FIRST_SC, IT8516E_FIRST_SC, 0x01, 0x01)
+		})
+	}
+
+	/*
+	 * Get CPU temperature from first PM channel (in 10th Kelvin)
+	 */
+	Method (CTK)
+	{
+		Store (EC_READ (0x52), Local0)
+		If (And (Local0, EC_ERROR_MASK)) {
+			Return (0)
+		}
+		Multiply (Local0, 10, Local0)	/* Convert to 10th °C */
+		Return (Add (Local0, 2732))	/* Return as 10th Kelvin */
+	}
+}
+#endif
+
+#ifdef IT8516E_SECOND_DATA
+Device (PM2) {
+	Name (_HID, EisaId("PNP0C02"))
+	Name (_STR, Unicode("IT8516E PM Channel 2"))
+	Name (_UID, SUPERIO_UID(PM, 2))
+
+	/*
+	 * The EC firmware exposes fan and GPIO control through the
+	 * second PM channel.
+	 */
+
+	#undef EC_DATA_IO
+	#define EC_DATA_IO IT8516E_SECOND_DATA
+	#undef EC_SC_IO
+	#define EC_SC_IO IT8516E_SECOND_SC
+	#include <ec/acpi/ec.asl>
+
+	Method (_CRS)
+	{
+		/* Announce the used i/o ports to the OS */
+		Return (ResourceTemplate () {
+			IO (Decode16, IT8516E_SECOND_DATA, IT8516E_SECOND_DATA, 0x01, 0x01)
+			IO (Decode16, IT8516E_SECOND_SC, IT8516E_SECOND_SC, 0x01, 0x01)
+		})
+	}
+
+	/*
+	 * Get CPU temperature from second PM channel (in 10th Kelvin)
+	 */
+	Method (CTK)
+	{
+		Acquire (EC_MUTEX, 0xffff)
+		Store (SEND_EC_COMMAND (0x20), Local0) /* GET_CPUTEMP */
+		If (And (Local0, EC_ERROR_MASK)) {
+			Release (EC_MUTEX)
+			Return (0)
+		}
+		Store (RECV_EC_DATA (), Local0)	/* Temp low byte in 64th °C */
+		If (And (Local0, EC_ERROR_MASK)) {
+			Release (EC_MUTEX)
+			Return (0)
+		}
+		Store (RECV_EC_DATA (), Local1)	/* Temp high byte in 64th °C */
+		If (And (Local1, EC_ERROR_MASK)) {
+			Release (EC_MUTEX)
+			Return (0)
+		}
+		Release (EC_MUTEX)
+
+		Or (ShiftLeft (Local1, 8), Local0, Local0)
+		Store (Divide (Multiply (Local0, 10), 64), Local0)	/* Convert to 10th °C */
+		Return (Add (Local0, 2732))				/* Return as 10th Kelvin */
+	}
+}
+#endif
diff --git a/src/ec/kontron/it8516e/chip.h b/src/ec/kontron/it8516e/chip.h
new file mode 100644
index 0000000..dddc5e0
--- /dev/null
+++ b/src/ec/kontron/it8516e/chip.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 secunet Security Networks 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 EC_KONTRON_IT8516E_CHIP_H
+#define EC_KONTRON_IT8516E_CHIP_H
+
+#include "ec.h"
+
+struct ec_kontron_it8516e_config {
+	/*
+	 * Per fan settings
+	 * Can be overwritten by fan1_mode, fan2_mode, fan1_target
+	 * and fan2_target options
+	 */
+	enum it8516e_fan_modes default_fan_mode[2];
+	u16 default_fan_target[2]; /* PWM: % / Speed: RPM / Thermal: °C */
+};
+
+#endif /* EC_KONTRON_IT8516E_CHIP_H */
diff --git a/src/ec/kontron/it8516e/ec.c b/src/ec/kontron/it8516e/ec.c
new file mode 100644
index 0000000..f4df9c7
--- /dev/null
+++ b/src/ec/kontron/it8516e/ec.c
@@ -0,0 +1,175 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 secunet Security Networks 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 <stdlib.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/pnp.h>
+#include <ec/acpi/ec.h>
+#include <pc80/mc146818rtc.h>
+
+#include "ec.h"
+#include "chip.h"
+
+typedef struct ec_kontron_it8516e_config config_t;
+
+enum { /* EC commands */
+	IT8516E_CMD_GET_FAN_MODE	= 0x10,
+	IT8516E_CMD_SET_FAN_MODE	= 0x11,
+	IT8516E_CMD_GET_FAN_PWM		= 0x12,
+	IT8516E_CMD_SET_FAN_PWM		= 0x13,
+	IT8516E_CMD_GET_FAN_SPEED	= 0x14,
+	IT8516E_CMD_SET_FAN_SPEED	= 0x15,
+	IT8516E_CMD_GET_FAN_TEMP	= 0x16,
+	IT8516E_CMD_SET_FAN_TEMP	= 0x17,
+};
+
+static void it8516e_set_fan_mode(const u8 idx, const u8 mode)
+{
+	if (send_ec_command(IT8516E_CMD_SET_FAN_MODE))
+		return;
+	if (send_ec_data(idx))
+		return;
+	send_ec_data(mode);
+}
+
+static void it8516e_set_fan_pwm(const u8 idx, const u8 pwm)
+{
+	if (send_ec_command(IT8516E_CMD_SET_FAN_PWM))
+		return;
+	if (send_ec_data(idx))
+		return;
+	send_ec_data(pwm);
+}
+
+static void it8516e_set_fan_speed(const u8 idx, const u16 speed)
+{
+	if (send_ec_command(IT8516E_CMD_SET_FAN_SPEED))
+		return;
+	if (send_ec_data(idx))
+		return;
+	if (send_ec_data(speed & 0xff))
+		return;
+	send_ec_data(speed >> 8);
+}
+
+static void it8516e_set_fan_temperature(const u8 idx, const u8 temp)
+{
+	if (send_ec_command(IT8516E_CMD_SET_FAN_TEMP))
+		return;
+	if (send_ec_data(idx))
+		return;
+	if (send_ec_data((temp << 6) & 0xff))
+		return;
+	send_ec_data(((temp << 6) >> 8) & 0xff);
+}
+
+static void it8516e_set_fan_from_options(const config_t *const config,
+					 const u8 fan_idx)
+{
+	static char fanX_mode[]		= "fanX_mode";
+	static char fanX_target[]	= "fanX_target";
+
+	u8 fan_mode = config->default_fan_mode[fan_idx];
+	u16 fan_target = config->default_fan_target[fan_idx];
+
+	fanX_mode[3] = '1' + fan_idx;
+	get_option(&fan_mode, fanX_mode);
+	if (!fan_mode)
+		fan_mode = IT8516E_MODE_AUTO;
+	it8516e_set_fan_mode(fan_idx, fan_mode);
+
+	fanX_target[3] = '1' + fan_idx;
+	get_option(&fan_target, fanX_target);
+	switch (fan_mode) {
+	case IT8516E_MODE_AUTO:
+		printk(BIOS_DEBUG,
+		       "Setting it8516e fan%d "
+		       "control to auto.\n",
+		       fan_idx + 1);
+		break;
+	case IT8516E_MODE_PWM:
+		printk(BIOS_DEBUG,
+		       "Setting it8516e fan%d "
+		       "control to %d%% PWM.\n",
+		       fan_idx + 1, fan_target);
+		it8516e_set_fan_pwm(fan_idx, fan_target);
+		break;
+	case IT8516E_MODE_SPEED:
+		printk(BIOS_DEBUG,
+		       "Setting it8516e fan%d "
+		       "control to %d RPMs.\n",
+		       fan_idx + 1, fan_target);
+		it8516e_set_fan_speed(fan_idx, fan_target);
+		break;
+	case IT8516E_MODE_THERMAL:
+		printk(BIOS_DEBUG,
+		       "Setting it8516e fan%d "
+		       "control to %d°C.\n",
+		       fan_idx + 1, fan_target);
+		it8516e_set_fan_temperature(
+			fan_idx, fan_target);
+		break;
+	}
+}
+
+static void it8516e_pm2_init(const device_t dev)
+{
+	const config_t *const config = dev->chip_info;
+
+	/* TODO: Set frequency / divider? */
+
+	ec_set_ports(find_resource(dev, PNP_IDX_IO1)->base,
+		     find_resource(dev, PNP_IDX_IO0)->base);
+
+	it8516e_set_fan_from_options(config, 0);
+	it8516e_set_fan_from_options(config, 1);
+}
+
+static struct device_operations it8516e_pm2_ops = {
+	.read_resources		= pnp_read_resources,
+	.set_resources		= pnp_set_resources,
+	.enable_resources	= pnp_enable_resources,
+	.enable			= pnp_enable,
+	.init			= it8516e_pm2_init
+};
+
+static struct pnp_info it8516e_dev_infos[] = {
+	{ NULL,             IT8516E_LDN_UART1, PNP_IO0 | PNP_IRQ0, { 0x07f8, }, },
+	{ NULL,             IT8516E_LDN_UART2, PNP_IO0 | PNP_IRQ0, { 0x07f8, }, },
+	{ NULL,             IT8516E_LDN_SWUC,  PNP_IO0 | PNP_IRQ0, { 0xff7e0, }, },
+	{ NULL,             IT8516E_LDN_MOUSE, PNP_IRQ0, },
+	{ NULL,             IT8516E_LDN_KBD,   PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x07ff, }, { 0x07ff, }, },
+	{ NULL,             IT8516E_LDN_SMFI,  PNP_IO0 | PNP_IRQ0, { 0xfff0, }, },
+	{ NULL,             IT8516E_LDN_BRAM,  PNP_IO0 | PNP_IO1, { 0xfffe, }, { 0xfffe, }, },
+	{ NULL,             IT8516E_LDN_PM1,   PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x07ff, }, { 0x07ff, }, },
+	{ &it8516e_pm2_ops, IT8516E_LDN_PM2,   PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x07ff, }, { 0x07ff, }, },
+	{ NULL,             IT8516E_LDN_PM3,   PNP_IO0 | PNP_IO1 | PNP_IRQ0, { 0x07ff, }, { 0x07ff, }, },
+};
+
+static void it8516e_enable(const device_t dev)
+{
+	pnp_enable_devices(dev, &pnp_ops,
+			   ARRAY_SIZE(it8516e_dev_infos), it8516e_dev_infos);
+}
+
+const struct chip_operations ec_kontron_it8516e_ops = {
+	CHIP_NAME("Kontron (Fintec/ITE) IT8516E EC")
+	.enable_dev = it8516e_enable
+};
diff --git a/src/ec/kontron/it8516e/ec.h b/src/ec/kontron/it8516e/ec.h
new file mode 100644
index 0000000..5bd2801
--- /dev/null
+++ b/src/ec/kontron/it8516e/ec.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2013 secunet Security Networks 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 EC_KONTRON_IT8516E_EC_H
+#define EC_KONTRON_IT8516E_EC_H
+
+enum { /* PNP logical device numbers */
+	IT8516E_LDN_UART1	= 0x01,
+	IT8516E_LDN_UART2	= 0x02,
+	IT8516E_LDN_SWUC	= 0x04,
+	IT8516E_LDN_MOUSE	= 0x05,
+	IT8516E_LDN_KBD		= 0x06,
+	IT8516E_LDN_SMFI	= 0x0f,
+	IT8516E_LDN_BRAM	= 0x10,
+	IT8516E_LDN_PM1		= 0x11,
+	IT8516E_LDN_PM2		= 0x12,
+	IT8516E_LDN_PM3		= 0x17,
+};
+
+enum it8516e_fan_modes { /* Possible modes of fan control */
+	IT8516E_MODE_AUTO	= 0x80,
+	IT8516E_MODE_PWM	= 0x01,
+	IT8516E_MODE_SPEED	= 0x02,
+	IT8516E_MODE_THERMAL	= 0x03,
+};
+
+#endif