123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright 2019 Google LLC
- * Copyright (C) 2015 - 2017 Intel Corp.
- * Copyright (C) 2017 - 2019 Siemens AG
- * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.)
- * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.)
- *
- * Portions from coreboot soc/intel/apollolake/chip.c
- */
- #define LOG_CATEGORY UCLASS_NORTHBRIDGE
- #include <common.h>
- #include <dm.h>
- #include <dt-structs.h>
- #include <log.h>
- #include <spl.h>
- #include <tables_csum.h>
- #include <acpi/acpi_table.h>
- #include <asm/acpi_nhlt.h>
- #include <asm/intel_pinctrl.h>
- #include <asm/intel_regs.h>
- #include <asm/io.h>
- #include <asm/pci.h>
- #include <asm/arch/acpi.h>
- #include <asm/arch/systemagent.h>
- #include <dt-bindings/sound/nhlt.h>
- #include <dm/acpi.h>
- enum {
- PCIEXBAR = 0x60,
- PCIEXBAR_LENGTH_256MB = 0,
- PCIEXBAR_LENGTH_128MB,
- PCIEXBAR_LENGTH_64MB,
- PCIEXBAR_PCIEXBAREN = 1 << 0,
- BGSM = 0xb4, /* Base GTT Stolen Memory */
- TSEG = 0xb8, /* TSEG base */
- TOLUD = 0xbc,
- };
- /**
- * struct apl_hostbridge_plat - platform data for hostbridge
- *
- * @dtplat: Platform data for of-platdata
- * @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_plat {
- #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;
- };
- static const struct nhlt_format_config dmic_1ch_formats[] = {
- /* 48 KHz 16-bits per sample. */
- {
- .num_channels = 1,
- .sample_freq_khz = 48,
- .container_bits_per_sample = 16,
- .valid_bits_per_sample = 16,
- .settings_file = "dmic-1ch-48khz-16b.dat",
- },
- };
- static const struct nhlt_dmic_array_config dmic_1ch_mic_config = {
- .tdm_config = {
- .config_type = NHLT_TDM_MIC_ARRAY,
- },
- .array_type = NHLT_MIC_ARRAY_VENDOR_DEFINED,
- };
- static const struct nhlt_endp_descriptor dmic_1ch_descriptors[] = {
- {
- .link = NHLT_LINK_PDM,
- .device = NHLT_PDM_DEV,
- .direction = NHLT_DIR_CAPTURE,
- .vid = NHLT_VID,
- .did = NHLT_DID_DMIC,
- .cfg = &dmic_1ch_mic_config,
- .cfg_size = sizeof(dmic_1ch_mic_config),
- .formats = dmic_1ch_formats,
- .num_formats = ARRAY_SIZE(dmic_1ch_formats),
- },
- };
- static const struct nhlt_format_config dmic_2ch_formats[] = {
- /* 48 KHz 16-bits per sample. */
- {
- .num_channels = 2,
- .sample_freq_khz = 48,
- .container_bits_per_sample = 16,
- .valid_bits_per_sample = 16,
- .settings_file = "dmic-2ch-48khz-16b.dat",
- },
- };
- static const struct nhlt_dmic_array_config dmic_2ch_mic_config = {
- .tdm_config = {
- .config_type = NHLT_TDM_MIC_ARRAY,
- },
- .array_type = NHLT_MIC_ARRAY_2CH_SMALL,
- };
- static const struct nhlt_endp_descriptor dmic_2ch_descriptors[] = {
- {
- .link = NHLT_LINK_PDM,
- .device = NHLT_PDM_DEV,
- .direction = NHLT_DIR_CAPTURE,
- .vid = NHLT_VID,
- .did = NHLT_DID_DMIC,
- .cfg = &dmic_2ch_mic_config,
- .cfg_size = sizeof(dmic_2ch_mic_config),
- .formats = dmic_2ch_formats,
- .num_formats = ARRAY_SIZE(dmic_2ch_formats),
- },
- };
- static const struct nhlt_format_config dmic_4ch_formats[] = {
- /* 48 KHz 16-bits per sample. */
- {
- .num_channels = 4,
- .sample_freq_khz = 48,
- .container_bits_per_sample = 16,
- .valid_bits_per_sample = 16,
- .settings_file = "dmic-4ch-48khz-16b.dat",
- },
- };
- static const struct nhlt_dmic_array_config dmic_4ch_mic_config = {
- .tdm_config = {
- .config_type = NHLT_TDM_MIC_ARRAY,
- },
- .array_type = NHLT_MIC_ARRAY_4CH_L_SHAPED,
- };
- static const struct nhlt_endp_descriptor dmic_4ch_descriptors[] = {
- {
- .link = NHLT_LINK_PDM,
- .device = NHLT_PDM_DEV,
- .direction = NHLT_DIR_CAPTURE,
- .vid = NHLT_VID,
- .did = NHLT_DID_DMIC,
- .cfg = &dmic_4ch_mic_config,
- .cfg_size = sizeof(dmic_4ch_mic_config),
- .formats = dmic_4ch_formats,
- .num_formats = ARRAY_SIZE(dmic_4ch_formats),
- },
- };
- static int apl_hostbridge_early_init_pinctrl(struct udevice *dev)
- {
- struct apl_hostbridge_plat *plat = dev_get_plat(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_plat *plat = dev_get_plat(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_of_to_plat(struct udevice *dev)
- {
- struct apl_hostbridge_plat *plat = dev_get_plat(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 int apl_acpi_hb_get_name(const struct udevice *dev, char *out_name)
- {
- return acpi_copy_name(out_name, "RHUB");
- }
- #ifdef CONFIG_GENERATE_ACPI_TABLE
- static int apl_acpi_hb_write_tables(const struct udevice *dev,
- struct acpi_ctx *ctx)
- {
- struct acpi_table_header *header;
- struct acpi_dmar *dmar;
- u32 val;
- /*
- * Create DMAR table only if virtualization is enabled. Due to some
- * constraints on Apollo Lake SoC (some stepping affected), VTD could
- * not be enabled together with IPU. Doing so will override and disable
- * VTD while leaving CAPID0_A still reporting that VTD is available.
- * As in this case FSP will lock VTD to disabled state, we need to make
- * sure that DMAR table generation only happens when at least DEFVTBAR
- * is enabled. Otherwise the DMAR header will be generated while the
- * content of the table will be missing.
- */
- dm_pci_read_config32(dev, CAPID0_A, &val);
- if ((val & VTD_DISABLE) ||
- !(readl(MCHBAR_REG(DEFVTBAR)) & VTBAR_ENABLED))
- return 0;
- log_debug("ACPI: * DMAR\n");
- dmar = (struct acpi_dmar *)ctx->current;
- header = &dmar->header;
- acpi_create_dmar(dmar, DMAR_INTR_REMAP);
- ctx->current += sizeof(struct acpi_dmar);
- apl_acpi_fill_dmar(ctx);
- /* (Re)calculate length and checksum */
- header->length = ctx->current - (void *)dmar;
- header->checksum = table_compute_checksum((void *)dmar, header->length);
- acpi_align(ctx);
- acpi_add_table(ctx, dmar);
- return 0;
- }
- #endif
- static int apl_acpi_setup_nhlt(const struct udevice *dev, struct acpi_ctx *ctx)
- {
- struct nhlt *nhlt = ctx->nhlt;
- u32 channels;
- ofnode node;
- node = ofnode_find_subnode(dev_ofnode(dev), "nhlt");
- if (ofnode_read_u32(node, "intel,dmic-channels", &channels))
- return log_msg_ret("channels", -EINVAL);
- switch (channels) {
- case 1:
- return nhlt_add_endpoints(nhlt, dmic_1ch_descriptors,
- ARRAY_SIZE(dmic_1ch_descriptors));
- case 2:
- return nhlt_add_endpoints(nhlt, dmic_2ch_descriptors,
- ARRAY_SIZE(dmic_2ch_descriptors));
- case 4:
- return nhlt_add_endpoints(nhlt, dmic_4ch_descriptors,
- ARRAY_SIZE(dmic_4ch_descriptors));
- }
- return log_msg_ret("channels", -EINVAL);
- }
- static int apl_hostbridge_remove(struct udevice *dev)
- {
- /*
- * TODO(sjg@chromium.org): Consider adding code from coreboot's
- * platform_fsp_notify_status()
- */
- return 0;
- }
- static ulong sa_read_reg(struct udevice *dev, int reg)
- {
- u32 val;
- /* All regions concerned for have 1 MiB alignment */
- dm_pci_read_config32(dev, BGSM, &val);
- return ALIGN_DOWN(val, 1 << 20);
- }
- ulong sa_get_tolud_base(struct udevice *dev)
- {
- return sa_read_reg(dev, TOLUD);
- }
- ulong sa_get_gsm_base(struct udevice *dev)
- {
- return sa_read_reg(dev, BGSM);
- }
- ulong sa_get_tseg_base(struct udevice *dev)
- {
- return sa_read_reg(dev, TSEG);
- }
- struct acpi_ops apl_hostbridge_acpi_ops = {
- .get_name = apl_acpi_hb_get_name,
- #ifdef CONFIG_GENERATE_ACPI_TABLE
- .write_tables = apl_acpi_hb_write_tables,
- #endif
- .setup_nhlt = apl_acpi_setup_nhlt,
- };
- static const struct udevice_id apl_hostbridge_ids[] = {
- { .compatible = "intel,apl-hostbridge" },
- { }
- };
- U_BOOT_DRIVER(intel_apl_hostbridge) = {
- .name = "intel_apl_hostbridge",
- .id = UCLASS_NORTHBRIDGE,
- .of_match = apl_hostbridge_ids,
- .of_to_plat = apl_hostbridge_of_to_plat,
- .probe = apl_hostbridge_probe,
- .remove = apl_hostbridge_remove,
- .plat_auto = sizeof(struct apl_hostbridge_plat),
- ACPI_OPS_PTR(&apl_hostbridge_acpi_ops)
- .flags = DM_FLAG_OS_PREPARE,
- };
|