4c8fbc0658
Use the common xDCI function to check if the controller is allowed in the current mode before enabling it. Otherwise, disable the PCI device if it has been enabled in devicetree. Change-Id: I5aea15511c52d1191babf551feb237f4144683e4 Signed-off-by: Duncan Laurie <dlaurie@chromium.org> Reviewed-on: https://review.coreboot.org/25364 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Furquan Shaikh <furquan@google.com> Reviewed-by: Aaron Durbin <adurbin@chromium.org>
91 lines
2.6 KiB
C
91 lines
2.6 KiB
C
/*
|
|
* This file is part of the coreboot project.
|
|
*
|
|
* Copyright 2016 Google Inc.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; version 2 of the License.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*/
|
|
|
|
#include <arch/io.h>
|
|
#include <console/console.h>
|
|
#include <device/device.h>
|
|
#include <device/pci.h>
|
|
#include <intelblocks/xdci.h>
|
|
#include <soc/pci_devs.h>
|
|
#include <timer.h>
|
|
|
|
#define DUAL_ROLE_CFG0 0x80d8
|
|
# define DRD_CONFIG_MASK (0x3 << 0)
|
|
# define DRD_CONFIG_DYNAMIC (0x0 << 0)
|
|
# define DRD_CONFIG_HOST (0x1 << 0)
|
|
# define DRD_CONFIG_DEVICE (0x2 << 0)
|
|
# define SW_VBUS_VALID_MASK (1 << 24)
|
|
# define SW_VBUS_DEASSERT_VALID (0 << 24)
|
|
# define SW_VBUS_ASSERT_VALID (1 << 24)
|
|
# define SW_IDPIN_EN_MASK (1 << 21)
|
|
# define SW_IDPIN_DIS (0 << 21)
|
|
# define SW_IDPIN_EN (1 << 21)
|
|
# define SW_IDPIN_MASK (1 << 20)
|
|
# define SW_IDPIN_HOST (0 << 20)
|
|
# define SW_IDPIN_DEVICE (1 << 20)
|
|
#define DUAL_ROLE_CFG1 0x80dc
|
|
# define DRD_MODE_MASK (1 << 29)
|
|
# define DRD_MODE_DEVICE (0 << 29)
|
|
# define DRD_MODE_HOST (1 << 29)
|
|
|
|
static void configure_host_mode_port0(struct device *dev)
|
|
{
|
|
uint32_t *cfg0;
|
|
uint32_t *cfg1;
|
|
const struct resource *res;
|
|
uint32_t reg;
|
|
struct stopwatch sw;
|
|
struct device *xdci_dev = PCH_DEV_XDCI;
|
|
|
|
/*
|
|
* Only default to host mode if the xdci device is present and
|
|
* enabled. If it's disabled assume the switch was already done
|
|
* in FSP.
|
|
*/
|
|
if (!dev->enabled || !xdci_dev->enabled || !xdci_can_enable())
|
|
return;
|
|
|
|
printk(BIOS_INFO, "Putting port 0 into host mode.\n");
|
|
|
|
res = find_resource(xdci_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);
|
|
reg &= ~(DRD_CONFIG_MASK | SW_IDPIN_EN_MASK | SW_IDPIN_MASK);
|
|
reg &= ~(SW_VBUS_VALID_MASK);
|
|
reg |= DRD_CONFIG_DYNAMIC | SW_IDPIN_EN | SW_IDPIN_HOST;
|
|
reg |= SW_VBUS_DEASSERT_VALID;
|
|
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_INFO, "Timed out waiting for host mode.\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
printk(BIOS_INFO, "XDCI port 0 host switch over took %lu ms\n",
|
|
stopwatch_duration_msecs(&sw));
|
|
}
|
|
|
|
void soc_xdci_init(struct device *dev)
|
|
{
|
|
configure_host_mode_port0(dev);
|
|
}
|