162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * AMD SoC Power Management Controller Driver Quirks
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (c) 2023, Advanced Micro Devices, Inc.
662306a36Sopenharmony_ci * All Rights Reserved.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Author: Mario Limonciello <mario.limonciello@amd.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/dmi.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/ioport.h>
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include "pmc.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistruct quirk_entry {
1862306a36Sopenharmony_ci	u32 s2idle_bug_mmio;
1962306a36Sopenharmony_ci	bool spurious_8042;
2062306a36Sopenharmony_ci};
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cistatic struct quirk_entry quirk_s2idle_bug = {
2362306a36Sopenharmony_ci	.s2idle_bug_mmio = 0xfed80380,
2462306a36Sopenharmony_ci};
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistatic struct quirk_entry quirk_spurious_8042 = {
2762306a36Sopenharmony_ci	.spurious_8042 = true,
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic const struct dmi_system_id fwbug_list[] = {
3162306a36Sopenharmony_ci	{
3262306a36Sopenharmony_ci		.ident = "L14 Gen2 AMD",
3362306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
3462306a36Sopenharmony_ci		.matches = {
3562306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
3662306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20X5"),
3762306a36Sopenharmony_ci		}
3862306a36Sopenharmony_ci	},
3962306a36Sopenharmony_ci	{
4062306a36Sopenharmony_ci		.ident = "T14s Gen2 AMD",
4162306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
4262306a36Sopenharmony_ci		.matches = {
4362306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
4462306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20XF"),
4562306a36Sopenharmony_ci		}
4662306a36Sopenharmony_ci	},
4762306a36Sopenharmony_ci	{
4862306a36Sopenharmony_ci		.ident = "X13 Gen2 AMD",
4962306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
5062306a36Sopenharmony_ci		.matches = {
5162306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
5262306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20XH"),
5362306a36Sopenharmony_ci		}
5462306a36Sopenharmony_ci	},
5562306a36Sopenharmony_ci	{
5662306a36Sopenharmony_ci		.ident = "T14 Gen2 AMD",
5762306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
5862306a36Sopenharmony_ci		.matches = {
5962306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
6062306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20XK"),
6162306a36Sopenharmony_ci		}
6262306a36Sopenharmony_ci	},
6362306a36Sopenharmony_ci	{
6462306a36Sopenharmony_ci		.ident = "T14 Gen1 AMD",
6562306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
6662306a36Sopenharmony_ci		.matches = {
6762306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
6862306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20UD"),
6962306a36Sopenharmony_ci		}
7062306a36Sopenharmony_ci	},
7162306a36Sopenharmony_ci	{
7262306a36Sopenharmony_ci		.ident = "T14 Gen1 AMD",
7362306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
7462306a36Sopenharmony_ci		.matches = {
7562306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
7662306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20UE"),
7762306a36Sopenharmony_ci		}
7862306a36Sopenharmony_ci	},
7962306a36Sopenharmony_ci	{
8062306a36Sopenharmony_ci		.ident = "T14s Gen1 AMD",
8162306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
8262306a36Sopenharmony_ci		.matches = {
8362306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
8462306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20UH"),
8562306a36Sopenharmony_ci		}
8662306a36Sopenharmony_ci	},
8762306a36Sopenharmony_ci	{
8862306a36Sopenharmony_ci		.ident = "T14s Gen1 AMD",
8962306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
9062306a36Sopenharmony_ci		.matches = {
9162306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
9262306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20UJ"),
9362306a36Sopenharmony_ci		}
9462306a36Sopenharmony_ci	},
9562306a36Sopenharmony_ci	{
9662306a36Sopenharmony_ci		.ident = "P14s Gen1 AMD",
9762306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
9862306a36Sopenharmony_ci		.matches = {
9962306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
10062306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "20Y1"),
10162306a36Sopenharmony_ci		}
10262306a36Sopenharmony_ci	},
10362306a36Sopenharmony_ci	{
10462306a36Sopenharmony_ci		.ident = "P14s Gen2 AMD",
10562306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
10662306a36Sopenharmony_ci		.matches = {
10762306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
10862306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "21A0"),
10962306a36Sopenharmony_ci		}
11062306a36Sopenharmony_ci	},
11162306a36Sopenharmony_ci	{
11262306a36Sopenharmony_ci		.ident = "P14s Gen2 AMD",
11362306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
11462306a36Sopenharmony_ci		.matches = {
11562306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
11662306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "21A1"),
11762306a36Sopenharmony_ci		}
11862306a36Sopenharmony_ci	},
11962306a36Sopenharmony_ci	/* https://bugzilla.kernel.org/show_bug.cgi?id=218024 */
12062306a36Sopenharmony_ci	{
12162306a36Sopenharmony_ci		.ident = "V14 G4 AMN",
12262306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
12362306a36Sopenharmony_ci		.matches = {
12462306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
12562306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "82YT"),
12662306a36Sopenharmony_ci		}
12762306a36Sopenharmony_ci	},
12862306a36Sopenharmony_ci	{
12962306a36Sopenharmony_ci		.ident = "V14 G4 AMN",
13062306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
13162306a36Sopenharmony_ci		.matches = {
13262306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
13362306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "83GE"),
13462306a36Sopenharmony_ci		}
13562306a36Sopenharmony_ci	},
13662306a36Sopenharmony_ci	{
13762306a36Sopenharmony_ci		.ident = "V15 G4 AMN",
13862306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
13962306a36Sopenharmony_ci		.matches = {
14062306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
14162306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "82YU"),
14262306a36Sopenharmony_ci		}
14362306a36Sopenharmony_ci	},
14462306a36Sopenharmony_ci	{
14562306a36Sopenharmony_ci		.ident = "V15 G4 AMN",
14662306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
14762306a36Sopenharmony_ci		.matches = {
14862306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
14962306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "83CQ"),
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci	},
15262306a36Sopenharmony_ci	{
15362306a36Sopenharmony_ci		.ident = "IdeaPad 1 14AMN7",
15462306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
15562306a36Sopenharmony_ci		.matches = {
15662306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
15762306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "82VF"),
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci	},
16062306a36Sopenharmony_ci	{
16162306a36Sopenharmony_ci		.ident = "IdeaPad 1 15AMN7",
16262306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
16362306a36Sopenharmony_ci		.matches = {
16462306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
16562306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "82VG"),
16662306a36Sopenharmony_ci		}
16762306a36Sopenharmony_ci	},
16862306a36Sopenharmony_ci	{
16962306a36Sopenharmony_ci		.ident = "IdeaPad 1 15AMN7",
17062306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
17162306a36Sopenharmony_ci		.matches = {
17262306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
17362306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "82X5"),
17462306a36Sopenharmony_ci		}
17562306a36Sopenharmony_ci	},
17662306a36Sopenharmony_ci	{
17762306a36Sopenharmony_ci		.ident = "IdeaPad Slim 3 14AMN8",
17862306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
17962306a36Sopenharmony_ci		.matches = {
18062306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
18162306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "82XN"),
18262306a36Sopenharmony_ci		}
18362306a36Sopenharmony_ci	},
18462306a36Sopenharmony_ci	{
18562306a36Sopenharmony_ci		.ident = "IdeaPad Slim 3 15AMN8",
18662306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
18762306a36Sopenharmony_ci		.matches = {
18862306a36Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "LENOVO"),
18962306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "82XQ"),
19062306a36Sopenharmony_ci		}
19162306a36Sopenharmony_ci	},
19262306a36Sopenharmony_ci	/* https://gitlab.freedesktop.org/drm/amd/-/issues/2684 */
19362306a36Sopenharmony_ci	{
19462306a36Sopenharmony_ci		.ident = "HP Laptop 15s-eq2xxx",
19562306a36Sopenharmony_ci		.driver_data = &quirk_s2idle_bug,
19662306a36Sopenharmony_ci		.matches = {
19762306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "HP"),
19862306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15s-eq2xxx"),
19962306a36Sopenharmony_ci		}
20062306a36Sopenharmony_ci	},
20162306a36Sopenharmony_ci	/* https://community.frame.work/t/tracking-framework-amd-ryzen-7040-series-lid-wakeup-behavior-feedback/39128 */
20262306a36Sopenharmony_ci	{
20362306a36Sopenharmony_ci		.ident = "Framework Laptop 13 (Phoenix)",
20462306a36Sopenharmony_ci		.driver_data = &quirk_spurious_8042,
20562306a36Sopenharmony_ci		.matches = {
20662306a36Sopenharmony_ci			DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
20762306a36Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Laptop 13 (AMD Ryzen 7040Series)"),
20862306a36Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VERSION, "03.03"),
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci	},
21162306a36Sopenharmony_ci	{}
21262306a36Sopenharmony_ci};
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/*
21562306a36Sopenharmony_ci * Laptops that run a SMI handler during the D3->D0 transition that occurs
21662306a36Sopenharmony_ci * specifically when exiting suspend to idle which can cause
21762306a36Sopenharmony_ci * large delays during resume when the IOMMU translation layer is enabled (the default
21862306a36Sopenharmony_ci * behavior) for NVME devices:
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * To avoid this firmware problem, skip the SMI handler on these machines before the
22162306a36Sopenharmony_ci * D0 transition occurs.
22262306a36Sopenharmony_ci */
22362306a36Sopenharmony_cistatic void amd_pmc_skip_nvme_smi_handler(u32 s2idle_bug_mmio)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	void __iomem *addr;
22662306a36Sopenharmony_ci	u8 val;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	if (!request_mem_region_muxed(s2idle_bug_mmio, 1, "amd_pmc_pm80"))
22962306a36Sopenharmony_ci		return;
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	addr = ioremap(s2idle_bug_mmio, 1);
23262306a36Sopenharmony_ci	if (!addr)
23362306a36Sopenharmony_ci		goto cleanup_resource;
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	val = ioread8(addr);
23662306a36Sopenharmony_ci	iowrite8(val & ~BIT(0), addr);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	iounmap(addr);
23962306a36Sopenharmony_cicleanup_resource:
24062306a36Sopenharmony_ci	release_mem_region(s2idle_bug_mmio, 1);
24162306a36Sopenharmony_ci}
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_civoid amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	if (dev->quirks && dev->quirks->s2idle_bug_mmio)
24662306a36Sopenharmony_ci		amd_pmc_skip_nvme_smi_handler(dev->quirks->s2idle_bug_mmio);
24762306a36Sopenharmony_ci}
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_civoid amd_pmc_quirks_init(struct amd_pmc_dev *dev)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	const struct dmi_system_id *dmi_id;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (dev->cpu_id == AMD_CPU_ID_CZN)
25462306a36Sopenharmony_ci		dev->disable_8042_wakeup = true;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	dmi_id = dmi_first_match(fwbug_list);
25762306a36Sopenharmony_ci	if (!dmi_id)
25862306a36Sopenharmony_ci		return;
25962306a36Sopenharmony_ci	dev->quirks = dmi_id->driver_data;
26062306a36Sopenharmony_ci	if (dev->quirks->s2idle_bug_mmio)
26162306a36Sopenharmony_ci		pr_info("Using s2idle quirk to avoid %s platform firmware bug\n",
26262306a36Sopenharmony_ci			dmi_id->ident);
26362306a36Sopenharmony_ci	if (dev->quirks->spurious_8042)
26462306a36Sopenharmony_ci		dev->disable_8042_wakeup = true;
26562306a36Sopenharmony_ci}
266