diff options
Diffstat (limited to 'src/soc/intel/apollolake')
-rw-r--r-- | src/soc/intel/apollolake/chip.c | 57 |
1 files changed, 57 insertions, 0 deletions
diff --git a/src/soc/intel/apollolake/chip.c b/src/soc/intel/apollolake/chip.c index 081bba373e..83a6baa5f5 100644 --- a/src/soc/intel/apollolake/chip.c +++ b/src/soc/intel/apollolake/chip.c @@ -49,9 +49,19 @@ #include <soc/cpu.h> #include <soc/pm.h> #include <soc/systemagent.h> +#include <timer.h> #include "chip.h" +#define DUAL_ROLE_CFG0 0x80d8 +#define SW_VBUS_VALID_MASK (1 << 24) +#define SW_IDPIN_EN_MASK (1 << 21) +#define SW_IDPIN_MASK (1 << 20) +#define SW_IDPIN_HOST (0 << 20) +#define DUAL_ROLE_CFG1 0x80dc +#define DRD_MODE_MASK (1 << 29) +#define DRD_MODE_HOST (1 << 29) + const char *soc_acpi_name(const struct device *dev) { if (dev->path.type == DEVICE_PATH_DOMAIN) @@ -654,6 +664,46 @@ static void drop_privilege_all(void) printk(BIOS_ERR, "failed to enable untrusted mode\n"); } +static void configure_xhci_host_mode_port0(void) +{ + uint32_t *cfg0; + uint32_t *cfg1; + const struct resource *res; + uint32_t reg; + struct stopwatch sw; + struct device *xhci_dev = PCH_DEV_XHCI; + + printk(BIOS_INFO, "Putting xHCI port 0 into host mode.\n"); + res = find_resource(xhci_dev, PCI_BASE_ADDRESS_0); + cfg0 = (void *)(uintptr_t)(res->base + DUAL_ROLE_CFG0); + cfg1 = (void *)(uintptr_t)(res->base + DUAL_ROLE_CFG1); + reg = read32(cfg0); + if (!(reg && SW_IDPIN_EN_MASK)) + return; + + reg &= ~(SW_IDPIN_MASK | SW_VBUS_VALID_MASK); + write32(cfg0, reg); + + stopwatch_init_msecs_expire(&sw, 10); + /* Wait for the host mode status bit. */ + while ((read32(cfg1) & DRD_MODE_MASK) != DRD_MODE_HOST) { + if (stopwatch_expired(&sw)) { + printk(BIOS_ERR, "Timed out waiting for host mode.\n"); + return; + } + } + + printk(BIOS_INFO, "xHCI port 0 host switch over took %lu ms\n", + stopwatch_duration_msecs(&sw)); +} + +static int check_xdci_enable(void) +{ + struct device *dev = PCH_DEV_XDCI; + + return !!dev->enabled; +} + void platform_fsp_notify_status(enum fsp_notify_phase phase) { if (phase == END_OF_FIRMWARE) { @@ -666,6 +716,13 @@ void platform_fsp_notify_status(enum fsp_notify_phase phase) * security. */ drop_privilege_all(); + + /* + * When USB OTG is set, GLK FSP enables xHCI SW ID pin and + * configures USB-C as device mode. Force USB-C into host mode. + */ + if (check_xdci_enable()) + configure_xhci_host_mode_port0(); } } |