aboutsummaryrefslogtreecommitdiff
path: root/src/ec/kontron
diff options
context:
space:
mode:
authorNico Huber <nico.huber@secunet.com>2017-09-19 14:13:34 +0200
committerPatrick Georgi <pgeorgi@google.com>2019-01-24 13:56:25 +0000
commit016ef9e9bc36c60101b707a8c1c926e78350befa (patch)
tree8c9254f2d4888d7bf14e18f2562f2fde564f724e /src/ec/kontron
parentb2e610011cfa8c821d93b474274fdab383462c49 (diff)
ec/kontron: Add support for Kontron kempld
A programmable logic device used by Kontron as EC on their COM express modules. The name `kempld` is taken from Linux kernel sources, as is the I2C driver. The meaning of the acronym is unclear, probably: Kontron Embedded Module PLD. Change-Id: If9a0826c4a8f5c8cd573610c2d10561334258b36 Signed-off-by: Nico Huber <nico.huber@secunet.com> Reviewed-on: https://review.coreboot.org/c/29476 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/ec/kontron')
-rw-r--r--src/ec/kontron/kempld/Kconfig5
-rw-r--r--src/ec/kontron/kempld/Makefile.inc4
-rw-r--r--src/ec/kontron/kempld/chip.h38
-rw-r--r--src/ec/kontron/kempld/early_kempld.c72
-rw-r--r--src/ec/kontron/kempld/kempld.c115
-rw-r--r--src/ec/kontron/kempld/kempld.h29
-rw-r--r--src/ec/kontron/kempld/kempld_i2c.c296
-rw-r--r--src/ec/kontron/kempld/kempld_internal.h46
8 files changed, 605 insertions, 0 deletions
diff --git a/src/ec/kontron/kempld/Kconfig b/src/ec/kontron/kempld/Kconfig
new file mode 100644
index 0000000000..647bd12d69
--- /dev/null
+++ b/src/ec/kontron/kempld/Kconfig
@@ -0,0 +1,5 @@
+config EC_KONTRON_KEMPLD
+ bool
+ help
+ Driver for Kontron's express module programmable logic device used
+ on their COMexpress modules.
diff --git a/src/ec/kontron/kempld/Makefile.inc b/src/ec/kontron/kempld/Makefile.inc
new file mode 100644
index 0000000000..0d5988625e
--- /dev/null
+++ b/src/ec/kontron/kempld/Makefile.inc
@@ -0,0 +1,4 @@
+bootblock-$(CONFIG_EC_KONTRON_KEMPLD) += early_kempld.c
+ramstage-$(CONFIG_EC_KONTRON_KEMPLD) += early_kempld.c
+ramstage-$(CONFIG_EC_KONTRON_KEMPLD) += kempld.c
+ramstage-$(CONFIG_EC_KONTRON_KEMPLD) += kempld_i2c.c
diff --git a/src/ec/kontron/kempld/chip.h b/src/ec/kontron/kempld/chip.h
new file mode 100644
index 0000000000..7f0693782a
--- /dev/null
+++ b/src/ec/kontron/kempld/chip.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef EC_KONTRON_KEMPLD_CHIP_H
+#define EC_KONTRON_KEMPLD_CHIP_H
+
+#define KEMPLD_NUM_UARTS 2
+
+enum kempld_uart_io {
+ KEMPLD_UART_3F8 = 0,
+ KEMPLD_UART_2F8 = 1,
+ KEMPLD_UART_3E8 = 2,
+ KEMPLD_UART_2E8 = 3,
+};
+
+struct kempld_uart {
+ enum kempld_uart_io io;
+ unsigned int irq;
+};
+
+struct ec_kontron_kempld_config {
+ struct kempld_uart uart[KEMPLD_NUM_UARTS];
+};
+
+#endif /* EC_KONTRON_KEMPLD_CHIP_H */
diff --git a/src/ec/kontron/kempld/early_kempld.c b/src/ec/kontron/kempld/early_kempld.c
new file mode 100644
index 0000000000..773b8b6ef9
--- /dev/null
+++ b/src/ec/kontron/kempld/early_kempld.c
@@ -0,0 +1,72 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 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.
+ */
+
+#include <stdint.h>
+#include <arch/io.h>
+#include <delay.h>
+
+#include "chip.h"
+#include "kempld.h"
+#include "kempld_internal.h"
+
+void kempld_write8(const uint8_t addr, const uint8_t data)
+{
+ outb(addr, KEMPLD_IDX);
+ outb(data, KEMPLD_DAT);
+}
+
+uint8_t kempld_read8(const uint8_t addr)
+{
+ outb(addr, KEMPLD_IDX);
+ return inb(KEMPLD_DAT);
+}
+
+int kempld_get_mutex(int timeout_ms)
+{
+ while (inb(KEMPLD_IDX) & KEMPLD_MUTEX_KEY && timeout_ms--)
+ mdelay(1);
+ return timeout_ms;
+}
+
+void kempld_release_mutex(void)
+{
+ outb(KEMPLD_MUTEX_KEY, KEMPLD_IDX);
+}
+
+void kempld_enable_uart_for_console(void)
+{
+ if (!IS_ENABLED(CONFIG_CONSOLE_SERIAL))
+ return;
+
+ if (kempld_get_mutex(100) < 0)
+ return;
+
+ switch (CONFIG_UART_FOR_CONSOLE) {
+ case 0:
+ kempld_write8(KEMPLD_UART_0,
+ KEMPLD_UART_ENABLE |
+ KEMPLD_UART_3F8 << KEMPLD_UART_IO_SHIFT);
+ break;
+ case 1:
+ kempld_write8(KEMPLD_UART_1,
+ KEMPLD_UART_ENABLE |
+ KEMPLD_UART_2F8 << KEMPLD_UART_IO_SHIFT);
+ break;
+ default:
+ break;
+ }
+
+ kempld_release_mutex();
+}
diff --git a/src/ec/kontron/kempld/kempld.c b/src/ec/kontron/kempld/kempld.c
new file mode 100644
index 0000000000..19c18804c2
--- /dev/null
+++ b/src/ec/kontron/kempld/kempld.c
@@ -0,0 +1,115 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 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.
+ */
+
+#include <console/console.h>
+#include <device/device.h>
+
+#include "chip.h"
+#include "kempld.h"
+#include "kempld_internal.h"
+
+static void kempld_uart_read_resources(struct device *dev)
+{
+ static const unsigned int io_addr[] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+
+ const struct ec_kontron_kempld_config *const config = dev->chip_info;
+
+ struct resource *const res_io = new_resource(dev, 0);
+ struct resource *const res_irq = new_resource(dev, 1);
+ const unsigned int uart = dev->path.generic.subid;
+ if (!config || !res_io || !res_irq || uart >= KEMPLD_NUM_UARTS)
+ return;
+
+ const enum kempld_uart_io io = config->uart[uart].io;
+ if (io >= ARRAY_SIZE(io_addr)) {
+ printk(BIOS_ERR, "KEMPLD: Bad io value '%d' for UART#%u\n.",
+ io, uart);
+ dev->enabled = false;
+ return;
+ }
+
+ const int irq = config->uart[uart].irq;
+ if (irq >= 16) {
+ printk(BIOS_ERR, "KEMPLD: Bad irq value '%d' for UART#%u\n.",
+ irq, uart);
+ dev->enabled = false;
+ return;
+ }
+
+ res_io->base = io_addr[io];
+ res_io->size = 8;
+ res_io->flags = IORESOURCE_IO | IORESOURCE_FIXED |
+ IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+ res_irq->base = irq;
+ res_irq->size = 1;
+ res_irq->flags = IORESOURCE_IO | IORESOURCE_FIXED |
+ IORESOURCE_STORED | IORESOURCE_ASSIGNED;
+
+ if (kempld_get_mutex(100) < 0)
+ return;
+
+ const uint8_t reg = uart ? KEMPLD_UART_1 : KEMPLD_UART_0;
+ const uint8_t val = kempld_read8(reg);
+ kempld_write8(reg, (val & ~(KEMPLD_UART_IO_MASK | KEMPLD_UART_IRQ_MASK))
+ | io << KEMPLD_UART_IO_SHIFT
+ | irq << KEMPLD_UART_IRQ_SHIFT);
+
+ kempld_release_mutex();
+}
+
+static void kempld_uart_enable_resources(struct device *dev)
+{
+ if (kempld_get_mutex(100) < 0)
+ return;
+
+ const unsigned int uart = dev->path.generic.subid;
+ const uint8_t reg = uart ? KEMPLD_UART_1 : KEMPLD_UART_0;
+ kempld_write8(reg, kempld_read8(reg) | KEMPLD_UART_ENABLE);
+
+ kempld_release_mutex();
+}
+
+static struct device_operations kempld_uart_ops = {
+ .read_resources = kempld_uart_read_resources,
+ .enable_resources = kempld_uart_enable_resources,
+};
+
+static void kempld_enable_dev(struct device *const dev)
+{
+ if (dev->path.type == DEVICE_PATH_GENERIC) {
+ switch (dev->path.generic.id) {
+ case 0:
+ if (dev->path.generic.subid < KEMPLD_NUM_UARTS) {
+ dev->ops = &kempld_uart_ops;
+ break;
+ }
+ case 1:
+ if (dev->path.generic.subid == 0) {
+ kempld_i2c_device_init(dev);
+ break;
+ }
+ default:
+ printk(BIOS_WARNING,
+ "KEMPLD: Spurious device %s.\n",
+ dev_path(dev));
+ break;
+ }
+ }
+}
+
+struct chip_operations ec_kontron_kempld_ops = {
+ CHIP_NAME("Kontron KEMPLD")
+ .enable_dev = kempld_enable_dev,
+};
diff --git a/src/ec/kontron/kempld/kempld.h b/src/ec/kontron/kempld/kempld.h
new file mode 100644
index 0000000000..fe5f54f02a
--- /dev/null
+++ b/src/ec/kontron/kempld/kempld.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef EC_KONTRON_KEMPLD_H
+#define EC_KONTRON_KEMPLD_H
+
+#include <stdint.h>
+
+void kempld_write8(uint8_t addr, uint8_t data);
+uint8_t kempld_read8(uint8_t addr);
+
+int kempld_get_mutex(int timeout_ms);
+void kempld_release_mutex(void);
+
+void kempld_enable_uart_for_console(void);
+
+#endif /* EC_KONTRON_KEMPLD_H */
diff --git a/src/ec/kontron/kempld/kempld_i2c.c b/src/ec/kontron/kempld/kempld_i2c.c
new file mode 100644
index 0000000000..fdc0b50dfc
--- /dev/null
+++ b/src/ec/kontron/kempld/kempld_i2c.c
@@ -0,0 +1,296 @@
+/*
+ * I2C bus driver for Kontron COM modules
+ *
+ * Copyright (C) 2017 secunet Security Networks AG
+ *
+ * Based on the similar driver in Linux:
+ *
+ * Copyright (c) 2010-2013 Kontron Europe GmbH
+ * Author: Michael Brunner <michael.brunner@kontron.com>
+ *
+ * The driver is based on the i2c-ocores driver by Peter Korsgaard.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * 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 <stdint.h>
+#include <console/console.h>
+#include <device/device.h>
+#include <device/i2c_bus.h>
+#include <timer.h>
+#include <delay.h>
+
+#include "kempld.h"
+#include "kempld_internal.h"
+
+#define KEMPLD_I2C_PRELOW 0x0b
+#define KEMPLD_I2C_PREHIGH 0x0c
+#define KEMPLD_I2C_DATA 0x0e
+
+#define KEMPLD_I2C_CTRL 0x0d
+#define I2C_CTRL_IEN 0x40
+#define I2C_CTRL_EN 0x80
+
+#define KEMPLD_I2C_STAT 0x0f
+#define I2C_STAT_IF 0x01
+#define I2C_STAT_TIP 0x02
+#define I2C_STAT_ARBLOST 0x20
+#define I2C_STAT_BUSY 0x40
+#define I2C_STAT_NACK 0x80
+
+#define KEMPLD_I2C_CMD 0x0f
+#define I2C_CMD_START 0x91
+#define I2C_CMD_STOP 0x41
+#define I2C_CMD_READ 0x21
+#define I2C_CMD_WRITE 0x11
+#define I2C_CMD_READ_ACK 0x21
+#define I2C_CMD_READ_NACK 0x29
+#define I2C_CMD_IACK 0x01
+
+#define KEMPLD_I2C_FREQ_MAX 2700 /* 2.7 mHz */
+#define KEMPLD_I2C_FREQ_STD 100 /* 100 kHz */
+
+#define EIO 5
+#define ENXIO 6
+#define EAGAIN 11
+#define EBUSY 16
+#define ETIMEDOUT 110
+
+enum kempld_i2c_state {
+ STATE_DONE = 0,
+ STATE_INIT,
+ STATE_ADDR,
+ STATE_ADDR10,
+ STATE_START,
+ STATE_WRITE,
+ STATE_READ,
+ STATE_ERROR,
+};
+
+struct kempld_i2c_data {
+ const struct i2c_msg *msg;
+ size_t pos;
+ size_t nmsgs;
+ enum kempld_i2c_state state;
+};
+
+/*
+ * kempld_get_mutex must be called prior to calling this function.
+ */
+static int kempld_i2c_process(struct kempld_i2c_data *const i2c)
+{
+ u8 stat = kempld_read8(KEMPLD_I2C_STAT);
+ const struct i2c_msg *msg = i2c->msg;
+ u8 addr;
+
+ /* Ready? */
+ if (stat & I2C_STAT_TIP)
+ return -EBUSY;
+
+ if (i2c->state == STATE_DONE || i2c->state == STATE_ERROR) {
+ /* Stop has been sent */
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_IACK);
+ if (i2c->state == STATE_ERROR)
+ return -EIO;
+ return 0;
+ }
+
+ /* Error? */
+ if (stat & I2C_STAT_ARBLOST) {
+ i2c->state = STATE_ERROR;
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return -EAGAIN;
+ }
+
+ if (i2c->state == STATE_INIT) {
+ if (stat & I2C_STAT_BUSY)
+ return -EBUSY;
+
+ i2c->state = STATE_ADDR;
+ }
+
+ if (i2c->state == STATE_ADDR) {
+ /* 10 bit address? */
+ if (i2c->msg->flags & I2C_M_TEN) {
+ addr = 0xf0 | ((i2c->msg->slave >> 7) & 0x6);
+ i2c->state = STATE_ADDR10;
+ } else {
+ addr = (i2c->msg->slave << 1);
+ i2c->state = STATE_START;
+ }
+
+ /* Set read bit if necessary */
+ addr |= (i2c->msg->flags & I2C_M_RD) ? 1 : 0;
+
+ kempld_write8(KEMPLD_I2C_DATA, addr);
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_START);
+
+ return 0;
+ }
+
+ /* Second part of 10 bit addressing */
+ if (i2c->state == STATE_ADDR10) {
+ kempld_write8(KEMPLD_I2C_DATA, i2c->msg->slave & 0xff);
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_WRITE);
+
+ i2c->state = STATE_START;
+ return 0;
+ }
+
+ if (i2c->state == STATE_START || i2c->state == STATE_WRITE) {
+ i2c->state = (msg->flags & I2C_M_RD) ? STATE_READ : STATE_WRITE;
+
+ if (stat & I2C_STAT_NACK) {
+ i2c->state = STATE_ERROR;
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return -ENXIO;
+ }
+ } else {
+ msg->buf[i2c->pos++] = kempld_read8(KEMPLD_I2C_DATA);
+ }
+
+ if (i2c->pos >= msg->len) {
+ i2c->nmsgs--;
+ i2c->msg++;
+ i2c->pos = 0;
+ msg = i2c->msg;
+
+ if (i2c->nmsgs) {
+ if (!(msg->flags & I2C_M_NOSTART)) {
+ i2c->state = STATE_ADDR;
+ return 0;
+ } else {
+ i2c->state = (msg->flags & I2C_M_RD)
+ ? STATE_READ : STATE_WRITE;
+ }
+ } else {
+ i2c->state = STATE_DONE;
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
+ return 0;
+ }
+ }
+
+ if (i2c->state == STATE_READ) {
+ kempld_write8(KEMPLD_I2C_CMD, i2c->pos == (msg->len - 1) ?
+ I2C_CMD_READ_NACK : I2C_CMD_READ_ACK);
+ } else {
+ kempld_write8(KEMPLD_I2C_DATA, msg->buf[i2c->pos++]);
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_WRITE);
+ }
+
+ return 0;
+}
+
+static int kempld_i2c_xfer(struct device *const dev,
+ const struct i2c_msg *const msgs,
+ const size_t num)
+{
+ struct kempld_i2c_data i2c;
+ struct stopwatch sw;
+ int ret;
+
+ if (kempld_get_mutex(100) < 0)
+ return -ENXIO;
+
+ i2c.msg = msgs;
+ i2c.pos = 0;
+ i2c.nmsgs = num;
+ i2c.state = STATE_INIT;
+
+ /* Handle the transfer */
+ stopwatch_init_msecs_expire(&sw, 1000);
+ while (!stopwatch_expired(&sw)) {
+ ret = kempld_i2c_process(&i2c);
+
+ if (i2c.state == STATE_DONE || i2c.state == STATE_ERROR) {
+ if (i2c.state == STATE_DONE) {
+ printk(BIOS_SPEW, "kempld_i2c: Processed %zu segments.\n", num);
+ ret = 0;
+ } else {
+ printk(BIOS_INFO, "kempld_i2c: Transfer failed.\n");
+ }
+ goto _release;
+ }
+
+ if (ret == 0)
+ stopwatch_init_msecs_expire(&sw, 1000);
+
+ udelay(10);
+ }
+
+ i2c.state = STATE_ERROR;
+ ret = -ETIMEDOUT;
+ printk(BIOS_INFO, "kempld_i2c: Transfer failed.\n");
+
+_release:
+ kempld_release_mutex();
+ return ret;
+}
+
+static const struct i2c_bus_operations kempld_i2c_bus_ops = {
+ .transfer = kempld_i2c_xfer,
+};
+
+static struct device_operations kempld_i2c_dev_ops = {
+ .scan_bus = &scan_smbus,
+ .ops_i2c_bus = &kempld_i2c_bus_ops,
+};
+
+void kempld_i2c_device_init(struct device *const dev)
+{
+ u16 prescale_corr;
+ long prescale;
+ u8 ctrl;
+ u8 stat;
+ u8 cfg;
+
+ if (kempld_get_mutex(100) < 0)
+ return;
+
+ /* Make sure the device is disabled */
+ ctrl = kempld_read8(KEMPLD_I2C_CTRL);
+ ctrl &= ~(I2C_CTRL_EN | I2C_CTRL_IEN);
+ kempld_write8(KEMPLD_I2C_CTRL, ctrl);
+
+ const u8 spec_major = KEMPLD_SPEC_GET_MAJOR(kempld_read8(KEMPLD_SPEC));
+ if (spec_major == 1)
+ prescale = KEMPLD_CLK / (KEMPLD_I2C_FREQ_STD * 5) - 1000;
+ else
+ prescale = KEMPLD_CLK / (KEMPLD_I2C_FREQ_STD * 4) - 3000;
+
+ if (prescale < 0)
+ prescale = 0;
+
+ /* Round to the best matching value */
+ prescale_corr = prescale / 1000;
+ if (prescale % 1000 >= 500)
+ prescale_corr++;
+
+ kempld_write8(KEMPLD_I2C_PRELOW, prescale_corr & 0xff);
+ kempld_write8(KEMPLD_I2C_PREHIGH, prescale_corr >> 8);
+
+ /* Disable I2C bus output on GPIO pins */
+ cfg = kempld_read8(KEMPLD_CFG);
+ cfg &= ~KEMPLD_CFG_GPIO_I2C_MUX;
+ kempld_write8(KEMPLD_CFG, cfg);
+
+ /* Enable the device */
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_IACK);
+ ctrl |= I2C_CTRL_EN;
+ kempld_write8(KEMPLD_I2C_CTRL, ctrl);
+
+ stat = kempld_read8(KEMPLD_I2C_STAT);
+ if (stat & I2C_STAT_BUSY)
+ kempld_write8(KEMPLD_I2C_CMD, I2C_CMD_STOP);
+
+ dev->ops = &kempld_i2c_dev_ops;
+
+ kempld_release_mutex();
+}
diff --git a/src/ec/kontron/kempld/kempld_internal.h b/src/ec/kontron/kempld/kempld_internal.h
new file mode 100644
index 0000000000..93351ce772
--- /dev/null
+++ b/src/ec/kontron/kempld/kempld_internal.h
@@ -0,0 +1,46 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef EC_KONTRON_KEMPLD_INTERNAL_H
+#define EC_KONTRON_KEMPLD_INTERNAL_H
+
+#include <device/device.h>
+
+/* i/o ports */
+#define KEMPLD_IDX 0xa80
+#define KEMPLD_MUTEX_KEY 0x80
+#define KEMPLD_DAT 0xa81
+
+/* indexed registers */
+#define KEMPLD_SPEC 0x06
+#define KEMPLD_SPEC_GET_MINOR(x) (x & 0x0f)
+#define KEMPLD_SPEC_GET_MAJOR(x) (x >> 4 & 0x0f)
+
+#define KEMPLD_CFG 0x37
+#define KEMPLD_CFG_GPIO_I2C_MUX (1 << 0)
+
+#define KEMPLD_UART_0 0x30
+#define KEMPLD_UART_1 0x31
+#define KEMPLD_UART_IRQ_SHIFT 0
+#define KEMPLD_UART_IRQ_MASK (0xf << KEMPLD_UART_IRQ_SHIFT)
+#define KEMPLD_UART_IO_SHIFT 4
+#define KEMPLD_UART_IO_MASK (0x3 << KEMPLD_UART_IO_SHIFT)
+#define KEMPLD_UART_ENABLE 0x80
+
+#define KEMPLD_CLK 33333333 /* 33MHz */
+
+void kempld_i2c_device_init(struct device *const dev);
+
+#endif /* EC_KONTRON_KEMPLD_INTERNAL_H */