summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/ish/build.mk31
-rw-r--r--chip/ish/clock.c20
-rw-r--r--chip/ish/config_chip.h79
-rw-r--r--chip/ish/config_flash_layout.h59
-rw-r--r--chip/ish/flash.c18
-rw-r--r--chip/ish/gpio.c34
-rw-r--r--chip/ish/hpet.h65
-rw-r--r--chip/ish/hwtimer.c129
-rw-r--r--chip/ish/i2c.c422
-rw-r--r--chip/ish/ipc.c398
-rw-r--r--chip/ish/ipc.h96
-rw-r--r--chip/ish/ish_i2c.h191
-rw-r--r--chip/ish/jtag.c13
-rw-r--r--chip/ish/registers.h105
-rw-r--r--chip/ish/system.c120
-rw-r--r--chip/ish/uart.c243
-rw-r--r--chip/ish/uart_defs.h222
17 files changed, 2245 insertions, 0 deletions
diff --git a/chip/ish/build.mk b/chip/ish/build.mk
new file mode 100644
index 0000000000..2206426757
--- /dev/null
+++ b/chip/ish/build.mk
@@ -0,0 +1,31 @@
+# -*- makefile -*-
+# Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+#
+# ISH chip specific files build
+#
+
+# ISH SoC has a Minute-IA core
+CORE:=minute-ia
+# Allow the i486 instruction set
+CFLAGS_CPU+=-march=pentium -mtune=i486 -m32
+
+ifeq ($(CONFIG_LTO),y)
+# Re-include the core's build.mk file so we can remove the lto flag.
+include core/$(CORE)/build.mk
+endif
+
+# Required chip modules
+chip-y+=clock.o gpio.o jtag.o system.o hwtimer.o uart.o flash.o
+chip-$(CONFIG_I2C)+=i2c.o
+chip-$(CONFIG_LPC)+=ipc.o
+chip-$(CONFIG_WATCHDOG)+=watchdog.o
+
+# location of the scripts and keys used to pack the SPI flash image
+SCRIPTDIR:=./chip/${CHIP}/util
+
+# Allow SPI size to be overridden by board specific size, default to 256KB.
+CHIP_SPI_SIZE_KB?=256
+
+$(out)/$(PROJECT).bin:
diff --git a/chip/ish/clock.c b/chip/ish/clock.c
new file mode 100644
index 0000000000..118061d997
--- /dev/null
+++ b/chip/ish/clock.c
@@ -0,0 +1,20 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Clocks and power management settings */
+
+#include "clock.h"
+#include "common.h"
+#include "util.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
+#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
+
+
+void clock_init(void)
+{
+ /* No initialization for ISH clock since D0ix is not enabled yet */
+}
diff --git a/chip/ish/config_chip.h b/chip/ish/config_chip.h
new file mode 100644
index 0000000000..ee31ccca05
--- /dev/null
+++ b/chip/ish/config_chip.h
@@ -0,0 +1,79 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_CONFIG_CHIP_H
+#define __CROS_EC_CONFIG_CHIP_H
+
+/* CPU core BFD configuration */
+#include "core/minute-ia/config_core.h"
+
+/* Number of IRQ vectors on the ISH */
+#define CONFIG_IRQ_COUNT 15
+
+/* Use a bigger console output buffer */
+#undef CONFIG_UART_TX_BUF_SIZE
+#define CONFIG_UART_TX_BUF_SIZE 2048
+
+/* Interval between HOOK_TICK notifications */
+#define HOOK_TICK_INTERVAL_MS 250
+#define HOOK_TICK_INTERVAL (HOOK_TICK_INTERVAL_MS * MSEC)
+
+/* Maximum number of deferrable functions */
+#define DEFERRABLE_MAX_COUNT 8
+
+
+/****************************************************************************/
+/* Memory mapping */
+/****************************************************************************/
+
+/* Define our SRAM layout. */
+#define CONFIG_ISH_SRAM_BASE_START 0xFF000000
+#define CONFIG_ISH_SRAM_BASE_END 0xFF0A0000
+#define CONFIG_ISH_SRAM_SIZE (CONFIG_ISH_SRAM_BASE_END - \
+ CONFIG_ISH_SRAM_BASE_START)
+
+/* Required for panic_output */
+#define CONFIG_RAM_SIZE CONFIG_ISH_SRAM_SIZE
+#define CONFIG_RAM_BASE CONFIG_ISH_SRAM_BASE_START
+
+/* System stack size */
+#define CONFIG_STACK_SIZE 1024
+
+/* non-standard task stack sizes */
+#define IDLE_TASK_STACK_SIZE 640
+#define LARGER_TASK_STACK_SIZE 1024
+#define HUGE_TASK_STACK_SIZE 2048
+/* Default task stack size */
+#define TASK_STACK_SIZE 640
+
+/****************************************************************************/
+/* Define our flash layout. */
+/* Note: The 4 macros below are unnecesasry for the ISH chip. However they are
+ * referenced in common files and hence retained to avoid build errors.
+ */
+
+/* Protect bank size 4K bytes */
+#define CONFIG_FLASH_BANK_SIZE 0x00001000
+/* Sector erase size 4K bytes */
+#define CONFIG_FLASH_ERASE_SIZE 0x00000000
+/* Minimum write size */
+#define CONFIG_FLASH_WRITE_SIZE 0x00000000
+/* Program memory base address */
+#define CONFIG_PROGRAM_MEMORY_BASE 0x00100000
+
+#include "config_flash_layout.h"
+
+/****************************************************************************/
+/* Customize the build */
+/* Optional features present on this chip */
+
+/* Note: ISH does not use the LPC bus but the protocol. */
+#define CONFIG_LPC
+
+/* GPIO - to be implemented */
+#define GPIO_PIN(index) (index)
+#define GPIO_PIN_MASK(pin, mask) ((pin), (mask))
+
+#endif /* __CROS_EC_CONFIG_CHIP_H */
diff --git a/chip/ish/config_flash_layout.h b/chip/ish/config_flash_layout.h
new file mode 100644
index 0000000000..b470702972
--- /dev/null
+++ b/chip/ish/config_flash_layout.h
@@ -0,0 +1,59 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_CONFIG_FLASH_LAYOUT_H
+#define __CROS_EC_CONFIG_FLASH_LAYOUT_H
+
+/* Mem-mapped, No external SPI for ISH */
+#undef CONFIG_EXTERNAL_STORAGE
+#define CONFIG_MAPPED_STORAGE
+#undef CONFIG_FLASH_PSTATE
+#undef CONFIG_SPI_FLASH
+
+#define CONFIG_ISH_BOOT_START 0xFF000000
+
+/*****************************************************************************/
+/* The following macros are not applicable for ISH, however the build fails if
+ * they are not defined. Ideally, there should be an option in EC build to
+ * turn off SPI and flash, making these unnecessary.
+ */
+
+#define CONFIG_MAPPED_STORAGE_BASE 0x0
+
+#define CONFIG_EC_PROTECTED_STORAGE_OFF (CONFIG_FLASH_SIZE - 0x20000)
+#define CONFIG_EC_PROTECTED_STORAGE_SIZE 0x20000
+#define CONFIG_EC_WRITABLE_STORAGE_OFF (CONFIG_FLASH_SIZE - 0x40000)
+#define CONFIG_EC_WRITABLE_STORAGE_SIZE 0x20000
+
+/* Unused for ISH - loader is external to ISH FW */
+#define CONFIG_LOADER_MEM_OFF 0
+#define CONFIG_LOADER_SIZE 0xC00
+
+
+/* RO/RW images - not relevant for ISH
+ */
+#define CONFIG_RO_MEM_OFF (CONFIG_LOADER_MEM_OFF + \
+ CONFIG_LOADER_SIZE)
+#define CONFIG_RO_SIZE (97 * 1024)
+#define CONFIG_RW_MEM_OFF CONFIG_RO_MEM_OFF
+#define CONFIG_RW_SIZE CONFIG_RO_SIZE
+
+/*****************************************************************************/
+
+/* Not relevant for ISH */
+#define CONFIG_BOOT_HEADER_STORAGE_OFF 0
+#define CONFIG_BOOT_HEADER_STORAGE_SIZE 0x240
+
+#define CONFIG_LOADER_STORAGE_OFF (CONFIG_BOOT_HEADER_STORAGE_OFF + \
+ CONFIG_BOOT_HEADER_STORAGE_SIZE)
+
+/* RO image immediately follows the loader image */
+#define CONFIG_RO_STORAGE_OFF (CONFIG_LOADER_STORAGE_OFF + \
+ CONFIG_LOADER_SIZE)
+
+/* RW image starts at the beginning of SPI */
+#define CONFIG_RW_STORAGE_OFF 0
+
+#endif /* __CROS_EC_CONFIG_FLASH_LAYOUT_H */
diff --git a/chip/ish/flash.c b/chip/ish/flash.c
new file mode 100644
index 0000000000..8ef4d1a73c
--- /dev/null
+++ b/chip/ish/flash.c
@@ -0,0 +1,18 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "common.h"
+#include "flash.h"
+
+
+/**
+ * Initialize the module.
+ *
+ * Applies at-boot protection settings if necessary.
+ */
+int flash_pre_init(void)
+{
+ return EC_SUCCESS;
+}
diff --git a/chip/ish/gpio.c b/chip/ish/gpio.c
new file mode 100644
index 0000000000..92304fc9b7
--- /dev/null
+++ b/chip/ish/gpio.c
@@ -0,0 +1,34 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* GPIO module for ISH */
+
+#include "common.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "registers.h"
+#include "system.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+
+test_mockable int gpio_get_level(enum gpio_signal signal)
+{
+ return 0;
+}
+
+void gpio_set_level(enum gpio_signal signal, int value)
+{
+}
+
+void gpio_pre_init(void)
+{
+}
+
+static void gpio_init(void)
+{
+ /* TBD */
+}
+DECLARE_HOOK(HOOK_INIT, gpio_init, HOOK_PRIO_DEFAULT);
diff --git a/chip/ish/hpet.h b/chip/ish/hpet.h
new file mode 100644
index 0000000000..c14df86ffb
--- /dev/null
+++ b/chip/ish/hpet.h
@@ -0,0 +1,65 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_HPET_H
+#define __CROS_EC_HPET_H
+
+#include "common.h"
+
+/* ISH HPET config and timer registers */
+#define GENERAL_CAPS_ID_REG 0x00
+#define GENERAL_CONFIG_REG 0x10
+#define GENERAL_INT_STAT_REG 0x20
+#define MAIN_COUNTER_REG 0xF0
+
+#define TIMER0_CONF_CAP_REG 0x100
+#define TIMER0_COMP_VAL_REG 0x108
+#define TIMER0_FSB_IR_REG 0x110
+
+#define TIMER1_CONF_CAP_REG 0x120
+#define TIMER1_COMP_VAL_REG 0x128
+#define TIMER1_FSB_IR_REG 0x130
+
+#define TIMER2_CONF_CAP_REG 0x140
+#define TIMER2_COMP_VAL_REG 0x148
+#define TIMER2_FSB_IR_REG 0x150
+
+#define CONTROL_AND_STATUS_REG 0x160
+
+#define HPET_ENABLE_CNF (1<<0)
+#define HPET_LEGACY_RT_CNF (1<<1)
+#define HPET_Tn_INT_TYPE_CNF (1<<1)
+#define HPET_Tn_INT_ENB_CNF (1<<2)
+#define HPET_Tn_TYPE_CNF (1<<3)
+#define HPET_Tn_32MODE_CNF (1<<8)
+#define HPET_Tn_INT_ROUTE_CNF_SHIFT 0x9
+#define HPET_Tn_INT_ROUTE_CNF_MASK (0x1f << 9)
+#define HPET_GEN_CONF_STATUS_BIT 0x8
+#define HPET_T0_CONF_CAP_BIT 0x4
+
+#define HPET_GENERAL_CONFIG REG32(ISH_HPET_BASE + GENERAL_CONFIG_REG)
+#define HPET_MAIN_COUNTER REG32(ISH_HPET_BASE + MAIN_COUNTER_REG)
+#define HPET_INTR_CLEAR REG32(ISH_HPET_BASE + GENERAL_INT_STAT_REG)
+#define HPET_CTRL_STATUS REG32(ISH_HPET_BASE + CONTROL_AND_STATUS_REG)
+
+#define HPET_TIMER_CONF_CAP(x) \
+ REG32(ISH_HPET_BASE + TIMER0_CONF_CAP_REG + (x * 0x20))
+#define HPET_TIMER_COMP(x) \
+ REG32(ISH_HPET_BASE + TIMER0_COMP_VAL_REG + (x * 0x20))
+
+#if defined CONFIG_ISH_20
+#define ISH_HPET_CLK_FREQ 1000000 /* 1 MHz clock */
+
+#elif defined CONFIG_ISH_30
+#define ISH_HPET_CLK_FREQ 12000000 /* 12 MHz clock */
+
+#elif defined CONFIG_ISH_40
+#define ISH_HPET_CLK_FREQ 32768 /* 32.768 KHz clock */
+#endif
+
+/* HPET timer 0 period of 10ms (100 ticks per second) */
+#define ISH_TICKS_PER_SEC 100
+
+#endif /* __CROS_EC_HPET_H */
diff --git a/chip/ish/hwtimer.c b/chip/ish/hwtimer.c
new file mode 100644
index 0000000000..13c07decd2
--- /dev/null
+++ b/chip/ish/hwtimer.c
@@ -0,0 +1,129 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* Hardware timers driver - HPET */
+
+#include "hpet.h"
+#include "hwtimer.h"
+#include "registers.h"
+#include "task.h"
+
+#define CPUTS(outstr) cputs(CC_CLOCK, outstr)
+#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ## args)
+
+void __hw_clock_event_set(uint32_t deadline)
+{
+ HPET_TIMER_COMP(1) = HPET_MAIN_COUNTER + deadline;
+ HPET_TIMER_CONF_CAP(1) |= HPET_Tn_INT_ENB_CNF;
+}
+
+uint32_t __hw_clock_event_get(void)
+{
+ return 0;
+}
+
+void __hw_clock_event_clear(void)
+{
+ HPET_TIMER_CONF_CAP(1) &= ~HPET_Tn_INT_ENB_CNF;
+}
+
+uint32_t __hw_clock_source_read(void)
+{
+ return HPET_MAIN_COUNTER;
+}
+
+void __hw_clock_source_set(uint32_t ts)
+{
+ HPET_GENERAL_CONFIG &= ~HPET_ENABLE_CNF;
+ HPET_MAIN_COUNTER = 0x00;
+
+ while (HPET_CTRL_STATUS & HPET_GEN_CONF_STATUS_BIT)
+ ;
+
+ HPET_GENERAL_CONFIG |= HPET_ENABLE_CNF;
+}
+
+static void __hw_clock_source_irq(int timer_id)
+{
+ /* Clear interrupt */
+ HPET_INTR_CLEAR = (1 << timer_id);
+
+ /* If IRQ is from timer 0, 32-bit timer overflowed */
+ process_timers(timer_id == 0);
+}
+
+void __hw_clock_source_irq_0(void)
+{
+ __hw_clock_source_irq(0);
+}
+DECLARE_IRQ(ISH_HPET_TIMER0_IRQ, __hw_clock_source_irq_0);
+
+void __hw_clock_source_irq_1(void)
+{
+ __hw_clock_source_irq(1);
+}
+DECLARE_IRQ(ISH_HPET_TIMER1_IRQ, __hw_clock_source_irq_1);
+
+int __hw_clock_source_init(uint32_t start_t)
+{
+
+ /*
+ * The timer can only fire interrupt when its value reaches zero.
+ * Therefore we need two timers:
+ * - Timer 0 as free running timer
+ * - Timer 1 as event timer
+ */
+
+ /* Disable HPET */
+ HPET_GENERAL_CONFIG &= ~HPET_ENABLE_CNF;
+ HPET_MAIN_COUNTER = 0x00;
+
+ /* Set comparator value */
+ HPET_TIMER_COMP(0) = ISH_HPET_CLK_FREQ / ISH_TICKS_PER_SEC;
+
+ /* Wait for timer to settle */
+ while (HPET_CTRL_STATUS & HPET_GEN_CONF_STATUS_BIT)
+ ;
+
+ /* Timer 0 - enable periodic mode */
+ HPET_TIMER_CONF_CAP(0) |= HPET_Tn_TYPE_CNF;
+ HPET_TIMER_CONF_CAP(0) |= HPET_Tn_32MODE_CNF;
+
+ while (HPET_CTRL_STATUS & HPET_T0_CONF_CAP_BIT)
+ ;
+
+ /* Set IRQ routing */
+#if ISH_HPET_TIMER0_IRQ < 32
+ HPET_TIMER_CONF_CAP(0) &= ~HPET_Tn_INT_ROUTE_CNF_MASK;
+ HPET_TIMER_CONF_CAP(0) |= (ISH_HPET_TIMER0_IRQ <<
+ HPET_Tn_INT_ROUTE_CNF_SHIFT);
+#else
+ HPET_TIMER_CONF_CAP(0) &= ~HPET_Tn_INT_ROUTE_CNF_MASK;
+#endif
+
+ while (HPET_CTRL_STATUS & HPET_T0_CONF_CAP_BIT)
+ ;
+
+ /* Level interrupt */
+ HPET_TIMER_CONF_CAP(0) |= HPET_Tn_INT_TYPE_CNF;
+ HPET_TIMER_CONF_CAP(1) |= HPET_Tn_INT_TYPE_CNF;
+
+ /* Unask HPET IRQ in IOAPIC */
+ task_enable_irq(ISH_HPET_TIMER0_IRQ);
+ task_enable_irq(ISH_HPET_TIMER1_IRQ);
+
+ /* Enable interrupt */
+ HPET_TIMER_CONF_CAP(0) |= HPET_Tn_INT_ENB_CNF;
+ HPET_TIMER_CONF_CAP(1) |= HPET_Tn_INT_ENB_CNF;
+
+ while (HPET_CTRL_STATUS & HPET_T0_CONF_CAP_BIT)
+ ;
+
+ /* Enable HPET main counter */
+ HPET_GENERAL_CONFIG |= HPET_ENABLE_CNF;
+
+ return ISH_HPET_TIMER1_IRQ; /* One shot */
+}
diff --git a/chip/ish/i2c.c b/chip/ish/i2c.c
new file mode 100644
index 0000000000..22bf3d81f1
--- /dev/null
+++ b/chip/ish/i2c.c
@@ -0,0 +1,422 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* I2C port module for ISH */
+
+#include "common.h"
+#include "console.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "i2c.h"
+#include "registers.h"
+#include "ish_i2c.h"
+#include "task.h"
+#include "timer.h"
+#include "hwtimer.h"
+#include "util.h"
+
+#define CPUTS(outstr) cputs(CC_I2C, outstr)
+#define CPRINTS(format, args...) cprints(CC_I2C, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_I2C, format, ## args)
+
+#define I2C_FLAG_REPEATED_START_DISABLED 0
+#define EVENT_FLAG_I2C_TIMEOUT TASK_EVENT_CUSTOM(1 << 1)
+
+static uint16_t default_hcnt_scl_100[] = {
+ 4000, 4420, 4920, 4400, 4000, 4000, 4300
+};
+
+static uint16_t default_lcnt_scl_100[] = {
+ 4720, 5180, 4990, 5333, 4700, 5200, 4950
+};
+
+static uint16_t default_hcnt_scl_400[] = {
+ 600, 820, 1120, 1066, 600, 600, 450
+};
+
+static uint16_t default_lcnt_scl_400[] = {
+ 1320, 1380, 1300, 1300, 1300, 1200, 1250
+};
+
+static uint16_t default_hcnt_scl_hs[] = { 160, 300, 160, 166, 175, 150, 162 };
+static uint16_t default_lcnt_scl_hs[] = { 320, 340, 320, 325, 325, 300, 297 };
+
+static uint8_t speed_val_arr[] = {
+ STD_SPEED_VAL, FAST_SPEED_VAL, HIGH_SPEED_VAL };
+
+static uint8_t bus_freq[ISH_I2C_PORT_COUNT] = {
+ I2C_FREQ_120, I2C_FREQ_120, I2C_FREQ_120
+};
+
+static struct i2c_context i2c_ctxs[ISH_I2C_PORT_COUNT] = {
+ {
+ .bus = 0,
+ .base = (uint32_t *) ISH_I2C0_BASE,
+ .speed = I2C_SPEED_FAST,
+ },
+ {
+ .bus = 1,
+ .base = (uint32_t *) ISH_I2C1_BASE,
+ .speed = I2C_SPEED_FAST,
+ },
+ {
+ .bus = 2,
+ .base = (uint32_t *) ISH_I2C2_BASE,
+ .speed = I2C_SPEED_FAST,
+ },
+};
+
+static struct i2c_bus_info board_config[ISH_I2C_PORT_COUNT] = {
+ {
+ .bus_id = 0,
+ .std_speed.sda_hold = DEFAULT_SDA_HOLD,
+ .fast_speed.sda_hold = DEFAULT_SDA_HOLD,
+ .high_speed.sda_hold = DEFAULT_SDA_HOLD,
+ },
+ {
+ .bus_id = 1,
+ .std_speed.sda_hold = DEFAULT_SDA_HOLD,
+ .fast_speed.sda_hold = DEFAULT_SDA_HOLD,
+ .high_speed.sda_hold = DEFAULT_SDA_HOLD,
+ },
+ {
+ .bus_id = 2,
+ .std_speed.sda_hold = DEFAULT_SDA_HOLD,
+ .fast_speed.sda_hold = DEFAULT_SDA_HOLD,
+ .high_speed.sda_hold = DEFAULT_SDA_HOLD,
+ },
+};
+
+static inline void i2c_mmio_write(uint32_t *base, uint8_t offset,
+ uint32_t data)
+{
+ REG32((uint32_t) ((uint8_t *)base + offset)) = data;
+}
+
+static inline uint32_t i2c_mmio_read(uint32_t *base, uint8_t offset)
+{
+ return REG32((uint32_t) ((uint8_t *)base + offset));
+}
+
+static inline uint8_t i2c_read_byte(uint32_t *addr, uint8_t reg,
+ uint8_t offset)
+{
+ uint32_t ret = i2c_mmio_read(addr, reg) >> offset;
+
+ return ret & 0xff;
+}
+
+static void i2c_intr_switch(uint32_t *base, int mode)
+{
+ switch (mode) {
+
+ case ENABLE_WRITE_INT:
+ i2c_mmio_write(base, IC_INTR_MASK, IC_INTR_WRITE_MASK_VAL);
+ break;
+
+ case ENABLE_READ_INT:
+ i2c_mmio_write(base, IC_INTR_MASK, IC_INTR_READ_MASK_VAL);
+ break;
+
+ case DISABLE_INT:
+ i2c_mmio_write(base, IC_INTR_MASK, 0);
+ /* clear interrupts: TX_ABORT
+ * Because the DW_apb_i2c's TX FIFO is forced into a
+ * flushed/reset state whenever a TX_ABRT event occurs, it
+ * is necessary for software to release the DW_apb_i2c from
+ * this state by reading the IC_CLR_TX_ABRT register before
+ * attempting to write into the TX FIFO
+ */
+ i2c_mmio_read(base, IC_CLR_TX_ABRT);
+ /* STOP_DET */
+ i2c_mmio_read(base, IC_CLR_STOP_DET);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void i2c_init_transaction(struct i2c_context *ctx,
+ uint8_t slave_addr, uint8_t flags)
+{
+ uint32_t con_value;
+ uint32_t *base = ctx->base;
+ struct i2c_bus_info *bus_info = &board_config[ctx->bus];
+ uint32_t clk_in_val = clk_in[bus_freq[ctx->bus]];
+
+ /* disable interrupts */
+ i2c_intr_switch(base, DISABLE_INT);
+
+ i2c_mmio_write(base, IC_ENABLE, IC_ENABLE_DISABLE);
+ i2c_mmio_write(base, IC_TAR, (slave_addr << IC_TAR_OFFSET) |
+ TAR_SPECIAL_VAL | IC_10BITADDR_MASTER_VAL);
+
+ /* set Clock SCL Count */
+ switch (ctx->speed) {
+
+ case I2C_SPEED_STD:
+ i2c_mmio_write(base, IC_SS_SCL_HCNT,
+ NS_2_COUNTERS(bus_info->std_speed.hcnt,
+ clk_in_val));
+ i2c_mmio_write(base, IC_SS_SCL_LCNT,
+ NS_2_COUNTERS(bus_info->std_speed.lcnt,
+ clk_in_val));
+ i2c_mmio_write(base, IC_SDA_HOLD,
+ NS_2_COUNTERS(bus_info->std_speed.sda_hold,
+ clk_in_val));
+ break;
+
+ case I2C_SPEED_FAST:
+ i2c_mmio_write(base, IC_FS_SCL_HCNT,
+ NS_2_COUNTERS(bus_info->fast_speed.hcnt,
+ clk_in_val));
+ i2c_mmio_write(base, IC_FS_SCL_LCNT,
+ NS_2_COUNTERS(bus_info->fast_speed.lcnt,
+ clk_in_val));
+ i2c_mmio_write(base, IC_SDA_HOLD,
+ NS_2_COUNTERS(bus_info->fast_speed.sda_hold,
+ clk_in_val));
+ break;
+
+ case I2C_SPEED_HIGH:
+ i2c_mmio_write(base, IC_HS_SCL_HCNT,
+ NS_2_COUNTERS(bus_info->high_speed.hcnt,
+ clk_in_val));
+ i2c_mmio_write(base, IC_HS_SCL_LCNT,
+ NS_2_COUNTERS(bus_info->high_speed.lcnt,
+ clk_in_val));
+ i2c_mmio_write(base, IC_SDA_HOLD,
+ NS_2_COUNTERS(bus_info->high_speed.sda_hold,
+ clk_in_val));
+
+ i2c_mmio_write(base, IC_FS_SCL_HCNT,
+ NS_2_COUNTERS(bus_info->fast_speed.hcnt,
+ clk_in_val));
+ i2c_mmio_write(base, IC_FS_SCL_LCNT,
+ NS_2_COUNTERS(bus_info->fast_speed.lcnt,
+ clk_in_val));
+ break;
+
+ default:
+ break;
+ }
+
+ /* in SPT HW we need to sync between I2C clock and data signals */
+ con_value = i2c_mmio_read(base, IC_CON);
+
+ if (flags & I2C_FLAG_REPEATED_START_DISABLED)
+ con_value &= ~IC_RESTART_EN_VAL;
+ else
+ con_value |= IC_RESTART_EN_VAL;
+
+ i2c_mmio_write(base, IC_CON, con_value);
+ i2c_mmio_write(base, IC_FS_SPKLEN, spkln[bus_freq[ctx->bus]]);
+ i2c_mmio_write(base, IC_HS_SPKLEN, spkln[bus_freq[ctx->bus]]);
+ i2c_mmio_write(base, IC_ENABLE, IC_ENABLE_ENABLE);
+}
+
+static void i2c_write_buffer(uint32_t *base, uint8_t len,
+ const uint8_t *buffer, ssize_t *cur_index,
+ ssize_t total_len)
+{
+ int i;
+ uint16_t out;
+
+ for (i = 0; i < len; i++) {
+
+ ++(*cur_index);
+ out = (buffer[i] << DATA_CMD_DAT_OFFSET) | DATA_CMD_WRITE_VAL;
+
+ if (*cur_index == total_len)
+ out |= DATA_CMD_STOP_VAL;
+
+ i2c_mmio_write(base, IC_DATA_CMD, out);
+ }
+}
+
+static void i2c_write_read_commands(uint32_t *base, uint8_t len)
+{
+ int i;
+
+ for (i = 0; i < len - 1; i++)
+ i2c_mmio_write(base, IC_DATA_CMD, DATA_CMD_READ_VAL);
+
+ i2c_mmio_write(base, IC_DATA_CMD,
+ DATA_CMD_READ_VAL | DATA_CMD_STOP_VAL);
+}
+
+int chip_i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_size,
+ uint8_t *in, int in_size, int flags)
+{
+ int i, is_read = 0;
+ ssize_t total_len;
+ uint64_t expire_ts;
+ struct i2c_context *ctx;
+ ssize_t curr_index = 0;
+
+ if (out_size == 0 && in_size == 0)
+ return EC_SUCCESS;
+
+ if (in_size > 0)
+ is_read = 1;
+
+ /* function interface specifies an 8-bit slave addr: convert it to
+ * a 7-bit addr to meet the expectations of the driver code.
+ */
+ slave_addr >>= 1;
+
+ ctx = &i2c_ctxs[port];
+ ctx->error_flag = 0;
+
+ total_len = 1 + (is_read ? 1 : in_size);
+
+ i2c_init_transaction(ctx, slave_addr, flags);
+
+ /* Write device id */
+ i2c_write_buffer(ctx->base, 1, out, &curr_index, total_len);
+
+ /* Write W data */
+ i2c_write_buffer(ctx->base, (is_read ? 0 : out_size - 1),
+ (is_read ? NULL : out + 1),
+ &curr_index, total_len);
+
+ if (is_read) {
+ /* Write R commands */
+ i2c_write_read_commands(ctx->base, in_size);
+
+ /* Set rx_theshold */
+ i2c_mmio_write(ctx->base, IC_RX_TL, in_size - 1);
+ }
+
+ /* Enable interrupts */
+ i2c_intr_switch(ctx->base,
+ is_read ? ENABLE_READ_INT : ENABLE_WRITE_INT);
+
+ /* Wait for interrupt */
+ ctx->wait_task_id = task_get_current();
+ task_wait_event_mask(EVENT_FLAG_I2C_TIMEOUT, -1);
+
+ if ((ctx->interrupts & M_TX_ABRT) == 0) {
+ if (is_read) {
+ /* read data */
+ for (i = 0; i < in_size; i++)
+ in[i] = i2c_read_byte(ctx->base,
+ IC_DATA_CMD, 0);
+ }
+
+ } else {
+ ctx->error_flag = 1;
+ }
+
+ ctx->reason = 0;
+ ctx->interrupts = 0;
+
+ /* do not disable device before master is idle */
+ expire_ts = __hw_clock_source_read() + I2C_TSC_TIMEOUT;
+
+ while (i2c_mmio_read(ctx->base, IC_STATUS) &
+ (1 << IC_STATUS_MASTER_ACTIVITY)) {
+
+ if (__hw_clock_source_read() >= expire_ts) {
+ ctx->error_flag = 1;
+ break;
+ }
+ }
+
+ i2c_mmio_write(ctx->base, IC_ENABLE, IC_ENABLE_DISABLE);
+
+#ifdef ISH_DEBUG
+ if (req.operation == I2C_READ) {
+ CPRINTF("I2C read len: %d [", req.r_len);
+ for (i = 0; i < req.r_len; i++)
+ CPRINTF("0x%0x ", req.r_data[i]);
+ CPUTS("]\n");
+ }
+#endif
+
+ return EC_SUCCESS;
+}
+
+static void i2c_interrupt_handler(struct i2c_context *ctx)
+{
+ /* check interrupts */
+ ctx->interrupts = i2c_mmio_read(ctx->base, IC_INTR_STAT);
+ ctx->reason = (uint16_t) i2c_mmio_read(ctx->base, IC_TX_ABRT_SOURCE);
+
+ /* disable interrupts */
+ i2c_intr_switch(ctx->base, DISABLE_INT);
+ task_set_event(ctx->wait_task_id, EVENT_FLAG_I2C_TIMEOUT, 0);
+}
+
+static void i2c_isr_bus0(void)
+{
+ i2c_interrupt_handler(&i2c_ctxs[0]);
+}
+DECLARE_IRQ(ISH_I2C0_IRQ, i2c_isr_bus0);
+
+static void i2c_isr_bus1(void)
+{
+ i2c_interrupt_handler(&i2c_ctxs[1]);
+}
+DECLARE_IRQ(ISH_I2C1_IRQ, i2c_isr_bus1);
+
+static void i2c_isr_bus2(void)
+{
+ i2c_interrupt_handler(&i2c_ctxs[2]);
+}
+DECLARE_IRQ(ISH_I2C2_IRQ, i2c_isr_bus2);
+
+static void i2c_init_hardware(struct i2c_context *ctx)
+{
+ uint32_t *base = ctx->base;
+
+ /* disable interrupts */
+ i2c_intr_switch(base, DISABLE_INT);
+ i2c_mmio_write(base, IC_ENABLE, IC_ENABLE_DISABLE);
+ i2c_mmio_write(base, IC_CON, (MASTER_MODE_VAL
+ | speed_val_arr[ctx->speed]
+ | IC_RESTART_EN_VAL
+ | IC_SLAVE_DISABLE_VAL));
+
+ i2c_mmio_write(base, IC_FS_SPKLEN, spkln[bus_freq[ctx->bus]]);
+ i2c_mmio_write(base, IC_HS_SPKLEN, spkln[bus_freq[ctx->bus]]);
+
+ /* get RX_FIFO and TX_FIFO depth */
+ ctx->max_rx_depth = i2c_read_byte(base, IC_COMP_PARAM_1,
+ RX_BUFFER_DEPTH_OFFSET) + 1;
+ ctx->max_tx_depth = i2c_read_byte(base, IC_COMP_PARAM_1,
+ TX_BUFFER_DEPTH_OFFSET) + 1;
+}
+
+static void i2c_initial_board_config(struct i2c_context *ctx)
+{
+ uint8_t freq = bus_freq[ctx->bus];
+ struct i2c_bus_info *bus_info = &board_config[ctx->bus];
+
+ bus_info->std_speed.hcnt = default_hcnt_scl_100[freq];
+ bus_info->std_speed.lcnt = default_lcnt_scl_100[freq];
+ bus_info->fast_speed.hcnt = default_hcnt_scl_400[freq];
+ bus_info->fast_speed.lcnt = default_lcnt_scl_400[freq];
+ bus_info->high_speed.hcnt = default_hcnt_scl_hs[freq];
+ bus_info->high_speed.lcnt = default_lcnt_scl_hs[freq];
+}
+
+static void i2c_init(void)
+{
+ int i;
+
+ for (i = 0; i < ISH_I2C_PORT_COUNT; i++) {
+ i2c_initial_board_config(&i2c_ctxs[i]);
+ i2c_init_hardware(&i2c_ctxs[i]);
+ }
+
+ task_enable_irq(ISH_I2C0_IRQ);
+ task_enable_irq(ISH_I2C1_IRQ);
+ task_enable_irq(ISH_I2C2_IRQ);
+
+ CPRINTS("Done i2c_init");
+}
+DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_INIT_I2C);
diff --git a/chip/ish/ipc.c b/chip/ish/ipc.c
new file mode 100644
index 0000000000..958a26d440
--- /dev/null
+++ b/chip/ish/ipc.c
@@ -0,0 +1,398 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* IPC module for ISH */
+
+/**
+ * IPC - Inter Processor Communication
+ * -----------------------------------
+ *
+ * IPC is a bi-directional doorbell based message passing interface sans
+ * session and transport layers, between hardware blocks. ISH uses IPC to
+ * communicate with the Host, PMC (Power Management Controller), CSME
+ * (Converged Security and Manageability Engine), Audio, Graphics and ISP.
+ *
+ * Both the initiator and target ends each have a 32-bit doorbell register and
+ * 128-byte message regions. In addition, the following register pairs help in
+ * synchronizing IPC.
+ *
+ * - Peripheral Interrupt Status Register (PISR)
+ * - Peripheral Interrupt Mask Register (PIMR)
+ * - Doorbell Clear Status Register (DB CSR)
+ */
+
+#include "registers.h"
+#include "console.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "lpc.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+#include "ipc.h"
+
+#define CPUTS(outstr) cputs(CC_LPC, outstr)
+#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_LPC, format, ## args)
+
+static struct host_packet ipc_packet; /* For host command processing */
+static struct host_cmd_handler_args host_cmd_args;
+static uint8_t host_cmd_flags; /* Flags from host command */
+static uint8_t params_copy[EC_LPC_HOST_PACKET_SIZE] __aligned(4);
+static uint8_t mem_mapped[0x200] __attribute__ ((section(".bss.big_align")));
+static struct ec_lpc_host_args *const ipc_host_args =
+ (struct ec_lpc_host_args *)mem_mapped;
+
+/* Array of peer contexts */
+struct ipc_if_ctx ipc_peer_ctxs[IPC_PEERS_COUNT] = {
+ [IPC_PEER_HOST_ID] = {
+ .in_msg_reg = IPC_HOST2ISH_MSG_REGS,
+ .out_msg_reg = IPC_ISH2HOST_MSG_REGS,
+ .in_drbl_reg = IPC_HOST2ISH_DOORBELL,
+ .out_drbl_reg = IPC_ISH2HOST_DOORBELL,
+ .clr_bit = IPC_INT_ISH2HOST_CLR_BIT,
+ .irq_in = ISH_IPC_HOST2ISH_IRQ,
+ .irq_clr = ISH_IPC_ISH2HOST_CLR_IRQ,
+ },
+ /* Other peers (PMC, CSME, etc) to be added when required */
+};
+
+/* Peripheral Interrupt Mask Register bits */
+static uint8_t pimr_bit_array[IPC_PEERS_COUNT][3] = {
+ {
+ IPC_PIMR_HOST2ISH_OFFS,
+ IPC_PIMR_HOST2ISH_OFFS,
+ IPC_PIMR_ISH2HOST_CLR_OFFS
+ },
+};
+
+/* Get protocol information */
+static int ipc_get_protocol_info(struct host_cmd_handler_args *args)
+{
+ struct ec_response_get_protocol_info *r = args->response;
+
+ memset(r, 0, sizeof(*r));
+ r->protocol_versions = (1 << 3);
+ r->max_request_packet_size = EC_LPC_HOST_PACKET_SIZE;
+ r->max_response_packet_size = EC_LPC_HOST_PACKET_SIZE;
+ r->flags = 0;
+
+ args->response_size = sizeof(*r);
+
+ return EC_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO, ipc_get_protocol_info,
+ EC_VER_MASK(0));
+
+/* Set/un-set PIMR bits */
+static void ipc_set_pimr(uint8_t peer_id, int set,
+ enum pimr_signal_type signal_type)
+{
+ uint32_t new_pimr_val;
+
+ new_pimr_val = (1 << (pimr_bit_array[peer_id][signal_type]));
+
+ interrupt_disable();
+
+ if (set)
+ REG32(IPC_PIMR) |= new_pimr_val;
+ else
+ REG32(IPC_PIMR) &= ~new_pimr_val;
+
+ interrupt_enable();
+}
+
+/**
+ * ipc_read: Host -> ISH communication
+ *
+ * 1. Host SW checks HOST2ISH doorbell bit[31] to ensure it is cleared.
+ * 2. Host SW writes data to HOST2ISH message registers (upto 128 bytes).
+ * 3. Host SW writes to HOST2ISH doorbell register, setting bit [31].
+ * 4. ISH FW recieves interrupt, checks PISR[0] to realize the event.
+ * 5. After reading data, ISH FW clears HOST2ISH DB bit[31].
+ * 6. Host SW recieves interrupt, reads Host PISR bit[8] to realize
+ * the message was consumed by ISH FW.
+ */
+static int ipc_read(uint8_t peer_id, void *out_buff, uint32_t buff_size)
+{
+#ifdef ISH_DEBUG
+ int i;
+#endif
+ struct ipc_if_ctx *ctx;
+ int retval = EC_SUCCESS;
+
+ ctx = &ipc_peer_ctxs[peer_id];
+
+ if (buff_size > IPC_MSG_MAX_SIZE)
+ retval = IPC_FAILURE;
+
+ if (retval >= 0) {
+ /* Copy message to out buffer. */
+ memcpy(out_buff, (const uint32_t *)ctx->in_msg_reg, buff_size);
+ retval = buff_size;
+
+#ifdef ISH_DEBUG
+ CPRINTF("ipc_read, len=0x%0x [", buff_size);
+ for (i = 0; i < buff_size; i++)
+ CPRINTF("0x%0x ", (uint8_t) ((char *)out_buff)[i]);
+ CPUTS("]\n");
+#endif
+ }
+
+ REG32(ctx->in_drbl_reg) = 0;
+ ipc_set_pimr(peer_id, SET_PIMR, PIMR_SIGNAL_IN);
+
+ return retval;
+}
+
+static int ipc_wait_until_msg_consumed(struct ipc_if_ctx *ctx, int timeout)
+{
+ int wait_sts = 0;
+ uint32_t drbl;
+
+ drbl = REG32(ctx->out_drbl_reg);
+ if (!(drbl & IPC_DRBL_BUSY_BIT)) {
+ /* doorbell is already cleared. we can continue */
+ return 0;
+ }
+
+ while (1) {
+ wait_sts = task_wait_event_mask(EVENT_FLAG_BIT_WRITE_IPC,
+ timeout);
+ drbl = REG32(ctx->out_drbl_reg);
+
+ if (!(drbl & IPC_DRBL_BUSY_BIT)) {
+ return 0;
+ } else if (wait_sts != 0) {
+ /* timeout */
+ return wait_sts;
+ }
+ }
+}
+
+/**
+ * ipc_write: ISH -> Host Communication
+ *
+ * 1. ISH FW ensures ISH2HOST doorbell busy bit [31] is cleared.
+ * 2. ISH FW writes data (upto 128 bytes) to ISH2HOST message registers.
+ * 3. ISH FW writes to ISH2HOST doorbell, busy bit (31) is set.
+ * 4. Host SW receives interrupt, reads host PISR[0] to realize event.
+ * 5. Upon reading data, Host driver clears ISH2HOST doorbell busy bit. This
+ * de-asserts the interrupt.
+ * 6. ISH FW also receieves an interrupt for the clear event.
+ */
+static int ipc_write(uint8_t peer_id, void *buff, uint32_t buff_size)
+{
+ struct ipc_if_ctx *ctx;
+ uint32_t drbl_val = 0;
+#ifdef ISH_DEBUG
+ int i;
+#endif
+
+ ctx = &ipc_peer_ctxs[peer_id];
+
+ if (ipc_wait_until_msg_consumed(ctx, IPC_TIMEOUT)) {
+ /* timeout */
+ return IPC_FAILURE;
+ }
+#ifdef ISH_DEBUG
+ CPRINTF("ipc_write, len=0x%0x [", buff_size);
+ for (i = 0; i < buff_size; i++)
+ CPRINTF("0x%0x ", (uint8_t) ((char *)buff)[i]);
+ CPUTS("]\n");
+#endif
+
+ /* write message */
+ if (buff_size <= IPC_MSG_MAX_SIZE) {
+ /* write to message register */
+ memcpy((uint32_t *) ctx->out_msg_reg, buff, buff_size);
+ drbl_val = IPC_BUILD_HEADER(buff_size, IPC_PROTOCOL_ECP,
+ SET_BUSY);
+ } else {
+ return IPC_FAILURE;
+ }
+
+ /* write doorbell */
+ REG32(ctx->out_drbl_reg) = drbl_val;
+
+ return EC_SUCCESS;
+}
+
+uint8_t *lpc_get_memmap_range(void)
+{
+ return mem_mapped + 0x100;
+}
+
+static uint8_t *ipc_get_hostcmd_data_range(void)
+{
+ return mem_mapped;
+}
+
+static void ipc_send_response_packet(struct host_packet *pkt)
+{
+ ipc_write(IPC_PEER_HOST_ID, pkt->response, pkt->response_size);
+}
+
+void lpc_set_host_event_state(uint32_t mask)
+{
+}
+
+void lpc_set_host_event_mask(enum lpc_host_event_type type, uint32_t mask)
+{
+}
+
+uint32_t lpc_get_host_event_mask(enum lpc_host_event_type type)
+{
+ return 0;
+}
+
+void lpc_clear_acpi_status_mask(uint8_t mask)
+{
+}
+
+/**
+ * IPC interrupts are recieved by the FW when a) Host SW rings doorbell and
+ * b) when Host SW clears doorbell busy bit [31].
+ *
+ * Doorbell Register (DB) bits
+ * ----+-------+--------+-----------+--------+------------+--------------------
+ * 31 | 30 29 | 28-20 |19 18 17 16| 15 14 | 13 12 11 10| 9 8 7 6 5 4 3 2 1 0
+ * ----+-------+--------+-----------+--------+------------+--------------------
+ * Busy|Options|Reserved| Command |Reserved| Protocol | Message Length
+ * ----+-------+--------+-----------+--------+------------+--------------------
+ *
+ * ISH Peripheral Interrupt Status Register:
+ * Bit 0 - If set, indicates interrupt was caused by setting Host2ISH DB
+ *
+ * ISH Peripheral Interrupt Mask Register
+ * Bit 0 - If set, mask interrupt caused by Host2ISH DB
+ *
+ * ISH Peripheral DB Clear Status Register
+ * Bit 0 - If set, indicates interrupt was caused by clearing Host2ISH DB
+ */
+static void ipc_interrupt_handler(void)
+{
+ uint32_t pisr = REG32(IPC_PISR);
+ uint32_t pimr = REG32(IPC_PIMR);
+ uint32_t busy_clear = REG32(IPC_BUSY_CLEAR);
+ uint32_t drbl = REG32(IPC_ISH2HOST_MSG_REGS);
+ uint8_t proto, cmd;
+
+ if ((pisr & IPC_PISR_HOST2ISH_BIT)
+ && (pimr & IPC_PIMR_HOST2ISH_BIT)) {
+
+ /* New message arrived */
+ ipc_set_pimr(IPC_PEER_HOST_ID, UNSET_PIMR, PIMR_SIGNAL_IN);
+ task_set_event(TASK_ID_IPC_COMM, EVENT_FLAG_BIT_READ_IPC, 0);
+ proto = IPC_HEADER_GET_PROTOCOL(drbl);
+ cmd = IPC_HEADER_GET_MNG_CMD(drbl);
+
+ if ((proto == IPC_PROTOCOL_MNG) && (cmd == MNG_TIME_UPDATE))
+ /* Ignoring time update from host */
+ ;
+ }
+
+ if ((busy_clear & IPC_INT_ISH2HOST_CLR_BIT)
+ && (pimr & IPC_PIMR_ISH2HOST_CLR_MASK_BIT)) {
+ /* Written message cleared */
+ REG32(IPC_BUSY_CLEAR) = IPC_ISH_FWSTS;
+ task_set_event(TASK_ID_IPC_COMM, EVENT_FLAG_BIT_WRITE_IPC, 0);
+ }
+}
+DECLARE_IRQ(ISH_IPC_HOST2ISH_IRQ, ipc_interrupt_handler);
+
+/* Task that listens for incomming IPC messages from Host and initiate host
+ * command processing.
+ */
+void ipc_comm_task(void)
+{
+ int ret = 0;
+ uint32_t out_drbl, pkt_len;
+
+ for (;;) {
+
+ ret = task_wait_event_mask(EVENT_FLAG_BIT_READ_IPC
+ | EVENT_FLAG_BIT_WRITE_IPC, -1);
+
+ if ((ret & EVENT_FLAG_BIT_WRITE_IPC))
+ continue;
+ else if (!(ret & EVENT_FLAG_BIT_READ_IPC))
+ continue;
+
+ /* Read the command byte. This clears the FRMH bit in
+ * the status byte.
+ */
+ out_drbl = REG32(IPC_HOST2ISH_DOORBELL);
+ pkt_len = out_drbl & IPC_HEADER_LENGTH_MASK;
+
+ ret = ipc_read(IPC_PEER_HOST_ID, ipc_host_args, pkt_len);
+ host_cmd_args.command = EC_COMMAND_PROTOCOL_3;
+
+ host_cmd_args.result = EC_RES_SUCCESS;
+ host_cmd_flags = ipc_host_args->flags;
+
+ /* We only support new style command (v3) now */
+ if (host_cmd_args.command == EC_COMMAND_PROTOCOL_3) {
+ ipc_packet.send_response = ipc_send_response_packet;
+
+ ipc_packet.request =
+ (const void *)ipc_get_hostcmd_data_range();
+ ipc_packet.request_temp = params_copy;
+ ipc_packet.request_max = sizeof(params_copy);
+ /* Don't know the request size so pass in
+ * the entire buffer
+ */
+ ipc_packet.request_size = EC_LPC_HOST_PACKET_SIZE;
+
+ ipc_packet.response =
+ (void *)ipc_get_hostcmd_data_range();
+ ipc_packet.response_max = EC_LPC_HOST_PACKET_SIZE;
+ ipc_packet.response_size = 0;
+
+ ipc_packet.driver_result = EC_RES_SUCCESS;
+ host_packet_receive(&ipc_packet);
+ usleep(10); /* To force yield */
+
+ continue;
+ } else {
+ /* Old style command unsupported */
+ host_cmd_args.result = EC_RES_INVALID_COMMAND;
+ }
+
+ /* Hand off to host command handler */
+ host_command_received(&host_cmd_args);
+ }
+}
+
+static void setup_ipc(void)
+{
+
+ task_enable_irq(ISH_IPC_HOST2ISH_IRQ);
+ task_enable_irq(ISH_IPC_ISH2HOST_CLR_IRQ);
+
+ ipc_set_pimr(IPC_PEER_HOST_ID, SET_PIMR, PIMR_SIGNAL_IN);
+ ipc_set_pimr(IPC_PEER_HOST_ID, SET_PIMR, PIMR_SIGNAL_CLR);
+}
+DECLARE_HOOK(HOOK_CHIPSET_STARTUP, setup_ipc, HOOK_PRIO_FIRST);
+
+static void ipc_init(void)
+{
+ CPRINTS("ipc_init");
+
+ /* Initialize host args and memory map to all zero */
+ memset(ipc_host_args, 0, sizeof(*ipc_host_args));
+ memset(lpc_get_memmap_range(), 0, EC_MEMMAP_SIZE);
+
+ setup_ipc();
+}
+DECLARE_HOOK(HOOK_INIT, ipc_init, HOOK_PRIO_INIT_LPC);
+
+/* On boards without a host, this command is used to set up IPC */
+static int ipc_command_init(int argc, char **argv)
+{
+ ipc_init();
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(ipcinit, ipc_command_init, NULL, NULL);
diff --git a/chip/ish/ipc.h b/chip/ish/ipc.h
new file mode 100644
index 0000000000..72968e94c4
--- /dev/null
+++ b/chip/ish/ipc.h
@@ -0,0 +1,96 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* IPC module for ISH */
+
+#ifndef __CROS_EC_IPC_H
+#define __CROS_ECIPC_H
+
+#define IPC_FAILURE -1
+#define IPC_TIMEOUT -1
+#define UNSET_PIMR 0
+#define SET_PIMR 1
+#define SET_BUSY 1
+
+#define IPC_PROTOCOL_MNG 3 /* Management protocol */
+#define IPC_PROTOCOL_ECP 4 /* EC protocol */
+#define MNG_TIME_UPDATE 5
+
+#define EVENT_FLAG_BIT_READ_IPC (1<<0)
+#define EVENT_FLAG_BIT_WRITE_IPC (1<<2)
+
+#define IPC_PIMR_HOST2ISH_OFFS (0)
+#define IPC_PIMR_HOST2ISH_OFFS (0)
+#define IPC_PIMR_ISH2HOST_CLR_OFFS (11)
+#define IPC_INT_ISH2HOST_CLR_OFFS (0)
+#define IPC_PISR_HOST2ISH_OFFS IPC_PIMR_HOST2ISH_OFFS
+#define IPC_MSG_MAX_SIZE 0x80
+#define IPC_DRBL_BUSY_OFFS (31)
+#define IPC_HEADER_PROTOCOL_OFFSET 10
+#define IPC_HEADER_PROTOCOL_MASK (0x0F)
+#define IPC_HEADER_MNG_CMD_MASK (0x0F)
+#define IPC_HEADER_LENGTH_MASK (0x03FF)
+#define IPC_HEADER_MNG_CMD_OFFSET 16
+#define IPC_HEADER_LENGTH_OFFSET 0
+#define IPC_OOB_MSG_OFFS (30)
+
+#define IPC_PIMR_HOST2ISH_BIT (1 << IPC_PIMR_HOST2ISH_OFFS)
+#define IPC_PIMR_ISH2HOST_CLR_MASK_BIT (1 << IPC_PIMR_ISH2HOST_CLR_OFFS)
+#define IPC_PIMR_HOST2ISH_BIT (1 << IPC_PIMR_HOST2ISH_OFFS)
+#define IPC_INT_ISH2HOST_CLR_BIT (1 << IPC_INT_ISH2HOST_CLR_OFFS)
+#define IPC_PISR_HOST2ISH_BIT (1 << IPC_PISR_HOST2ISH_OFFS)
+#define IPC_OOB_MSG_BIT (1 << IPC_OOB_MSG_OFFS)
+#define IPC_DRBL_BUSY_BIT (1 << IPC_DRBL_BUSY_OFFS)
+
+#define IPC_IS_BUSY(drbl_reg) \
+ ((drbl_reg & IPC_DRBL_BUSY_BIT) == ((uint32_t) IPC_DRBL_BUSY_BIT))
+
+#define IPC_HEADER_GET_PROTOCOL(drbl_reg) \
+ ((drbl_reg >> IPC_HEADER_PROTOCOL_OFFSET) & IPC_HEADER_PROTOCOL_MASK)
+
+#define IPC_HEADER_GET_MNG_CMD(drbl_reg) \
+ ((drbl_reg >> IPC_HEADER_MNG_CMD_OFFSET) & IPC_HEADER_MNG_CMD_MASK)
+
+#define IPC_HEADER_GET_LENGTH(drbl_reg) \
+ ((drbl_reg >> IPC_HEADER_LENGTH_OFFSET) & IPC_HEADER_LENGTH_MASK)
+
+#define IPC_BUILD_HEADER(length, protocol, busy) \
+ ((busy << IPC_DRBL_BUSY_OFFS) \
+ | (protocol << IPC_HEADER_PROTOCOL_OFFSET) \
+ | (length << IPC_HEADER_LENGTH_OFFSET))
+
+#define IPC_BUILD_MNG_MSG(cmd, length) \
+ ((1 << IPC_DRBL_BUSY_OFFS)\
+ | (IPC_PROTOCOL_MNG << IPC_HEADER_PROTOCOL_OFFSET) \
+ | (cmd << IPC_HEADER_MNG_CMD_OFFSET)\
+ | (length << IPC_HEADER_LENGTH_OFFSET))
+
+struct ipc_if_ctx {
+ uint32_t in_msg_reg;
+ uint32_t out_msg_reg;
+ uint32_t in_drbl_reg;
+ uint32_t out_drbl_reg;
+ uint32_t clr_bit;
+ uint8_t irq_in;
+ uint8_t irq_clr;
+};
+
+struct ipc_oob_msg {
+ uint32_t address;
+ uint32_t length;
+};
+
+enum pimr_signal_type {
+ PIMR_SIGNAL_IN = 0,
+ PIMR_SIGNAL_OUT = 1,
+ PIMR_SIGNAL_CLR = 2,
+};
+
+enum {
+ IPC_PEER_HOST_ID = 0,
+ IPC_PEERS_COUNT,
+};
+
+#endif /* __CROS_ECIPC_H */
diff --git a/chip/ish/ish_i2c.h b/chip/ish/ish_i2c.h
new file mode 100644
index 0000000000..0a894593ea
--- /dev/null
+++ b/chip/ish/ish_i2c.h
@@ -0,0 +1,191 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_ISH_I2C_H
+#define __CROS_EC_ISH_I2C_H
+
+#include <stdint.h>
+#include "task.h"
+
+#define I2C_TSC_TIMEOUT 2000000
+#define I2C_CALIB_ADDRESS 0x3
+#define I2C_INTERRUPT_TIMEOUT (TICKFREQ / 20)
+#define NS_IN_SEC 1000
+#define DEFAULT_SDA_HOLD 133
+#define NS_2_COUNTERS(ns, clk) ((ns * clk)/NS_IN_SEC)
+#define COUNTERS_2_NS(counters, clk) (counters * (NANOSECONDS_IN_SEC / \
+ (clk * HZ_IN_MEGAHZ)))
+
+enum {
+ /* speed mode values */
+ I2C_SPEED_STD = 0,
+ I2C_SPEED_FAST = 1,
+ I2C_SPEED_HIGH = 2,
+ /* freq mode values */
+ I2C_FREQ_25 = 0,
+ I2C_FREQ_50 = 1,
+ I2C_FREQ_100 = 2,
+ I2C_FREQ_120 = 3,
+ I2C_FREQ_40 = 4,
+ I2C_FREQ_20 = 5,
+ I2C_FREQ_37 = 6
+};
+
+const unsigned int clk_in[] = {
+ [I2C_FREQ_25] = 25,
+ [I2C_FREQ_50] = 50,
+ [I2C_FREQ_100] = 100,
+ [I2C_FREQ_120] = 120,
+ [I2C_FREQ_40] = 40,
+ [I2C_FREQ_20] = 20,
+ [I2C_FREQ_37] = 37,
+};
+
+const uint8_t spkln[] = {
+ [I2C_FREQ_25] = 2,
+ [I2C_FREQ_50] = 3,
+ [I2C_FREQ_100] = 5,
+ [I2C_FREQ_120] = 6,
+ [I2C_FREQ_40] = 2,
+ [I2C_FREQ_20] = 1,
+ [I2C_FREQ_37] = 2,
+};
+
+enum {
+ I2C_READ,
+ I2C_WRITE
+};
+
+enum {
+ /* REGISTERS */
+ IC_ENABLE = 0x6c,
+ IC_STATUS = 0x70,
+ IC_ENABLE_STATUS = 0x9c,
+ IC_CON = 0x00,
+ IC_TAR = 0x04,
+ IC_DATA_CMD = 0x10,
+ IC_RX_TL = 0x38,
+ IC_TX_TL = 0x3c,
+ IC_COMP_PARAM_1 = 0xf4,
+ IC_INTR_MASK = 0x30,
+ IC_RAW_INTR_STAT = 0x34,
+ IC_INTR_STAT = 0x2c,
+ IC_CLR_TX_ABRT = 0x54,
+ IC_TX_ABRT_SOURCE = 0x80,
+ IC_SS_SCL_HCNT = 0x14,
+ IC_SS_SCL_LCNT = 0x18,
+ IC_FS_SCL_HCNT = 0x1c,
+ IC_FS_SCL_LCNT = 0x20,
+ IC_HS_SCL_HCNT = 0x24,
+ IC_HS_SCL_LCNT = 0x28,
+ IC_CLR_STOP_DET = 0x60,
+ IC_CLR_START_DET = 0x64,
+ IC_TXFLR = 0x74,
+ IC_SDA_HOLD = 0x7c,
+ IC_FS_SPKLEN = 0xA0,
+ IC_HS_SPKLEN = 0xA4,
+ /* IC_ENABLE VALUES */
+ IC_ENABLE_ENABLE = 1,
+ IC_ENABLE_DISABLE = 0,
+ /* IC_STATUS OFFSETS */
+ IC_STATUS_MASTER_ACTIVITY = 5,
+ /* IC_CON OFFSETS */
+ MASTER_MODE_OFFSET = 0,
+ SPEED_OFFSET = 1,
+ IC_RESTART_EN_OFFSET = 5,
+ IC_SLAVE_DISABLE_OFFSET = 6,
+ /* IC_CON VALUES */
+ MASTER_MODE = 1,
+ STD_SPEED = 1,
+ FAST_SPEED = 2,
+ HIGH_SPEED = 3,
+ IC_RESTART_EN = 1,
+ IC_SLAVE_DISABLE = 1,
+ /* IC_CON WRITE VALUES */
+ MASTER_MODE_VAL = (MASTER_MODE << MASTER_MODE_OFFSET),
+ STD_SPEED_VAL = (STD_SPEED << SPEED_OFFSET),
+ FAST_SPEED_VAL = (FAST_SPEED << SPEED_OFFSET),
+ HIGH_SPEED_VAL = (HIGH_SPEED << SPEED_OFFSET),
+ SPEED_MASK = (0x3 << SPEED_OFFSET),
+ IC_RESTART_EN_VAL = (IC_RESTART_EN << IC_RESTART_EN_OFFSET),
+ IC_SLAVE_DISABLE_VAL = (IC_SLAVE_DISABLE << IC_SLAVE_DISABLE_OFFSET),
+ /* IC_TAR OFFSETS */
+ IC_TAR_OFFSET = 0,
+ SPECIAL_OFFSET = 11,
+ IC_10BITADDR_MASTER_OFFSET = 12,
+ /* IC_TAR VALUES */
+ TAR_SPECIAL = 0,
+ IC_10BITADDR_MASTER = 0,
+ /* IC_TAR WRITE VALUES */
+ IC_10BITADDR_MASTER_VAL =
+ (IC_10BITADDR_MASTER << IC_10BITADDR_MASTER_OFFSET),
+ TAR_SPECIAL_VAL = (TAR_SPECIAL << SPECIAL_OFFSET),
+ /* IC_DATA_CMD OFFSETS */
+ DATA_CMD_DAT_OFFSET = 0,
+ DATA_CMD_CMD_OFFSET = 8,
+ DATA_CMD_STOP_OFFSET = 9,
+ DATA_CMD_RESTART_OFFSET = 10,
+ /* IC_DATA_CMD VALUES */
+ DATA_CMD_READ = 1,
+ DATA_CMD_WRITE = 0,
+ DATA_CMD_STOP = 1,
+ DATA_CMD_RESTART = 1,
+ /* IC_DATA_CMD WRITE VALUES */
+ DATA_CMD_WRITE_VAL = (DATA_CMD_WRITE << DATA_CMD_CMD_OFFSET),
+ DATA_CMD_READ_VAL = (DATA_CMD_READ << DATA_CMD_CMD_OFFSET),
+ DATA_CMD_STOP_VAL = (DATA_CMD_STOP << DATA_CMD_STOP_OFFSET),
+ DATA_CMD_RESTART_VAL = (DATA_CMD_RESTART << DATA_CMD_RESTART_OFFSET),
+ /* IC_TX_TL */
+ IC_TX_TL_VAL = 0,
+ /* IC_COM_PARAM_OFFSETS */
+ TX_BUFFER_DEPTH_OFFSET = 16,
+ RX_BUFFER_DEPTH_OFFSET = 8,
+ /* IC_INTR_MASK VALUES */
+ M_RX_FULL = (1 << 2),
+ M_TX_EMPTY = (1 << 4),
+ M_TX_ABRT = (1 << 6),
+ M_STOP_DET = (1 << 9),
+ M_START_DET = (1 << 10),
+ IC_INTR_WRITE_MASK_VAL = (M_STOP_DET | M_TX_ABRT),
+ IC_INTR_READ_MASK_VAL = (M_RX_FULL | M_TX_ABRT),
+ DISABLE_INT = 0,
+ ENABLE_WRITE_INT = 1,
+ ENABLE_READ_INT = 2,
+ /* IC_ENABLE_STATUS_OFFSETS */
+ IC_EN_OFFSET = 0,
+ /* IC_ENABLE_STATUS_VALUES */
+ IC_EN_DISABLED_VAL = 0,
+ IC_EN_DISABLED = (IC_EN_DISABLED_VAL << IC_EN_OFFSET),
+ IC_EN_MASK = (1 << IC_EN_OFFSET),
+ /* IC_TX_ABRT_SOURCE bits */
+ ABRT_7B_ADDR_NOACK = 1,
+};
+
+struct i2c_bus_data {
+ uint16_t hcnt;
+ uint16_t lcnt;
+ uint16_t sda_hold;
+};
+
+struct i2c_bus_info {
+ uint8_t bus_id;
+ struct i2c_bus_data std_speed;
+ struct i2c_bus_data fast_speed;
+ struct i2c_bus_data high_speed;
+} __attribute__ ((__packed__));
+
+struct i2c_context {
+ uint32_t *base;
+ uint8_t max_rx_depth;
+ uint8_t max_tx_depth;
+ uint8_t bus;
+ uint32_t interrupts;
+ uint32_t reason;
+ uint8_t error_flag;
+ uint8_t speed;
+ task_id_t wait_task_id;
+};
+
+#endif /* __CROS_EC_ISH_I2C_H */
diff --git a/chip/ish/jtag.c b/chip/ish/jtag.c
new file mode 100644
index 0000000000..168364b6e1
--- /dev/null
+++ b/chip/ish/jtag.c
@@ -0,0 +1,13 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+/* Settings to enable JTAG debugging */
+
+#include "jtag.h"
+#include "registers.h"
+
+void jtag_pre_init(void)
+{
+ /* Not implemented yet */
+}
diff --git a/chip/ish/registers.h b/chip/ish/registers.h
new file mode 100644
index 0000000000..f92770ddbd
--- /dev/null
+++ b/chip/ish/registers.h
@@ -0,0 +1,105 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Registers and interrupts for Intel(R) Integrated Sensor Hub
+ */
+
+#ifndef __CROS_EC_REGISTERS_H
+#define __CROS_EC_REGISTERS_H
+
+#ifndef __ASSEMBLER__
+#include "common.h"
+
+/*
+ * ISH3.0 has 3 controllers. Locking must occur by-controller (not by-port).
+ */
+enum ish_i2c_port {
+ ISH_I2C0 = 0, /* Controller 0 */
+ ISH_I2C1 = 1, /* Controller 1 */
+ ISH_I2C2 = 2, /* Controller 2 */
+ I2C_PORT_COUNT,
+};
+#endif
+
+#define ISH_I2C_PORT_COUNT I2C_PORT_COUNT
+
+/* In ISH, the devices are mapped to pre-defined addresses in the 32-bit
+ * linear address space.
+ */
+#define ISH_I2C0_BASE 0x00100000
+#define ISH_I2C1_BASE 0x00102000
+#define ISH_I2C2_BASE 0x00105000
+#define ISH_UART_BASE 0x00103000
+#define ISH_IPC_BASE 0x00B00000
+#define ISH_IOAPIC_BASE 0xFEC00000
+#define ISH_HPET_BASE 0xFED00000
+#define ISH_LAPIC_BASE 0xFEE00000
+
+/* HW interrupt pins mapped to IOAPIC, from I/O sources */
+#define ISH_I2C0_IRQ 0
+#define ISH_I2C1_IRQ 1
+#define ISH_HPET_TIMER1_IRQ 8
+#define ISH_HPET_TIMER2_IRQ 11
+#define ISH_IPC_HOST2ISH_IRQ 12
+#define ISH_IPC_ISH2HOST_CLR_IRQ 24
+#define ISH_UART0_IRQ 34
+#define ISH_UART1_IRQ 35
+#define ISH_I2C2_IRQ 40
+#define ISH_HPET_TIMER0_IRQ 55
+
+/* Interrupt vectors 0-31 are architecture reserved.
+ * Vectors 32-255 are user-defined.
+ */
+#define USER_VEC_START 32
+/* Map IRQs to vectors after offset 10 for certain APIC interrupts */
+#define IRQ_TO_VEC(irq) (irq + USER_VEC_START + 10)
+
+/* APIC interrupt vectors */
+#define ISH_TS_VECTOR 0x20 /* Task switch vector */
+#define LAPIC_LVT_ERROR_VECTOR 0x21
+#define LAPIC_SPURIOUS_INT_VECTOR 0xff
+
+/* Interrupt to vector mapping. To be programmed into IOAPIC */
+#define ISH_I2C0_VEC IRQ_TO_VEC(ISH_I2C0_IRQ)
+#define ISH_I2C1_VEC IRQ_TO_VEC(ISH_I2C1_IRQ)
+#define ISH_I2C2_VEC IRQ_TO_VEC(ISH_I2C2_IRQ)
+#define ISH_HPET_TIMER0_VEC IRQ_TO_VEC(ISH_HPET_TIMER0_IRQ)
+#define ISH_HPET_TIMER1_VEC IRQ_TO_VEC(ISH_HPET_TIMER1_IRQ)
+#define ISH_HPET_TIMER2_VEC IRQ_TO_VEC(ISH_HPET_TIMER2_IRQ)
+#define ISH_IPC_ISH2HOST_CLR_VEC IRQ_TO_VEC(ISH_IPC_ISH2HOST_CLR_IRQ)
+#define ISH_UART0_VEC IRQ_TO_VEC(ISH_UART0_IRQ)
+#define ISH_UART1_VEC IRQ_TO_VEC(ISH_UART1_IRQ)
+#define ISH_IPC_VEC IRQ_TO_VEC(ISH_IPC_HOST2ISH_IRQ)
+
+/* IPC_Registers */
+#define IPC_PISR (ISH_IPC_BASE + 0x0)
+#define IPC_PIMR (ISH_IPC_BASE + 0x4)
+#define IPC_ISH2HOST_MSG_REGS (ISH_IPC_BASE + 0x60)
+#define IPC_ISH_FWSTS (ISH_IPC_BASE + 0x34)
+#define IPC_HOST2ISH_DOORBELL (ISH_IPC_BASE + 0x48)
+#define IPC_HOST2ISH_MSG_REGS (ISH_IPC_BASE + 0xE0)
+#define IPC_ISH2HOST_DOORBELL (ISH_IPC_BASE + 0x54)
+#define IPC_BUSY_CLEAR (ISH_IPC_BASE + 0x378)
+
+/* IOAPIC registers */
+#define IOAPIC_IDX 0xFEC00000
+#define IOAPIC_WDW 0xFEC00010
+#define IOAPIC_EOI_REG 0xFEC00040
+
+#define IOAPIC_VERSION 0x1
+#define IOAPIC_IOREDTBL 0x10
+#define IOAPIC_REDTBL_DELMOD_FIXED 0x00000000
+#define IOAPIC_REDTBL_DESTMOD_PHYS 0x00000000
+#define IOAPIC_REDTBL_INTPOL_HIGH 0x00000000
+#define IOAPIC_REDTBL_INTPOL_LOW 0x00002000
+#define IOAPIC_REDTBL_TRIGGER_EDGE 0x00000000
+#define IOAPIC_REDTBL_TRIGGER_LEVEL 0x00008000
+#define IOAPIC_REDTBL_MASK 0x00010000
+
+/* LAPIC registers */
+#define LAPIC_EOI_REG 0xFEE000B0
+#define LAPIC_ISR_REG 0xFEE00170
+#define LAPIC_ICR_REG (ISH_LAPIC_BASE + 0x300)
+
+#endif /* __CROS_EC_REGISTERS_H */
diff --git a/chip/ish/system.c b/chip/ish/system.c
new file mode 100644
index 0000000000..75f1d5a4a8
--- /dev/null
+++ b/chip/ish/system.c
@@ -0,0 +1,120 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* System module ISH (Not implemented) */
+
+#include "clock.h"
+#include "common.h"
+#include "console.h"
+#include "cpu.h"
+#include "gpio.h"
+#include "host_command.h"
+#include "registers.h"
+#include "shared_mem.h"
+#include "system.h"
+#include "hooks.h"
+#include "task.h"
+#include "timer.h"
+#include "util.h"
+#include "spi.h"
+
+/* Indices for hibernate data registers (RAM backed by VBAT) */
+enum hibdata_index {
+ HIBDATA_INDEX_SCRATCHPAD = 0, /* General-purpose scratchpad */
+ HIBDATA_INDEX_SAVED_RESET_FLAGS /* Saved reset flags */
+};
+
+int system_is_reboot_warm(void)
+{
+ return 0;
+}
+
+void system_pre_init(void)
+{
+}
+
+void chip_save_reset_flags(int flags)
+{
+}
+
+void _system_reset(int flags, int wake_from_hibernate)
+{
+}
+
+void system_reset(int flags)
+{
+ _system_reset(flags, 0);
+}
+
+const char *system_get_chip_vendor(void)
+{
+ return "intel";
+}
+
+const char *system_get_chip_name(void)
+{
+ return "intel";
+}
+
+static char to_hex(int x)
+{
+ if (x >= 0 && x <= 9)
+ return '0' + x;
+ return 'a' + x - 10;
+}
+
+const char *system_get_chip_revision(void)
+{
+ static char buf[3];
+ uint8_t rev = 0x86;
+
+ buf[0] = to_hex(rev / 16);
+ buf[1] = to_hex(rev & 0xf);
+ buf[2] = '\0';
+ return buf;
+}
+
+int system_get_vbnvcontext(uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
+int system_set_vbnvcontext(const uint8_t *block)
+{
+ return EC_ERROR_UNIMPLEMENTED;
+}
+
+int system_set_scratchpad(uint32_t value)
+{
+ return EC_SUCCESS;
+}
+
+uint32_t system_get_scratchpad(void)
+{
+ return 0;
+}
+
+void system_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+}
+
+void htimer_interrupt(void)
+{
+ /* Time to wake up */
+}
+
+enum system_image_copy_t system_get_shrspi_image_copy(void)
+{
+ return 0;
+}
+
+uint32_t system_get_lfw_address(void)
+{
+ return 0;
+}
+
+void system_set_image_copy(enum system_image_copy_t copy)
+{
+}
diff --git a/chip/ish/uart.c b/chip/ish/uart.c
new file mode 100644
index 0000000000..bb12624bcf
--- /dev/null
+++ b/chip/ish/uart.c
@@ -0,0 +1,243 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* UART module for ISH */
+#include "common.h"
+#include "console.h"
+#include "uart_defs.h"
+#include "atomic.h"
+#include "task.h"
+#include "registers.h"
+#include "uart.h"
+#include "uart_defs.h"
+#include "interrupts.h"
+
+#define CPUTS(outstr) cputs(CC_LPC, outstr)
+#define CPRINTS(format, args...) cprints(CC_LPC, format, ## args)
+#define CPRINTF(format, args...) cprintf(CC_LPC, format, ## args)
+
+static const uint32_t baud_conf[][BAUD_TABLE_MAX] = {
+ {B9600, 9600},
+ {B57600, 57600},
+ {B115200, 115200},
+ {B921600, 921600},
+ {B2000000, 2000000},
+ {B3000000, 3000000},
+ {B3250000, 3250000},
+ {B3500000, 3500000},
+ {B4000000, 4000000},
+ {B19200, 19200},
+};
+
+static struct uart_ctx uart_ctx[UART_DEVICES] = {
+ {
+ .id = 0,
+ .base = UART0_BASE,
+ .input_freq = UART_ISH_INPUT_FREQ,
+ .addr_interval = UART_ISH_ADDR_INTERVAL,
+ .uart_state = UART_STATE_CG,
+ },
+ {
+ .id = 1,
+ .base = UART1_BASE,
+ .input_freq = UART_ISH_INPUT_FREQ,
+ .addr_interval = UART_ISH_ADDR_INTERVAL,
+ .uart_state = UART_STATE_CG,
+ }
+};
+
+static int init_done;
+
+int uart_init_done(void)
+{
+ return init_done;
+}
+
+void uart_tx_start(void)
+{
+ /* TBD for RX and interrupt enabled TX */
+}
+
+void uart_tx_stop(void)
+{
+ /* TBD for RX and interrupt enabled TX */
+}
+
+void uart_tx_flush(void)
+{
+ /* TBD for RX and interrupt enabled TX */
+}
+
+int uart_tx_ready(void)
+{
+ return 1;
+}
+
+int uart_rx_available(void)
+{
+ /* No RX FIFO */
+ return 0;
+}
+
+void uart_write_char(char c)
+{
+ int id = 1; /* In ISH, UART1 is assigned for console outpu */
+
+ /* Wait till reciever is ready */
+ while ((REG8(LSR(id)) & LSR_TEMT) == 0)
+ ;
+
+ REG8(THR(id)) = c;
+}
+
+static int uart_return_baud_rate_by_id(int baud_rate_id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(baud_conf); i++) {
+ if (baud_conf[i][BAUD_IDX] == baud_rate_id)
+ return baud_conf[i][BAUD_SPEED];
+ }
+
+ return -1;
+}
+
+static void uart_hw_init(enum UART_PORT id)
+{
+ uint32_t divisor; /* baud rate divisor */
+ uint8_t mcr = 0;
+ uint8_t fcr = 0;
+ struct uart_ctx *ctx = &uart_ctx[id];
+
+ interrupt_disable();
+
+ /* Calculate baud rate divisor */
+ divisor = (ctx->input_freq / ctx->baud_rate) >> 4;
+
+ REG32(MUL(ctx->id)) = (divisor * ctx->baud_rate);
+ REG32(DIV(ctx->id)) = (ctx->input_freq / 16);
+ REG32(PS(ctx->id)) = 16;
+
+ /* Set the DLAB to access the baud rate divisor registers */
+ REG8(LCR(ctx->id)) = LCR_DLAB;
+ REG8(DLL(ctx->id)) = (divisor & 0xff);
+ REG8(DLH(ctx->id)) = ((divisor >> 8) & 0xff);
+
+ /* 8 data bits, 1 stop bit, no parity, clear DLAB */
+ REG8(LCR(ctx->id)) = LCR_8BIT_CHR;
+
+ if (ctx->client_flags & UART_CONFIG_HW_FLOW_CONTROL)
+ mcr = MCR_AUTO_FLOW_EN;
+
+ mcr |= MCR_INTR_ENABLE; /* needs to be set regardless of flow control */
+
+ mcr |= (MCR_RTS | MCR_DTR);
+ REG8(MCR(ctx->id)) = mcr;
+
+ fcr = FCR_FIFO_SIZE_64 | FCR_ITL_FIFO_64_BYTES_1;
+
+ /* configure FIFOs */
+ REG8(FCR(ctx->id)) = (fcr | FCR_FIFO_ENABLE
+ | FCR_RESET_RX | FCR_RESET_TX);
+
+ /* enable UART unit */
+ REG32(ABR(ctx->id)) = ABR_UUE;
+
+ /* clear the port */
+ REG8(RBR(ctx->id));
+ REG8(IER(ctx->id)) = 0x00;
+
+ interrupt_enable();
+}
+
+static void uart_stop_hw(enum UART_PORT id)
+{
+ int i;
+ uint32_t fifo_len;
+
+ /* Manually clearing the fifo from possible noise.
+ * Entering D0i3 when fifo is not cleared may result in a hang.
+ */
+ fifo_len = (REG32(FOR(id)) & FOR_OCCUPANCY_MASK) >> FOR_OCCUPANCY_OFFS;
+
+ for (i = 0; i < fifo_len; i++)
+ (void)REG8(RBR(id));
+
+ /* No interrupts are enabled */
+ REG8(IER(id)) = 0;
+ REG8(MCR(id)) = 0;
+
+ /* Clear and disable FIFOs */
+ REG8(FCR(id)) = (FCR_RESET_RX | FCR_RESET_TX);
+
+ /* Disable uart unit */
+ REG32(ABR(id)) = 0;
+}
+
+static int uart_client_init(enum UART_PORT id, uint32_t baud_rate_id, int flags)
+{
+
+ if ((uart_ctx[id].base == 0) || (id >= UART_DEVICES))
+ return UART_ERROR;
+
+ if (!bool_compare_and_swap_u32(&uart_ctx[id].is_open, 0, 1))
+ return UART_BUSY;
+
+ uart_ctx[id].baud_rate = uart_return_baud_rate_by_id(baud_rate_id);
+
+ if ((uart_ctx[id].baud_rate == -1) || (uart_ctx[id].baud_rate == 0))
+ uart_ctx[id].baud_rate = UART_DEFAULT_BAUD_RATE;
+
+ uart_ctx[id].client_flags = flags;
+
+ atomic_and(&uart_ctx[id].uart_state, ~UART_STATE_CG);
+ uart_hw_init(id);
+
+ return EC_SUCCESS;
+}
+
+static void uart_drv_init(void)
+{
+ int i;
+ uint32_t fifo_len;
+
+ /* Disable UART */
+ for (i = 0; i < UART_DEVICES; i++)
+ uart_stop_hw(i);
+
+ /* Enable HSU global interrupts (DMA/U0/U1) and set PMEN bit
+ * to allow PMU to clock gate ISH
+ */
+ REG32(HSU_BASE + HSU_REG_GIEN) = (GIEN_DMA_EN | GIEN_UART0_EN
+ | GIEN_UART1_EN | GIEN_PWR_MGMT);
+
+ /* There is a by design HW "bug" where all UARTs are enabled by default
+ * but they must be disbled to enter clock gating.
+ * UART0 and UART1 are disabled during their init - but we don't init
+ * UART2 so as a w/a we disable UART2 even though it isn't being used.
+ * we also clear UART 2 fifo, which may cause problem entrying TCG is
+ * not empty (we do the same for UART0 and 1 in "uart_stop_hw"
+ */
+
+ fifo_len = (REG32(UART2_BASE + UART_REG_FOR)
+ & FOR_OCCUPANCY_MASK) >> FOR_OCCUPANCY_OFFS;
+
+ for (i = 0; i < fifo_len; i++)
+ (void)REG8((UART2_BASE + UART_REG_RBR));
+
+ REG32(UART2_BASE + UART_REG_ABR) = 0;
+
+ task_enable_irq(ISH_UART0_IRQ);
+ task_enable_irq(ISH_UART1_IRQ);
+}
+
+void uart_init(void)
+{
+
+ uart_drv_init();
+
+ uart_client_init(UART_PORT_1, B115200, 0);
+ init_done = 1;
+}
diff --git a/chip/ish/uart_defs.h b/chip/ish/uart_defs.h
new file mode 100644
index 0000000000..8c431e21a8
--- /dev/null
+++ b/chip/ish/uart_defs.h
@@ -0,0 +1,222 @@
+/* Copyright (c) 2016 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* UART module for ISH */
+
+#ifndef __CROS_EC_UART_DEFS_H_
+#define __CROS_EC_UART_DEFS_H_
+
+#include <stdint.h>
+#include <stddef.h>
+
+#define UART_ERROR -1
+#define UART_BUSY -2
+#define HSU_BASE ISH_UART_BASE
+#define UART0_OFFS (0x80)
+#define UART0_BASE (ISH_UART_BASE + UART0_OFFS)
+#define UART0_SIZE (0x80)
+
+#define UART1_OFFS (0x100)
+#define UART1_BASE (ISH_UART_BASE + UART1_OFFS)
+#define UART1_SIZE (0x80)
+
+#define UART2_OFFS (0x180)
+#define UART2_BASE (ISH_UART_BASE + UART2_OFFS)
+#define UART2_SIZE (0x80)
+
+/* Register accesses */
+#define LSR(n) (uart_ctx[n].base + UART_REG_LSR * uart_ctx[n].addr_interval)
+#define THR(n) (uart_ctx[n].base + UART_REG_THR * uart_ctx[n].addr_interval)
+#define FOR(n) (uart_ctx[n].base + UART_REG_FOR * uart_ctx[n].addr_interval)
+#define RBR(n) (uart_ctx[n].base + UART_REG_RBR * uart_ctx[n].addr_interval)
+#define DLL(n) (uart_ctx[n].base + UART_REG_DLL * uart_ctx[n].addr_interval)
+#define DLH(n) (uart_ctx[n].base + UART_REG_DLH * uart_ctx[n].addr_interval)
+#define DLD(n) (uart_ctx[n].base + UART_REG_DLD * uart_ctx[n].addr_interval)
+#define IER(n) (uart_ctx[n].base + UART_REG_IER * uart_ctx[n].addr_interval)
+#define IIR(n) (uart_ctx[n].base + UART_REG_IIR * uart_ctx[n].addr_interval)
+#define FCR(n) (uart_ctx[n].base + UART_REG_FCR * uart_ctx[n].addr_interval)
+#define LCR(n) (uart_ctx[n].base + UART_REG_LCR * uart_ctx[n].addr_interval)
+#define MCR(n) (uart_ctx[n].base + UART_REG_MCR * uart_ctx[n].addr_interval)
+#define MSR(n) (uart_ctx[n].base + UART_REG_MSR * uart_ctx[n].addr_interval)
+#define FCTR(n) (uart_ctx[n].base + UART_REG_FCTR * uart_ctx[n].addr_interval)
+#define EFR(n) (uart_ctx[n].base + UART_REG_EFR * uart_ctx[n].addr_interval)
+#define RXTRG(n) \
+ (uart_ctx[n].base + UART_REG_RXTRG * uart_ctx[n].addr_interval)
+#define ABR(n) (uart_ctx[n].base + UART_REG_ABR * uart_ctx[n].addr_interval)
+#define PS(n) (uart_ctx[n].base + UART_REG_PS * uart_ctx[n].addr_interval)
+#define MUL(n) (uart_ctx[n].base + UART_REG_MUL * uart_ctx[n].addr_interval)
+#define DIV(n) (uart_ctx[n].base + UART_REG_DIV * uart_ctx[n].addr_interval)
+
+/* RBR: Receive Buffer register (BLAB bit = 0) */
+#define UART_REG_RBR (0)
+/* THR: Transmit Holding register (BLAB bit = 0) */
+#define UART_REG_THR (0)
+/* IER: Interrupt Enable register (BLAB bit = 0) */
+#define UART_REG_IER (1)
+
+#define FCR_FIFO_SIZE_16 (0x00)
+#define FCR_FIFO_SIZE_64 (0x20)
+#define FCR_ITL_FIFO_64_BYTES_1 (0x00)
+
+/* FCR: FIFO Control register */
+#define UART_REG_FCR (2)
+#define FCR_FIFO_ENABLE (0x01)
+#define FCR_RESET_RX (0x02)
+#define FCR_RESET_TX (0x04)
+
+/* LCR: Line Control register */
+#define UART_REG_LCR (3)
+#define LCR_DLAB (0x80)
+#define LCR_5BIT_CHR (0x00)
+#define LCR_6BIT_CHR (0x01)
+#define LCR_7BIT_CHR (0x02)
+#define LCR_8BIT_CHR (0x03)
+#define LCR_BIT_CHR_MASK (0x03)
+#define LCR_SB (0x40) /*Set Break */
+
+/* MCR: Modem Control register */
+#define UART_REG_MCR (4)
+#define MCR_DTR (0x1)
+#define MCR_RTS (0x2)
+#define MCR_LOO (0x10)
+#define MCR_INTR_ENABLE (0x08)
+#define MCR_AUTO_FLOW_EN (0x20)
+
+/* LSR: Line Status register */
+#define UART_REG_LSR (5)
+#define LSR_DR (0x01) /* Data Ready */
+#define LSR_OE (0x02) /* Overrun error */
+#define LSR_PE (0x04) /* Parity error */
+#define LSR_FE (0x08) /* Framing error */
+#define LSR_BI (0x10) /* Breaking interrupt */
+#define LSR_THR_EMPTY (0x20) /* Non FIFO mode: Transmit holding
+ * register empty
+ */
+#define LSR_TDRQ (0x20) /* FIFO mode: Transmit Data request */
+#define LSR_TEMT (0x40) /* Transmitter empty */
+
+#define FCR_ITL_FIFO_64_BYTES_56 (0xc0)
+
+#define IER_RECV (0x01)
+#define IER_TDRQ (0x02)
+#define IER_LINE_STAT (0x04)
+
+#define UART_REG_IIR (2)
+/* MSR: Modem Status register */
+#define UART_REG_MSR (6)
+
+/* DLL: Divisor Latch Reg. low byte (BLAB bit = 1) */
+#define UART_REG_DLL (0)
+
+/* DLH: Divisor Latch Reg. high byte (BLAB bit = 1) */
+#define UART_REG_DLH (1)
+
+/* DLH: Divisor Latch Fractional. (BLAB bit = 1) */
+#define UART_REG_DLD (2)
+
+/* FOR: Fifo O Register (ISH only) */
+#define UART_REG_FOR (0x20)
+#define FOR_OCCUPANCY_OFFS 0
+#define FOR_OCCUPANCY_MASK 0x7F
+
+/* ABR: Auto-Baud Control Register (ISH only) */
+#define UART_REG_ABR (0x24)
+#define ABR_UUE (0x10)
+
+/* Pre-Scalar Register (ISH only) */
+#define UART_REG_PS (0x30)
+
+/* DDS registers (ISH only) */
+#define UART_REG_MUL (0x34)
+#define UART_REG_DIV (0x38)
+
+/* G_IEN: Global Interrupt Enable (ISH only) */
+#define HSU_REG_GIEN (0)
+#define HSU_REG_GIST (4)
+
+#define GIEN_PWR_MGMT (0x01000000)
+#define GIEN_DMA_EN (0x00000020)
+#define GIEN_UART2_EN (0x00000004)
+#define GIEN_UART1_EN (0x00000002)
+#define GIEN_UART0_EN (0x00000001)
+#define GIST_DMA_EN (0x00000020)
+#define GIST_UART2_EN (0x00000004)
+#define GIST_UART1_EN (0x00000002)
+#define GIST_UART0_EN (0x00000001)
+#define GIST_UARTx_EN (GIST_UART0_EN|GIST_UART1_EN|GIST_UART2_EN)
+
+/* UART config flag, send to sc_io_control if the current UART line has HW
+ * flow control lines connected.
+ */
+#define UART_CONFIG_HW_FLOW_CONTROL (1<<0)
+
+ /* UART config flag for sc_io_control. If defined a sc_io_event_rx_msg is
+ * raised only when the rx buffer is completely full. Otherwise, the event
+ * is raised after a timeout is received on the UART line,
+ * and all data received until now is provided.
+ */
+#define UART_CONFIG_DELIVER_FULL_RX_BUF (1<<1)
+
+/* UART config flag for sc_io_control. If defined a sc_io_event_rx_buf_depleted
+ * is raised when all rx buffers that were added are full. Otherwise, no
+ * event is raised.
+ */
+#define UART_CONFIG_ANNOUNCE_DEPLETED_BUF (1<<2)
+
+#define UART_INT_DEVICES 2
+#define UART_EXT_DEVICES 8
+#define UART_DEVICES UART_INT_DEVICES
+#define UART_ISH_ADDR_INTERVAL 1
+
+#define B9600 0x0000d
+#define B57600 0x00000018
+#define B115200 0x00000011
+#define B921600 0x00000012
+#define B2000000 0x00000013
+#define B3000000 0x00000014
+#define B3250000 0x00000015
+#define B3500000 0x00000016
+#define B4000000 0x00000017
+#define B19200 0x0000e
+#define B38400 0x0000f
+
+/* KHZ, MHZ */
+#define KHZ(x) ((x) * 1000)
+#define MHZ(x) (KHZ(x) * 1000)
+#define UART_ISH_INPUT_FREQ MHZ(120)
+#define UART_DEFAULT_BAUD_RATE 115200
+#define UART_STATE_CG (1 << UART_OP_CG)
+
+enum UART_PORT {
+ UART_PORT_0,
+ UART_PORT_1,
+ UART_PORT_MAX
+};
+
+enum UART_OP {
+ UART_OP_READ,
+ UART_OP_WRITE,
+ UART_OP_CG,
+ UART_OP_MAX
+};
+
+enum {
+ BAUD_IDX,
+ BAUD_SPEED,
+ BAUD_TABLE_MAX
+};
+
+struct uart_ctx {
+ uint32_t id;
+ uint32_t base;
+ uint32_t addr_interval;
+ uint32_t uart_state;
+ uint32_t is_open;
+ uint32_t baud_rate;
+ uint32_t input_freq;
+ uint32_t client_flags;
+};
+
+#endif /* _CROS_EC_UART_DEFS_H_ */