summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2014-05-21 07:32:59 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-06-05 04:22:56 +0000
commit31369a69dbf34cff8d9135f5d503efa717e3da35 (patch)
treea77f2778fb71da215b5d8748a551d49e21e51e89
parent565f1cb5ae1ebd287e1bf00ab8245274a5ecbaa6 (diff)
downloadchrome-ec-31369a69dbf34cff8d9135f5d503efa717e3da35.tar.gz
samus: Add EC <-> PD i2c interface using host commands
Initial support for EC to PD communication using host command interface over i2c. BUG=chrome-os-partner:28351, chrome-os-partner:28352 BRANCH=none TEST=on EC console send hello host command: > pdcmd 0x01 0 0xa0 0xb0 0xc0 0xd0 Host command 0x01, returned 4 a4 b3 c2 d1 Change-Id: I0969808f455574ee456d6db8a60ce9b1204a0739 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/200786 Reviewed-by: Randall Spangler <rspangler@chromium.org>
-rw-r--r--board/samus/board.h2
-rw-r--r--board/samus_pd/board.h3
-rw-r--r--board/samus_pd/ec.tasklist1
-rw-r--r--chip/stm32/i2c-stm32f0.c194
-rw-r--r--chip/stm32/registers.h19
-rw-r--r--common/build.mk1
-rw-r--r--common/host_command.c10
-rw-r--r--common/host_command_master.c185
-rw-r--r--include/config.h6
-rw-r--r--include/host_command.h14
10 files changed, 433 insertions, 2 deletions
diff --git a/board/samus/board.h b/board/samus/board.h
index 2ec8fc899a..0b72482f9e 100644
--- a/board/samus/board.h
+++ b/board/samus/board.h
@@ -43,6 +43,7 @@
#define CONFIG_CHARGER_INPUT_CURRENT 2000
#define CONFIG_CHARGER_DISCHARGE_ON_AC
#define CONFIG_FANS 2
+#define CONFIG_HOST_CMD_MASTER
#define CONFIG_PECI_TJMAX 100
#define CONFIG_PWM
#define CONFIG_PWM_KBLIGHT
@@ -64,6 +65,7 @@
#define I2C_PORT_BACKLIGHT 0
#define I2C_PORT_BATTERY 0
#define I2C_PORT_CHARGER 0
+#define I2C_PORT_PD_MCU 0
#define I2C_PORT_ALS 1
#define I2C_PORT_ACCEL 1
#define I2C_PORT_LIGHTBAR 1
diff --git a/board/samus_pd/board.h b/board/samus_pd/board.h
index 265f3e18a0..65218b5b57 100644
--- a/board/samus_pd/board.h
+++ b/board/samus_pd/board.h
@@ -31,9 +31,8 @@
/* I2C ports configuration */
#define I2C_PORT_MASTER 1
-#define I2C_PORT_BATTERY I2C_PORT_MASTER
-#define I2C_PORT_CHARGER I2C_PORT_MASTER
#define I2C_PORT_SLAVE 0
+#define I2C_PORT_EC I2C_PORT_SLAVE
/*
* Allow dangerous commands all the time, since we don't have a write protect
diff --git a/board/samus_pd/ec.tasklist b/board/samus_pd/ec.tasklist
index a8250d57c1..1dbac0ba02 100644
--- a/board/samus_pd/ec.tasklist
+++ b/board/samus_pd/ec.tasklist
@@ -18,5 +18,6 @@
*/
#define CONFIG_TASK_LIST \
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
+ TASK_NOTEST(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
TASK_ALWAYS(CONSOLE, console_task, NULL, LARGER_TASK_STACK_SIZE) \
TASK_ALWAYS(PD, pd_task, NULL, TASK_STACK_SIZE)
diff --git a/chip/stm32/i2c-stm32f0.c b/chip/stm32/i2c-stm32f0.c
index cd93965503..ab41b65b71 100644
--- a/chip/stm32/i2c-stm32f0.c
+++ b/chip/stm32/i2c-stm32f0.c
@@ -9,6 +9,7 @@
#include "console.h"
#include "gpio.h"
#include "hooks.h"
+#include "host_command.h"
#include "i2c.h"
#include "registers.h"
#include "task.h"
@@ -25,6 +26,12 @@
/* Transmit timeout in microseconds */
#define I2C_TX_TIMEOUT_MASTER (10 * MSEC)
+/*
+ * Max data size for a version 3 request/response packet. This is
+ * big enough for EC_CMD_GET_VERSION plus header info.
+ */
+#define I2C_MAX_HOST_PACKET_SIZE 128
+
/**
* Wait for ISR register to contain the specified mask.
*
@@ -92,6 +99,10 @@ static void i2c_init_port(const struct i2c_port_t *p)
if (!(STM32_RCC_APB1ENR & (1 << (21 + port))))
STM32_RCC_APB1ENR |= 1 << (21 + port);
+ /* Default clock to i2c port 0 is HSI (8MHz). Change to SYSCLK. */
+ if (port == 0)
+ STM32_RCC_CFGR3 |= 0x10;
+
/* Configure GPIOs */
gpio_config_module(MODULE_I2C, 1);
@@ -100,6 +111,160 @@ static void i2c_init_port(const struct i2c_port_t *p)
}
/*****************************************************************************/
+#ifdef HAS_TASK_HOSTCMD
+/* Host command slave */
+/* Buffer for host commands (including version, error code and checksum) */
+static uint8_t host_buffer[I2C_MAX_HOST_PACKET_SIZE];
+static uint8_t params_copy[I2C_MAX_HOST_PACKET_SIZE] __aligned(4);
+static int host_i2c_resp_port;
+static int tx_pending;
+static struct host_packet i2c_packet;
+
+static void i2c_send_response_packet(struct host_packet *pkt)
+{
+ int size = pkt->response_size;
+ uint8_t *out = host_buffer;
+ int i = 0;
+
+ /* Ignore host command in-progress */
+ if (pkt->driver_result == EC_RES_IN_PROGRESS)
+ return;
+
+ /* Write result and size to first two bytes. */
+ *out++ = pkt->driver_result;
+ *out++ = size;
+
+ /* Transmit data when I2C tx buffer is empty until finished. */
+ while ((i < size + 2) && tx_pending) {
+ if (STM32_I2C_ISR(host_i2c_resp_port) & STM32_I2C_CR1_TXIE)
+ STM32_I2C_TXDR(host_i2c_resp_port) = host_buffer[i++];
+
+ /* I2C is slow, so let other things run while we wait */
+ usleep(50);
+ }
+}
+
+/* Process the command in the i2c host buffer */
+static void i2c_process_command(void)
+{
+ char *buff = host_buffer;
+
+ /*
+ * TODO(crosbug.com/p/29241): Combine this functionality with the
+ * i2c_process_command function in chip/stm32/i2c-stm32f.c to make one
+ * host command i2c process function which handles all protocol
+ * versions.
+ */
+ if (*buff >= EC_COMMAND_PROTOCOL_3) {
+ i2c_packet.send_response = i2c_send_response_packet;
+
+ i2c_packet.request = (const void *)(&buff[1]);
+ i2c_packet.request_temp = params_copy;
+ i2c_packet.request_max = sizeof(params_copy);
+ /* Don't know the request size so pass in the entire buffer */
+ i2c_packet.request_size = I2C_MAX_HOST_PACKET_SIZE;
+
+ /*
+ * Stuff response at buff[2] to leave the first two bytes of
+ * buffer available for the result and size to send over i2c.
+ */
+ i2c_packet.response = (void *)(&buff[2]);
+ i2c_packet.response_max = I2C_MAX_HOST_PACKET_SIZE;
+ i2c_packet.response_size = 0;
+
+ i2c_packet.driver_result = EC_RES_SUCCESS;
+ } else {
+ /* Only host command protocol 3 is supported. */
+ i2c_packet.driver_result = EC_RES_INVALID_HEADER;
+ }
+ host_packet_receive(&i2c_packet);
+}
+
+static void i2c_event_handler(int port)
+{
+ int i2c_isr;
+ static int rx_pending, buf_idx;
+
+ i2c_isr = STM32_I2C_ISR(port);
+
+ /*
+ * Check for error conditions. Note, arbitration loss and bus error
+ * are the only two errors we can get as a slave allowing clock
+ * stretching and in non-SMBus mode.
+ */
+ if (i2c_isr & (STM32_I2C_ISR_ARLO | STM32_I2C_ISR_BERR)) {
+ rx_pending = 0;
+ tx_pending = 0;
+
+ /* Make sure TXIS interrupt is disabled */
+ STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_TXIE;
+
+ /* Clear error status bits */
+ STM32_I2C_ICR(port) |= STM32_I2C_ICR_BERRCF |
+ STM32_I2C_ICR_ARLOCF;
+ }
+
+ /* Transfer matched our slave address */
+ if (i2c_isr & STM32_I2C_ISR_ADDR) {
+ if (i2c_isr & STM32_I2C_ISR_DIR) {
+ /* Transmitter slave */
+ /* Clear transmit buffer */
+ STM32_I2C_ISR(port) |= STM32_I2C_ISR_TXE;
+
+ /* Enable txis interrupt to start response */
+ STM32_I2C_CR1(port) |= STM32_I2C_CR1_TXIE;
+ } else {
+ /* Receiver slave */
+ buf_idx = 0;
+ rx_pending = 1;
+ }
+
+ /* Clear ADDR bit by writing to ADDRCF bit */
+ STM32_I2C_ICR(port) |= STM32_I2C_ICR_ADDRCF;
+ }
+
+ /* Stop condition on bus */
+ if (i2c_isr & STM32_I2C_ISR_STOP) {
+ rx_pending = 0;
+ tx_pending = 0;
+
+ /* Make sure TXIS interrupt is disabled */
+ STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_TXIE;
+
+ /* Clear STOPF bit by writing to STOPCF bit */
+ STM32_I2C_ICR(port) |= STM32_I2C_ICR_STOPCF;
+ }
+
+ /* Receiver full event */
+ if (i2c_isr & STM32_I2C_ISR_RXNE)
+ host_buffer[buf_idx++] = STM32_I2C_RXDR(port);
+
+ /* Transmitter empty event */
+ if (i2c_isr & STM32_I2C_ISR_TXIS) {
+ if (port == I2C_PORT_EC) { /* host is waiting for PD response */
+ if (rx_pending) {
+ host_i2c_resp_port = port;
+ /*
+ * Disable TXIS interrupt, transmission will
+ * be done by host command task.
+ */
+ STM32_I2C_CR1(port) &= ~STM32_I2C_CR1_TXIE;
+
+ i2c_process_command();
+ /* Reset host buffer after end of transfer */
+ rx_pending = 0;
+ tx_pending = 1;
+ } else {
+ STM32_I2C_TXDR(port) = 0xec;
+ }
+ }
+ }
+}
+void i2c2_event_interrupt(void) { i2c_event_handler(I2C_PORT_EC); }
+DECLARE_IRQ(STM32_IRQ_I2C1, i2c2_event_interrupt, 2);
+#endif
+
+/*****************************************************************************/
/* Interface */
int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes,
@@ -255,5 +420,34 @@ static void i2c_init(void)
for (i = 0; i < i2c_ports_used; i++, p++)
i2c_init_port(p);
+
+#ifdef HAS_TASK_HOSTCMD
+ STM32_I2C_CR1(I2C_PORT_EC) |= STM32_I2C_CR1_RXIE | STM32_I2C_CR1_ERRIE
+ | STM32_I2C_CR1_ADDRIE | STM32_I2C_CR1_STOPIE;
+ STM32_I2C_OAR1(I2C_PORT_EC) = 0x8000 | CONFIG_USB_PD_I2C_SLAVE_ADDR;
+ task_enable_irq(STM32_IRQ_I2C1);
+#endif
}
DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT);
+
+/**
+ * Get protocol information
+ */
+static int i2c_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 = I2C_MAX_HOST_PACKET_SIZE;
+ r->max_response_packet_size = I2C_MAX_HOST_PACKET_SIZE;
+ r->flags = 0;
+
+ args->response_size = sizeof(*r);
+
+ return EC_SUCCESS;
+}
+DECLARE_HOST_COMMAND(EC_CMD_GET_PROTOCOL_INFO,
+ i2c_get_protocol_info,
+ EC_VER_MASK(0));
+
diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h
index c3e0f19e49..4e9dbd1419 100644
--- a/chip/stm32/registers.h
+++ b/chip/stm32/registers.h
@@ -407,6 +407,12 @@ typedef volatile struct timer_ctlr timer_ctlr_t;
#ifdef CHIP_FAMILY_STM32F0
#define STM32_I2C_CR1(n) REG32(stm32_i2c_reg(n, 0x00))
#define STM32_I2C_CR1_PE (1 << 0)
+#define STM32_I2C_CR1_TXIE (1 << 1)
+#define STM32_I2C_CR1_RXIE (1 << 2)
+#define STM32_I2C_CR1_ADDRIE (1 << 3)
+#define STM32_I2C_CR1_NACKIE (1 << 4)
+#define STM32_I2C_CR1_STOPIE (1 << 5)
+#define STM32_I2C_CR1_ERRIE (1 << 7)
#define STM32_I2C_CR2(n) REG32(stm32_i2c_reg(n, 0x04))
#define STM32_I2C_CR2_RD_WRN (1 << 10)
#define STM32_I2C_CR2_START (1 << 13)
@@ -419,15 +425,28 @@ typedef volatile struct timer_ctlr timer_ctlr_t;
#define STM32_I2C_TIMINGR(n) REG32(stm32_i2c_reg(n, 0x10))
#define STM32_I2C_TIMEOUTR(n) REG32(stm32_i2c_reg(n, 0x14))
#define STM32_I2C_ISR(n) REG32(stm32_i2c_reg(n, 0x18))
+#define STM32_I2C_ISR_TXE (1 << 0)
#define STM32_I2C_ISR_TXIS (1 << 1)
#define STM32_I2C_ISR_RXNE (1 << 2)
+#define STM32_I2C_ISR_ADDR (1 << 3)
#define STM32_I2C_ISR_NACK (1 << 4)
#define STM32_I2C_ISR_STOP (1 << 5)
#define STM32_I2C_ISR_TC (1 << 6)
#define STM32_I2C_ISR_BERR (1 << 8)
#define STM32_I2C_ISR_ARLO (1 << 9)
+#define STM32_I2C_ISR_OVR (1 << 10)
+#define STM32_I2C_ISR_PECERR (1 << 11)
+#define STM32_I2C_ISR_TIMEOUT (1 << 12)
+#define STM32_I2C_ISR_ALERT (1 << 13)
#define STM32_I2C_ISR_BUSY (1 << 15)
+#define STM32_I2C_ISR_DIR (1 << 16)
#define STM32_I2C_ICR(n) REG32(stm32_i2c_reg(n, 0x1C))
+#define STM32_I2C_ICR_ADDRCF (1 << 3)
+#define STM32_I2C_ICR_STOPCF (1 << 5)
+#define STM32_I2C_ICR_BERRCF (1 << 8)
+#define STM32_I2C_ICR_ARLOCF (1 << 9)
+#define STM32_I2C_ICR_OVRCF (1 << 10)
+#define STM32_I2C_ICR_TIMEOUTCF (1 << 12)
#define STM32_I2C_PECR(n) REG32(stm32_i2c_reg(n, 0x20))
#define STM32_I2C_RXDR(n) REG32(stm32_i2c_reg(n, 0x24))
#define STM32_I2C_TXDR(n) REG32(stm32_i2c_reg(n, 0x28))
diff --git a/common/build.mk b/common/build.mk
index e8a5900695..18c1c47579 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -43,6 +43,7 @@ common-$(CONFIG_EXTPOWER_SPRING)+=extpower_spring.o
common-$(CONFIG_FANS)+=fan.o
common-$(CONFIG_FLASH)+=flash.o
common-$(CONFIG_FMAP)+=fmap.o
+common-$(CONFIG_HOST_CMD_MASTER)+=host_command_master.o
common-$(CONFIG_I2C)+=i2c.o
common-$(CONFIG_I2C_ARBITRATION)+=i2c_arbitration.o
common-$(CONFIG_KEYBOARD_PROTOCOL_8042)+=keyboard_8042.o
diff --git a/common/host_command.c b/common/host_command.c
index 36344ac7ec..9f72fe7f43 100644
--- a/common/host_command.c
+++ b/common/host_command.c
@@ -166,6 +166,11 @@ void host_command_received(struct host_cmd_handler_args *args)
return;
}
+ /*
+ * TODO (crosbug.com/p/29315): This is typically running in interrupt
+ * context, so it woud be better not to send the response here, and to
+ * let the host command task send the response.
+ */
/* Send the response now */
host_send_response(args);
}
@@ -331,6 +336,11 @@ void host_packet_receive(struct host_packet *pkt)
return;
host_packet_bad:
+ /*
+ * TODO (crosbug.com/p/29315): This is typically running in interrupt
+ * context, so it woud be better not to send the response here, and to
+ * let the host command task send the response.
+ */
/* Improperly formed packet from host, so send an error response */
host_packet_respond(&args0);
}
diff --git a/common/host_command_master.c b/common/host_command_master.c
new file mode 100644
index 0000000000..55e3befbee
--- /dev/null
+++ b/common/host_command_master.c
@@ -0,0 +1,185 @@
+/* Copyright (c) 2014 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.
+ */
+
+/* Host command master module for Chrome EC */
+
+#include "common.h"
+#include "console.h"
+#include "host_command.h"
+#include "i2c.h"
+#include "util.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_HOSTCMD, outstr)
+#define CPRINTF(format, args...) cprintf(CC_HOSTCMD, format, ## args)
+
+/*
+ * Sends a command to the PD (protocol v3).
+ *
+ * Returns >= 0 for success, or negative if error.
+ */
+int pd_host_command(int command, int version,
+ const void *outdata, int outsize,
+ void *indata, int insize)
+{
+ int ret, i;
+ int resp_len;
+ struct ec_host_request rq;
+ struct ec_host_response rs;
+ static uint8_t req_buf[EC_LPC_HOST_PACKET_SIZE];
+ static uint8_t resp_buf[EC_LPC_HOST_PACKET_SIZE];
+ uint8_t sum = 0;
+ const uint8_t *c;
+ uint8_t *d;
+
+ /* Fail if output size is too big */
+ if (outsize + sizeof(rq) > EC_LPC_HOST_PACKET_SIZE)
+ return -EC_RES_REQUEST_TRUNCATED;
+
+ /* Fill in request packet */
+ rq.struct_version = EC_HOST_REQUEST_VERSION;
+ rq.checksum = 0;
+ rq.command = command;
+ rq.command_version = version;
+ rq.reserved = 0;
+ rq.data_len = outsize;
+
+ /* Copy data and start checksum */
+ for (i = 0, c = (const uint8_t *)outdata; i < outsize; i++, c++) {
+ req_buf[sizeof(rq) + 1 + i] = *c;
+ sum += *c;
+ }
+
+ /* Finish checksum */
+ for (i = 0, c = (const uint8_t *)&rq; i < sizeof(rq); i++, c++)
+ sum += *c;
+
+ /* Write checksum field so the entire packet sums to 0 */
+ rq.checksum = (uint8_t)(-sum);
+
+ /* Copy header */
+ for (i = 0, c = (const uint8_t *)&rq; i < sizeof(rq); i++, c++)
+ req_buf[1 + i] = *c;
+
+ /* Set command to use protocol v3 */
+ req_buf[0] = EC_COMMAND_PROTOCOL_3;
+
+ /*
+ * Transmit all data and receive 2 bytes for return value and response
+ * length.
+ */
+ i2c_lock(I2C_PORT_PD_MCU, 1);
+ ret = i2c_xfer(I2C_PORT_PD_MCU, CONFIG_USB_PD_I2C_SLAVE_ADDR,
+ &req_buf[0], outsize + sizeof(rq) + 1, &resp_buf[0],
+ 2, I2C_XFER_START);
+ i2c_lock(I2C_PORT_PD_MCU, 0);
+ if (ret) {
+ CPRINTF("[%T i2c transaction 1 failed: %d]\n", ret);
+ return -ret;
+ }
+
+ ret = resp_buf[0];
+ resp_len = resp_buf[1];
+
+ if (ret)
+ CPRINTF("[%T command 0x%02x returned error %d]\n", command,
+ ret);
+
+ if (resp_len > (insize + sizeof(rs))) {
+ CPRINTF("[%T response size is too large %d > %d]\n",
+ resp_len, insize + sizeof(rs));
+ return -EC_RES_RESPONSE_TOO_BIG;
+ }
+
+ /* Receive remaining data */
+ i2c_lock(I2C_PORT_PD_MCU, 1);
+ ret = i2c_xfer(I2C_PORT_PD_MCU, CONFIG_USB_PD_I2C_SLAVE_ADDR, 0, 0,
+ &resp_buf[2], resp_len, I2C_XFER_STOP);
+ i2c_lock(I2C_PORT_PD_MCU, 0);
+ if (ret) {
+ CPRINTF("[%T i2c transaction 2 failed: %d]\n", ret);
+ return -ret;
+ }
+
+ /* Read back response header and start checksum */
+ sum = 0;
+ for (i = 0, d = (uint8_t *)&rs; i < sizeof(rs); i++, d++) {
+ *d = resp_buf[i + 2];
+ sum += *d;
+ }
+
+ if (rs.struct_version != EC_HOST_RESPONSE_VERSION) {
+ CPRINTF("[%T PD response version mismatch]\n");
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ if (rs.reserved) {
+ CPRINTF("[%T PD response reserved != 0]\n");
+ return -EC_RES_INVALID_RESPONSE;
+ }
+
+ if (rs.data_len > insize) {
+ CPRINTF("[%T PD returned too much data]\n");
+ return -EC_RES_RESPONSE_TOO_BIG;
+ }
+
+ /* Read back data and update checksum */
+ resp_len -= sizeof(rs);
+ for (i = 0, d = (uint8_t *)indata; i < resp_len; i++, d++) {
+ *d = resp_buf[sizeof(rs) + i + 2];
+ sum += *d;
+ }
+
+
+ if ((uint8_t)sum) {
+ CPRINTF("[%T command 0x%02x bad checksum returned: "
+ "%d]\n", command, sum);
+ return -EC_RES_ERROR;
+ }
+
+ /* Return output buffer size */
+ return resp_len;
+}
+
+static int command_pd_mcu(int argc, char **argv)
+{
+ char *e;
+ static char outbuf[128];
+ static char inbuf[128];
+ int command, version;
+ int i, ret, tmp;
+
+ if (argc < 3)
+ return EC_ERROR_PARAM_COUNT;
+
+ command = strtoi(argv[1], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM1;
+
+ version = strtoi(argv[2], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ for (i = 3; i < argc; i++) {
+ tmp = strtoi(argv[i], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM3;
+ outbuf[i-3] = tmp;
+ }
+
+ ret = pd_host_command(command, version, &outbuf, argc - 3, &inbuf,
+ sizeof(inbuf));
+
+ ccprintf("Host command 0x%02x, returned %d\n", command, ret);
+ for (i = 0; i < ret; i++)
+ ccprintf("0x%02x\n", inbuf[i]);
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(pdcmd, command_pd_mcu,
+ "cmd ver [params]",
+ "Send PD host command",
+ NULL);
+
diff --git a/include/config.h b/include/config.h
index 4700e00dbb..86b43d2509 100644
--- a/include/config.h
+++ b/include/config.h
@@ -496,6 +496,9 @@
/*****************************************************************************/
+/* Support EC acting as host master for other MCUs. */
+#undef CONFIG_HOST_CMD_MASTER
+
/*
* Support the host asking the EC about the status of the most recent host
* command.
@@ -860,6 +863,9 @@
/* USB PD transmit uses SPI master */
#undef CONFIG_USB_PD_TX_USES_SPI_MASTER
+/* USB PD MCU slave address for host commands */
+#define CONFIG_USB_PD_I2C_SLAVE_ADDR 0x3c
+
/* Support simple control of power to the device's USB ports */
#undef CONFIG_USB_PORT_POWER_DUMB
diff --git a/include/host_command.h b/include/host_command.h
index 158367a80b..1fbf0b6554 100644
--- a/include/host_command.h
+++ b/include/host_command.h
@@ -207,4 +207,18 @@ void host_packet_receive(struct host_packet *pkt);
*/
void host_throttle_cpu(int throttle);
+/**
+ * Send host command to PD MCU.
+ *
+ * @param command Host command number
+ * @param version Version of host command
+ * @param outdata Pointer to buffer of out data
+ * @param outsize Size of buffer to out data
+ * @param indata Pointer to buffer to store response
+ * @param insize Size of buffer to store response
+ */
+int pd_host_command(int command, int version,
+ const void *outdata, int outsize,
+ void *indata, int insize);
+
#endif /* __CROS_EC_HOST_COMMAND_H */