blob: dd82e5ebcca18f400a9eaf81fc0f1836f841f96d [file] [log] [blame]
Felix Held971c9442023-09-15 22:12:41 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <amdblocks/data_fabric.h>
4#include <arch/hpet.h>
5#include <console/console.h>
6#include <cpu/x86/lapic_def.h>
7#include <soc/data_fabric.h>
8#include <types.h>
9
10static void data_fabric_disable_mmio_reg(unsigned int reg)
11{
12 union df_mmio_control ctrl = { .dst_fabric_id = IOMS0_FABRIC_ID };
13 data_fabric_broadcast_write32(DF_MMIO_CONTROL(reg), ctrl.raw);
14 data_fabric_broadcast_write32(DF_MMIO_BASE(reg), 0);
15 data_fabric_broadcast_write32(DF_MMIO_LIMIT(reg), 0);
16}
17
18static bool is_mmio_reg_disabled(unsigned int reg)
19{
20 union df_mmio_control ctrl;
21 ctrl.raw = data_fabric_broadcast_read32(DF_MMIO_CONTROL(reg));
22 return !(ctrl.we || ctrl.re);
23}
24
25static int data_fabric_find_unused_mmio_reg(void)
26{
27 for (unsigned int i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
28 if (is_mmio_reg_disabled(i))
29 return i;
30 }
31 return -1;
32}
33
34void data_fabric_set_mmio_np(void)
35{
36 /*
37 * Mark region from HPET-LAPIC or 0xfed00000-0xfee00000-1 as NP.
38 *
39 * AGESA has already programmed the NB MMIO routing, however nothing
40 * is yet marked as non-posted.
41 *
42 * If there exists an overlapping routing base/limit pair, trim its
43 * base or limit to avoid the new NP region. If any pair exists
44 * completely within HPET-LAPIC range, remove it. If any pair surrounds
45 * HPET-LAPIC, it must be split into two regions.
46 *
47 * TODO(b/156296146): Remove the settings from AGESA and allow coreboot
48 * to own everything. If not practical, consider erasing all settings
49 * and have coreboot reprogram them. At that time, make the source
50 * below more flexible.
51 * * Note that the code relies on the granularity of the HPET and
52 * LAPIC addresses being sufficiently large that the shifted limits
53 * +/-1 are always equivalent to the non-shifted values +/-1.
54 */
55
56 unsigned int i;
57 int reg;
58 uint32_t base, limit;
59 union df_mmio_control ctrl;
60 const uint32_t np_bot = HPET_BASE_ADDRESS >> DF_MMIO_SHIFT;
61 const uint32_t np_top = (LAPIC_DEFAULT_BASE - 1) >> DF_MMIO_SHIFT;
62
63 data_fabric_print_mmio_conf();
64
65 for (i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
66 /* Adjust all registers that overlap */
67 ctrl.raw = data_fabric_broadcast_read32(DF_MMIO_CONTROL(i));
68 if (!(ctrl.we || ctrl.re))
69 continue; /* not enabled */
70
71 base = data_fabric_broadcast_read32(DF_MMIO_BASE(i));
72 limit = data_fabric_broadcast_read32(DF_MMIO_LIMIT(i));
73
74 if (base > np_top || limit < np_bot)
75 continue; /* no overlap at all */
76
77 if (base >= np_bot && limit <= np_top) {
78 data_fabric_disable_mmio_reg(i); /* 100% within, so remove */
79 continue;
80 }
81
82 if (base < np_bot && limit > np_top) {
83 /* Split the configured region */
84 data_fabric_broadcast_write32(DF_MMIO_LIMIT(i), np_bot - 1);
85 reg = data_fabric_find_unused_mmio_reg();
86 if (reg < 0) {
87 /* Although a pair could be freed later, this condition is
88 * very unusual and deserves analysis. Flag an error and
89 * leave the topmost part unconfigured. */
90 printk(BIOS_ERR, "Not enough NB MMIO routing registers\n");
91 continue;
92 }
93 data_fabric_broadcast_write32(DF_MMIO_BASE(reg), np_top + 1);
94 data_fabric_broadcast_write32(DF_MMIO_LIMIT(reg), limit);
95 data_fabric_broadcast_write32(DF_MMIO_CONTROL(reg), ctrl.raw);
96 continue;
97 }
98
99 /* If still here, adjust only the base or limit */
100 if (base <= np_bot)
101 data_fabric_broadcast_write32(DF_MMIO_LIMIT(i), np_bot - 1);
102 else
103 data_fabric_broadcast_write32(DF_MMIO_BASE(i), np_top + 1);
104 }
105
106 reg = data_fabric_find_unused_mmio_reg();
107 if (reg < 0) {
108 printk(BIOS_ERR, "cannot configure region as NP\n");
109 return;
110 }
111
112 union df_mmio_control np_ctrl = { .dst_fabric_id = IOMS0_FABRIC_ID,
113 .np = 1, .we = 1, .re = 1 };
114 data_fabric_broadcast_write32(DF_MMIO_BASE(reg), np_bot);
115 data_fabric_broadcast_write32(DF_MMIO_LIMIT(reg), np_top);
116 data_fabric_broadcast_write32(DF_MMIO_CONTROL(reg), np_ctrl.raw);
117
118 data_fabric_print_mmio_conf();
119}