From bcc5de5f25bc8edabaf1d2331a0565aeaa934a1d Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 2 Jun 2025 10:46:04 +0000 Subject: [PATCH 01/10] amd-apml: sbrmi: Add sbrmi device as per the SBRMI device instance ID * From Venice SBRMI device ID is 1, instead of checking each device PID, we should check for the Instance ID. Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta --- drivers/misc/amd-apml/sbrmi.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/misc/amd-apml/sbrmi.c b/drivers/misc/amd-apml/sbrmi.c index e110ab47813380..32d65137f915ca 100644 --- a/drivers/misc/amd-apml/sbrmi.c +++ b/drivers/misc/amd-apml/sbrmi.c @@ -610,9 +610,9 @@ static int sbrmi_i3c_probe(struct i3c_device *i3cdev) int ret; dev_info(dev, "SBRMI: PID: %llx\n", i3cdev->desc->info.pid); - if (!((i3cdev->desc->info.pid == 0x1000) || (i3cdev->desc->info.pid == 0x22400000002) || - (i3cdev->desc->info.pid == 0x1118) || (i3cdev->desc->info.pid == 0x1001118))) - { + + if (!(I3C_PID_INSTANCE_ID(i3cdev->desc->info.pid) == 1 || + i3cdev->desc->info.pid == 0x22400000002)) { dev_info(dev, "SBRMI: PID Error: %llx\n", i3cdev->desc->info.pid); return -ENXIO; } From c77f047863b2eae36dd15ec1e330d1347d5a54f7 Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 2 Jun 2025 10:48:45 +0000 Subject: [PATCH 02/10] amd-apml: sbtsi: Add sbtsi device as per the SBTSI device instance ID * From Venice SBTSI device ID is 0, instead of checking each device PID, we should check for the Instance ID. Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta --- drivers/misc/amd-apml/apml_sbtsi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/misc/amd-apml/apml_sbtsi.c b/drivers/misc/amd-apml/apml_sbtsi.c index 64389739a431be..5209a243603d38 100644 --- a/drivers/misc/amd-apml/apml_sbtsi.c +++ b/drivers/misc/amd-apml/apml_sbtsi.c @@ -301,10 +301,8 @@ static int sbtsi_i3c_probe(struct i3c_device *i3cdev) struct regmap *regmap; dev_err(dev, "SBTSI: PID: %llx\n", i3cdev->desc->info.pid); - if (!((i3cdev->desc->info.pid == 0x0) || (i3cdev->desc->info.pid == 0x22400000001) || - (i3cdev->desc->info.pid == 0x118) || (i3cdev->desc->info.pid == 0x010118) || - (i3cdev->desc->info.pid == 0x01000118) || (i3cdev->desc->info.pid == 0x01010118))) - { + if (!(I3C_PID_INSTANCE_ID(i3cdev->desc->info.pid) == 0 || + i3cdev->desc->info.pid == 0x22400000001)) { dev_err(dev, "SBTSI: Error PID: %llx\n", i3cdev->desc->info.pid); return -ENXIO; } From 416a90d927027de4124d97ae503932635343d12c Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 2 Jun 2025 10:51:38 +0000 Subject: [PATCH 03/10] amd-apml: sbtsi: Add device IDs for socket 0 and Socket 1 for Fam:0x1A, Fam:0x50 - SBRMI/TSI devices for new APML has PID as per below description. [11:0] Additional ID: 0x118 [15:12] SB-TSI(0x0) [31:16] [16]: DIE_ID, [25:24]: SOCKET ID sock 0 die 0: 0x0 sock 0 die 1: 0x1 sock 1 die 0: 0x100 sock 1 die 1: 0x101 [32]: PID type select, it is 0 now to select fixed vendor value; [47:33]: Manufacture ID, MIPI alliance has allocated the value for each company, AMD should be 0x0112 Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta --- drivers/misc/amd-apml/apml_sbtsi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/misc/amd-apml/apml_sbtsi.c b/drivers/misc/amd-apml/apml_sbtsi.c index 5209a243603d38..28cea9b82ddb3c 100644 --- a/drivers/misc/amd-apml/apml_sbtsi.c +++ b/drivers/misc/amd-apml/apml_sbtsi.c @@ -421,6 +421,10 @@ static const struct i3c_device_id sbtsi_i3c_id[] = { I3C_DEVICE_EXTRA_INFO(0, 0x0101, 0x118, NULL), /* P1 - IOD1 - SBTSI */ I3C_DEVICE_EXTRA_INFO(0x112, 0, 0x1, NULL), I3C_DEVICE_EXTRA_INFO(0, 0x0, 0x0, NULL), + I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x118, NULL), /* Socket:0, IOD:0 */ + I3C_DEVICE_EXTRA_INFO(0x112, 0x1, 0x118, NULL), /* Socket:0, IOD:1 */ + I3C_DEVICE_EXTRA_INFO(0x112, 0x100, 0x118, NULL), /* Socket:1 IOD:0 */ + I3C_DEVICE_EXTRA_INFO(0x112, 0x101, 0x118, NULL), /* Socket:1 IOD:1 */ {} }; MODULE_DEVICE_TABLE(i3c, sbtsi_i3c_id); From 3cbafb7a966994ddf74fed8e69edd992403f0234 Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 2 Jun 2025 10:57:48 +0000 Subject: [PATCH 04/10] amd-apml: sbrmi: Add device IDs for socket 0 and Socket 1 for Fam:0x1A, Fam:0x50 - PID for SBRMI devices in Fam:0x1A, Fam:0x50 is defines as: [11:0] Additional ID: 0x118 [15:12] SB-TSI(0x0)/SB-RMI(0x1) [31:16] [16]: DIE_ID, [25:24]: SOCKET ID sock 0 die 0: 0x0 sock 0 die 1: 0x1 sock 1 die 0: 0x100 sock 1 die 1: 0x101 [32]: PID type select, it is 0 now to select fixed vendor value; [47:33]: Manufacture ID, MIPI alliance has allocated the value for each company, AMD should be 0x0112 Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta --- drivers/misc/amd-apml/sbrmi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/misc/amd-apml/sbrmi.c b/drivers/misc/amd-apml/sbrmi.c index 32d65137f915ca..78197c928b5bac 100644 --- a/drivers/misc/amd-apml/sbrmi.c +++ b/drivers/misc/amd-apml/sbrmi.c @@ -755,6 +755,8 @@ static const struct i3c_device_id sbrmi_i3c_id[] = { I3C_DEVICE_EXTRA_INFO(0, 0x000, 0x1118, NULL), /* P0 - IOD0 - SBRMI */ I3C_DEVICE_EXTRA_INFO(0, 0x100, 0x1118, NULL), /* P1 - IOD0 - SBRMI */ I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x2, NULL), + I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x118, NULL), /* Socket:0, IOD:0 */ + I3C_DEVICE_EXTRA_INFO(0x112, 0x100, 0x118, NULL), /* Socket:1 IOD:0 */ I3C_DEVICE_EXTRA_INFO(0, 0x0, 0x0, NULL), {} }; From 0666518dcac6760a467f1a0f1850c6f179df93a1 Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 2 Jun 2025 11:28:15 +0000 Subject: [PATCH 05/10] linux: i3c: Extra info should not be updated in the driver - Extra info, part of PID is standard and should not be change. This device id will be used by other drivers, which can break. Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta --- drivers/i3c/device.c | 1 - drivers/misc/amd-apml/sbrmi.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/i3c/device.c b/drivers/i3c/device.c index d39d73b142bc9a..0b4b47bf11ac74 100644 --- a/drivers/i3c/device.c +++ b/drivers/i3c/device.c @@ -366,7 +366,6 @@ i3c_device_match_id(struct i3c_device *i3cdev, part = I3C_PID_PART_ID(devinfo.pid); ext_info = I3C_PID_EXTRA_INFO(devinfo.pid); inst = I3C_PID_INSTANCE_ID(devinfo.pid); - ext_info = ext_info | (inst << 12); rndpid = I3C_PID_RND_LOWER_32BITS(devinfo.pid); printk(" i3c_device_match_id: manuf 0x%x, part 0x%x, inst 0x%x, ext_info 0x%x \n", manuf, part, inst, ext_info); diff --git a/drivers/misc/amd-apml/sbrmi.c b/drivers/misc/amd-apml/sbrmi.c index 78197c928b5bac..791311b928f036 100644 --- a/drivers/misc/amd-apml/sbrmi.c +++ b/drivers/misc/amd-apml/sbrmi.c @@ -752,8 +752,8 @@ static const struct of_device_id __maybe_unused sbrmi_of_match[] = { MODULE_DEVICE_TABLE(of, sbrmi_of_match); static const struct i3c_device_id sbrmi_i3c_id[] = { - I3C_DEVICE_EXTRA_INFO(0, 0x000, 0x1118, NULL), /* P0 - IOD0 - SBRMI */ - I3C_DEVICE_EXTRA_INFO(0, 0x100, 0x1118, NULL), /* P1 - IOD0 - SBRMI */ + I3C_DEVICE_EXTRA_INFO(0, 0x000, 0x118, NULL), /* P0 - IOD0 - SBRMI */ + I3C_DEVICE_EXTRA_INFO(0, 0x100, 0x118, NULL), /* P1 - IOD0 - SBRMI */ I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x2, NULL), I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x118, NULL), /* Socket:0, IOD:0 */ I3C_DEVICE_EXTRA_INFO(0x112, 0x100, 0x118, NULL), /* Socket:1 IOD:0 */ From ca272c9301be8e42d8aa73c453e0eedd9d72fbdd Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 2 Jun 2025 14:33:21 +0000 Subject: [PATCH 06/10] amd-apml: sbrmi: update label for hwmon entry to include socket_iod number Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta --- drivers/misc/amd-apml/sbrmi.c | 40 +++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/misc/amd-apml/sbrmi.c b/drivers/misc/amd-apml/sbrmi.c index 791311b928f036..e230d11aa3b06e 100644 --- a/drivers/misc/amd-apml/sbrmi.c +++ b/drivers/misc/amd-apml/sbrmi.c @@ -443,6 +443,7 @@ static int sbrmi_i2c_probe(struct i2c_client *client) struct device *dev = &client->dev; struct device *hwmon_dev; struct apml_sbrmi_device *rmi_dev; + const char *hwmon_dev_name; rmi_dev = devm_kzalloc(dev, sizeof(struct apml_sbrmi_device), GFP_KERNEL); if (!rmi_dev) @@ -455,7 +456,21 @@ static int sbrmi_i2c_probe(struct i2c_client *client) dev_set_drvdata(dev, (void *)rmi_dev); - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + rmi_dev->dev_static_addr = client->addr; + + switch (rmi_dev->dev_static_addr) { + case 0x3c: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbrmi_%s", "0.0"); + break; + case 0x38: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbrmi_%s", "1.0"); + break; + default: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbrmi_"); + break; + } + + hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_dev_name, rmi_dev, &sbrmi_chip_info, NULL); @@ -463,8 +478,6 @@ static int sbrmi_i2c_probe(struct i2c_client *client) if (!hwmon_dev) return PTR_ERR_OR_ZERO(hwmon_dev); - rmi_dev->dev_static_addr = client->addr; - init_completion(&rmi_dev->misc_fops_done); return create_misc_rmi_device(rmi_dev, dev); } @@ -608,6 +621,7 @@ static int sbrmi_i3c_probe(struct i3c_device *i3cdev) struct device *hwmon_dev; struct apml_sbrmi_device *rmi_dev; int ret; + const char *hwmon_dev_name; dev_info(dev, "SBRMI: PID: %llx\n", i3cdev->desc->info.pid); @@ -631,7 +645,22 @@ static int sbrmi_i3c_probe(struct i3c_device *i3cdev) dev_set_drvdata(dev, (void *)rmi_dev); - hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbrmi_i3c", rmi_dev, + /* Need to verify for the static address for i3cdev */ + rmi_dev->dev_static_addr = i3cdev->desc->info.static_addr; + + switch (rmi_dev->dev_static_addr) { + case 0x3c: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbrmi_%s", "0.0"); + break; + case 0x38: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbrmi_%s", "1.0"); + break; + default: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbrmi_"); + break; + } + + hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_dev_name, rmi_dev, &sbrmi_chip_info, NULL); if (!hwmon_dev) @@ -640,9 +669,6 @@ static int sbrmi_i3c_probe(struct i3c_device *i3cdev) return PTR_ERR_OR_ZERO(hwmon_dev); } - /* Need to verify for the static address for i3cdev */ - rmi_dev->dev_static_addr = i3cdev->desc->info.static_addr; - i3c_sbrmi_cache = kmem_cache_create_usercopy("i3c-data-cache", sizeof(struct i3c_sbrmi_data), 0, 0, 0, sizeof(struct i3c_sbrmi_data), NULL); From 249523310296014cc9f7dd967bb0e7bc142b88f1 Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Mon, 2 Jun 2025 14:45:38 +0000 Subject: [PATCH 07/10] amd_apml: sbtsi: update label for hwmon entry to include socket & dieid number Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta --- drivers/misc/amd-apml/apml_sbtsi.c | 52 ++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/drivers/misc/amd-apml/apml_sbtsi.c b/drivers/misc/amd-apml/apml_sbtsi.c index 28cea9b82ddb3c..8e1bc176cefe18 100644 --- a/drivers/misc/amd-apml/apml_sbtsi.c +++ b/drivers/misc/amd-apml/apml_sbtsi.c @@ -299,6 +299,7 @@ static int sbtsi_i3c_probe(struct i3c_device *i3cdev) .val_bits = 8, }; struct regmap *regmap; + const char *hwmon_dev_name; dev_err(dev, "SBTSI: PID: %llx\n", i3cdev->desc->info.pid); if (!(I3C_PID_INSTANCE_ID(i3cdev->desc->info.pid) == 0 || @@ -324,8 +325,29 @@ static int sbtsi_i3c_probe(struct i3c_device *i3cdev) tsi_dev->regmap = regmap; mutex_init(&tsi_dev->lock); + /* Need to verify for the static address for i3cdev */ + tsi_dev->dev_static_addr = i3cdev->desc->info.static_addr; + + switch (tsi_dev->dev_static_addr) { + case 0x44: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "0.1"); + break; + case 0x45: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "1.1"); + break; + case 0x48: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "1.0"); + break; + case 0x4c: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "0.0"); + break; + default: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_"); + break; + } + dev_set_drvdata(dev, (void *)tsi_dev); - hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbtsi_i3c", tsi_dev, + hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_dev_name, tsi_dev, &sbtsi_chip_info, NULL); if (!hwmon_dev) @@ -334,9 +356,6 @@ static int sbtsi_i3c_probe(struct i3c_device *i3cdev) return PTR_ERR_OR_ZERO(hwmon_dev); } - /* Need to verify for the static address for i3cdev */ - tsi_dev->dev_static_addr = i3cdev->desc->info.static_addr; - return create_misc_tsi_device(tsi_dev, dev); } @@ -354,6 +373,7 @@ static int sbtsi_i2c_probe(struct i2c_client *client) .reg_bits = 8, .val_bits = 8, }; + const char *hwmon_dev_name; tsi_dev = devm_kzalloc(dev, sizeof(struct apml_sbtsi_device), GFP_KERNEL); if (!tsi_dev) @@ -366,7 +386,27 @@ static int sbtsi_i2c_probe(struct i2c_client *client) dev_set_drvdata(dev, (void *)tsi_dev); - hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, + tsi_dev->dev_static_addr = client->addr; + + switch (tsi_dev->dev_static_addr) { + case 0x44: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "0.1"); + break; + case 0x45: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "1.1"); + break; + case 0x48: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "1.0"); + break; + case 0x4c: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_%s", "0.0"); + break; + default: + hwmon_dev_name = devm_kasprintf(dev, GFP_KERNEL, "sbtsi_"); + break; + } + + hwmon_dev = devm_hwmon_device_register_with_info(dev, hwmon_dev_name, tsi_dev, &sbtsi_chip_info, NULL); @@ -374,8 +414,6 @@ static int sbtsi_i2c_probe(struct i2c_client *client) if (!hwmon_dev) return PTR_ERR_OR_ZERO(hwmon_dev); - tsi_dev->dev_static_addr = client->addr; - return create_misc_tsi_device(tsi_dev, dev); } From 1a104c99bfbfad8090ed29fe305ff7e5249476b7 Mon Sep 17 00:00:00 2001 From: sathya priya kumar Date: Mon, 2 Jun 2025 17:41:07 +0530 Subject: [PATCH 08/10] amd-apml: alertl: Add support for AMD APML Alert_L platform driver Processors from AMD provide APML ALERT_L for BMC users to monitor events. APML Alert_L is asserted in multiple events, - Machine Check Exception occurs within the system - The processor alerts the SBI on system fatal error event - Set by hardware as a result of a 0x71/0x72/0x73 command completion - Set by firmware to indicate the completion of a mailbox operation - High/Low Temperature Alert APML Alert_L module define uevents to notify registered userspace processes of the alert event. Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta Signed-off-by: sathya priya kumar --- drivers/misc/amd-apml/Kconfig | 11 + drivers/misc/amd-apml/Makefile | 1 + drivers/misc/amd-apml/apml_alertl.c | 362 +++++++++++++++++++++++++++ drivers/misc/amd-apml/apml_alertl.h | 24 ++ drivers/misc/amd-apml/apml_sbtsi.c | 29 ++- drivers/misc/amd-apml/sbtsi-common.h | 20 ++ include/uapi/linux/amd-apml.h | 20 +- 7 files changed, 454 insertions(+), 13 deletions(-) create mode 100644 drivers/misc/amd-apml/apml_alertl.c create mode 100644 drivers/misc/amd-apml/apml_alertl.h create mode 100644 drivers/misc/amd-apml/sbtsi-common.h diff --git a/drivers/misc/amd-apml/Kconfig b/drivers/misc/amd-apml/Kconfig index 6fed94971b0fb1..3cbfd5ccd8e713 100644 --- a/drivers/misc/amd-apml/Kconfig +++ b/drivers/misc/amd-apml/Kconfig @@ -24,3 +24,14 @@ config APML_SBTSI This driver can also be built as a module. If so, the module will be called apml_sbtsi. + +config APML_ALERTL + tristate "Emulated apml alertl interface driver over i3c bus" + depends on APML_SBRMI && APML_SBTSI + default n + help + If you say yes here you get support for emulated alertl + interface on AMD SoCs with APML interface connected to a BMC device. + + This driver can also be built as a module. If so, the module will + be called apml_alertl. diff --git a/drivers/misc/amd-apml/Makefile b/drivers/misc/amd-apml/Makefile index 7eef318915f122..864ea61baf6d2a 100644 --- a/drivers/misc/amd-apml/Makefile +++ b/drivers/misc/amd-apml/Makefile @@ -6,3 +6,4 @@ obj-$(CONFIG_APML_SBRMI) += sbrmi.o sbrmi-common.o obj-$(CONFIG_APML_SBTSI) += apml_sbtsi.o +obj-$(CONFIG_APML_ALERTL) += apml_alertl.o diff --git a/drivers/misc/amd-apml/apml_alertl.c b/drivers/misc/amd-apml/apml_alertl.c new file mode 100644 index 00000000000000..abde2d4ecea6f4 --- /dev/null +++ b/drivers/misc/amd-apml/apml_alertl.c @@ -0,0 +1,362 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * alert_l.c - Alert_l driver for AMD APML devices + * + * Copyright (C) 2022-2023 Advanced Micro Devices, Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sbrmi-common.h" +#include "apml_alertl.h" +#include "sbtsi-common.h" + +#define DRIVER_NAME "apml_alertl" + +#define RAS_STATUS_REG 0x4C +#define STATUS_REG 0x2 +#define TSI_STATUS_REG 0x2 +#define RAS_ALERT_STATUS BIT(1) +#define RAS_ALERT_ASYNC BIT(3) + +#define MAX_SOC_LEN 11 +#define MAX_ERR_LEN 18 + +MODULE_ALIAS("apml_alertl:" DRIVER_NAME); + +/* Read TSI Status register to identify the RAS error */ +static int tsi_alert_check(struct apml_alertl_data *oob_adata, int *temp_status, u8 soc_die_num) +{ + struct apml_message msg = { 0 }; + int ret; + + if (!oob_adata->tsi_dev[soc_die_num] || !oob_adata->tsi_dev[soc_die_num]->regmap) + return 0; + msg.data_in.reg_in[REG_OFF_INDEX] = TSI_STATUS_REG; + + mutex_lock(&oob_adata->tsi_dev[soc_die_num]->lock); + ret = regmap_read(oob_adata->tsi_dev[soc_die_num]->regmap, + msg.data_in.reg_in[REG_OFF_INDEX], + temp_status); + mutex_unlock(&oob_adata->tsi_dev[soc_die_num]->lock); + + return ret; +} + +/* Read RAS Status register to identify the RAS error */ +static int rmi_alert_check(struct apml_alertl_data *oob_adata, int *status, u8 soc_die_num) +{ + struct apml_message msg = { 0 }; + int ret; + + if (!oob_adata->rmi_dev[soc_die_num] || !oob_adata->rmi_dev[soc_die_num]->regmap) + return 0; + msg.data_in.reg_in[REG_OFF_INDEX] = RAS_STATUS_REG; + + mutex_lock(&oob_adata->rmi_dev[soc_die_num]->lock); + ret = regmap_read(oob_adata->rmi_dev[soc_die_num]->regmap, + msg.data_in.reg_in[REG_OFF_INDEX], + status); + mutex_unlock(&oob_adata->rmi_dev[soc_die_num]->lock); + + return ret; +} + +static u8 static_addr_to_socket(u8 static_addr) +{ + /* + * [3:0] = Socket Index + * [7:4] = die Index + * Mapping: + * 0x3c, 0x4c -> Socket 0, die 0, + * 0x44 -> Socket 0, die 1, + * 0x38, 0x48 -> Socket 1, die 0, + * 0x4c -> Socket 1, die 1. + */ + switch (static_addr) { + case 0x3c: + case 0x4c: + return 0; + case 0x44: + return (0 | (1 << 4)); + case 0x38: + case 0x48: + return 1; + case 0x45: + return (1 | (1 << 4)); + default: + return 0xff; + } +} + +static int send_uevent(u8 static_address, u32 alert_src, struct device *dev) +{ + u8 soc_die_num = 0; + char sock[MAX_SOC_LEN]; + char src[MAX_ERR_LEN]; + char *alert_source[] = { sock, src, NULL }; + + soc_die_num = static_addr_to_socket(static_address); + if (soc_die_num == 0xFF) { + pr_err("Device static address not valid\n"); + return -ENODEV; + } + + snprintf(sock, sizeof(sock), "Socket=0x%x", soc_die_num); + snprintf(src, sizeof(src), "Source=0x%x", alert_src); + pr_err("apml_alertl:Sock:0x%x Src:0x%x\n", soc_die_num, alert_src); + + pr_debug("Sending uevent to user space...\n"); + kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, alert_source); + return 0; +} + +static irqreturn_t alert_l_irq_thread_handler(int irq, void *dev_id) +{ + struct apml_alertl_data *oob_adata = dev_id; + struct apml_message msg = { 0 }; + struct device *dev = oob_adata->dev; + unsigned int ras_status = 0; + unsigned int temp_status = 0; + u32 rt_src = 0; + u8 static_addr = 0; + int ret, i; + + for (i = 0; i < oob_adata->num_of_tsi_devs; i++) { + rt_src = 0; + /* Check for TSI alert */ + ret = tsi_alert_check(oob_adata, &temp_status, i); + if (ret < 0) + pr_err("Failed to read TSI status register\n"); + + if (!temp_status) + continue; + + rt_src = (temp_status << 24); + static_addr = oob_adata->tsi_dev[i]->dev_static_addr; + + ret = send_uevent(static_addr, rt_src, dev); + if (ret) + return ret; + } + + for (i = 0; i < oob_adata->num_of_rmi_devs; i++) { + rt_src = 0; + /* Check for RAS alerts */ + ret = rmi_alert_check(oob_adata, &ras_status, i); + if (ret < 0) + pr_err("Failed to read RAS status register\n"); + + if (!ras_status) + continue; + + rt_src = ras_status; + static_addr = oob_adata->rmi_dev[i]->dev_static_addr; + + ret = send_uevent(static_addr, rt_src, dev); + if (ret) + return ret; + + /* Clear the RMI Status and RAS Status register */ + if (!oob_adata->rmi_dev[i] || !oob_adata->rmi_dev[i]->regmap) + return -ENODEV; + + if (ras_status) { + mutex_lock(&oob_adata->rmi_dev[i]->lock); + msg.data_in.reg_in[REG_OFF_INDEX] = RAS_STATUS_REG; + ret = regmap_write(oob_adata->rmi_dev[i]->regmap, + msg.data_in.reg_in[REG_OFF_INDEX], + ras_status); + if (ret < 0) + pr_err("Failed to clear RMI status register\n"); + + msg.data_in.reg_in[REG_OFF_INDEX] = STATUS_REG; + ret = regmap_write(oob_adata->rmi_dev[i]->regmap, + msg.data_in.reg_in[REG_OFF_INDEX], + RAS_ALERT_ASYNC); + mutex_unlock(&oob_adata->rmi_dev[i]->lock); + if (ret < 0) { + pr_err("Failed to clear RAS status register\n"); + return ret; + } + } + } + return IRQ_HANDLED; +} + +static void *get_apml_dev_byphandle(struct device_node *dnode, + const char *phandle_name, + int index) +{ + struct device_node *d_node; + struct device *dev; + void *apml_dev; + + if (!phandle_name || !dnode) + return NULL; + + d_node = of_parse_phandle(dnode, phandle_name, index); + if (IS_ERR_OR_NULL(d_node)) + return NULL; + + if (strcmp(phandle_name, "sbrmi") == 0) { + dev = bus_find_device(&i3c_bus_type, NULL, d_node, sbrmi_match_i3c); + if (!dev) { + dev = bus_find_device(&i2c_bus_type, NULL, d_node, sbrmi_match_i2c); + if (IS_ERR_OR_NULL(dev)) { + of_node_put(d_node); + return NULL; + } + } + } else if (strcmp(phandle_name, "sbtsi") == 0) { + dev = bus_find_device(&i3c_bus_type, NULL, d_node, sbtsi_match_i3c); + if (!dev) { + dev = bus_find_device(&i2c_bus_type, NULL, d_node, sbtsi_match_i2c); + if (IS_ERR_OR_NULL(dev)) { + of_node_put(d_node); + return NULL; + } + } + } + + of_node_put(d_node); + apml_dev = dev_get_drvdata(dev); + if (IS_ERR_OR_NULL(apml_dev)) + return NULL; + + return apml_dev; +} + +static int apml_alertl_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *dnode = dev->of_node; + struct apml_sbrmi_device **rmi_dev; + struct apml_sbtsi_device **tsi_dev; + struct apml_alertl_data *oob_alert; + struct gpio_desc *alertl_gpiod; + u32 irq_num; + u32 num_dev = 0; + int ret = 0; + int i = 0; + + /* Allocate memory to oob_alert_data structure */ + oob_alert = devm_kzalloc(dev, sizeof(struct apml_alertl_data), + GFP_KERNEL); + if (!oob_alert) + return -ENOMEM; + /* identify the number of devices associated with each RMI alert */ + num_dev = of_property_count_elems_of_size(dnode, "sbrmi", + sizeof(phandle)); + oob_alert->num_of_rmi_devs = num_dev; + + /* identify the number of devices associated with each TSI alert */ + num_dev = of_property_count_elems_of_size(dnode, "sbtsi", + sizeof(phandle)); + oob_alert->num_of_tsi_devs = num_dev; + + /* Allocate memory as per the number of RMI devices */ + rmi_dev = devm_kzalloc(dev, oob_alert->num_of_rmi_devs * sizeof(struct apml_sbrmi_device), + GFP_KERNEL); + if (!rmi_dev) + return -ENOMEM; + oob_alert->rmi_dev = rmi_dev; + + /* Allocate memory as per the number of TSI devices */ + tsi_dev = devm_kzalloc(dev, oob_alert->num_of_tsi_devs * sizeof(struct apml_sbtsi_device), + GFP_KERNEL); + if (!tsi_dev) + return -ENOMEM; + oob_alert->tsi_dev = tsi_dev; + oob_alert->dev = dev; + + /* + * For each of the Alerts get the device associated + * Currently the ALert_L driver identification is only supported + * over I3C. We can add property in dts to identify the bus type + */ + + for (i = 0; i < oob_alert->num_of_rmi_devs; i++) { + rmi_dev[i] = get_apml_dev_byphandle(pdev->dev.of_node, "sbrmi", i); + if (!rmi_dev[i]) { + pr_err("Error getting APML SBRMI device. Exiting\n"); + return -EINVAL; + } + } + + for (i = 0; i < oob_alert->num_of_tsi_devs; i++) { + tsi_dev[i] = get_apml_dev_byphandle(pdev->dev.of_node, "sbtsi", i); + if (!tsi_dev[i]) { + pr_err("Error getting APML SBTSI device. Exiting\n"); + return -EINVAL; + } + } + + /* Get the alert_l gpios, irq_number for the GPIO and register ISR*/ + alertl_gpiod = devm_gpiod_get(dev, NULL, GPIOD_IN); + if (IS_ERR(alertl_gpiod)) { + dev_err(&pdev->dev, "Unable to retrieve gpio\n"); + return PTR_ERR(alertl_gpiod); + } + + ret = gpiod_to_irq(alertl_gpiod); + if (ret < 0) { + dev_err(dev, "No corresponding irq for gpio error: %d\n", ret); + return ret; + } + irq_num = ret; + pr_debug("Register IRQ:%u\n", irq_num); + /* + * TODO: naming can be updated for the irq on + * basis of socket number + */ + ret = devm_request_threaded_irq(dev, irq_num, + NULL, + (void *)alert_l_irq_thread_handler, + IRQF_TRIGGER_FALLING | IRQF_ONESHOT, + "apml_irq", oob_alert); + if (ret) { + pr_err("Cannot register IRQ:%u\n", irq_num); + return ret; + } + + /* Set the platform data to pdev */ + platform_set_drvdata(pdev, oob_alert); + + return 0; +} + +static int alert_remove(struct platform_device *pdev) +{ + return 0; +} + +static const struct of_device_id apml_alertl_dt_ids[] = { + {.compatible = "apml-alertl", }, + {}, +}; +MODULE_DEVICE_TABLE(of, apml_alertl_dt_ids); + +static struct platform_driver apml_alertl_driver = { + .driver = { + .name = DRIVER_NAME, + .of_match_table = of_match_ptr(apml_alertl_dt_ids), + }, + .probe = apml_alertl_probe, + .remove = alert_remove, +}; + +module_platform_driver(apml_alertl_driver); +MODULE_AUTHOR("Akshay Gupta "); +MODULE_AUTHOR("Naveenkrishna Chatradhi "); +MODULE_DESCRIPTION("AMD APML ALERT_L Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/misc/amd-apml/apml_alertl.h b/drivers/misc/amd-apml/apml_alertl.h new file mode 100644 index 00000000000000..88706bedd38405 --- /dev/null +++ b/drivers/misc/amd-apml/apml_alertl.h @@ -0,0 +1,24 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2021-2022 Advanced Micro Devices, Inc. + */ + +#ifndef _AMD_APML_ALERT_L__ +#define _AMD_APML_ALERT_L__ + +#include "sbrmi-common.h" + +/* APML_ALERTL send uevent to userspace for temparature + * alert, RAS (fatal and non-fatal) error with environmental + * data including socket_die and alertl source information. + */ + +struct apml_alertl_data { + struct apml_sbrmi_device **rmi_dev; + struct apml_sbtsi_device **tsi_dev; + struct device *dev; + u8 num_of_rmi_devs; + u8 num_of_tsi_devs; +} __packed; + +#endif /*_AMD_APML_ALERT_L__*/ diff --git a/drivers/misc/amd-apml/apml_sbtsi.c b/drivers/misc/amd-apml/apml_sbtsi.c index 8e1bc176cefe18..1ff8f7ef638958 100644 --- a/drivers/misc/amd-apml/apml_sbtsi.c +++ b/drivers/misc/amd-apml/apml_sbtsi.c @@ -25,7 +25,7 @@ #include #include - +#include "sbtsi-common.h" /* * SB-TSI registers only support SMBus byte data access. "_INT" registers are * the integer part of a temperature value or limit, and "_DEC" registers are @@ -60,13 +60,6 @@ #define SBTSI_DEC_OFFSET 5 #define SBTSI_DEC_MASK 0x7 -struct apml_sbtsi_device { - struct miscdevice sbtsi_misc_dev; - struct regmap *regmap; - struct mutex lock; - u8 dev_static_addr; -} __packed; - /* * From SB-TSI spec: CPU temperature readings and limit registers encode the * temperature in increments of 0.125 from 0 to 255.875. The "high byte" @@ -503,6 +496,26 @@ static struct i2c_driver sbtsi_driver = { module_i3c_i2c_driver(sbtsi_i3c_driver, &sbtsi_driver) +int sbtsi_match_i3c(struct device *dev, const void *data) +{ + const struct device_node *node = (const struct device_node *)data; + + if (dev->of_node == node && dev->driver == &sbtsi_i3c_driver.driver) + return 1; + return 0; +} +EXPORT_SYMBOL_GPL(sbtsi_match_i3c); + +int sbtsi_match_i2c(struct device *dev, const void *data) +{ + const struct device_node *node = (const struct device_node *)data; + + if (dev->of_node == node && dev->driver == &sbtsi_driver.driver) + return 1; + return 0; +} +EXPORT_SYMBOL_GPL(sbtsi_match_i2c); + MODULE_AUTHOR("Kun Yi "); MODULE_DESCRIPTION("Hwmon driver for AMD SB-TSI emulated sensor"); MODULE_LICENSE("GPL"); diff --git a/drivers/misc/amd-apml/sbtsi-common.h b/drivers/misc/amd-apml/sbtsi-common.h new file mode 100644 index 00000000000000..199a2d80c5476c --- /dev/null +++ b/drivers/misc/amd-apml/sbtsi-common.h @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * sbtsi-common.h - hwmon driver for a SBI Temperature Sensor Interface (SB-TSI) + * compliant AMD SoC temperature device. + * Also register to misc driver with an IOCTL. + * + * Copyright (c) 2020, Google Inc. + * Copyright (c) 2020, Kun Yi + * Copyright (C) 2025 Advanced Micro Devices, Inc. + */ + +struct apml_sbtsi_device { + struct miscdevice sbtsi_misc_dev; + struct regmap *regmap; + struct mutex lock; //lock for tsi devices + u8 dev_static_addr; +} __packed; + +int sbtsi_match_i2c(struct device *dev, const void *data); +int sbtsi_match_i3c(struct device *dev, const void *data); diff --git a/include/uapi/linux/amd-apml.h b/include/uapi/linux/amd-apml.h index 4a6bd7057b4ba9..db304b2e2fdf84 100644 --- a/include/uapi/linux/amd-apml.h +++ b/include/uapi/linux/amd-apml.h @@ -7,11 +7,21 @@ #include -/* - * Currently signal 33 to 64 are unused, - * using user signal number from that range - */ -#define USR_SIGNAL 44 +#ifndef BIT +#define BIT(n) (1U << (n)) +#endif + +enum apml_ras_alert_src { + APML_FATAL_ALERT = BIT(0), + APML_FCH_ALERT = BIT(1), + APML_RESET_CTRL_ALERT = BIT(2), + APML_MCA_ALERT = BIT(3), + APML_DRAM_CECC_ALERT = BIT(4), + APML_PCIE_ALERT = BIT(5), + APML_CPU_SHUTDOWN = BIT(6), + APML_TEMP_LOW_ALERT = BIT(27), + APML_TEMP_HIGH_ALERT = BIT(28), +}; enum apml_protocol { APML_CPUID = 0x1000, From df7cc4bdaf4a3f8df976412d24dc3836117c55ab Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Fri, 30 May 2025 11:58:24 +0530 Subject: [PATCH 09/10] amd-apml: alertl: dts changes for Morocco & Congo -Add alertl node for morocco and congo platforms Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta Signed-off-by: Sathya Priya Kumar --- arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-congo.dts | 11 +++++++++++ arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-morocco.dts | 11 +++++++++++ 2 files changed, 22 insertions(+) diff --git a/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-congo.dts b/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-congo.dts index 73e1c5e7233397..5d8afd80f86686 100644 --- a/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-congo.dts +++ b/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-congo.dts @@ -894,6 +894,17 @@ #endif }; +/ { + /* Alert_L associated with socket 0 */ + alertl_sock0 { + compatible = "apml-alertl"; + status = "okay"; + gpios = <<pi0_gpio 20 GPIO_ACTIVE_LOW>; + sbrmi = <&sbrmi_p0_iod0>; + sbtsi = <&sbtsi_p0_iod0>; + }; +}; + #ifdef I3C_HUB #define JESD300_SPD_I3C_MODE(bus, index, addr) \ diff --git a/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-morocco.dts b/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-morocco.dts index 441ecd98bc4e07..a0aa43f82b9542 100644 --- a/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-morocco.dts +++ b/arch/arm64/boot/dts/aspeed/aspeed-bmc-amd-morocco.dts @@ -984,6 +984,17 @@ #endif }; +/ { + /* Alert_L associated with socket 0 */ + alertl_sock0 { + compatible = "apml-alertl"; + status = "okay"; + gpios = <<pi0_gpio 20 GPIO_ACTIVE_LOW>; + sbrmi = <&sbrmi_p0_iod0>; + sbtsi = <&sbtsi_p0_iod0>; + }; +}; + #ifdef I3C_HUB #define JESD300_SPD_I3C_MODE(bus, index, addr) \ From 0f54429b0d8f9a2e935fa7c300601444ba54ea15 Mon Sep 17 00:00:00 2001 From: Akshay Gupta Date: Tue, 3 Jun 2025 10:25:25 +0000 Subject: [PATCH 10/10] amd-apml: doc: Documentation for dts changes for Alert_L module Reviewed-by: Naveen Krishna Chatradhi Signed-off-by: Akshay Gupta Signed-off-by: sathya priya kumar --- .../bindings/misc/amd,apml-alertl.yaml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 Documentation/devicetree/bindings/misc/amd,apml-alertl.yaml diff --git a/Documentation/devicetree/bindings/misc/amd,apml-alertl.yaml b/Documentation/devicetree/bindings/misc/amd,apml-alertl.yaml new file mode 100644 index 00000000000000..1f0d123a6e8f2e --- /dev/null +++ b/Documentation/devicetree/bindings/misc/amd,apml-alertl.yaml @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/hwmon/amd,apml-alertl.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: > + Sideband Remote Management Interface (SB-RMI) compliant + AMD APML Alert_L GPIO. + +maintainers: + - Akshay Gupta + +description: | + Processors from AMD provide APML ALERT_L for BMC users to + monitor events. + APML Alert_L is asserted in multiple events, + - Machine Check Exception occurs within the system + - The processor alerts the SBI on system fatal error event + - Set by hardware as a result of a 0x71/0x72/0x73 command completion + - Set by firmware to indicate the completion of a mailbox operation + - High/Low Temperature Alert + + APML Alert_L module define uevents to notify userspace of the + alert event. + +properties: + compatible: + enum: + - apml-alertl + +required: + - compatible + - gpio + - sbrmi + - sbtsi + +additionalProperties: false + +examples: + - | + /* Alert_L associated with Socket 0 */ + alertl_sock0 { + compatible = "apml-alertl"; + status = "okay"; + gpios = <<pi0_gpio 20 GPIO_ACTIVE_LOW>; + sbrmi = <&sbrmi_p0_iod0>; + sbtsi = <&sbtsi_p0_iod0>; + }; +...