summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJaiber John <jaiber.j.john@intel.com>2016-03-31 23:49:53 +0530
committerchrome-bot <chrome-bot@chromium.org>2016-11-04 18:31:29 -0700
commitd7b938f857755a6a9a7ffbe9f281a14821675a9f (patch)
tree829973af641af0124b847871248e7a9b4027456a
parentcbae8f9b321f33734a34cb85c82636bbfa7663ee (diff)
downloadchrome-ec-d7b938f857755a6a9a7ffbe9f281a14821675a9f.tar.gz
ish: Add support for ISH chip
This patch adds the initial support for ISH chip to enable the EC firmware to boot on Intel Integrated Sensor Hub (ISH). The following are enabled: 1. Inter-Processor Communication (IPC) driver that enables the ISH to communicate with the host Operating system via shared registers. 2. High Precision Event Timer (HPET) driver that provides configurable timers for the FW to use in task scheduling. 3. I2C bus driver for accessing sensors. 4. UART console driver with TX support only. BUG=chrome-os-partner:51851 BRANCH=None TEST=`make buildall -j` Change-Id: I15d4c201b799cfa79bed220ee573b75f5cd7b1f7 Signed-off-by: Jaiber John <jaiber.j.john@intel.com> Signed-off-by: Alex Brill <alexander.brill@intel.com> Signed-off-by: Gomathi Kumar <gomathi.kumar@intel.com> Reviewed-on: https://chromium-review.googlesource.com/336710 Commit-Ready: Raj Mojumder <raj.mojumder@intel.com> Tested-by: Jaiber J John <jaiber.j.john@intel.com> Tested-by: Raj Mojumder <raj.mojumder@intel.com> Reviewed-by: Jaiber J John <jaiber.j.john@intel.com> Reviewed-by: Raj Mojumder <raj.mojumder@intel.com> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
-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_ */