@@ -95,6 +95,22 @@ config I2C_AMD_MP2
This driver can also be built as modules. If so, the modules will
be called i2c-amd-mp2-pci and i2c-amd-mp2-plat.
+config I2C_AMD_ASF
+ tristate "AMD ASF I2C Controller Support"
+ depends on ACPI && I2C_PIIX4
+ help
+ This option enables support for the AMD ASF (Alert Standard Format)
+ I2C controller. The AMD ASF controller is an SMBus controller with
+ built-in ASF functionality, allowing it to issue generic SMBus
+ packets and communicate with the DASH controller using MCTP over
+ ASF.
+
+ If you have an AMD system with ASF support and want to enable this
+ functionality, say Y or M here. If unsure, say N.
+
+ To compile this driver as a module, choose M here: the module will
+ be called i2c_amd_asf_plat.
+
config I2C_HIX5HD2
tristate "Hix5hd2 high-speed I2C driver"
depends on ARCH_HISI || ARCH_HIX5HD2 || COMPILE_TEST
@@ -38,6 +38,7 @@ obj-$(CONFIG_I2C_POWERMAC) += i2c-powermac.o
# Embedded system I2C/SMBus host controller drivers
obj-$(CONFIG_I2C_ALTERA) += i2c-altera.o
obj-$(CONFIG_I2C_AMD_MP2) += i2c-amd-mp2-pci.o i2c-amd-mp2-plat.o
+obj-$(CONFIG_I2C_AMD_ASF) += i2c-amd-asf-plat.o
obj-$(CONFIG_I2C_ASPEED) += i2c-aspeed.o
obj-$(CONFIG_I2C_AT91) += i2c-at91.o
i2c-at91-objs := i2c-at91-core.o i2c-at91-master.o
new file mode 100644
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Alert Standard Format Platform Driver
+ *
+ * Copyright (c) 2024, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ * Sanket Goswami <Sanket.Goswami@amd.com>
+ */
+
+#include <linux/acpi.h>
+#include <linux/i2c-smbus.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "i2c-piix4.h"
+
+static const char *sb800_asf_port_name = " port 1";
+
+struct amd_asf_dev {
+ struct device *dev;
+ struct i2c_adapter adap;
+ struct sb800_mmio_cfg mmio_cfg;
+ unsigned short port_addr;
+};
+
+static int amd_asf_probe(struct platform_device *pdev)
+{
+ struct resource_entry *rentry;
+ struct amd_asf_dev *asf_dev;
+ struct acpi_device *adev;
+ LIST_HEAD(res_list);
+ int ret;
+
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (!adev)
+ return dev_err_probe(&pdev->dev, -ENODEV, "Failed to get ASF device\n");
+
+ asf_dev = devm_kzalloc(&pdev->dev, sizeof(*asf_dev), GFP_KERNEL);
+ if (!asf_dev)
+ return dev_err_probe(&pdev->dev, -ENOMEM, "Failed to allocate memory\n");
+
+ asf_dev->dev = &pdev->dev;
+ platform_set_drvdata(pdev, asf_dev);
+
+ asf_dev->adap.owner = THIS_MODULE;
+ asf_dev->mmio_cfg.use_mmio = true;
+ asf_dev->adap.class = I2C_CLASS_HWMON;
+
+ ret = acpi_dev_get_resources(adev, &res_list, NULL, NULL);
+ if (ret < 0)
+ return dev_err_probe(&pdev->dev, ret, "Error getting ASF ACPI resource: %d\n", ret);
+
+ list_for_each_entry(rentry, &res_list, node) {
+ switch (resource_type(rentry->res)) {
+ case IORESOURCE_IO:
+ asf_dev->port_addr = rentry->res->start;
+ break;
+ default:
+ dev_warn(&adev->dev, "Invalid ASF resource\n");
+ break;
+ }
+ }
+
+ acpi_dev_free_resource_list(&res_list);
+ /* Set up the sysfs linkage to our parent device */
+ asf_dev->adap.dev.parent = &pdev->dev;
+
+ snprintf(asf_dev->adap.name, sizeof(asf_dev->adap.name),
+ "SMBus ASF adapter%s at %04x", sb800_asf_port_name, asf_dev->port_addr);
+
+ i2c_set_adapdata(&asf_dev->adap, asf_dev);
+ ret = i2c_add_adapter(&asf_dev->adap);
+ if (ret) {
+ release_region(asf_dev->port_addr, SMBIOSIZE);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void amd_asf_remove(struct platform_device *pdev)
+{
+ struct amd_asf_dev *dev = platform_get_drvdata(pdev);
+
+ if (dev->port_addr) {
+ i2c_del_adapter(&dev->adap);
+ release_region(dev->port_addr, SMBIOSIZE);
+ }
+}
+
+static const struct acpi_device_id amd_asf_acpi_ids[] = {
+ {"AMDI001A", 0},
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, amd_asf_acpi_ids);
+
+static struct platform_driver amd_asf_driver = {
+ .driver = {
+ .name = "i2c-amd-asf",
+ .acpi_match_table = amd_asf_acpi_ids,
+ },
+ .probe = amd_asf_probe,
+ .remove_new = amd_asf_remove,
+};
+module_platform_driver(amd_asf_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("AMD Alert Standard Format Driver");
@@ -84,6 +84,7 @@
#define SB800_PIIX4_FCH_PM_ADDR 0xFED80300
#define SB800_PIIX4_FCH_PM_SIZE 8
+#define SB800_ASF_ACPI_PATH "\\_SB.ASFC"
/* insmod parameters */
@@ -1021,6 +1022,9 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int retval;
bool is_sb800 = false;
+ bool is_asf = false;
+ acpi_status status;
+ acpi_handle handle;
if ((dev->vendor == PCI_VENDOR_ID_ATI &&
dev->device == PCI_DEVICE_ID_ATI_SBX00_SMBUS &&
@@ -1083,10 +1087,16 @@ static int piix4_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
}
+ status = acpi_get_handle(NULL, (acpi_string)SB800_ASF_ACPI_PATH, &handle);
+ if (ACPI_SUCCESS(status))
+ is_asf = true;
+
if (dev->vendor == PCI_VENDOR_ID_AMD &&
(dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS ||
dev->device == PCI_DEVICE_ID_AMD_KERNCZ_SMBUS)) {
- retval = piix4_setup_sb800(dev, id, 1);
+ /* Do not setup AUX port if ASF is enabled */
+ if (!is_asf)
+ retval = piix4_setup_sb800(dev, id, 1);
}
if (retval > 0) {