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