Hi Simon, On Mon, Nov 25, 2019 at 12:12 PM Simon Glass <s...@chromium.org> wrote: > > This driver models the hostbridge as a northbridge. It simply sets up the > graphics BAR. It supports of-platdata. > > Signed-off-by: Simon Glass <s...@chromium.org> > --- > > Changes in v5: None > Changes in v4: > - Avoid needing to know internals of pinctrl in this driver > - Move code to pinctrl driver > - Switch over to use pinctrl for pad init/config > > Changes in v3: > - Move pad programming into the hostbridge to reduce TPL device-tree size > - Use pci_get_devfn() > > Changes in v2: None > > arch/x86/cpu/apollolake/Makefile | 1 + > arch/x86/cpu/apollolake/hostbridge.c | 179 +++++++++++++++++++++++++++ > 2 files changed, 180 insertions(+) > create mode 100644 arch/x86/cpu/apollolake/hostbridge.c > > diff --git a/arch/x86/cpu/apollolake/Makefile > b/arch/x86/cpu/apollolake/Makefile > index 3a8c2f66a3..4d3c08f84e 100644 > --- a/arch/x86/cpu/apollolake/Makefile > +++ b/arch/x86/cpu/apollolake/Makefile > @@ -4,5 +4,6 @@ > > obj-$(CONFIG_SPL_BUILD) += systemagent.o > > +obj-y += hostbridge.o > obj-y += pmc.o > obj-y += uart.o > diff --git a/arch/x86/cpu/apollolake/hostbridge.c > b/arch/x86/cpu/apollolake/hostbridge.c > new file mode 100644 > index 0000000000..25fb51dd9a > --- /dev/null > +++ b/arch/x86/cpu/apollolake/hostbridge.c > @@ -0,0 +1,179 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright 2019 Google LLC > + */ > + > +#include <common.h> > +#include <dm.h> > +#include <dt-structs.h> > +#include <spl.h> > +#include <asm/intel_pinctrl.h> > +#include <asm/intel_regs.h> > +#include <asm/pci.h> > +#include <asm/arch/systemagent.h> > + > +/** > + * struct apl_hostbridge_platdata - platform data for hostbridge > + * > + * @num_cfgs: Number of configuration words for each pad
There is no num_cfgs member in this struct > + * @early_pads: Early pad data to set up, each (pad, cfg0, cfg1) > + * @early_pads_count: Number of pads to process > + * @pciex_region_size: BAR length in bytes > + * @bdf: Bus/device/function of hostbridge > + */ > +struct apl_hostbridge_platdata { > +#if CONFIG_IS_ENABLED(OF_PLATDATA) > + struct dtd_intel_apl_hostbridge dtplat; > +#endif > + u32 *early_pads; > + int early_pads_count; > + uint pciex_region_size; > + pci_dev_t bdf; > +}; > + > +enum { > + PCIEXBAR = 0x60, > + PCIEXBAR_LENGTH_256MB = 0, > + PCIEXBAR_LENGTH_128MB, > + PCIEXBAR_LENGTH_64MB, > + > + PCIEXBAR_PCIEXBAREN = 1 << 0, > + > + TSEG = 0xb8, /* TSEG base */ > +}; > + > +static int apl_hostbridge_early_init_pinctrl(struct udevice *dev) > +{ > + struct apl_hostbridge_platdata *plat = dev_get_platdata(dev); > + struct udevice *pinctrl; > + int ret; > + > + ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl); > + if (ret) > + return log_msg_ret("no hostbridge pinctrl", ret); > + > + return pinctrl_config_pads(pinctrl, plat->early_pads, > + plat->early_pads_count); > +} > + > +static int apl_hostbridge_early_init(struct udevice *dev) > +{ > + struct apl_hostbridge_platdata *plat = dev_get_platdata(dev); > + u32 region_size; > + ulong base; > + u32 reg; > + int ret; > + > + /* Set up the MCHBAR */ > + pci_x86_read_config(plat->bdf, MCHBAR, &base, PCI_SIZE_32); > + base = MCH_BASE_ADDRESS; > + pci_x86_write_config(plat->bdf, MCHBAR, base | 1, PCI_SIZE_32); > + > + /* > + * The PCIEXBAR is assumed to live in the memory mapped IO space under > + * 4GiB > + */ > + pci_x86_write_config(plat->bdf, PCIEXBAR + 4, 0, PCI_SIZE_32); > + > + switch (plat->pciex_region_size >> 20) { > + default: > + case 256: > + region_size = PCIEXBAR_LENGTH_256MB; > + break; > + case 128: > + region_size = PCIEXBAR_LENGTH_128MB; > + break; > + case 64: > + region_size = PCIEXBAR_LENGTH_64MB; > + break; > + } > + > + reg = CONFIG_MMCONF_BASE_ADDRESS | (region_size << 1) > + | PCIEXBAR_PCIEXBAREN; > + pci_x86_write_config(plat->bdf, PCIEXBAR, reg, PCI_SIZE_32); > + > + /* > + * TSEG defines the base of SMM range. BIOS determines the base > + * of TSEG memory which must be at or below Graphics base of GTT > + * Stolen memory, hence its better to clear TSEG register early > + * to avoid power on default non-zero value (if any). > + */ > + pci_x86_write_config(plat->bdf, TSEG, 0, PCI_SIZE_32); > + > + ret = apl_hostbridge_early_init_pinctrl(dev); > + if (ret) > + return log_msg_ret("pinctrl", ret); > + > + return 0; > +} > + > +static int apl_hostbridge_ofdata_to_platdata(struct udevice *dev) > +{ > + struct apl_hostbridge_platdata *plat = dev_get_platdata(dev); > + struct udevice *pinctrl; > + int ret; > + > + /* > + * The host bridge holds the early pad data needed to get through TPL. > + * This is a small amount of data, enough to fit in TPL, so we keep it > + * separate from the full pad data, stored in the fsp-s subnode. That > + * subnode is not present in TPL, to save space. > + */ > + ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl); > + if (ret) > + return log_msg_ret("no hostbridge PINCTRL", ret); > +#if !CONFIG_IS_ENABLED(OF_PLATDATA) > + int root; > + > + /* Get length of PCI Express Region */ > + plat->pciex_region_size = dev_read_u32_default(dev, > "pciex-region-size", > + 256 << 20); > + > + root = pci_get_devfn(dev); > + if (root < 0) > + return log_msg_ret("Cannot get host-bridge PCI address", > root); > + plat->bdf = root; > + > + ret = pinctrl_read_pads(pinctrl, dev_ofnode(dev), "early-pads", > + &plat->early_pads, &plat->early_pads_count); > + if (ret) > + return log_msg_ret("early-pads", ret); > +#else > + struct dtd_intel_apl_hostbridge *dtplat = &plat->dtplat; > + int size; > + > + plat->pciex_region_size = dtplat->pciex_region_size; > + plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]); > + > + /* Assume that if everything is 0, it is empty */ > + plat->early_pads = dtplat->early_pads; > + size = ARRAY_SIZE(dtplat->early_pads); > + plat->early_pads_count = pinctrl_count_pads(pinctrl, plat->early_pads, > + size); > + > +#endif > + > + return 0; > +} > + > +static int apl_hostbridge_probe(struct udevice *dev) > +{ > + if (spl_phase() == PHASE_TPL) > + return apl_hostbridge_early_init(dev); > + > + return 0; > +} > + > +static const struct udevice_id apl_hostbridge_ids[] = { > + { .compatible = "intel,apl-hostbridge" }, > + { } > +}; > + > +U_BOOT_DRIVER(apl_hostbridge_drv) = { > + .name = "intel_apl_hostbridge", > + .id = UCLASS_NORTHBRIDGE, > + .of_match = apl_hostbridge_ids, > + .ofdata_to_platdata = apl_hostbridge_ofdata_to_platdata, > + .probe = apl_hostbridge_probe, > + .platdata_auto_alloc_size = sizeof(struct apl_hostbridge_platdata), > +}; > -- Regards, Bin _______________________________________________ U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot