coreboot-kgpe-d16/src/drivers/usb/pci_ehci.c
Kyösti Mälkki 5bd926428e usbdebug: Sanity check PCI EHCI location
If requested EHCI function is not on bus 0, we would
need to open MMIO windows and configuration register
space for the connected upstream PCI bridge for it
to work. We don't plan to do so.

Change-Id: I7c1c60f9d9890dedfedc9d977faf5152ba362692
Signed-off-by: Kyösti Mälkki <kyosti.malkki@gmail.com>
Reviewed-on: https://review.coreboot.org/c/30692
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Felix Held <felix-coreboot@felixheld.de>
2019-01-07 10:38:26 +00:00

134 lines
3.6 KiB
C

/*
* This file is part of the coreboot project.
*
* Copyright (C) 2006 Eric Biederman (ebiederm@xmission.com)
* Copyright (C) 2007 AMD
*
* 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 <stddef.h>
#include <console/console.h>
#include <device/pci_ehci.h>
#include <arch/io.h>
#include <device/pci.h>
#include <device/pci_def.h>
#include <string.h>
#include "ehci_debug.h"
#include "ehci.h"
#if ENV_RAMSTAGE
static struct device_operations *ehci_drv_ops;
static struct device_operations ehci_dbg_ops;
#endif
int ehci_debug_hw_enable(unsigned int *base, unsigned int *dbg_offset)
{
pci_devfn_t dbg_dev = pci_ehci_dbg_dev(CONFIG_USBDEBUG_HCD_INDEX);
/* We only support controllers on bus 0. */
if (PCI_DEV2SEGBUS(dbg_dev) != 0)
return -1;
#ifdef __SIMPLE_DEVICE__
pci_devfn_t dev = dbg_dev;
#else
struct device *dev = pcidev_path_on_root(PCI_DEV2DEVFN(dbg_dev));
#endif
u32 class = pci_read_config32(dev, PCI_CLASS_REVISION) >> 8;
if (class != PCI_EHCI_CLASSCODE)
return -1;
u8 pm_cap = pci_find_capability(dev, PCI_CAP_ID_PM);
if (pm_cap) {
u16 pm_ctrl = pci_read_config16(dev, pm_cap + PCI_PM_CTRL);
/* Set to D0 and disable PM events. */
pm_ctrl &= ~PCI_PM_CTRL_PME_ENABLE;
pm_ctrl &= ~PCI_PM_CTRL_STATE_MASK;
pci_write_config16(dev, pm_cap + PCI_PM_CTRL, pm_ctrl);
}
u8 pos = pci_find_capability(dev, PCI_CAP_ID_EHCI_DEBUG);
if (!pos)
return -1;
u32 cap = pci_read_config32(dev, pos);
/* FIXME: We should remove static EHCI_BAR_INDEX. */
u8 ehci_bar = 0x10 + 4 * ((cap >> 29) - 1);
if (ehci_bar != EHCI_BAR_INDEX)
return -1;
pci_write_config32(dev, ehci_bar, CONFIG_EHCI_BAR);
pci_write_config8(dev, PCI_COMMAND, PCI_COMMAND_MEMORY |
PCI_COMMAND_MASTER);
*base = CONFIG_EHCI_BAR;
*dbg_offset = (cap>>16) & 0x1ffc;
return 0;
}
void ehci_debug_select_port(unsigned int port)
{
pci_devfn_t dbg_dev = pci_ehci_dbg_dev(CONFIG_USBDEBUG_HCD_INDEX);
pci_ehci_dbg_set_port(dbg_dev, port);
}
#if ENV_RAMSTAGE
static void pci_ehci_set_resources(struct device *dev)
{
struct resource *res;
printk(BIOS_DEBUG, "%s EHCI Debug Port hook triggered\n", dev_path(dev));
usbdebug_disable();
if (ehci_drv_ops->set_resources)
ehci_drv_ops->set_resources(dev);
res = find_resource(dev, EHCI_BAR_INDEX);
if (!res)
return;
usbdebug_re_enable((u32)res->base);
report_resource_stored(dev, res, "");
printk(BIOS_DEBUG, "%s EHCI Debug Port relocated\n", dev_path(dev));
}
void pci_ehci_read_resources(struct device *dev)
{
pci_devfn_t dbg_dev = pci_ehci_dbg_dev(CONFIG_USBDEBUG_HCD_INDEX);
if (!ehci_drv_ops && pci_match_simple_dev(dev, dbg_dev)) {
memcpy(&ehci_dbg_ops, dev->ops, sizeof(ehci_dbg_ops));
ehci_drv_ops = dev->ops;
ehci_dbg_ops.set_resources = pci_ehci_set_resources;
dev->ops = &ehci_dbg_ops;
printk(BIOS_DEBUG, "%s EHCI BAR hook registered\n", dev_path(dev));
} else {
printk(BIOS_DEBUG, "More than one caller of %s from %s\n", __func__, dev_path(dev));
}
pci_dev_read_resources(dev);
}
#endif
u8 *pci_ehci_base_regs(pci_devfn_t sdev)
{
#ifdef __SIMPLE_DEVICE__
u8 *base = (u8 *)(pci_read_config32(sdev, EHCI_BAR_INDEX) & ~0x0f);
#else
struct device *dev = pcidev_path_on_root(PCI_DEV2DEVFN(sdev));
u8 *base = (u8 *)(pci_read_config32(dev, EHCI_BAR_INDEX) & ~0x0f);
#endif
return base + HC_LENGTH(read32(base));
}