-
Notifications
You must be signed in to change notification settings - Fork 210
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Only supported operation is smc_write_u32() for turning the dp2hdmi converter on M2 desktop systems on. Signed-off-by: Janne Grunau <[email protected]>
- Loading branch information
Showing
3 changed files
with
199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,6 +124,7 @@ OBJECTS := \ | |
sart.o \ | ||
sep.o \ | ||
sio.o \ | ||
smc.o \ | ||
smp.o \ | ||
start.o \ | ||
startup.o \ | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |