summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorScott Collyer <scollyer@google.com>2020-05-21 22:10:36 -0700
committerCommit Bot <commit-bot@chromium.org>2020-09-29 23:52:36 +0000
commitcf21f6fc6e182fb39447686934efc2be1d79de7a (patch)
tree82e8897a9e8ba65ed3f4949b017d13c492978a59
parent77d86a6161e9388c48a607c654844ec2798a017d (diff)
downloadchrome-ec-cf21f6fc6e182fb39447686934efc2be1d79de7a.tar.gz
stm32g4: Initial UCPD driver for type-c functionality
The STM32G4 contains a UCPD block that includes similar functions as a TCPC. This CL contains an initial version of the driver required to use this function. This CL adds register block definitions and the implementation of tcpci driver functions required to support type-c operation. This CL does not include support for USB-PD functionality. BUG=b:167601672 BRANCH=None TEST=verfied type-c attaches properly on quiche Signed-off-by: Scott Collyer <scollyer@google.com> Change-Id: I3e7912f33efa716501896b1f96b4c6d67db0f573 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2213840 Tested-by: Scott Collyer <scollyer@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Scott Collyer <scollyer@chromium.org>
-rw-r--r--chip/stm32/build.mk1
-rw-r--r--chip/stm32/registers-stm32g4.h193
-rw-r--r--chip/stm32/ucpd-stm32gx.c277
-rw-r--r--chip/stm32/ucpd-stm32gx.h111
4 files changed, 582 insertions, 0 deletions
diff --git a/chip/stm32/build.mk b/chip/stm32/build.mk
index a951c0eb21..f2d5720961 100644
--- a/chip/stm32/build.mk
+++ b/chip/stm32/build.mk
@@ -98,3 +98,4 @@ chip-$(CONFIG_USB_ISOCHRONOUS)+=usb_isochronous.o
chip-$(CONFIG_USB_PD_TCPC)+=usb_pd_phy.o
chip-$(CONFIG_USB_SPI)+=usb_spi.o
endif
+chip-$(CONFIG_USB_PD_TCPM_STM32GX)+=ucpd-stm32gx.o
diff --git a/chip/stm32/registers-stm32g4.h b/chip/stm32/registers-stm32g4.h
index 6e519bc9fb..4fe97e4c29 100644
--- a/chip/stm32/registers-stm32g4.h
+++ b/chip/stm32/registers-stm32g4.h
@@ -252,6 +252,195 @@
/* Register definitions */
+/* --- UCPD --- */
+#define STM32_UCPD_REG(port, offset) \
+ REG32(((STM32_UCPD1_BASE + ((port) * 0x400)) + (offset)))
+
+#define STM32_UCPD_CFGR1(port) STM32_UCPD_REG(port, 0x00)
+#define STM32_UCPD_CFGR2(port) STM32_UCPD_REG(port, 0x04)
+#define STM32_UCPD_CR(port) STM32_UCPD_REG(port, 0x0c)
+#define STM32_UCPD_IMR(port) STM32_UCPD_REG(port, 0x10)
+#define STM32_UCPD_SR(port) STM32_UCPD_REG(port, 0x14)
+#define STM32_UCPD_ICR(port) STM32_UCPD_REG(port, 0x18)
+#define STM32_UCPD_TX_ORDSETR(port) STM32_UCPD_REG(port, 0x1c)
+#define STM32_UCPD_TX_PAYSZR(port) STM32_UCPD_REG(port, 0x20)
+#define STM32_UCPD_TXDR(port) STM32_UCPD_REG(port, 0x24)
+#define STM32_UCPD_RX_ORDSETR(port) STM32_UCPD_REG(port, 0x28)
+#define STM32_UCPD_RX_PAYSZR(port) STM32_UCPD_REG(port, 0x2c)
+#define STM32_UCPD_RXDR(port) STM32_UCPD_REG(port, 0x30)
+#define STM32_UCPD_RX_ORDEXTR1(port) STM32_UCPD_REG(port, 0x34)
+#define STM32_UCPD_RX_ORDEXTR2(port) STM32_UCPD_REG(port, 0x38)
+
+/* --- UCPD CFGR1 Bit Definitions --- */
+#define STM32_UCPD_CFGR1_HBITCLKD_SHIFT 0
+#define STM32_UCPD_CFGR1_HBITCLKD_MASK ((0x3f) << \
+ (STM32_UCPD_CFGR1_HBITCLKD_SHIFT))
+#define STM32_UCPD_CFGR1_HBITCLKD_VAL(x) ((x) << \
+ STM32_UCPD_CFGR1_HBITCLKD_SHIFT)
+#define STM32_UCPD_CFGR1_IFRGAP_SHIFT 6
+#define STM32_UCPD_CFGR1_IFRGAP_MASK ((0x1f) << \
+ (STM32_UCPD_CFGR1_IFRGAP_SHIFT))
+#define STM32_UCPD_CFGR1_IFRGAP_VAL(x) ((x) << \
+ STM32_UCPD_CFGR1_IFRGAP_SHIFT)
+#define STM32_UCPD_CFGR1_TRANSWIN_SHIFT 11
+#define STM32_UCPD_CFGR1_TRANSWIN_MASK ((0x1f) << \
+ (STM32_UCPD_CFGR1_TRANSWIN_SHIFT))
+#define STM32_UCPD_CFGR1_TRANSWIN_VAL(x) ((x) << \
+ STM32_UCPD_CFGR1_TRANSWIN_SHIFT)
+#define STM32_UCPD_CFGR1_PSC_CLK_SHIFT 17
+#define STM32_UCPD_CFGR1_PSC_CLK_MASK ((0x7) << \
+ STM32_UCPD_CFGR1_PSC_CLK_SHIFT)
+#define STM32_UCPD_CFGR1_PSC_CLK_VAL(x) ((x) << \
+ STM32_UCPD_CFGR1_PSC_CLK_SHIFT)
+#define STM32_UCPD_CFGR1_RXORDSETEN_SHIFT 20
+#define STM32_UCPD_CFGR1_RXORDSETEN_MASK ((0x1ff) << \
+ STM32_UCPD_CFGR1_RXORDSETEN_SHIFT)
+#define STM32_UCPD_CFGR1_RXORDSETEN_VAL(x) ((x) << \
+ STM32_UCPD_CFGR1_RXORDSETEN_SHIFT)
+#define STM32_UCPD_CFGR1_TXDMAEN BIT(29)
+#define STM32_UCPD_CFGR1_RXDMAEN BIT(30)
+#define STM32_UCPD_CFGR1_UCPDEN BIT(31)
+
+/* --- UCPD CFGR2 Bit Definitions --- */
+#define STM32_UCPD_CFGR2_RXFILTDIS BIT(0)
+#define STM32_UCPD_CFGR2_RXFILT2N3 BIT(1)
+#define STM32_UCPD_CFGR2_FORCECLK BIT(2)
+#define STM32_UCPD_CFGR2_WUPEN BIT(3)
+
+/* --- UCPD CR Bit Definitions --- */
+#define STM32_UCPD_CR_TXMODE_SHIFT 0
+#define STM32_UCPD_CR_TXMODE_MASK ((0x3) << \
+ (STM32_UCPD_CR_TXMODE_SHIFT))
+#define STM32_UCPD_CR_TXMODE_VAL(x) ((x) << STM32_UCPD_CR_TXMODE_SHIFT)
+#define STM32_UCPD_CR_TXSEND BIT(2)
+#define STM32_UCPD_CR_TXHRST BIT(3)
+#define STM32_UCPD_CR_RXMODE BIT(4)
+#define STM32_UCPD_CR_PHYRXEN BIT(5)
+#define STM32_UCPD_CR_PHYCCSEL BIT(6)
+#define STM32_UCPD_CR_ANASUBMODE_SHIFT 7
+#define STM32_UCPD_CR_ANASUBMODE_MASK ((0x3) << \
+ (STM32_UCPD_CR_ANASUBMODE_SHIFT))
+#define STM32_UCPD_CR_ANASUBMODE_VAL(x) ((x) << \
+ STM32_UCPD_CR_ANASUBMODE_SHIFT)
+#define STM32_UCPD_CR_ANAMODE BIT(9)
+#define STM32_UCPD_CR_CCENABLE_SHIFT 10
+#define STM32_UCPD_CR_CCENABLE_MASK ((0x3) << \
+ (STM32_UCPD_CR_CCENABLE_SHIFT))
+#define STM32_UCPD_CR_CCENABLE_VAL(x) ((x) << \
+ STM32_UCPD_CR_CCENABLE_SHIFT)
+#define STM32_UCPD_CR_FRSRXEN BIT(16)
+#define STM32_UCPD_CR_FRSTX BIT(17)
+#define STM32_UCPD_CR_RDCH BIT(18)
+#define STM32_UCPD_CR_CC1TCDIS BIT(20)
+#define STM32_UCPD_CR_CC2TCDIS BIT(21)
+
+/* --- UCPD IMR Bit Definitions --- */
+#define STM32_UCPD_IMR_TXISIE BIT(0)
+#define STM32_UCPD_IMR_TXMSGDISCIE BIT(1)
+#define STM32_UCPD_IMR_TXMSGSENTIE BIT(2)
+#define STM32_UCPD_IMR_TXMSGABTIE BIT(3)
+#define STM32_UCPD_IMR_HRSTDISCIE BIT(4)
+#define STM32_UCPD_IMR_HRSTSENTIE BIT(5)
+#define STM32_UCPD_IMR_TXUNDIE BIT(6)
+#define STM32_UCPD_IMR_RXNEIE BIT(8)
+#define STM32_UCPD_IMR_RXORDDETIE BIT(9)
+#define STM32_UCPD_IMR_RXHRSTDETIE BIT(10)
+#define STM32_UCPD_IMR_RXOVRIE BIT(11)
+#define STM32_UCPD_IMR_RXMSGENDIE BIT(12)
+#define STM32_UCPD_IMR_TYPECEVT1IE BIT(14)
+#define STM32_UCPD_IMR_TYPECEVT2IE BIT(15)
+#define STM32_UCPD_IMR_FRSEVTIE BIT(20)
+
+/* --- UCPD SR Bit Definitions --- */
+#define STM32_UCPD_SR_TXIS BIT(0)
+#define STM32_UCPD_SR_TXMSGDISC BIT(1)
+#define STM32_UCPD_SR_TXMSGSENT BIT(2)
+#define STM32_UCPD_SR_TXMSGABT BIT(3)
+#define STM32_UCPD_SR_HRSTDISC BIT(4)
+#define STM32_UCPD_SR_HRSTSENT BIT(5)
+#define STM32_UCPD_SR_TXUND BIT(6)
+#define STM32_UCPD_SR_RXNE BIT(8)
+#define STM32_UCPD_SR_RXORDDET BIT(9)
+#define STM32_UCPD_SR_RXHRSTDET BIT(10)
+#define STM32_UCPD_SR_RXOVR BIT(11)
+#define STM32_UCPD_SR_RXMSGEND BIT(12)
+#define STM32_UCPD_SR_RXERR BIT(13)
+#define STM32_UCPD_SR_TYPECEVT1 BIT(14)
+#define STM32_UCPD_SR_TYPECEVT2 BIT(15)
+#define STM32_UCPD_SR_VSTATE_CC1_SHIFT 16
+#define STM32_UCPD_SR_VSTATE_CC1_MASK ((0x3) << \
+ (STM32_UCPD_SR_VSTATE_CC1_SHIFT))
+#define STM32_UCPD_SR_VSTATE_CC1_VAL(x) ((x) << \
+ STM32_UCPD_SR_VSTATE_CC1_SHIFT)
+#define STM32_UCPD_SR_VSTATE_CC2_SHIFT 18
+#define STM32_UCPD_SR_VSTATE_CC2_MASK ((0x3) << \
+ (STM32_UCPD_SR_VSTATE_CC2_SHIFT))
+#define STM32_UCPD_SR_VSTATE_CC2_VAL(x) ((x) << \
+ STM32_UCPD_SR_VSTATE_CC2_SHIFT)
+#define STM32_UCPD_SR_FRSEVT BIT(20)
+
+#define STM32_UCPD_SR_VSTATE_OPEN 3
+#define STM32_UCPD_SR_VSTATE_RA 0
+
+/* --- UCPD ICR Bit Definitions --- */
+#define STM32_UCPD_ICR_TXMSGDISCCF BIT(1)
+#define STM32_UCPD_ICR_TXMSGSENTCF BIT(2)
+#define STM32_UCPD_ICR_TXMSGABTCF BIT(3)
+#define STM32_UCPD_ICR_HRSTDISCCF BIT(4)
+#define STM32_UCPD_ICR_HRSTSENTCF BIT(5)
+#define STM32_UCPD_ICR_TXUNDCF BIT(6)
+#define STM32_UCPD_ICR_RXORDDETCF BIT(9)
+#define STM32_UCPD_ICR_RXHRSTDETCF BIT(10)
+#define STM32_UCPD_ICR_RXOVRCF BIT(11)
+#define STM32_UCPD_ICR_RXMSGENDCF BIT(12)
+#define STM32_UCPD_ICR_TYPECEVT1CF BIT(14)
+#define STM32_UCPD_ICR_TYPECEVT2CF BIT(15)
+#define STM32_UCPD_ICR_FRSEVTCF BIT(20)
+
+
+/* --- UCPD TX_ORDSETR Bit Definitions --- */
+#define STM32_UCPD_TX_ORDSETR_SHIFT 0
+#define STM32_UCPD_TX_ORDSETR_MASK ((0xfffff) << \
+ (STM32_UCPD_TX_ORDSETR_SHIFT))
+#define STM32_UCPD_TX_ORDSETR_VAL(x) ((x) << STM32_UCPD_TX_ORDSETR_SHIFT)
+
+/* --- UCPD TX_PAYSZR Bit Definitions --- */
+#define STM32_UCPD_TX_PAYSZR_SHIFT 0
+#define STM32_UCPD_TX_PAYSZR_MASK ((0x3ff) << \
+ (STM32_UCPD_TX_PAYSZR_SHIFT))
+#define STM32_UCPD_TX_PAYSZR_VAL(x) ((x) << STM32_UCPD_TX_PAYSZR_SHIFT)
+
+/* --- UCPD TXDR Bit Definitions --- */
+#define STM32_UCPD_TXDR_SHIFT 0
+#define STM32_UCPD_TXDR_MASK ((0xff) << \
+ (STM32_UCPD_TXDR_SHIFT))
+#define STM32_UCPD_TXDR_VAL(x) ((x) << STM32_UCPD_TXDR_SHIFT)
+
+/* --- UCPD RX_ORDSETR Bit Definitions --- */
+#define STM32_UCPD_RXORDSETR_SHIFT 0
+#define STM32_UCPD_RXORDSETR_MASK ((0x7) << \
+ (STM32_UCPD_RXORDSETR_SHIFT))
+#define STM32_UCPD_RXORDSETR_VAL(x) ((x) << STM32_UCPD_RXORDSETR_SHIFT)
+#define STM32_UCPD_RXSOP3OF4 BIT(3)
+#define STM32_UCPD_RXSOPKINVALID_SHIFT 4
+#define STM32_UCPD_RXSOPKINVALID_MASK ((0x7) << \
+ (STM32_UCPD_RXSOPKINVALID_SHIFT))
+#define STM32_UCPD_RXSOPKINVALID_VAL(x) ((x) << \
+ STM32_UCPD_RXSOPKINVALID_SHIFT)
+
+/* --- UCPD RX_PAYSZR Bit Definitions --- */
+#define STM32_UCPD_RX_PAYSZR_SHIFT 0
+#define STM32_UCPD_RX_PAYSZR_MASK ((0x3ff) << \
+ (STM32_UCPD_RX_PAYSZR_SHIFT))
+#define STM32_UCPD_RX_PAYSZR_VAL(x) ((x) << STM32_UCPD_RX_PAYSZR_SHIFT)
+
+/* --- UCPD TXDR Bit Definitions --- */
+#define STM32_UCPD_RXDR_SHIFT 0
+#define STM32_UCPD_RXDR_MASK ((0xff) << \
+ (STM32_UCPD_RXDR_SHIFT))
+#define STM32_UCPD_RXDR_VAL(x) ((x) << STM32_UCPD_RXDR_SHIFT)
+
+
/* --- USART --- */
#define STM32_USART_CR1(base) STM32_USART_REG(base, 0x00)
#define STM32_USART_CR2(base) STM32_USART_REG(base, 0x04)
@@ -508,6 +697,7 @@
/* --- RCC APB1ENR2 Bit Definitions --- */
#define STM32_RCC_APB1ENR2_LPUART1EN BIT(0)
#define STM32_RCC_APB1ENR2_I2C4EN BIT(1)
+#define STM32_RCC_APB1ENR2_UPCD1EN BIT(8)
/* --- RCC APB2ENR Bit Definitions --- */
#define STM32_RCC_APB2ENR_SYSCFGEN BIT(0)
@@ -591,6 +781,9 @@
#define STM32_PWR_RESET_CAUSE_CLR STM32_PWR_SCR
#define RESET_CAUSE_SBF_CLR STM32_PWR_SCR_CSBF
+#define STM32_PWR_CR3_UCPD1_STDBY BIT(13)
+#define STM32_PWR_CR3_UCPD1_DBDIS BIT(14)
+
/* --- System Config Registers --- */
#define STM32_SYSCFG_MEMRMP REG32(STM32_SYSCFG_BASE + 0x00)
#define STM32_SYSCFG_PMC REG32(STM32_SYSCFG_BASE + 0x04)
diff --git a/chip/stm32/ucpd-stm32gx.c b/chip/stm32/ucpd-stm32gx.c
new file mode 100644
index 0000000000..1355d9f042
--- /dev/null
+++ b/chip/stm32/ucpd-stm32gx.c
@@ -0,0 +1,277 @@
+/* Copyright 2020 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.
+ */
+
+/* STM32GX UCPD module for Chrome EC */
+
+#include "clock.h"
+#include "common.h"
+#include "gpio.h"
+#include "hooks.h"
+#include "registers.h"
+#include "task.h"
+#include "ucpd-stm32gx.h"
+#include "usb_pd.h"
+#include "usb_pd_tcpm.h"
+#include "util.h"
+
+
+/*
+ * UCPD is fed directly from HSI which is @ 16MHz. The ucpd_clk goes to
+ * a prescaler who's output feeds the 'half-bit' divider which is used
+ * to generate clock for delay counters and BMC Rx/Tx blocks. The rx is
+ * designed to work in freq ranges of 6 <--> 18 MHz, however recommended
+ * range is 9 <--> 18 MHz.
+ *
+ * ------- @ 16 MHz --------- @ ~600 kHz -------------
+ * HSI ---->| /psc |-------->| /hbit |--------------->| trans_cnt |
+ * ------- --------- | -------------
+ * | -------------
+ * |---------->| ifrgap_cnt|
+ * -------------
+ * Requirements:
+ * 1. hbit_clk ~= 600 kHz: 16 MHz / 600 kHz = 26.67
+ * 2. tTransitionWindow - 12 to 20 uSec
+ * 3. tInterframGap - uSec
+ *
+ * hbit_clk = HSI_clk / 26 = 615,385 kHz = 1.625 uSec period
+ * tTransitionWindow = 1.625 uS * 8 = 13 uS
+ * tInterFrameGap = 1.625 uS * 17 = 27.625 uS
+ */
+#define UCPD_PSC_DIV 1
+#define UCPD_HBIT_DIV 26
+#define UCPD_TRANSWIN_HBIT_CNT 8
+#define UCPD_IFRGAP_HBIT_CNT 17
+
+#define UCPD_ANASUB_TO_RP(r) ((r - 1) & 0x3)
+#define UCPD_RP_TO_ANASUB(r) ((r + 1) & 0x3)
+
+static void ucpd_port_enable(int port, int enable)
+{
+ if (enable)
+ STM32_UCPD_CFGR1(port) |= STM32_UCPD_CFGR1_UCPDEN;
+ else
+ STM32_UCPD_CFGR1(port) &= ~STM32_UCPD_CFGR1_UCPDEN;
+}
+
+static int ucpd_is_cc_pull_active(int port, enum usbpd_cc_pin cc_line)
+{
+ int cc_enable = STM32_UCPD_CR(port) & STM32_UCPD_CR_CCENABLE_MASK >>
+ STM32_UCPD_CR_CCENABLE_SHIFT;
+
+ return ((cc_enable >> cc_line) & 0x1);
+}
+
+void stm32gx_ucpd1_irq(void)
+{
+ /* STM32_IRQ_UCPD indicates this is from UCPD1, so port = 0 */
+ int port = 0;
+ uint32_t sr = STM32_UCPD_SR(port);
+
+ if (sr & (STM32_UCPD_SR_TYPECEVT1 | STM32_UCPD_SR_TYPECEVT2)) {
+ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0);
+ }
+ /* Clear interrupts now that PD events have been set */
+ STM32_UCPD_ICR(port) = sr;
+}
+DECLARE_IRQ(STM32_IRQ_UCPD1, stm32gx_ucpd1_irq, 1);
+
+int stm32gx_ucpd_init(int port)
+{
+ uint32_t cfgr1_reg;
+
+ /*
+ * After exiting reset, stm32gx will have dead battery mode enabled by
+ * default which connects Rd to CC1/CC2. This should be disabled when EC
+ * is powered up.
+ */
+ STM32_PWR_CR3 |= STM32_PWR_CR3_UCPD1_DBDIS;
+
+ /* Ensure that clock to UCPD is enabled */
+ STM32_RCC_APB1ENR2 |= STM32_RCC_APB1ENR2_UPCD1EN;
+
+ /*
+ * CFGR1 must be written when UCPD peripheral is disabled. Note that
+ * disabling ucpd causes the peripheral to quit any ongoing activity and
+ * sets all ucpd registers back their default values.
+ */
+ ucpd_port_enable(port, 0);
+
+ cfgr1_reg = STM32_UCPD_CFGR1_PSC_CLK_VAL(UCPD_PSC_DIV - 1) |
+ STM32_UCPD_CFGR1_TRANSWIN_VAL(UCPD_TRANSWIN_CNT - 1) |
+ STM32_UCPD_CFGR1_IFRGAP_VAL(UCPD_IFRGAP_CNT - 1) |
+ STM32_UCPD_CFGR1_HBITCLKD_VAL(UCPD_HBIT_DIV - 1);
+ STM32_UCPD_CFGR1(port) = cfgr1_reg;
+
+ /* Enable ucpd */
+ ucpd_port_enable(port, 1);
+
+ /* Configure CC change interrupts */
+ STM32_UCPD_IMR(port) = STM32_UCPD_IMR_TYPECEVT1IE |
+ STM32_UCPD_IMR_TYPECEVT2IE;
+ STM32_UCPD_ICR(port) = STM32_UCPD_ICR_TYPECEVT1CF |
+ STM32_UCPD_ICR_TYPECEVT2CF;
+
+ /* Enable UCPD interrupts */
+ task_enable_irq(STM32_IRQ_UCPD1);
+
+ return EC_SUCCESS;
+}
+
+int stm32gx_ucpd_release(int port)
+{
+ ucpd_port_enable(port, 0);
+
+ return EC_SUCCESS;
+}
+
+int stm32gx_ucpd_get_cc(int port, enum tcpc_cc_voltage_status *cc1,
+ enum tcpc_cc_voltage_status *cc2)
+{
+ int vstate_cc1;
+ int vstate_cc2;
+ int anamode;
+ uint32_t sr;
+
+ /*
+ * cc_voltage_status is determined from vstate_cc bit field in the
+ * status register. The meaning of the value vstate_cc depends on
+ * current value of ANAMODE (src/snk).
+ *
+ * vstate_cc maps directly to cc_state from tcpci spec when ANAMODE = 1,
+ * but needs to be modified slightly for case ANAMODE = 0.
+ *
+ * If presenting Rp (source), then need to to a circular shift of
+ * vstate_ccx value:
+ * vstate_cc | cc_state
+ * ------------------
+ * 0 -> 1
+ * 1 -> 2
+ * 2 -> 0
+ */
+
+ /* Get vstate_ccx values and power role */
+ sr = STM32_UCPD_SR(port);
+ /* Get Rp or Rd active */
+ anamode = !!(STM32_UCPD_CR(port) & STM32_UCPD_CR_ANAMODE);
+ vstate_cc1 = (sr & STM32_UCPD_SR_VSTATE_CC1_MASK) >>
+ STM32_UCPD_SR_VSTATE_CC1_SHIFT;
+ vstate_cc2 = (sr & STM32_UCPD_SR_VSTATE_CC2_MASK) >>
+ STM32_UCPD_SR_VSTATE_CC2_SHIFT;
+
+ /* Do circular shift if port == source */
+ if (anamode) {
+ if (vstate_cc1 != STM32_UCPD_SR_VSTATE_RA)
+ vstate_cc1 += 4;
+ if (vstate_cc2 != STM32_UCPD_SR_VSTATE_RA)
+ vstate_cc2 += 4;
+ } else {
+ if (vstate_cc1 != STM32_UCPD_SR_VSTATE_OPEN)
+ vstate_cc1 = (vstate_cc1 + 1) % 3;
+ if (vstate_cc2 != STM32_UCPD_SR_VSTATE_OPEN)
+ vstate_cc2 = (vstate_cc2 + 1) % 3;
+ }
+
+ *cc1 = vstate_cc1;
+ *cc2 = vstate_cc2;
+
+ return EC_SUCCESS;
+}
+
+int stm32gx_ucpd_get_role_control(int port)
+{
+ int role_control;
+ int cc1;
+ int cc2;
+ int anamode = !!(STM32_UCPD_CR(port) & STM32_UCPD_CR_ANAMODE);
+ int anasubmode = (STM32_UCPD_CR(port) & STM32_UCPD_CR_ANASUBMODE_MASK)
+ >> STM32_UCPD_CR_ANASUBMODE_SHIFT;
+
+ /*
+ * Role control register is defined as:
+ * R_cc1 -> b 1:0
+ * R_cc2 -> b 3:2
+ * Rp -> b 5:4
+ *
+ * In TCPCI, CCx is defined as:
+ * 00b -> Ra
+ * 01b -> Rp
+ * 10b -> Rd
+ * 11b -> Open (don't care)
+ *
+ * For ucpd, this information is encoded in ANAMODE and ANASUBMODE
+ * fields as follows:
+ * ANAMODE CCx
+ * 0 -> Rp -> 1
+ * 1 -> Rd -> 2
+ *
+ * ANASUBMODE:
+ * 00b -> TYPEC_RP_RESERVED (open)
+ * 01b -> TYPEC_RP_USB
+ * 10b -> TYPEC_RP_1A5
+ * 11b -> TYPEC_RP_3A0
+ *
+ * CCx = ANAMODE + 1, if CCx is enabled
+ * Rp = (ANASUBMODE - 1) & 0x3
+ */
+ cc1 = ucpd_is_cc_pull_active(port, USBPD_CC_PIN_1) ? anamode + 1 :
+ TYPEC_CC_OPEN;
+ cc2 = ucpd_is_cc_pull_active(port, USBPD_CC_PIN_2) ? anamode + 1 :
+ TYPEC_CC_OPEN;
+ role_control = cc1 | (cc2 << 2);
+ /* Circular shift anasubmode to convert to Rp range */
+ role_control |= (UCPD_ANASUB_TO_RP(anasubmode) << 4);
+
+ return role_control;
+}
+
+int stm32gx_ucpd_set_cc(int port, int cc_pull, int rp)
+{
+ uint32_t cr = STM32_UCPD_CR(port);
+
+ /*
+ * Always set ANASUBMODE to match desired Rp. TCPM layer has a valid
+ * range of 0, 1, or 2. This range maps to 1, 2, or 3 in ucpd for
+ * ANASUBMODE.
+ */
+ cr &= ~STM32_UCPD_CR_ANASUBMODE_MASK;
+ cr |= STM32_UCPD_CR_ANASUBMODE_VAL(UCPD_RP_TO_ANASUB(rp));
+
+ /* Disconnect both pull from both CC lines by default */
+ cr &= ~STM32_UCPD_CR_CCENABLE_MASK;
+ /* Set ANAMODE if cc_pull is Rd */
+ if (cc_pull == TYPEC_CC_RD) {
+ cr |= STM32_UCPD_CR_ANAMODE | STM32_UCPD_CR_CCENABLE_MASK;
+ /* Clear ANAMODE if cc_pull is Rp */
+ } else if (cc_pull == TYPEC_CC_RP) {
+ cr &= ~(STM32_UCPD_CR_ANAMODE);
+ cr |= STM32_UCPD_CR_CCENABLE_MASK;
+ }
+
+ /* Update pull values */
+ STM32_UCPD_CR(port) = cr;
+
+ /* TODO(b/): Should this return error if cc_pull == Ra */
+ return EC_SUCCESS;
+}
+
+int stm32gx_ucpd_set_polarity(int port, enum tcpc_cc_polarity polarity)
+{
+ /*
+ * Polarity impacts the PHYCCSEL, CCENABLE, and CCxTCDIS fields. This
+ * function is called when polarity is updated at TCPM layer. STM32Gx
+ * only supports POLARITY_CC1 or POLARITY_CC2 and this is stored in the
+ * PHYCCSEL bit in the CR register.
+ */
+ if (polarity > POLARITY_CC2)
+ return EC_ERROR_UNIMPLEMENTED;
+
+ if (polarity == POLARITY_CC1)
+ STM32_UCPD_CR(port) &= ~STM32_UCPD_CR_PHYCCSEL;
+ else if (polarity == POLARITY_CC2)
+ STM32_UCPD_CR(port) |= STM32_UCPD_CR_PHYCCSEL;
+
+ return EC_SUCCESS;
+}
+
diff --git a/chip/stm32/ucpd-stm32gx.h b/chip/stm32/ucpd-stm32gx.h
new file mode 100644
index 0000000000..f0a73cb29e
--- /dev/null
+++ b/chip/stm32/ucpd-stm32gx.h
@@ -0,0 +1,111 @@
+/* Copyright 2020 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_UCPD_STM32GX_H
+#define __CROS_EC_UCPD_STM32GX_H
+
+/* STM32 UCPD driver for Chrome EC */
+
+#include "usb_pd_tcpm.h"
+
+/*
+ * K-codes and ordered set defines. These codes and sets are used to encode
+ * which type of USB-PD message is being sent. This information can be found in
+ * the USB-PD spec section 5.4 - 5.6. This info is also included in the STM32G4
+ * TRM (RM0440) 45.4.3
+ */
+#define UCPD_SYNC1 0x18u
+#define UCPD_SYNC2 0x11u
+#define UCPD_SYNC3 0x06u
+#define UCPD_RST1 0x07u
+#define UCPD_RST2 0x19u
+#define UCPD_EOP 0x0Du
+
+enum ucpd_tx_ordset {
+ TX_ORDERSET_SOP = (UCPD_SYNC1 |
+ (UCPD_SYNC1<<5u) |
+ (UCPD_SYNC1<<10u) |
+ (UCPD_SYNC2<<15u)),
+ TX_ORDERSET_SOP1 = (UCPD_SYNC1 |
+ (UCPD_SYNC1<<5u) |
+ (UCPD_SYNC3<<10u) |
+ (UCPD_SYNC3<<15u)),
+ TX_ORDERSET_SOP2 = (UCPD_SYNC1 |
+ (UCPD_SYNC3<<5u) |
+ (UCPD_SYNC1<<10u) |
+ (UCPD_SYNC3<<15u)),
+ TX_ORDERSET_HARD_RESET = (UCPD_RST1 |
+ (UCPD_RST1<<5u) |
+ (UCPD_RST1<<10u) |
+ (UCPD_RST2<<15u)),
+ TX_ORDERSET_CABLE_RESET =
+ (UCPD_RST1 |
+ (UCPD_SYNC1<<5u) |
+ (UCPD_RST1<<10u) |
+ (UCPD_SYNC3<<15u)),
+ TX_ORDERSET_SOP1_DEBUG = (UCPD_SYNC1 |
+ (UCPD_RST2<<5u) |
+ (UCPD_RST2<<10u) |
+ (UCPD_SYNC3<<15u)),
+ TX_ORDERSET_SOP2_DEBUG = (UCPD_SYNC1 |
+ (UCPD_RST2<<5u) |
+ (UCPD_SYNC3<<10u) |
+ (UCPD_SYNC2<<15u)),
+};
+
+/**
+ * STM32Gx UCPD implementation of tcpci .init method
+ *
+ * @param usbc_port -> USB-C Port number
+ * @return EC_SUCCESS
+ */
+int stm32gx_ucpd_init(int usbc_port);
+
+/**
+ * STM32Gx UCPD implementation of tcpci .release method
+ *
+ * @param usbc_port -> USB-C Port number
+ * @return EC_SUCCESS
+ */
+int stm32gx_ucpd_release(int usbc_port);
+
+/**
+ * STM32Gx UCPD implementation of tcpci .get_cc method
+ *
+ * @param usbc_port -> USB-C Port number
+ * @param *cc1 -> pointer to cc1 result
+ * @param *cc2 -> pointer to cc2 result
+ * @return EC_SUCCESS
+ */
+int stm32gx_ucpd_get_cc(int usbc_port, enum tcpc_cc_voltage_status *cc1,
+ enum tcpc_cc_voltage_status *cc2);
+
+/**
+ * STM32Gx equivalent for TCPCI role_control register
+ *
+ * @param usbc_port -> USB-C Port number
+ * @return EC_SUCCESS
+ */
+int stm32gx_ucpd_get_role_control(int usbc_port);
+
+/**
+ * STM32Gx UCPD implementation of tcpci .set_cc method
+ *
+ * @param usbc_port -> USB-C Port number
+ * @param cc_pull -> Rp or Rd selection
+ * @param rp -> value of Rp (if cc_pull == Rp)
+ * @return EC_SUCCESS
+ */
+int stm32gx_ucpd_set_cc(int usbc_port, int cc_pull, int rp);
+
+/**
+ * STM32Gx UCPD implementation of tcpci .set_cc method
+ *
+ * @param usbc_port -> USB-C Port number
+ * @param polarity -> CC1 or CC2 selection
+ * @return EC_SUCCESS
+ */
+int stm32gx_ucpd_set_polarity(int usbc_port, enum tcpc_cc_polarity polarity);
+
+#endif /* __CROS_EC_UCPD_STM32GX_H */