[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250312123055.1735-2-messigoatcr7nop@gmail.com>
Date: Wed, 12 Mar 2025 18:00:22 +0530
From: Subu Dwevedi <messigoatcr7nop@...il.com>
To:
Cc: Subu Dwevedi <messigoatcr7nop@...il.com>,
Henrik Rydberg <rydberg@...math.org>,
Jean Delvare <jdelvare@...e.com>,
Guenter Roeck <linux@...ck-us.net>,
linux-hwmon@...r.kernel.org,
linux-kernel@...r.kernel.org
Subject: [PATCH 1/2] hwmon/applesmc: add MMIO for newer macs
Add basic MMIO support to AppleSMC for T2 Macs,
enabling it only when supported.
This replaces the legacy port-based method for
key reading, writing, and metadata operations
(retrieving keys by index and obtaining key information)
Signed-off-by: Subu Dwevedi <messigoatcr7nop@...il.com>
---
drivers/hwmon/applesmc.c | 223 +++++++++++++++++++++++++++++++++++++--
1 file changed, 213 insertions(+), 10 deletions(-)
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index fc6d6a9053ce..1be4a4026a6e 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -17,6 +17,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
@@ -142,7 +143,9 @@ static struct platform_device *pdev;
static s16 rest_x;
static s16 rest_y;
static u8 backlight_state[2];
-
+static u8 *__iomem mmio_base;
+static bool is_mmio;
+static u32 mmio_base_addr, mmio_base_size;
static struct device *hwmon_dev;
static struct input_dev *applesmc_idev;
@@ -245,7 +248,108 @@ static int send_argument(const char *key)
return 0;
}
-static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
+/*
+ * MMIO Impliementation
+ */
+
+static void clearArbitration(void)
+{
+ if (ioread8(mmio_base + 0x4005))
+ return iowrite8(0, mmio_base + 0x4005);
+}
+static int waitForKeyDone(void)
+{
+ int i = 1000; //millisecounds
+ u8 status;
+
+ while (i) {
+ msleep(1);
+ i--;
+
+ status = ioread8(mmio_base + 0x4005);
+ if (status & 0x20)
+ return 0;
+ }
+
+ return -EIO;
+}
+static int mmio_read_smc(u8 cmd, const char *key, u8 *buffer, u64 len)
+{
+ u8 i, u = 0;
+
+ clearArbitration();
+ iowrite32(*((u32 *)key), mmio_base + 0x78);
+ iowrite8(0x15, mmio_base + 0x7E);
+ iowrite8(cmd, mmio_base + 0x7F);
+
+ if (waitForKeyDone())
+ return -EIO;
+
+ i = ioread8(mmio_base + 0x7F);
+ if (i)
+ return -EIO;
+ if (cmd == APPLESMC_READ_CMD) {
+ i = ioread8(mmio_base + 0x7D);
+ if (i > len || !i)
+ return -EIO;
+
+ while (u < i) {
+ if ((i - u) < 4) {
+ if ((i - u) < 2) {
+ buffer[u] = ioread8(mmio_base + u);
+ u += 1;
+ } else {
+ *(u16 *)&buffer[u] = ioread16(mmio_base + u);
+ u += 2;
+ }
+ } else {
+ *(u32 *)&buffer[u] = ioread32(mmio_base + u);
+ u += 4;
+ }
+ }
+ } else
+ memcpy_fromio(buffer, mmio_base + 0x0, len);
+
+ return 0;
+}
+static int mmio_write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
+{
+ u8 i = 0;
+
+ clearArbitration();
+ iowrite32(*((u32 *)key), mmio_base + 0x78);
+ while (i < len) {
+ if (len - i < 4) {
+ if (len - i < 2) {
+ iowrite8(buffer[i], mmio_base + i);
+ i += 1;
+ } else {
+ iowrite16(*(u16 *)&buffer[i], mmio_base + i);
+ i += 2;
+ }
+ } else {
+ iowrite32(*(u32 *)&buffer[i], mmio_base + i);
+ i += 4;
+ }
+ }
+ iowrite8(len, mmio_base + 0x7D);
+ iowrite8(0x15, mmio_base + 0x7E);
+ iowrite8(cmd, mmio_base + 0x7F);
+ if (waitForKeyDone())
+ return -EIO;
+
+ i = ioread8(mmio_base + 0x7F);
+ if (i)
+ return -EIO;
+
+ return 0;
+}
+
+/*
+ * Port Based IO implementation
+ *
+ */
+static int port_read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
{
u8 status, data = 0;
int i;
@@ -289,7 +393,7 @@ static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
return wait_status(0, SMC_STATUS_BUSY);
}
-static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
+static int port_write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
{
int i;
int ret;
@@ -317,7 +421,23 @@ static int write_smc(u8 cmd, const char *key, const u8 *buffer, u8 len)
return wait_status(0, SMC_STATUS_BUSY);
}
+static int write_smc(u8 cmd, const char *key, const u8 *buffer,
+ u8 len)
+{
+ if (is_mmio)
+ return mmio_write_smc(cmd, key, buffer, len);
+
+ return port_write_smc(cmd, key, buffer, len);
+}
+static int read_smc(u8 cmd, const char *key, u8 *buffer, u8 len)
+{
+ if (is_mmio)
+ return mmio_read_smc(cmd, key, buffer, len);
+
+
+ return port_read_smc(cmd, key, buffer, len);
+}
static int read_register_count(unsigned int *count)
{
__be32 be;
@@ -379,18 +499,39 @@ static const struct applesmc_entry *applesmc_get_entry_by_index(int index)
if (cache->valid)
goto out;
+
be = cpu_to_be32(index);
- ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (u8 *)&be, key, 4);
- if (ret)
- goto out;
- ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
+ ret = read_smc(APPLESMC_GET_KEY_BY_INDEX_CMD, (const char *) &be, (u8 *) key, 4);
if (ret)
goto out;
+ if (is_mmio) {
+ clearArbitration();
+ iowrite32(*((u32 *)key), mmio_base + 0x78);
+ iowrite8(0, mmio_base + 0x7E);
+ iowrite8(APPLESMC_GET_KEY_TYPE_CMD, mmio_base + 0x7F);
+ ret = waitForKeyDone();
+ if (ret)
+ goto out;
+
+ ret = ioread8(mmio_base + 0x7F);
+ if (ret)
+ goto out;
+
+ *(u32 *)cache->type = ioread32(mmio_base + 0x7F);
+ cache->len = ioread8(mmio_base + 5);
+ cache->flags = ioread8(mmio_base + 6);
+
+ } else {
+ ret = read_smc(APPLESMC_GET_KEY_TYPE_CMD, key, info, 6);
+ if (ret)
+ goto out;
+
+ cache->len = info[0];
+ memcpy(cache->type, &info[1], 4);
+ cache->flags = info[5];
+ }
memcpy(cache->key, key, 4);
- cache->len = info[0];
- memcpy(cache->type, &info[1], 4);
- cache->flags = info[5];
cache->valid = true;
out:
@@ -558,7 +699,64 @@ static int applesmc_init_index(struct applesmc_registers *s)
return 0;
}
+/*
+ * applesmc_init_mmio_try - Try to initialize MMIO
+ */
+static int applesmc_init_mmio_try(void)
+{
+ u8 ldkn_version;
+ acpi_status status;
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_device *adev;
+ struct acpi_resource *res;
+
+ adev = acpi_dev_get_first_match_dev("APP0001", NULL, -1);
+ if (!adev)
+ return -ENXIO;
+
+ status = acpi_get_current_resources(adev->handle, &buffer);
+ if (ACPI_FAILURE(status))
+ return -ENXIO;
+
+ res = buffer.pointer;
+ while (res->type != ACPI_RESOURCE_TYPE_END_TAG) {
+ if (res->type == ACPI_RESOURCE_TYPE_FIXED_MEMORY32) {
+ if (res->data.fixed_memory32.address_length < 0x4006)
+ return -ENXIO;
+
+ mmio_base_addr = res->data.fixed_memory32.address;
+ mmio_base_size = res->data.fixed_memory32.address_length;
+ is_mmio = true;
+ break;
+ }
+ res = ACPI_NEXT_RESOURCE(res);
+ }
+ kfree(buffer.pointer);
+ acpi_dev_put(adev);
+
+ if (!is_mmio)
+ return -ENXIO;
+
+ mmio_base = ioremap(mmio_base_addr, mmio_base_size);
+
+ if (!mmio_base)
+ return -ENXIO;
+ if (ioread8(mmio_base + 0x4005) == 0xFF)
+ goto out;
+
+ if (read_smc(APPLESMC_READ_CMD, "LDKN", &ldkn_version, 1))
+ goto out;
+
+ if (ldkn_version < 2)
+ goto out;
+
+ return 0;
+out:
+ pr_warn("cannot enable MMIO will use PMIO\n");
+ iounmap(mmio_base);
+ return -ENXIO;
+}
/*
* applesmc_init_smcreg_try - Try to initialize register cache. Idempotent.
*/
@@ -1321,6 +1519,8 @@ static int __init applesmc_init(void)
ret = -ENXIO;
goto out;
}
+ if (applesmc_init_mmio_try())
+ is_mmio = false;
ret = platform_driver_register(&applesmc_driver);
if (ret)
@@ -1407,6 +1607,9 @@ static void __exit applesmc_exit(void)
applesmc_destroy_smcreg();
platform_device_unregister(pdev);
platform_driver_unregister(&applesmc_driver);
+ if (is_mmio)
+ iounmap(mmio_base);
+
release_region(APPLESMC_DATA_PORT, APPLESMC_NR_PORTS);
}
--
2.43.0
Powered by blists - more mailing lists