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