1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * AMD SoC Power Management Controller Driver Quirks
4 *
5 * Copyright (c) 2023, Advanced Micro Devices, Inc.
6 * All Rights Reserved.
7 *
8 * Author: Mario Limonciello <mario.limonciello@amd.com>
9 */
10
11 #include <linux/dmi.h>
12 #include <linux/io.h>
13 #include <linux/ioport.h>
14
15 #include "pmc.h"
16
17 struct quirk_entry {
18 u32 s2idle_bug_mmio;
19 bool spurious_8042;
20 };
21
22 static struct quirk_entry quirk_s2idle_bug = {
23 .s2idle_bug_mmio = 0xfed80380,
24 };
25
26 static struct quirk_entry quirk_spurious_8042 = {
27 .spurious_8042 = true,
28 };
29
30 static const struct dmi_system_id fwbug_list[] = {
31 {
32 .ident = "L14 Gen2 AMD",
33 .driver_data = &quirk_s2idle_bug,
34 .matches = {
35 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
36 DMI_MATCH(DMI_PRODUCT_NAME, "20X5"),
37 }
38 },
39 {
40 .ident = "T14s Gen2 AMD",
41 .driver_data = &quirk_s2idle_bug,
42 .matches = {
43 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
44 DMI_MATCH(DMI_PRODUCT_NAME, "20XF"),
45 }
46 },
47 {
48 .ident = "X13 Gen2 AMD",
49 .driver_data = &quirk_s2idle_bug,
50 .matches = {
51 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
52 DMI_MATCH(DMI_PRODUCT_NAME, "20XH"),
53 }
54 },
55 {
56 .ident = "T14 Gen2 AMD",
57 .driver_data = &quirk_s2idle_bug,
58 .matches = {
59 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
60 DMI_MATCH(DMI_PRODUCT_NAME, "20XK"),
61 }
62 },
63 {
64 .ident = "T14 Gen1 AMD",
65 .driver_data = &quirk_s2idle_bug,
66 .matches = {
67 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
68 DMI_MATCH(DMI_PRODUCT_NAME, "20UD"),
69 }
70 },
71 {
72 .ident = "T14 Gen1 AMD",
73 .driver_data = &quirk_s2idle_bug,
74 .matches = {
75 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
76 DMI_MATCH(DMI_PRODUCT_NAME, "20UE"),
77 }
78 },
79 {
80 .ident = "T14s Gen1 AMD",
81 .driver_data = &quirk_s2idle_bug,
82 .matches = {
83 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
84 DMI_MATCH(DMI_PRODUCT_NAME, "20UH"),
85 }
86 },
87 {
88 .ident = "T14s Gen1 AMD",
89 .driver_data = &quirk_s2idle_bug,
90 .matches = {
91 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
92 DMI_MATCH(DMI_PRODUCT_NAME, "20UJ"),
93 }
94 },
95 {
96 .ident = "P14s Gen1 AMD",
97 .driver_data = &quirk_s2idle_bug,
98 .matches = {
99 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
100 DMI_MATCH(DMI_PRODUCT_NAME, "20Y1"),
101 }
102 },
103 {
104 .ident = "P14s Gen2 AMD",
105 .driver_data = &quirk_s2idle_bug,
106 .matches = {
107 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
108 DMI_MATCH(DMI_PRODUCT_NAME, "21A0"),
109 }
110 },
111 {
112 .ident = "P14s Gen2 AMD",
113 .driver_data = &quirk_s2idle_bug,
114 .matches = {
115 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
116 DMI_MATCH(DMI_PRODUCT_NAME, "21A1"),
117 }
118 },
119 /* https://bugzilla.kernel.org/show_bug.cgi?id=218024 */
120 {
121 .ident = "V14 G4 AMN",
122 .driver_data = &quirk_s2idle_bug,
123 .matches = {
124 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
125 DMI_MATCH(DMI_PRODUCT_NAME, "82YT"),
126 }
127 },
128 {
129 .ident = "V14 G4 AMN",
130 .driver_data = &quirk_s2idle_bug,
131 .matches = {
132 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
133 DMI_MATCH(DMI_PRODUCT_NAME, "83GE"),
134 }
135 },
136 {
137 .ident = "V15 G4 AMN",
138 .driver_data = &quirk_s2idle_bug,
139 .matches = {
140 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
141 DMI_MATCH(DMI_PRODUCT_NAME, "82YU"),
142 }
143 },
144 {
145 .ident = "V15 G4 AMN",
146 .driver_data = &quirk_s2idle_bug,
147 .matches = {
148 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
149 DMI_MATCH(DMI_PRODUCT_NAME, "83CQ"),
150 }
151 },
152 {
153 .ident = "IdeaPad 1 14AMN7",
154 .driver_data = &quirk_s2idle_bug,
155 .matches = {
156 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
157 DMI_MATCH(DMI_PRODUCT_NAME, "82VF"),
158 }
159 },
160 {
161 .ident = "IdeaPad 1 15AMN7",
162 .driver_data = &quirk_s2idle_bug,
163 .matches = {
164 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
165 DMI_MATCH(DMI_PRODUCT_NAME, "82VG"),
166 }
167 },
168 {
169 .ident = "IdeaPad 1 15AMN7",
170 .driver_data = &quirk_s2idle_bug,
171 .matches = {
172 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
173 DMI_MATCH(DMI_PRODUCT_NAME, "82X5"),
174 }
175 },
176 {
177 .ident = "IdeaPad Slim 3 14AMN8",
178 .driver_data = &quirk_s2idle_bug,
179 .matches = {
180 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
181 DMI_MATCH(DMI_PRODUCT_NAME, "82XN"),
182 }
183 },
184 {
185 .ident = "IdeaPad Slim 3 15AMN8",
186 .driver_data = &quirk_s2idle_bug,
187 .matches = {
188 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
189 DMI_MATCH(DMI_PRODUCT_NAME, "82XQ"),
190 }
191 },
192 /* https://gitlab.freedesktop.org/drm/amd/-/issues/2684 */
193 {
194 .ident = "HP Laptop 15s-eq2xxx",
195 .driver_data = &quirk_s2idle_bug,
196 .matches = {
197 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
198 DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15s-eq2xxx"),
199 }
200 },
201 /* https://community.frame.work/t/tracking-framework-amd-ryzen-7040-series-lid-wakeup-behavior-feedback/39128 */
202 {
203 .ident = "Framework Laptop 13 (Phoenix)",
204 .driver_data = &quirk_spurious_8042,
205 .matches = {
206 DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
207 DMI_MATCH(DMI_PRODUCT_NAME, "Laptop 13 (AMD Ryzen 7040Series)"),
208 DMI_MATCH(DMI_BIOS_VERSION, "03.03"),
209 }
210 },
211 {
212 .ident = "Framework Laptop 13 (Phoenix)",
213 .driver_data = &quirk_spurious_8042,
214 .matches = {
215 DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
216 DMI_MATCH(DMI_PRODUCT_NAME, "Laptop 13 (AMD Ryzen 7040Series)"),
217 DMI_MATCH(DMI_BIOS_VERSION, "03.05"),
218 }
219 },
220 {}
221 };
222
223 /*
224 * Laptops that run a SMI handler during the D3->D0 transition that occurs
225 * specifically when exiting suspend to idle which can cause
226 * large delays during resume when the IOMMU translation layer is enabled (the default
227 * behavior) for NVME devices:
228 *
229 * To avoid this firmware problem, skip the SMI handler on these machines before the
230 * D0 transition occurs.
231 */
amd_pmc_skip_nvme_smi_handler(u32 s2idle_bug_mmio)232 static void amd_pmc_skip_nvme_smi_handler(u32 s2idle_bug_mmio)
233 {
234 void __iomem *addr;
235 u8 val;
236
237 if (!request_mem_region_muxed(s2idle_bug_mmio, 1, "amd_pmc_pm80"))
238 return;
239
240 addr = ioremap(s2idle_bug_mmio, 1);
241 if (!addr)
242 goto cleanup_resource;
243
244 val = ioread8(addr);
245 iowrite8(val & ~BIT(0), addr);
246
247 iounmap(addr);
248 cleanup_resource:
249 release_mem_region(s2idle_bug_mmio, 1);
250 }
251
amd_pmc_process_restore_quirks(struct amd_pmc_dev * dev)252 void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev)
253 {
254 if (dev->quirks && dev->quirks->s2idle_bug_mmio)
255 amd_pmc_skip_nvme_smi_handler(dev->quirks->s2idle_bug_mmio);
256 }
257
amd_pmc_quirks_init(struct amd_pmc_dev * dev)258 void amd_pmc_quirks_init(struct amd_pmc_dev *dev)
259 {
260 const struct dmi_system_id *dmi_id;
261
262 if (dev->cpu_id == AMD_CPU_ID_CZN)
263 dev->disable_8042_wakeup = true;
264
265 dmi_id = dmi_first_match(fwbug_list);
266 if (!dmi_id)
267 return;
268 dev->quirks = dmi_id->driver_data;
269 if (dev->quirks->s2idle_bug_mmio)
270 pr_info("Using s2idle quirk to avoid %s platform firmware bug\n",
271 dmi_id->ident);
272 if (dev->quirks->spurious_8042)
273 dev->disable_8042_wakeup = true;
274 }
275