Skip to content

Commit f802a93

Browse files
aunali11Naim
authored andcommitted
applesmc-t2: basic mmio interface implementation
This change introduces a basic MMIO-based interface implementation required to communicate with the SMC on T2 Macs. The MMIO interface is enabled only when it's supported on the running system. The MMIO interface replaces legacy port-based SMC key reads, writes and metadata requests (getting key by index and getting key info). (Based on patch by @MCMrARM) Signed-off-by: Aun-Ali Zaidi <admin@kodeit.net>
1 parent 6fbdbee commit f802a93

1 file changed

Lines changed: 231 additions & 6 deletions

File tree

drivers/hwmon/applesmc-t2.c

Lines changed: 231 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,18 @@
4242

4343
#define APPLESMC_NR_PORTS 32 /* 0x300-0x31f */
4444

45+
#define APPLESMC_IOMEM_KEY_DATA 0
46+
#define APPLESMC_IOMEM_KEY_STATUS 0x4005
47+
#define APPLESMC_IOMEM_KEY_NAME 0x78
48+
#define APPLESMC_IOMEM_KEY_DATA_LEN 0x7D
49+
#define APPLESMC_IOMEM_KEY_SMC_ID 0x7E
50+
#define APPLESMC_IOMEM_KEY_CMD 0x7F
51+
#define APPLESMC_IOMEM_MIN_SIZE 0x4006
52+
53+
#define APPLESMC_IOMEM_KEY_TYPE_CODE 0
54+
#define APPLESMC_IOMEM_KEY_TYPE_DATA_LEN 5
55+
#define APPLESMC_IOMEM_KEY_TYPE_FLAGS 6
56+
4557
#define APPLESMC_MAX_DATA_LENGTH 32
4658

4759
/* Apple SMC status bits */
@@ -138,10 +150,13 @@ struct applesmc_registers {
138150

139151
struct applesmc_device {
140152
struct acpi_device *dev;
153+
struct device *ldev;
141154
struct applesmc_registers reg;
142155

143-
bool port_base_set;
156+
bool port_base_set, iomem_base_set;
144157
u16 port_base;
158+
u8 *__iomem iomem_base;
159+
u32 iomem_base_addr, iomem_base_size;
145160

146161
s16 rest_x;
147162
s16 rest_y;
@@ -347,16 +362,156 @@ static int port_get_smc_key_info(struct applesmc_device *smc,
347362
return 0;
348363
}
349364

365+
366+
/*
367+
* MMIO based communication.
368+
* TODO: Use updated mechanism for cmd timeout/retry
369+
*/
370+
371+
static void iomem_clear_status(struct applesmc_device *smc)
372+
{
373+
if (ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS))
374+
iowrite8(0, smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
375+
}
376+
377+
static int iomem_wait_read(struct applesmc_device *smc)
378+
{
379+
u8 status;
380+
int us;
381+
int i;
382+
383+
us = APPLESMC_MIN_WAIT;
384+
for (i = 0; i < 24 ; i++) {
385+
status = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
386+
if (status & 0x20)
387+
return 0;
388+
usleep_range(us, us * 2);
389+
if (i > 9)
390+
us <<= 1;
391+
}
392+
393+
dev_warn(smc->ldev, "%s... timeout\n", __func__);
394+
return -EIO;
395+
}
396+
397+
static int iomem_read_smc(struct applesmc_device *smc, u8 cmd, const char *key,
398+
u8 *buffer, u8 len)
399+
{
400+
u8 err, remote_len;
401+
u32 key_int = *((u32 *) key);
402+
403+
iomem_clear_status(smc);
404+
iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
405+
iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
406+
iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
407+
408+
if (iomem_wait_read(smc))
409+
return -EIO;
410+
411+
err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
412+
if (err != 0) {
413+
dev_warn(smc->ldev, "read_smc_mmio(%x %8x/%.4s) failed: %u\n",
414+
cmd, key_int, key, err);
415+
return -EIO;
416+
}
417+
418+
if (cmd == APPLESMC_READ_CMD) {
419+
remote_len = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_DATA_LEN);
420+
if (remote_len != len) {
421+
dev_warn(smc->ldev,
422+
"read_smc_mmio(%x %8x/%.4s) failed: buffer length mismatch (remote = %u, requested = %u)\n",
423+
cmd, key_int, key, remote_len, len);
424+
return -EINVAL;
425+
}
426+
} else {
427+
remote_len = len;
428+
}
429+
430+
memcpy_fromio(buffer, smc->iomem_base + APPLESMC_IOMEM_KEY_DATA,
431+
remote_len);
432+
433+
dev_dbg(smc->ldev, "read_smc_mmio(%x %8x/%.4s): buflen=%u reslen=%u\n",
434+
cmd, key_int, key, len, remote_len);
435+
print_hex_dump_bytes("read_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, remote_len);
436+
return 0;
437+
}
438+
439+
static int iomem_get_smc_key_type(struct applesmc_device *smc, const char *key,
440+
struct applesmc_entry *e)
441+
{
442+
u8 err;
443+
u8 cmd = APPLESMC_GET_KEY_TYPE_CMD;
444+
u32 key_int = *((u32 *) key);
445+
446+
iomem_clear_status(smc);
447+
iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
448+
iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
449+
iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
450+
451+
if (iomem_wait_read(smc))
452+
return -EIO;
453+
454+
err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
455+
if (err != 0) {
456+
dev_warn(smc->ldev, "get_smc_key_type_mmio(%.4s) failed: %u\n", key, err);
457+
return -EIO;
458+
}
459+
460+
e->len = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_DATA_LEN);
461+
*((uint32_t *) e->type) = ioread32(
462+
smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_CODE);
463+
e->flags = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_TYPE_FLAGS);
464+
465+
dev_dbg(smc->ldev, "get_smc_key_type_mmio(%.4s): len=%u type=%.4s flags=%x\n",
466+
key, e->len, e->type, e->flags);
467+
return 0;
468+
}
469+
470+
static int iomem_write_smc(struct applesmc_device *smc, u8 cmd, const char *key,
471+
const u8 *buffer, u8 len)
472+
{
473+
u8 err;
474+
u32 key_int = *((u32 *) key);
475+
476+
iomem_clear_status(smc);
477+
iowrite32(key_int, smc->iomem_base + APPLESMC_IOMEM_KEY_NAME);
478+
memcpy_toio(smc->iomem_base + APPLESMC_IOMEM_KEY_DATA, buffer, len);
479+
iowrite32(len, smc->iomem_base + APPLESMC_IOMEM_KEY_DATA_LEN);
480+
iowrite32(0, smc->iomem_base + APPLESMC_IOMEM_KEY_SMC_ID);
481+
iowrite32(cmd, smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
482+
483+
if (iomem_wait_read(smc))
484+
return -EIO;
485+
486+
err = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_CMD);
487+
if (err != 0) {
488+
dev_warn(smc->ldev, "write_smc_mmio(%x %.4s) failed: %u\n", cmd, key, err);
489+
print_hex_dump_bytes("write_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, len);
490+
return -EIO;
491+
}
492+
493+
dev_dbg(smc->ldev, "write_smc_mmio(%x %.4s): buflen=%u\n", cmd, key, len);
494+
print_hex_dump_bytes("write_smc_mmio(): ", DUMP_PREFIX_NONE, buffer, len);
495+
return 0;
496+
}
497+
498+
350499
static int read_smc(struct applesmc_device *smc, const char *key,
351500
u8 *buffer, u8 len)
352501
{
353-
return port_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
502+
if (smc->iomem_base_set)
503+
return iomem_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
504+
else
505+
return port_read_smc(smc, APPLESMC_READ_CMD, key, buffer, len);
354506
}
355507

356508
static int write_smc(struct applesmc_device *smc, const char *key,
357509
const u8 *buffer, u8 len)
358510
{
359-
return port_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
511+
if (smc->iomem_base_set)
512+
return iomem_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
513+
else
514+
return port_write_smc(smc, APPLESMC_WRITE_CMD, key, buffer, len);
360515
}
361516

362517
static int get_smc_key_by_index(struct applesmc_device *smc,
@@ -365,14 +520,21 @@ static int get_smc_key_by_index(struct applesmc_device *smc,
365520
__be32 be;
366521

367522
be = cpu_to_be32(index);
368-
return port_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
369-
(const char *) &be, (u8 *) key, 4);
523+
if (smc->iomem_base_set)
524+
return iomem_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
525+
(const char *) &be, (u8 *) key, 4);
526+
else
527+
return port_read_smc(smc, APPLESMC_GET_KEY_BY_INDEX_CMD,
528+
(const char *) &be, (u8 *) key, 4);
370529
}
371530

372531
static int get_smc_key_info(struct applesmc_device *smc, const char *key,
373532
struct applesmc_entry *info)
374533
{
375-
return port_get_smc_key_info(smc, key, info);
534+
if (smc->iomem_base_set)
535+
return iomem_get_smc_key_type(smc, key, info);
536+
else
537+
return port_get_smc_key_info(smc, key, info);
376538
}
377539

378540
static int read_register_count(struct applesmc_device *smc,
@@ -746,6 +908,7 @@ static int applesmc_add(struct acpi_device *dev)
746908
if (!smc)
747909
return -ENOMEM;
748910
smc->dev = dev;
911+
smc->ldev = &dev->dev;
749912
mutex_init(&smc->reg.mutex);
750913

751914
dev_set_drvdata(&dev->dev, smc);
@@ -807,6 +970,20 @@ static acpi_status applesmc_walk_resources(struct acpi_resource *res,
807970
}
808971
return AE_OK;
809972

973+
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
974+
if (!smc->iomem_base_set) {
975+
if (res->data.fixed_memory32.address_length <
976+
APPLESMC_IOMEM_MIN_SIZE) {
977+
dev_warn(smc->ldev, "found iomem but it's too small: %u\n",
978+
res->data.fixed_memory32.address_length);
979+
return AE_OK;
980+
}
981+
smc->iomem_base_addr = res->data.fixed_memory32.address;
982+
smc->iomem_base_size = res->data.fixed_memory32.address_length;
983+
smc->iomem_base_set = true;
984+
}
985+
return AE_OK;
986+
810987
case ACPI_RESOURCE_TYPE_END_TAG:
811988
if (smc->port_base_set)
812989
return AE_OK;
@@ -818,6 +995,8 @@ static acpi_status applesmc_walk_resources(struct acpi_resource *res,
818995
}
819996
}
820997

998+
static int applesmc_try_enable_iomem(struct applesmc_device *smc);
999+
8211000
static int applesmc_init_resources(struct applesmc_device *smc)
8221001
{
8231002
int ret;
@@ -830,11 +1009,57 @@ static int applesmc_init_resources(struct applesmc_device *smc)
8301009
if (!request_region(smc->port_base, APPLESMC_NR_PORTS, "applesmc"))
8311010
return -ENXIO;
8321011

1012+
if (smc->iomem_base_set) {
1013+
if (applesmc_try_enable_iomem(smc))
1014+
smc->iomem_base_set = false;
1015+
}
1016+
8331017
return 0;
8341018
}
8351019

1020+
static int applesmc_try_enable_iomem(struct applesmc_device *smc)
1021+
{
1022+
u8 test_val, ldkn_version;
1023+
1024+
dev_dbg(smc->ldev, "Trying to enable iomem based communication\n");
1025+
smc->iomem_base = ioremap(smc->iomem_base_addr, smc->iomem_base_size);
1026+
if (!smc->iomem_base)
1027+
goto out;
1028+
1029+
/* Apple's driver does this check for some reason */
1030+
test_val = ioread8(smc->iomem_base + APPLESMC_IOMEM_KEY_STATUS);
1031+
if (test_val == 0xff) {
1032+
dev_warn(smc->ldev,
1033+
"iomem enable failed: initial status is 0xff (is %x)\n",
1034+
test_val);
1035+
goto out_iomem;
1036+
}
1037+
1038+
if (read_smc(smc, "LDKN", &ldkn_version, 1)) {
1039+
dev_warn(smc->ldev, "iomem enable failed: ldkn read failed\n");
1040+
goto out_iomem;
1041+
}
1042+
1043+
if (ldkn_version < 2) {
1044+
dev_warn(smc->ldev,
1045+
"iomem enable failed: ldkn version %u is less than minimum (2)\n",
1046+
ldkn_version);
1047+
goto out_iomem;
1048+
}
1049+
1050+
return 0;
1051+
1052+
out_iomem:
1053+
iounmap(smc->iomem_base);
1054+
1055+
out:
1056+
return -ENXIO;
1057+
}
1058+
8361059
static void applesmc_free_resources(struct applesmc_device *smc)
8371060
{
1061+
if (smc->iomem_base_set)
1062+
iounmap(smc->iomem_base);
8381063
release_region(smc->port_base, APPLESMC_NR_PORTS);
8391064
}
8401065

0 commit comments

Comments
 (0)