mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-24 23:53:04 +00:00
smc: Add minimal smc client
Only supported operation is smc_write_u32() for turning the dp2hdmi converter on M2 desktop systems on. Signed-off-by: Janne Grunau <j@jannau.net>
This commit is contained in:
parent
b65c7d1edc
commit
517c8e5f5b
3 changed files with 199 additions and 0 deletions
1
Makefile
1
Makefile
|
@ -124,6 +124,7 @@ OBJECTS := \
|
|||
sart.o \
|
||||
sep.o \
|
||||
sio.o \
|
||||
smc.o \
|
||||
smp.o \
|
||||
start.o \
|
||||
startup.o \
|
||||
|
|
181
src/smc.c
Normal file
181
src/smc.c
Normal file
|
@ -0,0 +1,181 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#include "assert.h"
|
||||
#include "malloc.h"
|
||||
#include "smc.h"
|
||||
#include "string.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define SMC_READ_KEY 0x10
|
||||
#define SMC_WRITE_KEY 0x11
|
||||
#define SMC_GET_KEY_BY_INDEX 0x12
|
||||
#define SMC_GET_KEY_INFO 0x13
|
||||
#define SMC_INITIALIZE 0x17
|
||||
#define SMC_NOTIFICATION 0x18
|
||||
#define SMC_RW_KEY 0x20
|
||||
|
||||
#define SMC_MSG_TYPE GENMASK(7, 0)
|
||||
#define SMC_MSG_ID GENMASK(15, 12)
|
||||
|
||||
#define SMC_WRITE_KEY_SIZE GENMASK(23, 16)
|
||||
#define SMC_WRITE_KEY_KEY GENMASK(63, 32)
|
||||
|
||||
#define SMC_RESULT_RESULT GENMASK(7, 0)
|
||||
#define SMC_RESULT_ID GENMASK(15, 12)
|
||||
#define SMC_RESULT_SIZE GENMASK(31, 16)
|
||||
#define SMC_RESULT_VALUE GENMASK(63, 32)
|
||||
|
||||
#define SMC_NUM_IDS 16
|
||||
|
||||
#define SMC_ENDPOINT 0x20
|
||||
|
||||
struct smc_dev {
|
||||
asc_dev_t *asc;
|
||||
rtkit_dev_t *rtkit;
|
||||
|
||||
void *shmem;
|
||||
u32 msgid;
|
||||
|
||||
bool outstanding[SMC_NUM_IDS];
|
||||
u64 ret[SMC_NUM_IDS];
|
||||
};
|
||||
|
||||
static void smc_handle_msg(smc_dev_t *smc, u64 msg)
|
||||
{
|
||||
if (!smc->shmem)
|
||||
smc->shmem = (void *)msg;
|
||||
else {
|
||||
u8 result = FIELD_GET(SMC_RESULT_RESULT, msg);
|
||||
u8 id = FIELD_GET(SMC_RESULT_ID, msg);
|
||||
if (result == SMC_NOTIFICATION) {
|
||||
printf("SMC: Notification: 0x%08lx\n", FIELD_GET(SMC_RESULT_VALUE, msg));
|
||||
return;
|
||||
}
|
||||
smc->outstanding[id] = false;
|
||||
smc->ret[id] = msg;
|
||||
}
|
||||
}
|
||||
|
||||
static int smc_work(smc_dev_t *smc)
|
||||
{
|
||||
int ret;
|
||||
struct rtkit_message msg;
|
||||
|
||||
while ((ret = rtkit_recv(smc->rtkit, &msg)) == 0)
|
||||
;
|
||||
|
||||
if (ret < 0) {
|
||||
printf("SMC: rtkit_recv failed!\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (msg.ep != SMC_ENDPOINT) {
|
||||
printf("SMC: received message for unexpected endpoint 0x%02x\n", msg.ep);
|
||||
return 0;
|
||||
}
|
||||
|
||||
smc_handle_msg(smc, msg.msg);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smc_send(smc_dev_t *smc, u64 message)
|
||||
{
|
||||
struct rtkit_message msg;
|
||||
|
||||
msg.ep = SMC_ENDPOINT;
|
||||
msg.msg = message;
|
||||
|
||||
rtkit_send(smc->rtkit, &msg);
|
||||
}
|
||||
|
||||
static int smc_cmd(smc_dev_t *smc, u64 message)
|
||||
{
|
||||
u8 id = smc->msgid++ & 0xF;
|
||||
assert(!smc->outstanding[id]);
|
||||
smc->outstanding[id] = true;
|
||||
|
||||
message |= FIELD_PREP(SMC_MSG_ID, id);
|
||||
|
||||
smc_send(smc, message);
|
||||
while (smc->outstanding[id])
|
||||
smc_work(smc);
|
||||
|
||||
u64 result = smc->ret[id];
|
||||
u32 ret = FIELD_GET(SMC_RESULT_RESULT, result);
|
||||
if (ret) {
|
||||
printf("SMC: smc_cmd[0x%x] failed: %u\n", id, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void smc_shutdown(smc_dev_t *smc)
|
||||
{
|
||||
rtkit_quiesce(smc->rtkit);
|
||||
rtkit_free(smc->rtkit);
|
||||
asc_free(smc->asc);
|
||||
free(smc);
|
||||
}
|
||||
|
||||
smc_dev_t *smc_init()
|
||||
{
|
||||
smc_dev_t *smc = calloc(1, sizeof(smc_dev_t));
|
||||
if (!smc)
|
||||
return NULL;
|
||||
|
||||
smc->asc = asc_init("/arm-io/smc");
|
||||
if (!smc->asc) {
|
||||
printf("SMC: failed to initialize ASC\n");
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
smc->rtkit = rtkit_init("smc", smc->asc, NULL, NULL, NULL, true);
|
||||
if (!smc->rtkit) {
|
||||
printf("SMC: failed to initialize RTKit\n");
|
||||
goto out_asc;
|
||||
}
|
||||
|
||||
if (!rtkit_boot(smc->rtkit)) {
|
||||
printf("SMC: failed to boot RTKit\n");
|
||||
goto out_rtkit;
|
||||
}
|
||||
|
||||
if (!rtkit_start_ep(smc->rtkit, SMC_ENDPOINT)) {
|
||||
printf("SMC: failed start SMC endpoint\n");
|
||||
goto out_rtkit;
|
||||
}
|
||||
|
||||
u64 initialize =
|
||||
FIELD_PREP(SMC_MSG_TYPE, SMC_INITIALIZE) | FIELD_PREP(SMC_MSG_ID, smc->msgid++);
|
||||
|
||||
smc_send(smc, initialize);
|
||||
|
||||
while (!smc->shmem) {
|
||||
int ret = smc_work(smc);
|
||||
if (ret < 0)
|
||||
goto out_rtkit;
|
||||
}
|
||||
|
||||
return smc;
|
||||
|
||||
out_rtkit:
|
||||
rtkit_free(smc->rtkit);
|
||||
out_asc:
|
||||
asc_free(smc->asc);
|
||||
out_free:
|
||||
free(smc);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int smc_write_u32(smc_dev_t *smc, u32 key, u32 value)
|
||||
{
|
||||
memcpy(smc->shmem, &value, sizeof(value));
|
||||
u64 msg = FIELD_PREP(SMC_MSG_TYPE, SMC_WRITE_KEY);
|
||||
msg |= FIELD_PREP(SMC_WRITE_KEY_SIZE, sizeof(value));
|
||||
msg |= FIELD_PREP(SMC_WRITE_KEY_KEY, key);
|
||||
|
||||
return smc_cmd(smc, msg);
|
||||
}
|
17
src/smc.h
Normal file
17
src/smc.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SMC_H
|
||||
#define SMC_H
|
||||
|
||||
#include "asc.h"
|
||||
#include "rtkit.h"
|
||||
#include "types.h"
|
||||
|
||||
typedef struct smc_dev smc_dev_t;
|
||||
|
||||
int smc_write_u32(smc_dev_t *smc, u32 key, u32 value);
|
||||
|
||||
smc_dev_t *smc_init(void);
|
||||
void smc_shutdown(smc_dev_t *smc);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue