hostbridge.c 10 KB

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