blob: 0ee8ed56c74f7be74428f3c07e85921af52506e1 [file] [log] [blame] [edit]
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <config.h>
#include <common.h>
#include <asm/arch/io.h>
#include <command.h>
#include <malloc.h>
#define LOGBUF_RDFLG 0x80000000
#define RTOSINFO_PHY_ADDR (0x80000000 + 0x1000)
struct xrtosinfo_t {
u32 version;
u32 status;
u32 cpumask;
u32 flags;
u32 logbuf_len;
u32 logbuf_phy;
u32 rtos_run_flag;
u32 android_status;
u32 reserved0;
u32 reserved1;
};
struct logbuf_t {
uint32_t write;
uint32_t read;
char buf[0];
};
static struct xrtosinfo_t *rtosinfo;
static struct logbuf_t *logbuf;
static int detect_quit_cmd(void)
{
int quit = 0;
int key = 0;
if (tstc()) { /* we got a key press */
key = getc(); /* consume input */
switch (key) {
case 'q':
case 'Q':
quit = 1;
break;
}
}
return quit;
}
static inline void logbuf_begin_get_log(void)
{
u32 rd1, rd2;
rd1 = READ_ONCE(logbuf->read);
rd2 = (rd1 | LOGBUF_RDFLG);
WRITE_ONCE(logbuf->read, rd2);
}
static inline int logbuf_get_readptr(const char **pbuf)
{
const u32 logbuf_len = rtosinfo->logbuf_len - sizeof(struct logbuf_t);
u32 rd1, rd2, wt;
int len;
rd1 = READ_ONCE(logbuf->read);
wt = READ_ONCE(logbuf->write);
rd2 = (rd1 & ~LOGBUF_RDFLG);
if (rd2 <= wt)
len = wt - rd2;
else
len = logbuf_len - rd2;
if (pbuf)
*pbuf = (const char *)logbuf->buf + rd2;
return len;
}
static inline void logbuf_post_get_log(int len, int last)
{
const u32 logbuf_len = rtosinfo->logbuf_len - sizeof(struct logbuf_t);
u32 rd1, rd2;
rd1 = READ_ONCE(logbuf->read);
rd2 = (rd1 & ~LOGBUF_RDFLG);
rd2 += len;
if (rd2 >= logbuf_len)
rd2 -= logbuf_len;
if (last == 0)
rd2 |= (rd1 & LOGBUF_RDFLG);
WRITE_ONCE(logbuf->read, rd2);
}
static bool map_freertos_logbuf(void)
{
void *buf;
buf = map_physmem(RTOSINFO_PHY_ADDR, sizeof(struct xrtosinfo_t), MAP_WRBACK);
if (!buf) {
puts("Failed to map RTOSINFO memory\n");
return false;
}
rtosinfo = (struct xrtosinfo_t *)buf;
logbuf = (struct logbuf_t *)map_physmem(rtosinfo->logbuf_phy,
rtosinfo->logbuf_len,
MAP_WRBACK);
if (!logbuf) {
puts("Failed to map log buf\n");
unmap_physmem(buf, sizeof(struct xrtosinfo_t));
return false;
}
return true;
}
static void unmap_freertos_logbuf(void)
{
unmap_physmem(logbuf, rtosinfo->logbuf_len);
unmap_physmem(rtosinfo, sizeof(struct xrtosinfo_t));
logbuf = NULL;
rtosinfo = NULL;
}
static void output_freertos_logbuf(const char *p, int len)
{
#define TMP_BUF_LEN 128
static char tmpbuf[TMP_BUF_LEN + 1];
if (len > 0) {
int remain = len;
do {
int copylen = remain;
if (copylen > TMP_BUF_LEN)
copylen = TMP_BUF_LEN;
memcpy(tmpbuf, p, copylen);
tmpbuf[copylen] = 0;
puts(tmpbuf);
p += copylen;
remain -= copylen;
} while (remain > 0);
}
}
int do_freertos_log(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
int quit = 0;
const char *p;
int cnt = 0;
if (argc < 2)
return CMD_RET_USAGE;
if (strncmp(argv[1], "read", 4) == 0) {
if (!map_freertos_logbuf())
return CMD_RET_FAILURE;
logbuf_begin_get_log();
cnt = logbuf_get_readptr(&p);
if (cnt > 0)
output_freertos_logbuf(p, cnt);
logbuf_post_get_log(cnt, true);
unmap_freertos_logbuf();
} else if (strncmp(argv[1], "autoread", 8) == 0) {
if (!map_freertos_logbuf())
return CMD_RET_FAILURE;
do {
logbuf_begin_get_log();
cnt = logbuf_get_readptr(&p);
if (cnt > 0)
output_freertos_logbuf(p, cnt);
logbuf_post_get_log(cnt, true);
quit = detect_quit_cmd();
} while (!quit);
unmap_freertos_logbuf();
} else {
printf("arg error\n");
return CMD_RET_USAGE;
}
return 0;
}
static char freertos_log_help_text[] =
"read freertos log\n"
"[read log once ]\n"
"[autoread auto read, 'q' exit]\n";
U_BOOT_CMD(freertos_log, 2, 0, do_freertos_log,
"freerots_log commands", freertos_log_help_text
);