mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-06 15:01:35 +00:00
chip: it83xx: add USBPD module
Add USBPD module for it8320 emulation board
BRANCH=none
BUG=none
TEST=manual
plug zinger adapter, connect uart console and type commands:
pd 1 dev [20|12|5]
pd 1 charger
pd 1 swap power
and check PD states
Change-Id: I9ca1822deeb4b4dce1279a09490ed4175890cf3a
Signed-off-by: Leon-Lee <leon.lee@ite.com.tw>
Signed-off-by: Dino Li <dino.li@ite.com.tw>
Reviewed-on: https://chromium-review.googlesource.com/326230
Reviewed-by: Shawn N <shawnn@chromium.org>
This commit is contained in:
@@ -414,6 +414,14 @@ void gpio_pre_init(void)
|
||||
|
||||
IT83XX_GPIO_GCR = 0x06;
|
||||
|
||||
#ifndef CONFIG_USB_PD_TCPM_ITE83XX
|
||||
/* To prevent cc pins leakage if we don't use pd module */
|
||||
for (i = 0; i < USBPD_PORT_COUNT; i++) {
|
||||
IT83XX_USBPD_CCGCR(i) = 0x1f;
|
||||
IT83XX_USBPD_CCPSR(i) = 0x66;
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < GPIO_COUNT; i++, g++) {
|
||||
flags = g->flags;
|
||||
|
||||
|
||||
@@ -4,10 +4,42 @@
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
#include "intc.h"
|
||||
#include "it83xx_pd.h"
|
||||
#include "kmsc_chip.h"
|
||||
#include "registers.h"
|
||||
#include "task.h"
|
||||
#include "kmsc_chip.h"
|
||||
#include "intc.h"
|
||||
#include "usb_pd.h"
|
||||
|
||||
#ifdef CONFIG_USB_PD_TCPM_ITE83XX
|
||||
static void chip_pd_irq(enum usbpd_port port)
|
||||
{
|
||||
task_clear_pending_irq(usbpd_ctrl_regs[port].irq);
|
||||
|
||||
/* check status */
|
||||
if (USBPD_IS_HARD_RESET_DETECT(port)) {
|
||||
/* clear interrupt */
|
||||
IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_HARD_RESET_DETECT;
|
||||
task_set_event(PD_PORT_TO_TASK_ID(port),
|
||||
PD_EVENT_TCPC_RESET, 0);
|
||||
} else {
|
||||
if (USBPD_IS_RX_DONE(port)) {
|
||||
/* mask RX done interrupt */
|
||||
IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE;
|
||||
/* clear RX done interrupt */
|
||||
IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_RX_DONE;
|
||||
task_set_event(PD_PORT_TO_TASK_ID(port),
|
||||
PD_EVENT_RX, 0);
|
||||
}
|
||||
if (USBPD_IS_TX_DONE(port)) {
|
||||
/* clear TX done interrupt */
|
||||
IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_TX_DONE;
|
||||
task_set_event(PD_PORT_TO_TASK_ID(port),
|
||||
TASK_EVENT_PHY_TX_DONE, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void intc_cpu_int_group_5(void)
|
||||
{
|
||||
@@ -74,6 +106,15 @@ void intc_cpu_int_group_12(void)
|
||||
peci_interrupt();
|
||||
break;
|
||||
#endif
|
||||
#ifdef CONFIG_USB_PD_TCPM_ITE83XX
|
||||
case IT83XX_IRQ_USBPD0:
|
||||
chip_pd_irq(USBPD_PORT_A);
|
||||
break;
|
||||
|
||||
case IT83XX_IRQ_USBPD1:
|
||||
chip_pd_irq(USBPD_PORT_B);
|
||||
break;
|
||||
#endif /* CONFIG_USB_PD_TCPM_ITE83XX */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -86,7 +127,7 @@ void intc_cpu_int_group_6(void)
|
||||
int intc_group_6 = intc_get_ec_int();
|
||||
|
||||
switch (intc_group_6) {
|
||||
|
||||
#ifdef CONFIG_I2C
|
||||
case IT83XX_IRQ_SMB_A:
|
||||
i2c_interrupt(IT83XX_I2C_CH_A);
|
||||
break;
|
||||
@@ -110,7 +151,7 @@ void intc_cpu_int_group_6(void)
|
||||
case IT83XX_IRQ_SMB_F:
|
||||
i2c_interrupt(IT83XX_I2C_CH_F);
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ static const struct {
|
||||
IRQ_GROUP(17, {-1, -1, -1, -1, -1, -1, -1, -1}),
|
||||
IRQ_GROUP(18, { 2, 2, 2, 2, 2, 4, 4, 7}),
|
||||
IRQ_GROUP(19, { 6, 6, 12, 3, 3, 3, 3, 3}),
|
||||
IRQ_GROUP(20, {12, 12, -1, -1, -1, -1, -1, -1}),
|
||||
IRQ_GROUP(20, {12, 12, -1, -1, -1, 12, 12, -1}),
|
||||
};
|
||||
|
||||
int chip_enable_irq(int irq)
|
||||
|
||||
@@ -146,7 +146,13 @@
|
||||
#define IT83XX_IRQ_EXT_TIMER7 159
|
||||
#define IT83XX_IRQ_PECI 160
|
||||
#define IT83XX_IRQ_SOFTWARE 161
|
||||
#define IT83XX_IRQ_COUNT 162
|
||||
#define IT83XX_IRQ_WKO162 162
|
||||
#define IT83XX_IRQ_WKO163 163
|
||||
#define IT83XX_IRQ_WKO164 164
|
||||
#define IT83XX_IRQ_USBPD0 165
|
||||
#define IT83XX_IRQ_USBPD1 166
|
||||
#define IT83XX_IRQ_WKO167 167
|
||||
#define IT83XX_IRQ_COUNT 168
|
||||
|
||||
/* IRQ dispatching to CPU INT vectors */
|
||||
#define IT83XX_CPU_INT_IRQ_1 2
|
||||
@@ -291,6 +297,12 @@
|
||||
#define IT83XX_CPU_INT_IRQ_159 3
|
||||
#define IT83XX_CPU_INT_IRQ_160 12
|
||||
#define IT83XX_CPU_INT_IRQ_161 12
|
||||
#define IT83XX_CPU_INT_IRQ_162 12
|
||||
#define IT83XX_CPU_INT_IRQ_163 12
|
||||
#define IT83XX_CPU_INT_IRQ_164 12
|
||||
#define IT83XX_CPU_INT_IRQ_165 12
|
||||
#define IT83XX_CPU_INT_IRQ_166 12
|
||||
#define IT83XX_CPU_INT_IRQ_167 12
|
||||
|
||||
/* "Fake" IRQ to declare in readable fashion all WKO IRQ routed to INT#2 */
|
||||
#define CPU_INT_2_ALL_GPIOS 255
|
||||
@@ -622,6 +634,7 @@ enum ec_pll_ctrl {
|
||||
#define IT83XX_ECPM_SCDCR1 REG8(IT83XX_ECPM_BASE+0x0d)
|
||||
#define IT83XX_ECPM_SCDCR2 REG8(IT83XX_ECPM_BASE+0x0e)
|
||||
#define IT83XX_ECPM_SCDCR3 REG8(IT83XX_ECPM_BASE+0x0f)
|
||||
#define IT83XX_ECPM_SCDCR4 REG8(IT83XX_ECPM_BASE+0x10)
|
||||
|
||||
/*
|
||||
* The clock gate offsets combine the register offset from ECPM_BASE and the
|
||||
@@ -1087,6 +1100,75 @@ enum i2c_channels {
|
||||
IT83XX_I2C_PORT_COUNT,
|
||||
};
|
||||
|
||||
/* USBPD Controller */
|
||||
#define IT83XX_USBPD_BASE(port) (0x00F03700 + (0x100 * (port)))
|
||||
|
||||
#define IT83XX_USBPD_GCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0)
|
||||
#define USBPD_REG_MASK_SW_RESET_BIT (1 << 7)
|
||||
#define USBPD_REG_MASK_TYPE_C_DETECT_RESET (1 << 6)
|
||||
#define USBPD_REG_MASK_BMC_PHY (1 << 4)
|
||||
#define USBPD_REG_MASK_AUTO_SEND_SW_RESET (1 << 3)
|
||||
#define USBPD_REG_MASK_AUTO_SEND_HW_RESET (1 << 2)
|
||||
#define USBPD_REG_MASK_SNIFFER_MODE (1 << 1)
|
||||
#define USBPD_REG_MASK_GLOBAL_ENABLE (1 << 0)
|
||||
#define IT83XX_USBPD_PDMSR(p) REG8(IT83XX_USBPD_BASE(p)+0x01)
|
||||
#define USBPD_REG_MASK_SOPPP_ENABLE (1 << 7)
|
||||
#define USBPD_REG_MASK_SOPP_ENABLE (1 << 6)
|
||||
#define USBPD_REG_MASK_SOP_ENABLE (1 << 5)
|
||||
#define IT83XX_USBPD_CCGCR(p) REG8(IT83XX_USBPD_BASE(p)+0x04)
|
||||
#define USBPD_REG_MASK_DISABLE_CC (1 << 4)
|
||||
#define IT83XX_USBPD_CCCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x05)
|
||||
#define IT83XX_USBPD_CCPSR(p) REG8(IT83XX_USBPD_BASE(p)+0x06)
|
||||
#define USBPD_REG_MASK_DISCONNECT_POWER_CC2 (1 << 5)
|
||||
#define USBPD_REG_MASK_DISCONNECT_POWER_CC1 (1 << 1)
|
||||
#define IT83XX_USBPD_DFPVDR(p) REG8(IT83XX_USBPD_BASE(p)+0x08)
|
||||
#define IT83XX_USBPD_UFPVDR(p) REG8(IT83XX_USBPD_BASE(p)+0x09)
|
||||
#define IT83XX_USBPD_CCADCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0C)
|
||||
#define IT83XX_USBPD_ISR(p) REG8(IT83XX_USBPD_BASE(p)+0x14)
|
||||
#define USBPD_REG_MASK_TYPE_C_DETECT (1 << 7)
|
||||
#define USBPD_REG_MASK_CABLE_RESET_DETECT (1 << 6)
|
||||
#define USBPD_REG_MASK_HARD_RESET_DETECT (1 << 5)
|
||||
#define USBPD_REG_MASK_MSG_RX_DONE (1 << 4)
|
||||
#define USBPD_REG_MASK_AUTO_SOFT_RESET_TX_DONE (1 << 3)
|
||||
#define USBPD_REG_MASK_HARD_RESET_TX_DONE (1 << 2)
|
||||
#define USBPD_REG_MASK_MSG_TX_DONE (1 << 1)
|
||||
#define USBPD_REG_MASK_TIMER_TIMEOUT (1 << 0)
|
||||
#define IT83XX_USBPD_IMR(p) REG8(IT83XX_USBPD_BASE(p)+0x15)
|
||||
#define IT83XX_USBPD_MTCR(p) REG8(IT83XX_USBPD_BASE(p)+0x18)
|
||||
#define USBPD_REG_MASK_SW_RESET_TX_STAT (1 << 3)
|
||||
#define USBPD_REG_MASK_TX_BUSY_STAT (1 << 2)
|
||||
#define USBPD_REG_MASK_TX_DISCARD_STAT (1 << 2)
|
||||
#define USBPD_REG_MASK_TX_ERR_STAT (1 << 1)
|
||||
#define USBPD_REG_MASK_TX_START (1 << 0)
|
||||
#define IT83XX_USBPD_MTSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x19)
|
||||
#define USBPD_REG_MASK_CABLE_ENABLE (1 << 7)
|
||||
#define USBPD_REG_MASK_SEND_HW_RESET (1 << 6)
|
||||
#define USBPD_REG_MASK_SEND_BIST_MODE_2 (1 << 5)
|
||||
#define IT83XX_USBPD_MTSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x1A)
|
||||
#define IT83XX_USBPD_VDMMCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1B)
|
||||
#define IT83XX_USBPD_MRSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1C)
|
||||
#define USBPD_REG_MASK_RX_MSG_VALID (1 << 0)
|
||||
#define IT83XX_USBPD_PEFSMR(p) REG8(IT83XX_USBPD_BASE(p)+0x1D)
|
||||
#define IT83XX_USBPD_PES0R(p) REG8(IT83XX_USBPD_BASE(p)+0x1E)
|
||||
#define IT83XX_USBPD_PES1R(p) REG8(IT83XX_USBPD_BASE(p)+0x1F)
|
||||
#define IT83XX_USBPD_TDO_BASE(p) (IT83XX_USBPD_BASE(p)+0x20)
|
||||
#define IT83XX_USBPD_AGTMHLR(p) REG8(IT83XX_USBPD_BASE(p)+0x3C)
|
||||
#define IT83XX_USBPD_AGTMHHR(p) REG8(IT83XX_USBPD_BASE(p)+0x3D)
|
||||
#define IT83XX_USBPD_TMHLR(p) REG8(IT83XX_USBPD_BASE(p)+0x3E)
|
||||
#define IT83XX_USBPD_TMHHR(p) REG8(IT83XX_USBPD_BASE(p)+0x3F)
|
||||
#define IT83XX_USBPD_RDO_BASE(p) (IT83XX_USBPD_BASE(p)+0x40)
|
||||
#define IT83XX_USBPD_RMH_BASE(p) (IT83XX_USBPD_BASE(p)+0x5E)
|
||||
#define IT83XX_USBPD_RMHLR(p) REG8(IT83XX_USBPD_BASE(p)+0x5E)
|
||||
#define IT83XX_USBPD_RMHHR(p) REG8(IT83XX_USBPD_BASE(p)+0x5F)
|
||||
#define IT83XX_USBPD_BMCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x64)
|
||||
#define IT83XX_USBPD_PDMHSR(p) REG8(IT83XX_USBPD_BASE(p)+0x65)
|
||||
|
||||
enum usbpd_port {
|
||||
USBPD_PORT_A,
|
||||
USBPD_PORT_B,
|
||||
USBPD_PORT_COUNT,
|
||||
};
|
||||
|
||||
/* --- MISC (not implemented yet) --- */
|
||||
|
||||
#define IT83XX_PS2_BASE 0x00F01700
|
||||
|
||||
@@ -276,9 +276,11 @@ static int command_rw_ec_reg(int argc, char **argv)
|
||||
{
|
||||
volatile uint8_t *addr;
|
||||
uint8_t value = 0;
|
||||
#ifdef CONFIG_EC2I
|
||||
enum ec2i_message em;
|
||||
enum logical_device_number ldn;
|
||||
enum host_pnpcfg_index idx;
|
||||
#endif
|
||||
int i;
|
||||
char *e;
|
||||
|
||||
@@ -297,6 +299,7 @@ static int command_rw_ec_reg(int argc, char **argv)
|
||||
|
||||
/* access PNPCFG registers */
|
||||
if (((uint32_t)addr & 0xffff0000) == 0xec210000) {
|
||||
#ifdef CONFIG_EC2I
|
||||
/* set LDN */
|
||||
ldn = ((uint32_t)addr & 0xff00) >> 8;
|
||||
idx = (uint32_t)addr & 0xff;
|
||||
@@ -326,6 +329,9 @@ static int command_rw_ec_reg(int argc, char **argv)
|
||||
ccprintf(" %02x", value);
|
||||
}
|
||||
}
|
||||
#else
|
||||
return EC_ERROR_ACCESS_DENIED;
|
||||
#endif
|
||||
/* access EC registers */
|
||||
} else {
|
||||
/* write register */
|
||||
|
||||
@@ -77,6 +77,7 @@ driver-$(CONFIG_THERMISTOR_NCP15WB)+=temp_sensor/thermistor_ncp15wb.o
|
||||
driver-$(CONFIG_USB_PD_TCPM_STUB)+=tcpm/stub.o
|
||||
driver-$(CONFIG_USB_PD_TCPM_TCPCI)+=tcpm/tcpci.o
|
||||
driver-$(CONFIG_USB_PD_TCPM_FUSB302)+=tcpm/fusb302.o
|
||||
driver-$(CONFIG_USB_PD_TCPM_ITE83XX)+=tcpm/it83xx.o
|
||||
|
||||
# USB switches
|
||||
driver-$(CONFIG_USB_SWITCH_PI3USB9281)+=usb_switch_pi3usb9281.o
|
||||
|
||||
456
driver/tcpm/it83xx.c
Normal file
456
driver/tcpm/it83xx.c
Normal file
@@ -0,0 +1,456 @@
|
||||
/* Copyright 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.
|
||||
*/
|
||||
|
||||
/* TCPM for MCU also running TCPC */
|
||||
|
||||
#include "common.h"
|
||||
#include "config.h"
|
||||
#include "console.h"
|
||||
#include "it83xx_pd.h"
|
||||
#include "registers.h"
|
||||
#include "system.h"
|
||||
#include "task.h"
|
||||
#include "timer.h"
|
||||
#include "util.h"
|
||||
#include "usb_pd.h"
|
||||
#include "usb_pd_tcpm.h"
|
||||
|
||||
const struct usbpd_ctrl_t usbpd_ctrl_regs[] = {
|
||||
{&IT83XX_GPIO_GPCRF4, &IT83XX_GPIO_GPCRF5, IT83XX_IRQ_USBPD0},
|
||||
{&IT83XX_GPIO_GPCRH1, &IT83XX_GPIO_GPCRH2, IT83XX_IRQ_USBPD1},
|
||||
};
|
||||
BUILD_ASSERT(ARRAY_SIZE(usbpd_ctrl_regs) == USBPD_PORT_COUNT);
|
||||
|
||||
static enum tcpc_cc_voltage_status it83xx_get_cc(
|
||||
enum usbpd_port port,
|
||||
enum usbpd_cc_pin cc_pin)
|
||||
{
|
||||
enum usbpd_ufp_volt_status ufp_volt;
|
||||
enum usbpd_dfp_volt_status dfp_volt;
|
||||
enum tcpc_cc_voltage_status cc_state = TYPEC_CC_VOLT_OPEN;
|
||||
int pull;
|
||||
|
||||
pull = (cc_pin == USBPD_CC_PIN_1) ?
|
||||
USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) :
|
||||
USBPD_GET_CC2_PULL_REGISTER_SELECTION(port);
|
||||
|
||||
/* select Rp */
|
||||
if (pull)
|
||||
CLEAR_MASK(cc_state, (1 << 2));
|
||||
/* select Rd */
|
||||
else
|
||||
SET_MASK(cc_state, (1 << 2));
|
||||
|
||||
/* sink */
|
||||
if (USBPD_GET_POWER_ROLE(port) == USBPD_POWER_ROLE_CONSUMER) {
|
||||
if (cc_pin == USBPD_CC_PIN_1)
|
||||
ufp_volt = IT83XX_USBPD_UFPVDR(port) & 0xf;
|
||||
else
|
||||
ufp_volt = (IT83XX_USBPD_UFPVDR(port) >> 4) & 0xf;
|
||||
|
||||
switch (ufp_volt) {
|
||||
case USBPD_UFP_STATE_SNK_DEF:
|
||||
cc_state |= (TYPEC_CC_VOLT_SNK_DEF & 3);
|
||||
break;
|
||||
case USBPD_UFP_STATE_SNK_1_5:
|
||||
cc_state |= (TYPEC_CC_VOLT_SNK_1_5 & 3);
|
||||
break;
|
||||
case USBPD_UFP_STATE_SNK_3_0:
|
||||
cc_state |= (TYPEC_CC_VOLT_SNK_3_0 & 3);
|
||||
break;
|
||||
case USBPD_UFP_STATE_SNK_OPEN:
|
||||
cc_state = TYPEC_CC_VOLT_OPEN;
|
||||
break;
|
||||
default:
|
||||
cc_state = TYPEC_CC_VOLT_OPEN;
|
||||
break;
|
||||
}
|
||||
/* source */
|
||||
} else {
|
||||
if (cc_pin == USBPD_CC_PIN_1)
|
||||
dfp_volt = IT83XX_USBPD_DFPVDR(port) & 0xf;
|
||||
else
|
||||
dfp_volt = (IT83XX_USBPD_DFPVDR(port) >> 4) & 0xf;
|
||||
|
||||
switch (dfp_volt) {
|
||||
case USBPD_DFP_STATE_SRC_RA:
|
||||
cc_state |= TYPEC_CC_VOLT_RA;
|
||||
break;
|
||||
case USBPD_DFP_STATE_SRC_RD:
|
||||
cc_state |= TYPEC_CC_VOLT_RD;
|
||||
break;
|
||||
case USBPD_DFP_STATE_SRC_OPEN:
|
||||
cc_state = TYPEC_CC_VOLT_OPEN;
|
||||
break;
|
||||
default:
|
||||
cc_state = TYPEC_CC_VOLT_OPEN;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return cc_state;
|
||||
}
|
||||
|
||||
static void it83xx_rx_data(enum usbpd_port port, int *head, uint32_t *buf)
|
||||
{
|
||||
struct usbpd_header *p_head = (struct usbpd_header *)head;
|
||||
*head = 0;
|
||||
|
||||
if (!USBPD_IS_RX_DONE(port))
|
||||
return;
|
||||
|
||||
/* store header */
|
||||
*p_head = *((struct usbpd_header *)IT83XX_USBPD_RMH_BASE(port));
|
||||
/* check data message */
|
||||
if (p_head->data_obj_num)
|
||||
memcpy(buf,
|
||||
(uint8_t *)IT83XX_USBPD_RDO_BASE(port),
|
||||
p_head->data_obj_num * 4);
|
||||
/*
|
||||
* Note: clear RX done interrupt after get the data.
|
||||
* If clear this bit, USBPD receives next packet
|
||||
*/
|
||||
IT83XX_USBPD_MRSR(port) = USBPD_REG_MASK_RX_MSG_VALID;
|
||||
}
|
||||
|
||||
static enum tcpc_transmit_complete it83xx_tx_data(
|
||||
enum usbpd_port port,
|
||||
enum tcpm_transmit_type type,
|
||||
uint8_t msg_type,
|
||||
uint8_t length,
|
||||
const uint32_t *buf)
|
||||
{
|
||||
int r;
|
||||
uint32_t evt;
|
||||
|
||||
/* set message type */
|
||||
IT83XX_USBPD_MTSR0(port) =
|
||||
(IT83XX_USBPD_MTSR0(port) & ~0x1f) | (msg_type & 0xf);
|
||||
/* SOP type: bit[5:4] 00 SOP, 01 SOP', 10 SOP" */
|
||||
IT83XX_USBPD_MTSR1(port) =
|
||||
(IT83XX_USBPD_MTSR1(port) & ~0x30) | ((type & 0x3) << 4);
|
||||
/* bit7: transmit message is send to cable or not */
|
||||
if (TCPC_TX_SOP == type)
|
||||
IT83XX_USBPD_MTSR0(port) &= ~USBPD_REG_MASK_CABLE_ENABLE;
|
||||
else
|
||||
IT83XX_USBPD_MTSR0(port) |= USBPD_REG_MASK_CABLE_ENABLE;
|
||||
/* clear msg length */
|
||||
IT83XX_USBPD_MTSR1(port) &= (~0x7);
|
||||
/* Limited by PD_HEADER_CNT() */
|
||||
ASSERT(length <= 0x7);
|
||||
|
||||
if (length) {
|
||||
/* set data bit */
|
||||
IT83XX_USBPD_MTSR0(port) |= (1 << 4);
|
||||
/* set data length setting */
|
||||
IT83XX_USBPD_MTSR1(port) |= length;
|
||||
/* set data */
|
||||
memcpy((uint8_t *)IT83XX_USBPD_TDO_BASE(port), buf, length * 4);
|
||||
}
|
||||
|
||||
for (r = 0; r <= PD_RETRY_COUNT; r++) {
|
||||
/* Start TX */
|
||||
USBPD_KICK_TX_START(port);
|
||||
evt = task_wait_event_mask(TASK_EVENT_PHY_TX_DONE,
|
||||
PD_T_TCPC_TX_TIMEOUT);
|
||||
/* check TX status */
|
||||
if (USBPD_IS_TX_ERR(port) || (evt & TASK_EVENT_TIMER)) {
|
||||
/*
|
||||
* If discard, means HW doesn't send the msg and resend.
|
||||
*/
|
||||
if (USBPD_IS_TX_DISCARD(port))
|
||||
continue;
|
||||
else
|
||||
return TCPC_TX_COMPLETE_FAILED;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (r > PD_RETRY_COUNT)
|
||||
return TCPC_TX_COMPLETE_DISCARDED;
|
||||
|
||||
return TCPC_TX_COMPLETE_SUCCESS;
|
||||
}
|
||||
|
||||
static enum tcpc_transmit_complete it83xx_send_hw_reset(enum usbpd_port port,
|
||||
enum tcpm_transmit_type reset_type)
|
||||
{
|
||||
if (reset_type == TCPC_TX_CABLE_RESET)
|
||||
IT83XX_USBPD_MTSR0(port) |= USBPD_REG_MASK_CABLE_ENABLE;
|
||||
else
|
||||
IT83XX_USBPD_MTSR0(port) &= ~USBPD_REG_MASK_CABLE_ENABLE;
|
||||
|
||||
/* send hard reset */
|
||||
USBPD_SEND_HARD_RESET(port);
|
||||
usleep(MSEC);
|
||||
|
||||
if (IT83XX_USBPD_MTSR0(port) & USBPD_REG_MASK_SEND_HW_RESET)
|
||||
return TCPC_TX_COMPLETE_FAILED;
|
||||
|
||||
return TCPC_TX_COMPLETE_SUCCESS;
|
||||
}
|
||||
|
||||
static void it83xx_send_bist_mode2_pattern(enum usbpd_port port)
|
||||
{
|
||||
USBPD_ENABLE_SEND_BIST_MODE_2(port);
|
||||
usleep(PD_T_BIST_TRANSMIT);
|
||||
USBPD_DISABLE_SEND_BIST_MODE_2(port);
|
||||
}
|
||||
|
||||
static void it83xx_enable_vconn(enum usbpd_port port, int enabled)
|
||||
{
|
||||
enum usbpd_cc_pin cc_pin;
|
||||
|
||||
if (USBPD_GET_PULL_CC_SELECTION(port))
|
||||
cc_pin = USBPD_CC_PIN_1;
|
||||
else
|
||||
cc_pin = USBPD_CC_PIN_2;
|
||||
|
||||
if (enabled) {
|
||||
/* Disable unused CC to become VCONN */
|
||||
if (cc_pin == USBPD_CC_PIN_1) {
|
||||
IT83XX_USBPD_CCCSR(port) =
|
||||
(IT83XX_USBPD_CCCSR(port) | 0xa0) & ~0xa;
|
||||
IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port)
|
||||
& ~USBPD_REG_MASK_DISCONNECT_POWER_CC2)
|
||||
| USBPD_REG_MASK_DISCONNECT_POWER_CC1;
|
||||
} else {
|
||||
IT83XX_USBPD_CCCSR(port) =
|
||||
(IT83XX_USBPD_CCCSR(port) | 0xa) & ~0xa0;
|
||||
IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port)
|
||||
& ~USBPD_REG_MASK_DISCONNECT_POWER_CC1)
|
||||
| USBPD_REG_MASK_DISCONNECT_POWER_CC2;
|
||||
}
|
||||
} else {
|
||||
/* Enable cc1 and cc2 */
|
||||
IT83XX_USBPD_CCCSR(port) &= ~0xaa;
|
||||
IT83XX_USBPD_CCPSR(port) |=
|
||||
(USBPD_REG_MASK_DISCONNECT_POWER_CC1 |
|
||||
USBPD_REG_MASK_DISCONNECT_POWER_CC2);
|
||||
}
|
||||
}
|
||||
|
||||
static void it83xx_set_power_role(enum usbpd_port port, int power_role)
|
||||
{
|
||||
/* PD_ROLE_SINK 0, PD_ROLE_SOURCE 1 */
|
||||
if (power_role == PD_ROLE_SOURCE) {
|
||||
/* bit0: source */
|
||||
SET_MASK(IT83XX_USBPD_PDMSR(port), (1 << 0));
|
||||
/* bit1: CC1 select Rp */
|
||||
SET_MASK(IT83XX_USBPD_CCGCR(port), (1 << 1));
|
||||
/* bit3: CC2 select Rp */
|
||||
SET_MASK(IT83XX_USBPD_BMCSR(port), (1 << 3));
|
||||
} else {
|
||||
/* bit0: sink */
|
||||
CLEAR_MASK(IT83XX_USBPD_PDMSR(port), (1 << 0));
|
||||
/* bit1: CC1 select Rd */
|
||||
CLEAR_MASK(IT83XX_USBPD_CCGCR(port), (1 << 1));
|
||||
/* bit3: CC2 select Rd */
|
||||
CLEAR_MASK(IT83XX_USBPD_BMCSR(port), (1 << 3));
|
||||
}
|
||||
}
|
||||
|
||||
static void it83xx_set_data_role(enum usbpd_port port, int pd_role)
|
||||
{
|
||||
/* 0: PD_ROLE_UFP 1: PD_ROLE_DFP */
|
||||
IT83XX_USBPD_PDMSR(port) =
|
||||
(IT83XX_USBPD_PDMSR(port) & ~0xc) | ((pd_role & 0x1) << 2);
|
||||
}
|
||||
|
||||
static void it83xx_init(enum usbpd_port port, int role)
|
||||
{
|
||||
/* defalut PD Clock = PLL 48 / 6 = 8M. */
|
||||
IT83XX_ECPM_SCDCR4 = (IT83XX_ECPM_SCDCR4 & 0xf0) | 5;
|
||||
/* reset */
|
||||
IT83XX_USBPD_GCR(port) = 0;
|
||||
USBPD_SW_RESET(port);
|
||||
/* set SOP: receive SOP message only.
|
||||
* bit[7]: SOP" support enable.
|
||||
* bit[6]: SOP' support enable.
|
||||
* bit[5]: SOP support enable.
|
||||
*/
|
||||
IT83XX_USBPD_PDMSR(port) = USBPD_REG_MASK_SOP_ENABLE;
|
||||
/* W/C status */
|
||||
IT83XX_USBPD_ISR(port) = 0xff;
|
||||
/* enable cc, select cc1 and Rd (80uA output when Rp selected) */
|
||||
IT83XX_USBPD_CCGCR(port) = 0xd;
|
||||
/* change data role as the same power role */
|
||||
it83xx_set_data_role(port, role);
|
||||
/* set power role */
|
||||
it83xx_set_power_role(port, role);
|
||||
/* disable all interrupts */
|
||||
IT83XX_USBPD_IMR(port) = 0xff;
|
||||
/* enable tx done and reset detect interrupt */
|
||||
IT83XX_USBPD_IMR(port) &= ~(USBPD_REG_MASK_MSG_TX_DONE |
|
||||
USBPD_REG_MASK_HARD_RESET_DETECT);
|
||||
IT83XX_USBPD_CCPSR(port) = 0xff;
|
||||
/* cc connect */
|
||||
IT83XX_USBPD_CCCSR(port) = 0;
|
||||
/* disable vconn */
|
||||
it83xx_enable_vconn(port, 0);
|
||||
/* TX start from high */
|
||||
IT83XX_USBPD_CCADCR(port) |= (1 << 6);
|
||||
/* enable cc1/cc2 */
|
||||
*usbpd_ctrl_regs[port].cc1 = 0x86;
|
||||
*usbpd_ctrl_regs[port].cc2 = 0x86;
|
||||
task_clear_pending_irq(usbpd_ctrl_regs[port].irq);
|
||||
task_enable_irq(usbpd_ctrl_regs[port].irq);
|
||||
USBPD_START(port);
|
||||
}
|
||||
|
||||
static void it83xx_select_polarity(enum usbpd_port port,
|
||||
enum usbpd_cc_pin cc_pin)
|
||||
{
|
||||
/* cc1/cc2 selection */
|
||||
if (cc_pin == USBPD_CC_PIN_1)
|
||||
SET_MASK(IT83XX_USBPD_CCGCR(port), (1 << 0));
|
||||
else
|
||||
CLEAR_MASK(IT83XX_USBPD_CCGCR(port), (1 << 0));
|
||||
}
|
||||
|
||||
static void it83xx_set_cc(enum usbpd_port port, int pull)
|
||||
{
|
||||
if (pull == TYPEC_CC_RD)
|
||||
it83xx_set_power_role(port, PD_ROLE_SINK);
|
||||
else if (pull == TYPEC_CC_RP)
|
||||
it83xx_set_power_role(port, PD_ROLE_SOURCE);
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_init(int port)
|
||||
{
|
||||
/* Initialize physical layer */
|
||||
it83xx_init(port, PD_ROLE_DEFAULT);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_get_cc(int port, int *cc1, int *cc2)
|
||||
{
|
||||
*cc2 = it83xx_get_cc(port, USBPD_CC_PIN_2);
|
||||
*cc1 = it83xx_get_cc(port, USBPD_CC_PIN_1);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_set_cc(int port, int pull)
|
||||
{
|
||||
it83xx_set_cc(port, pull);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_set_polarity(int port, int polarity)
|
||||
{
|
||||
it83xx_select_polarity(port, polarity);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_set_vconn(int port, int enable)
|
||||
{
|
||||
#ifdef CONFIG_USBC_VCONN
|
||||
it83xx_enable_vconn(port, enable);
|
||||
/* vconn switch */
|
||||
board_pd_vconn_ctrl(port,
|
||||
USBPD_GET_PULL_CC_SELECTION(port) ?
|
||||
USBPD_CC_PIN_2 :
|
||||
USBPD_CC_PIN_1, enable);
|
||||
#endif
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_set_msg_header(int port, int power_role, int data_role)
|
||||
{
|
||||
it83xx_set_power_role(port, power_role);
|
||||
it83xx_set_data_role(port, data_role);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_set_rx_enable(int port, int enable)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (enable) {
|
||||
IT83XX_USBPD_IMR(port) &= ~USBPD_REG_MASK_MSG_RX_DONE;
|
||||
USBPD_ENABLE_BMC_PHY(port);
|
||||
} else {
|
||||
IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE;
|
||||
USBPD_DISABLE_BMC_PHY(port);
|
||||
}
|
||||
|
||||
/* If any PD port is connected, then disable deep sleep */
|
||||
for (i = 0; i < CONFIG_USB_PD_PORT_COUNT; ++i)
|
||||
if (IT83XX_USBPD_GCR(port) | USBPD_REG_MASK_BMC_PHY)
|
||||
break;
|
||||
|
||||
if (i == CONFIG_USB_PD_PORT_COUNT)
|
||||
enable_sleep(SLEEP_MASK_USB_PD);
|
||||
else
|
||||
disable_sleep(SLEEP_MASK_USB_PD);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_get_message(int port, uint32_t *payload, int *head)
|
||||
{
|
||||
it83xx_rx_data(port, head, payload);
|
||||
/* un-mask RX done interrupt */
|
||||
IT83XX_USBPD_IMR(port) &= ~USBPD_REG_MASK_MSG_RX_DONE;
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
static int it83xx_tcpm_transmit(int port,
|
||||
enum tcpm_transmit_type type,
|
||||
uint16_t header,
|
||||
const uint32_t *data)
|
||||
{
|
||||
int status = TCPC_TX_COMPLETE_FAILED;
|
||||
|
||||
switch (type) {
|
||||
case TCPC_TX_SOP:
|
||||
case TCPC_TX_SOP_PRIME:
|
||||
case TCPC_TX_SOP_PRIME_PRIME:
|
||||
status = it83xx_tx_data(port,
|
||||
type,
|
||||
PD_HEADER_TYPE(header),
|
||||
PD_HEADER_CNT(header),
|
||||
data);
|
||||
break;
|
||||
case TCPC_TX_BIST_MODE_2:
|
||||
it83xx_send_bist_mode2_pattern(port);
|
||||
status = TCPC_TX_COMPLETE_SUCCESS;
|
||||
break;
|
||||
case TCPC_TX_HARD_RESET:
|
||||
case TCPC_TX_CABLE_RESET:
|
||||
status = it83xx_send_hw_reset(port, type);
|
||||
break;
|
||||
default:
|
||||
status = TCPC_TX_COMPLETE_FAILED;
|
||||
break;
|
||||
}
|
||||
pd_transmit_complete(port, status);
|
||||
|
||||
return EC_SUCCESS;
|
||||
}
|
||||
|
||||
const struct tcpm_drv it83xx_tcpm_drv = {
|
||||
.init = &it83xx_tcpm_init,
|
||||
.get_cc = &it83xx_tcpm_get_cc,
|
||||
#ifdef CONFIG_USB_PD_TCPM_VBUS
|
||||
.get_vbus_level = NULL,
|
||||
#endif
|
||||
.set_cc = &it83xx_tcpm_set_cc,
|
||||
.set_polarity = &it83xx_tcpm_set_polarity,
|
||||
.set_vconn = &it83xx_tcpm_set_vconn,
|
||||
.set_msg_header = &it83xx_tcpm_set_msg_header,
|
||||
.set_rx_enable = &it83xx_tcpm_set_rx_enable,
|
||||
.get_message = &it83xx_tcpm_get_message,
|
||||
.transmit = &it83xx_tcpm_transmit,
|
||||
.tcpc_alert = NULL,
|
||||
};
|
||||
112
driver/tcpm/it83xx_pd.h
Normal file
112
driver/tcpm/it83xx_pd.h
Normal file
@@ -0,0 +1,112 @@
|
||||
/* Copyright 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.
|
||||
*/
|
||||
|
||||
/* USB Power delivery port management */
|
||||
#ifndef __CROS_EC_DRIVER_TCPM_IT83XX_H
|
||||
#define __CROS_EC_DRIVER_TCPM_IT83XX_H
|
||||
|
||||
#define TASK_EVENT_PHY_TX_DONE TASK_EVENT_CUSTOM((1 << 17))
|
||||
|
||||
#define SET_MASK(reg, bit_mask) ((reg) |= (bit_mask))
|
||||
#define CLEAR_MASK(reg, bit_mask) ((reg) &= (~(bit_mask)))
|
||||
#define IS_MASK_SET(reg, bit_mask) (((reg) & (bit_mask)) != 0)
|
||||
#define IS_MASK_CLEAR(reg, bit_mask) (((reg) & (bit_mask)) == 0)
|
||||
|
||||
/* macros for set */
|
||||
#define USBPD_KICK_TX_START(port) \
|
||||
SET_MASK(IT83XX_USBPD_MTCR(port), \
|
||||
USBPD_REG_MASK_TX_START)
|
||||
#define USBPD_SEND_HARD_RESET(port) \
|
||||
SET_MASK(IT83XX_USBPD_MTSR0(port), \
|
||||
USBPD_REG_MASK_SEND_HW_RESET)
|
||||
#define USBPD_SW_RESET(port) \
|
||||
SET_MASK(IT83XX_USBPD_GCR(port), \
|
||||
USBPD_REG_MASK_SW_RESET_BIT)
|
||||
#define USBPD_ENABLE_BMC_PHY(port) \
|
||||
SET_MASK(IT83XX_USBPD_GCR(port), \
|
||||
USBPD_REG_MASK_BMC_PHY)
|
||||
#define USBPD_DISABLE_BMC_PHY(port) \
|
||||
CLEAR_MASK(IT83XX_USBPD_GCR(port), \
|
||||
USBPD_REG_MASK_BMC_PHY)
|
||||
#define USBPD_START(port) \
|
||||
CLEAR_MASK(IT83XX_USBPD_CCGCR(port), \
|
||||
USBPD_REG_MASK_DISABLE_CC)
|
||||
#define USBPD_ENABLE_SEND_BIST_MODE_2(port) \
|
||||
SET_MASK(IT83XX_USBPD_MTSR0(port), \
|
||||
USBPD_REG_MASK_SEND_BIST_MODE_2)
|
||||
#define USBPD_DISABLE_SEND_BIST_MODE_2(port) \
|
||||
CLEAR_MASK(IT83XX_USBPD_MTSR0(port), \
|
||||
USBPD_REG_MASK_SEND_BIST_MODE_2)
|
||||
|
||||
/* macros for get */
|
||||
#define USBPD_GET_POWER_ROLE(port) \
|
||||
(IT83XX_USBPD_PDMSR(port) & 1)
|
||||
#define USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) \
|
||||
(IT83XX_USBPD_CCGCR(port) & (1 << 1))
|
||||
#define USBPD_GET_CC2_PULL_REGISTER_SELECTION(port) \
|
||||
(IT83XX_USBPD_BMCSR(port) & (1 << 3))
|
||||
#define USBPD_GET_PULL_CC_SELECTION(port) \
|
||||
(IT83XX_USBPD_CCGCR(port) & 1)
|
||||
|
||||
/* macros for check */
|
||||
#define USBPD_IS_TX_ERR(port) \
|
||||
IS_MASK_SET(IT83XX_USBPD_MTCR(port), USBPD_REG_MASK_TX_ERR_STAT)
|
||||
#define USBPD_IS_TX_DISCARD(port) \
|
||||
IS_MASK_SET(IT83XX_USBPD_MTCR(port), USBPD_REG_MASK_TX_DISCARD_STAT)
|
||||
|
||||
/* macros for PD ISR */
|
||||
#define USBPD_IS_HARD_RESET_DETECT(port) \
|
||||
IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_HARD_RESET_DETECT)
|
||||
#define USBPD_IS_TX_DONE(port) \
|
||||
IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_TX_DONE)
|
||||
#define USBPD_IS_RX_DONE(port) \
|
||||
IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_RX_DONE)
|
||||
|
||||
enum usbpd_cc_pin {
|
||||
USBPD_CC_PIN_1,
|
||||
USBPD_CC_PIN_2,
|
||||
};
|
||||
|
||||
enum usbpd_ufp_volt_status {
|
||||
USBPD_UFP_STATE_SNK_OPEN = 0,
|
||||
USBPD_UFP_STATE_SNK_DEF = 1,
|
||||
USBPD_UFP_STATE_SNK_1_5 = 3,
|
||||
USBPD_UFP_STATE_SNK_3_0 = 7,
|
||||
};
|
||||
|
||||
enum usbpd_dfp_volt_status {
|
||||
USBPD_DFP_STATE_SRC_RA = 0,
|
||||
USBPD_DFP_STATE_SRC_RD = 1,
|
||||
USBPD_DFP_STATE_SRC_OPEN = 3,
|
||||
};
|
||||
|
||||
enum usbpd_power_role {
|
||||
USBPD_POWER_ROLE_CONSUMER,
|
||||
USBPD_POWER_ROLE_PROVIDER,
|
||||
USBPD_POWER_ROLE_CONSUMER_PROVIDER,
|
||||
USBPD_POWER_ROLE_PROVIDER_CONSUMER,
|
||||
};
|
||||
|
||||
struct usbpd_header {
|
||||
uint8_t msg_type : 4;
|
||||
uint8_t reserved : 1;
|
||||
uint8_t port_role : 1;
|
||||
uint8_t spec_ver : 2;
|
||||
uint8_t power_role : 1;
|
||||
uint8_t msg_id : 3;
|
||||
uint8_t data_obj_num : 3;
|
||||
uint8_t reserved2 : 1;
|
||||
};
|
||||
|
||||
struct usbpd_ctrl_t {
|
||||
volatile uint8_t *cc1;
|
||||
volatile uint8_t *cc2;
|
||||
uint8_t irq;
|
||||
};
|
||||
|
||||
extern const struct usbpd_ctrl_t usbpd_ctrl_regs[];
|
||||
extern const struct tcpm_drv it83xx_tcpm_drv;
|
||||
|
||||
#endif /* __CROS_EC_DRIVER_TCPM_IT83XX_H */
|
||||
@@ -1858,6 +1858,7 @@
|
||||
#undef CONFIG_USB_PD_TCPM_STUB
|
||||
#undef CONFIG_USB_PD_TCPM_TCPCI
|
||||
#undef CONFIG_USB_PD_TCPM_FUSB302
|
||||
#undef CONFIG_USB_PD_TCPM_ITE83XX
|
||||
|
||||
/*
|
||||
* Use this option if the TCPC port controller supports the optional register
|
||||
|
||||
Reference in New Issue
Block a user