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/4434 */
193 {
194 .ident = "Lenovo Yoga 6 13ALC6",
195 .driver_data = &quirk_s2idle_bug,
196 .matches = {
197 DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
198 DMI_MATCH(DMI_PRODUCT_NAME, "82ND"),
199 }
200 },
201 /* https://gitlab.freedesktop.org/drm/amd/-/issues/2684 */
202 {
203 .ident = "HP Laptop 15s-eq2xxx",
204 .driver_data = &quirk_s2idle_bug,
205 .matches = {
206 DMI_MATCH(DMI_SYS_VENDOR, "HP"),
207 DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15s-eq2xxx"),
208 }
209 },
210 /* https://community.frame.work/t/tracking-framework-amd-ryzen-7040-series-lid-wakeup-behavior-feedback/39128 */
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.03"),
218 }
219 },
220 {
221 .ident = "Framework Laptop 13 (Phoenix)",
222 .driver_data = &quirk_spurious_8042,
223 .matches = {
224 DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
225 DMI_MATCH(DMI_PRODUCT_NAME, "Laptop 13 (AMD Ryzen 7040Series)"),
226 DMI_MATCH(DMI_BIOS_VERSION, "03.05"),
227 }
228 },
229 {
230 .ident = "MECHREVO Wujie 14X (GX4HRXL)",
231 .driver_data = &quirk_spurious_8042,
232 .matches = {
233 DMI_MATCH(DMI_BOARD_NAME, "WUJIE14-GX4HRXL"),
234 }
235 },
236 {
237 .ident = "MECHREVO Yilong15Pro Series GM5HG7A",
238 .driver_data = &quirk_spurious_8042,
239 .matches = {
240 DMI_MATCH(DMI_SYS_VENDOR, "MECHREVO"),
241 DMI_MATCH(DMI_PRODUCT_NAME, "Yilong15Pro Series GM5HG7A"),
242 }
243 },
244 /* https://bugzilla.kernel.org/show_bug.cgi?id=220116 */
245 {
246 .ident = "PCSpecialist Lafite Pro V 14M",
247 .driver_data = &quirk_spurious_8042,
248 .matches = {
249 DMI_MATCH(DMI_SYS_VENDOR, "PCSpecialist"),
250 DMI_MATCH(DMI_PRODUCT_NAME, "Lafite Pro V 14M"),
251 }
252 },
253 {
254 .ident = "TUXEDO Stellaris Slim 15 AMD Gen6",
255 .driver_data = &quirk_spurious_8042,
256 .matches = {
257 DMI_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
258 }
259 },
260 {
261 .ident = "TUXEDO InfinityBook Pro 14/15 AMD Gen10",
262 .driver_data = &quirk_spurious_8042,
263 .matches = {
264 DMI_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
265 }
266 },
267 {
268 .ident = "TUXEDO InfinityBook Pro 14/15 AMD Gen10",
269 .driver_data = &quirk_spurious_8042,
270 .matches = {
271 DMI_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
272 }
273 },
274 {}
275 };
276
277 /*
278 * Laptops that run a SMI handler during the D3->D0 transition that occurs
279 * specifically when exiting suspend to idle which can cause
280 * large delays during resume when the IOMMU translation layer is enabled (the default
281 * behavior) for NVME devices:
282 *
283 * To avoid this firmware problem, skip the SMI handler on these machines before the
284 * D0 transition occurs.
285 */
amd_pmc_skip_nvme_smi_handler(u32 s2idle_bug_mmio)286 static void amd_pmc_skip_nvme_smi_handler(u32 s2idle_bug_mmio)
287 {
288 void __iomem *addr;
289 u8 val;
290
291 if (!request_mem_region_muxed(s2idle_bug_mmio, 1, "amd_pmc_pm80"))
292 return;
293
294 addr = ioremap(s2idle_bug_mmio, 1);
295 if (!addr)
296 goto cleanup_resource;
297
298 val = ioread8(addr);
299 iowrite8(val & ~BIT(0), addr);
300
301 iounmap(addr);
302 cleanup_resource:
303 release_mem_region(s2idle_bug_mmio, 1);
304 }
305
amd_pmc_process_restore_quirks(struct amd_pmc_dev * dev)306 void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev)
307 {
308 if (dev->quirks && dev->quirks->s2idle_bug_mmio)
309 amd_pmc_skip_nvme_smi_handler(dev->quirks->s2idle_bug_mmio);
310 }
311
amd_pmc_quirks_init(struct amd_pmc_dev * dev)312 void amd_pmc_quirks_init(struct amd_pmc_dev *dev)
313 {
314 const struct dmi_system_id *dmi_id;
315
316 if (dev->cpu_id == AMD_CPU_ID_CZN)
317 dev->disable_8042_wakeup = true;
318
319 dmi_id = dmi_first_match(fwbug_list);
320 if (!dmi_id)
321 return;
322 dev->quirks = dmi_id->driver_data;
323 if (dev->quirks->s2idle_bug_mmio)
324 pr_info("Using s2idle quirk to avoid %s platform firmware bug\n",
325 dmi_id->ident);
326 if (dev->quirks->spurious_8042)
327 dev->disable_8042_wakeup = true;
328 }
329