1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright 2019 Google LLC 4 * Copyright (C) 2015 - 2017 Intel Corp. 5 * Copyright (C) 2017 - 2019 Siemens AG 6 * (Written by Alexandru Gagniuc <alexandrux.gagniuc@intel.com> for Intel Corp.) 7 * (Written by Andrey Petrov <andrey.petrov@intel.com> for Intel Corp.) 8 * 9 * Portions from coreboot soc/intel/apollolake/chip.c 10 */ 11 12#define LOG_CATEGORY UCLASS_NORTHBRIDGE 13 14#include <common.h> 15#include <dm.h> 16#include <dt-structs.h> 17#include <log.h> 18#include <spl.h> 19#include <tables_csum.h> 20#include <acpi/acpi_table.h> 21#include <asm/acpi_nhlt.h> 22#include <asm/intel_pinctrl.h> 23#include <asm/intel_regs.h> 24#include <asm/io.h> 25#include <asm/pci.h> 26#include <asm/arch/acpi.h> 27#include <asm/arch/hostbridge.h> 28#include <asm/arch/systemagent.h> 29#include <dt-bindings/sound/nhlt.h> 30#include <dm/acpi.h> 31 32enum { 33 PCIEXBAR = 0x60, 34 PCIEXBAR_LENGTH_256MB = 0, 35 PCIEXBAR_LENGTH_128MB, 36 PCIEXBAR_LENGTH_64MB, 37 38 PCIEXBAR_PCIEXBAREN = 1 << 0, 39 40 BGSM = 0xb4, /* Base GTT Stolen Memory */ 41 TSEG = 0xb8, /* TSEG base */ 42 TOLUD = 0xbc, 43}; 44 45#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) 46static const struct nhlt_format_config dmic_1ch_formats[] = { 47 /* 48 KHz 16-bits per sample. */ 48 { 49 .num_channels = 1, 50 .sample_freq_khz = 48, 51 .container_bits_per_sample = 16, 52 .valid_bits_per_sample = 16, 53 .settings_file = "dmic-1ch-48khz-16b.dat", 54 }, 55}; 56 57static const struct nhlt_dmic_array_config dmic_1ch_mic_config = { 58 .tdm_config = { 59 .config_type = NHLT_TDM_MIC_ARRAY, 60 }, 61 .array_type = NHLT_MIC_ARRAY_VENDOR_DEFINED, 62}; 63 64static const struct nhlt_endp_descriptor dmic_1ch_descriptors[] = { 65 { 66 .link = NHLT_LINK_PDM, 67 .device = NHLT_PDM_DEV, 68 .direction = NHLT_DIR_CAPTURE, 69 .vid = NHLT_VID, 70 .did = NHLT_DID_DMIC, 71 .cfg = &dmic_1ch_mic_config, 72 .cfg_size = sizeof(dmic_1ch_mic_config), 73 .formats = dmic_1ch_formats, 74 .num_formats = ARRAY_SIZE(dmic_1ch_formats), 75 }, 76}; 77 78static const struct nhlt_format_config dmic_2ch_formats[] = { 79 /* 48 KHz 16-bits per sample. */ 80 { 81 .num_channels = 2, 82 .sample_freq_khz = 48, 83 .container_bits_per_sample = 16, 84 .valid_bits_per_sample = 16, 85 .settings_file = "dmic-2ch-48khz-16b.dat", 86 }, 87}; 88 89static const struct nhlt_dmic_array_config dmic_2ch_mic_config = { 90 .tdm_config = { 91 .config_type = NHLT_TDM_MIC_ARRAY, 92 }, 93 .array_type = NHLT_MIC_ARRAY_2CH_SMALL, 94}; 95 96static const struct nhlt_endp_descriptor dmic_2ch_descriptors[] = { 97 { 98 .link = NHLT_LINK_PDM, 99 .device = NHLT_PDM_DEV, 100 .direction = NHLT_DIR_CAPTURE, 101 .vid = NHLT_VID, 102 .did = NHLT_DID_DMIC, 103 .cfg = &dmic_2ch_mic_config, 104 .cfg_size = sizeof(dmic_2ch_mic_config), 105 .formats = dmic_2ch_formats, 106 .num_formats = ARRAY_SIZE(dmic_2ch_formats), 107 }, 108}; 109 110static const struct nhlt_format_config dmic_4ch_formats[] = { 111 /* 48 KHz 16-bits per sample. */ 112 { 113 .num_channels = 4, 114 .sample_freq_khz = 48, 115 .container_bits_per_sample = 16, 116 .valid_bits_per_sample = 16, 117 .settings_file = "dmic-4ch-48khz-16b.dat", 118 }, 119}; 120 121static const struct nhlt_dmic_array_config dmic_4ch_mic_config = { 122 .tdm_config = { 123 .config_type = NHLT_TDM_MIC_ARRAY, 124 }, 125 .array_type = NHLT_MIC_ARRAY_4CH_L_SHAPED, 126}; 127 128static const struct nhlt_endp_descriptor dmic_4ch_descriptors[] = { 129 { 130 .link = NHLT_LINK_PDM, 131 .device = NHLT_PDM_DEV, 132 .direction = NHLT_DIR_CAPTURE, 133 .vid = NHLT_VID, 134 .did = NHLT_DID_DMIC, 135 .cfg = &dmic_4ch_mic_config, 136 .cfg_size = sizeof(dmic_4ch_mic_config), 137 .formats = dmic_4ch_formats, 138 .num_formats = ARRAY_SIZE(dmic_4ch_formats), 139 }, 140}; 141#endif 142 143static int apl_hostbridge_early_init_pinctrl(struct udevice *dev) 144{ 145 struct apl_hostbridge_plat *plat = dev_get_plat(dev); 146 struct udevice *pinctrl; 147 int ret; 148 149 ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl); 150 if (ret) 151 return log_msg_ret("no hostbridge pinctrl", ret); 152 153 return pinctrl_config_pads(pinctrl, plat->early_pads, 154 plat->early_pads_count); 155} 156 157static int apl_hostbridge_early_init(struct udevice *dev) 158{ 159 struct apl_hostbridge_plat *plat = dev_get_plat(dev); 160 u32 region_size; 161 ulong base; 162 u32 reg; 163 int ret; 164 165 /* Set up the MCHBAR */ 166 pci_x86_read_config(plat->bdf, MCHBAR, &base, PCI_SIZE_32); 167 base = MCH_BASE_ADDRESS; 168 pci_x86_write_config(plat->bdf, MCHBAR, base | 1, PCI_SIZE_32); 169 170 /* 171 * The PCIEXBAR is assumed to live in the memory mapped IO space under 172 * 4GiB 173 */ 174 pci_x86_write_config(plat->bdf, PCIEXBAR + 4, 0, PCI_SIZE_32); 175 176 switch (plat->pciex_region_size >> 20) { 177 default: 178 case 256: 179 region_size = PCIEXBAR_LENGTH_256MB; 180 break; 181 case 128: 182 region_size = PCIEXBAR_LENGTH_128MB; 183 break; 184 case 64: 185 region_size = PCIEXBAR_LENGTH_64MB; 186 break; 187 } 188 189 reg = CONFIG_MMCONF_BASE_ADDRESS | (region_size << 1) 190 | PCIEXBAR_PCIEXBAREN; 191 pci_x86_write_config(plat->bdf, PCIEXBAR, reg, PCI_SIZE_32); 192 193 /* 194 * TSEG defines the base of SMM range. BIOS determines the base 195 * of TSEG memory which must be at or below Graphics base of GTT 196 * Stolen memory, hence its better to clear TSEG register early 197 * to avoid power on default non-zero value (if any). 198 */ 199 pci_x86_write_config(plat->bdf, TSEG, 0, PCI_SIZE_32); 200 201 ret = apl_hostbridge_early_init_pinctrl(dev); 202 if (ret) 203 return log_msg_ret("pinctrl", ret); 204 205 return 0; 206} 207 208static int apl_hostbridge_of_to_plat(struct udevice *dev) 209{ 210 struct apl_hostbridge_plat *plat = dev_get_plat(dev); 211 struct udevice *pinctrl; 212 int ret; 213 214 /* 215 * The host bridge holds the early pad data needed to get through TPL. 216 * This is a small amount of data, enough to fit in TPL, so we keep it 217 * separate from the full pad data, stored in the fsp-s subnode. That 218 * subnode is not present in TPL, to save space. 219 */ 220 ret = uclass_first_device_err(UCLASS_PINCTRL, &pinctrl); 221 if (ret) 222 return log_msg_ret("no hostbridge PINCTRL", ret); 223#if CONFIG_IS_ENABLED(OF_REAL) 224 int root; 225 226 /* Get length of PCI Express Region */ 227 plat->pciex_region_size = dev_read_u32_default(dev, "pciex-region-size", 228 256 << 20); 229 230 root = pci_get_devfn(dev); 231 if (root < 0) 232 return log_msg_ret("Cannot get host-bridge PCI address", root); 233 plat->bdf = root; 234 235 ret = pinctrl_read_pads(pinctrl, dev_ofnode(dev), "early-pads", 236 &plat->early_pads, &plat->early_pads_count); 237 if (ret) 238 return log_msg_ret("early-pads", ret); 239#else 240 struct dtd_intel_apl_hostbridge *dtplat = &plat->dtplat; 241 int size; 242 243 plat->pciex_region_size = dtplat->pciex_region_size; 244 plat->bdf = pci_ofplat_get_devfn(dtplat->reg[0]); 245 246 /* Assume that if everything is 0, it is empty */ 247 plat->early_pads = dtplat->early_pads; 248 size = ARRAY_SIZE(dtplat->early_pads); 249 plat->early_pads_count = pinctrl_count_pads(pinctrl, plat->early_pads, 250 size); 251 252#endif 253 254 return 0; 255} 256 257static int apl_hostbridge_probe(struct udevice *dev) 258{ 259 if (spl_phase() == PHASE_TPL) 260 return apl_hostbridge_early_init(dev); 261 262 return 0; 263} 264 265static int apl_acpi_hb_get_name(const struct udevice *dev, char *out_name) 266{ 267 return acpi_copy_name(out_name, "RHUB"); 268} 269 270#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) 271static int apl_acpi_hb_write_tables(const struct udevice *dev, 272 struct acpi_ctx *ctx) 273{ 274 struct acpi_table_header *header; 275 struct acpi_dmar *dmar; 276 u32 val; 277 278 /* 279 * Create DMAR table only if virtualization is enabled. Due to some 280 * constraints on Apollo Lake SoC (some stepping affected), VTD could 281 * not be enabled together with IPU. Doing so will override and disable 282 * VTD while leaving CAPID0_A still reporting that VTD is available. 283 * As in this case FSP will lock VTD to disabled state, we need to make 284 * sure that DMAR table generation only happens when at least DEFVTBAR 285 * is enabled. Otherwise the DMAR header will be generated while the 286 * content of the table will be missing. 287 */ 288 dm_pci_read_config32(dev, CAPID0_A, &val); 289 if ((val & VTD_DISABLE) || 290 !(readl(MCHBAR_REG(DEFVTBAR)) & VTBAR_ENABLED)) 291 return 0; 292 293 log_debug("ACPI: * DMAR\n"); 294 dmar = (struct acpi_dmar *)ctx->current; 295 header = &dmar->header; 296 acpi_create_dmar(dmar, DMAR_INTR_REMAP); 297 ctx->current += sizeof(struct acpi_dmar); 298 apl_acpi_fill_dmar(ctx); 299 300 /* (Re)calculate length and checksum */ 301 header->length = ctx->current - (void *)dmar; 302 header->checksum = table_compute_checksum((void *)dmar, header->length); 303 304 acpi_align(ctx); 305 acpi_add_table(ctx, dmar); 306 307 return 0; 308} 309 310static int apl_acpi_setup_nhlt(const struct udevice *dev, struct acpi_ctx *ctx) 311{ 312 struct nhlt *nhlt = ctx->nhlt; 313 u32 channels; 314 ofnode node; 315 316 node = ofnode_find_subnode(dev_ofnode(dev), "nhlt"); 317 if (ofnode_read_u32(node, "intel,dmic-channels", &channels)) 318 return log_msg_ret("channels", -EINVAL); 319 switch (channels) { 320 case 1: 321 return nhlt_add_endpoints(nhlt, dmic_1ch_descriptors, 322 ARRAY_SIZE(dmic_1ch_descriptors)); 323 case 2: 324 return nhlt_add_endpoints(nhlt, dmic_2ch_descriptors, 325 ARRAY_SIZE(dmic_2ch_descriptors)); 326 case 4: 327 return nhlt_add_endpoints(nhlt, dmic_4ch_descriptors, 328 ARRAY_SIZE(dmic_4ch_descriptors)); 329 } 330 331 return log_msg_ret("channels", -EINVAL); 332} 333#endif 334 335static int apl_hostbridge_remove(struct udevice *dev) 336{ 337 /* 338 * TODO(sjg@chromium.org): Consider adding code from coreboot's 339 * platform_fsp_notify_status() 340 */ 341 342 return 0; 343} 344 345static ulong sa_read_reg(struct udevice *dev, int reg) 346{ 347 u32 val; 348 349 /* All regions concerned for have 1 MiB alignment */ 350 dm_pci_read_config32(dev, BGSM, &val); 351 352 return ALIGN_DOWN(val, 1 << 20); 353} 354 355ulong sa_get_tolud_base(struct udevice *dev) 356{ 357 return sa_read_reg(dev, TOLUD); 358} 359 360ulong sa_get_gsm_base(struct udevice *dev) 361{ 362 return sa_read_reg(dev, BGSM); 363} 364 365ulong sa_get_tseg_base(struct udevice *dev) 366{ 367 return sa_read_reg(dev, TSEG); 368} 369 370struct acpi_ops apl_hostbridge_acpi_ops = { 371 .get_name = apl_acpi_hb_get_name, 372#if CONFIG_IS_ENABLED(GENERATE_ACPI_TABLE) 373 .write_tables = apl_acpi_hb_write_tables, 374 .setup_nhlt = apl_acpi_setup_nhlt, 375#endif 376}; 377 378#if CONFIG_IS_ENABLED(OF_REAL) 379static const struct udevice_id apl_hostbridge_ids[] = { 380 { .compatible = "intel,apl-hostbridge" }, 381 { } 382}; 383#endif 384 385U_BOOT_DRIVER(intel_apl_hostbridge) = { 386 .name = "intel_apl_hostbridge", 387 .id = UCLASS_NORTHBRIDGE, 388 .of_match = of_match_ptr(apl_hostbridge_ids), 389 .of_to_plat = apl_hostbridge_of_to_plat, 390 .probe = apl_hostbridge_probe, 391 .remove = apl_hostbridge_remove, 392 .plat_auto = sizeof(struct apl_hostbridge_plat), 393 ACPI_OPS_PTR(&apl_hostbridge_acpi_ops) 394 .flags = DM_FLAG_OS_PREPARE, 395}; 396