440 lines
10 KiB
C
Executable File
440 lines
10 KiB
C
Executable File
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
#include <linux/lotus/timestamp.h>
|
|
#include <common.h>
|
|
#include <asm/io.h>
|
|
|
|
#ifdef CONFIG_TARGET_XMFALCON
|
|
static timestamp_type stopwatch_get_running_timer(void);
|
|
#define timestamp_get_time() stopwatch_get_running_timer()
|
|
#define convert_to_final_stamp(value) (value)
|
|
#define UNIT_STR "us"
|
|
#define TIMESTAMP_FMT "%-16llu"UNIT_STR
|
|
|
|
|
|
#define REG_OPERATION_DELAY_US (10 * 1000)
|
|
typedef union {
|
|
u32 value;
|
|
struct {
|
|
/* [0] timer trigger */
|
|
u32 timer_trigger : 1;
|
|
/* [2] timer clear */
|
|
u32 timer_clear : 1;
|
|
/* [3] running timer trigger */
|
|
u32 running_timer_trigger : 1;
|
|
/* [3:31] reserved */
|
|
u32 reserved : 29;
|
|
};
|
|
} stopwatch_cfg;
|
|
|
|
typedef union {
|
|
u32 value;
|
|
struct {
|
|
/* [0:3] timer trigger */
|
|
u32 timer_sel : 4;
|
|
/* [4:31] reserved */
|
|
u32 reserved : 28;
|
|
};
|
|
} stopwatch_sel;
|
|
|
|
/*---------------------------------
|
|
* timestamp
|
|
*--------------------------------*/
|
|
static u32 get_timestamp_count(void)
|
|
{
|
|
return readl(TIMESTAMP_CNT_ADDR);
|
|
}
|
|
|
|
static void update_timestamp_count(u32 cnt)
|
|
{
|
|
writel(cnt, TIMESTAMP_CNT_ADDR);
|
|
}
|
|
|
|
void timestamp_clear(void)
|
|
{
|
|
writel(0, TIMESTAMP_CNT_ADDR);
|
|
}
|
|
|
|
void timestamp_mark(const char *func, u32 line, u32 type)
|
|
{
|
|
timestamp_type stamp = timestamp_get_time();
|
|
u32 cnt = get_timestamp_count();
|
|
|
|
if (cnt >= TIMESTAMP_MAX_ITEM_CNT) {
|
|
printf("No timestamp item!\n");
|
|
return;
|
|
}
|
|
|
|
timestamp_item *item =
|
|
(timestamp_item *)(uintptr_t)TIMESTAMP_ITEM_START_ADDR;
|
|
item[cnt].stamp = stamp;
|
|
item[cnt].func = (char *)func;
|
|
item[cnt].line = line;
|
|
item[cnt].type = type;
|
|
cnt++;
|
|
update_timestamp_count(cnt);
|
|
}
|
|
|
|
void timestamp_print(u32 type)
|
|
{
|
|
const u32 cnt = get_timestamp_count();
|
|
timestamp_type time0 = 0;
|
|
timestamp_item *items =
|
|
(timestamp_item *)(uintptr_t)TIMESTAMP_ITEM_START_ADDR;
|
|
timestamp_type stamp = 0;
|
|
|
|
for (u32 i = 0; i < cnt; i++) {
|
|
timestamp_type time = convert_to_final_stamp(items[i].stamp);
|
|
const char *func = items[i].func;
|
|
u32 line = items[i].line;
|
|
if (type == items[i].type) {
|
|
if (func != NULL) {
|
|
printf("time stamp[%-3u] = "TIMESTAMP_FMT" gap = "TIMESTAMP_FMT""
|
|
" type: %-5u line: %-5u func: %s\n",
|
|
i + 1, time, time - stamp,
|
|
items[i].type, line, func);
|
|
} else {
|
|
printf("time stamp[%-3u] = "TIMESTAMP_FMT" gap = "TIMESTAMP_FMT""
|
|
" type: %-5u line: %-5u\n",
|
|
i + 1, time, time - stamp,
|
|
items[i].type, line);
|
|
}
|
|
}
|
|
stamp = time;
|
|
if (i == 0) {
|
|
time0 = time;
|
|
}
|
|
if (i == (cnt - 1)) {
|
|
printf("total time from stamp[%-3d] to [%-3d] gap = "
|
|
TIMESTAMP_FMT"\n", 1, i + 1, time - time0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int do_timestamp(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
TIME_STAMP(0);
|
|
return 0;
|
|
}
|
|
U_BOOT_CMD(timestamp, 1, 1, do_timestamp,
|
|
"Mark a time stamp",
|
|
"");
|
|
|
|
/*---------------------------------
|
|
* stopwatch
|
|
*--------------------------------*/
|
|
static timestamp_type stopwatch_get(u32 point)
|
|
{
|
|
stopwatch_sel sel = {0};
|
|
|
|
sel.timer_sel = point;
|
|
writel(sel.value, (STOPWATCH_CTRL_REG1));
|
|
udelay(REG_OPERATION_DELAY_US);
|
|
timestamp_type value = readl(STOPWATCH_VALUE_REG);
|
|
value += (timestamp_type)readl(STOPWATCH_VALUE_REG_H) << 32;
|
|
return value;
|
|
}
|
|
|
|
static timestamp_type stopwatch_get_running_timer(void)
|
|
{
|
|
stopwatch_cfg cfg = {0};
|
|
|
|
cfg.running_timer_trigger = 1; /* true */
|
|
writel(cfg.value, (STOPWATCH_CTRL_REG2));
|
|
|
|
/* 4us at least to wait */
|
|
udelay(4);
|
|
timestamp_type value = readl(STOPWATCH_RUNNING_VALUE_REG);
|
|
value += (timestamp_type)readl(STOPWATCH_RUNNING_VALUE_REG_H) << 32;
|
|
return value;
|
|
}
|
|
|
|
void stopwatch_trigger(void)
|
|
{
|
|
stopwatch_cfg cfg = {0};
|
|
|
|
cfg.timer_clear = 0; /* false */
|
|
cfg.timer_trigger = 1; /* true */
|
|
writel(cfg.value, (STOPWATCH_CTRL_REG2));
|
|
}
|
|
|
|
void stopwatch_clear(void)
|
|
{
|
|
stopwatch_cfg cfg = {0};
|
|
|
|
cfg.timer_clear = 1; /* true */
|
|
cfg.timer_trigger = 0; /* false */
|
|
writel(cfg.value, (STOPWATCH_CTRL_REG2));
|
|
}
|
|
|
|
void stopwatch_print(void)
|
|
{
|
|
timestamp_type time;
|
|
u32 point;
|
|
printf("-----------------------------\n");
|
|
printf("STOPWATCH(boot)[0-%d]: \n", TIMESTAMP_STOPWATCH_POINT_MAX - 1);
|
|
for (point = 0; point < TIMESTAMP_STOPWATCH_POINT_MAX; point++) {
|
|
time = stopwatch_get(point);
|
|
printf("%-3d ", point);
|
|
printf(TIMESTAMP_FMT"\n", time);
|
|
}
|
|
printf("-----------------------------\n");
|
|
}
|
|
|
|
/* #define STOPWATCH_TEST */
|
|
#ifdef STOPWATCH_TEST
|
|
static int do_stopwatch_test(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
#define __NUM 60
|
|
u32 value[__NUM];
|
|
int i;
|
|
|
|
for (i = 0; i < __NUM; i += 2) {
|
|
writel(1 << 16, STOPWATCH_CTRL_REG);
|
|
udelay(4);
|
|
value[i] = readl(STOPWATCH_RUNNING_VALUE_REG);
|
|
value[i + 1] = readl(STOPWATCH_RUNNING_VALUE_REG_H);
|
|
}
|
|
|
|
printf("------------------------------------------------\n");
|
|
printf("STOPWATCH RUNNING TIMER(boot)[0-%d]: \n", __NUM / 2);
|
|
for (i = 0; i < __NUM; i += 2) {
|
|
printf("%8u_%-8u us", value[i + 1], value[i]);
|
|
if (i == 0)
|
|
printf(", gap: 0 us\n");
|
|
else {
|
|
printf(", gap: %-8u us\n", value[i] - value[i - 2]);
|
|
if (value[i] - value[i - 2] > 10) {
|
|
printf("Gap Exception!!");
|
|
hang();
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("------------------------------------------------\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_CMD(stopwatch_test, 1, 1, do_stopwatch_test,
|
|
"stopwatch_test",
|
|
"");
|
|
#endif
|
|
|
|
#else
|
|
|
|
static timestamp_type stopwatch_get_running_timer(void);
|
|
#define timestamp_get_time() stopwatch_get_running_timer()
|
|
#define convert_to_final_stamp(value) (value)
|
|
#define UNIT_STR "us"
|
|
#define TIMESTAMP_FMT "%-16llu"UNIT_STR
|
|
|
|
|
|
#define REG_OPERATION_DELAY_US (10 * 1000)
|
|
typedef union {
|
|
u32 value;
|
|
struct {
|
|
/* [0] 1:timer trigger enable,system will record current time */
|
|
u32 timer_trigger : 1;
|
|
/* [2] 1:timer clear enable, system will clear timer's value in reg */
|
|
u32 timer_clear : 1;
|
|
/* [2-5]:timer select */
|
|
u32 timer_sel : 4;
|
|
/* [6:15] reserved */
|
|
u32 reserved1 : 10;
|
|
/* [16] running timer trigger */
|
|
u32 running_timer_trigger : 1;
|
|
/* [17:31] reserved */
|
|
u32 reserved2 : 15;
|
|
};
|
|
} stopwatch_cfg;
|
|
|
|
|
|
/*---------------------------------
|
|
* timestamp
|
|
*--------------------------------*/
|
|
static u32 get_timestamp_count(void)
|
|
{
|
|
return readl(TIMESTAMP_CNT_ADDR);
|
|
}
|
|
|
|
static void update_timestamp_count(u32 cnt)
|
|
{
|
|
writel(cnt, TIMESTAMP_CNT_ADDR);
|
|
}
|
|
|
|
void timestamp_clear(void)
|
|
{
|
|
writel(0, TIMESTAMP_CNT_ADDR);
|
|
}
|
|
|
|
void timestamp_mark(const char *func, u32 line, u32 type)
|
|
{
|
|
timestamp_type stamp = timestamp_get_time();
|
|
u32 cnt = get_timestamp_count();
|
|
|
|
if (cnt >= TIMESTAMP_MAX_ITEM_CNT) {
|
|
printf("No timestamp item!\n");
|
|
return;
|
|
}
|
|
|
|
timestamp_item *item =
|
|
(timestamp_item *)(uintptr_t)TIMESTAMP_ITEM_START_ADDR;
|
|
item[cnt].stamp = stamp;
|
|
item[cnt].func = (char *)func;
|
|
item[cnt].line = line;
|
|
item[cnt].type = type;
|
|
cnt++;
|
|
update_timestamp_count(cnt);
|
|
}
|
|
|
|
void timestamp_print(u32 type)
|
|
{
|
|
const u32 cnt = get_timestamp_count();
|
|
timestamp_type time0 = 0;
|
|
timestamp_item *items =
|
|
(timestamp_item *)(uintptr_t)TIMESTAMP_ITEM_START_ADDR;
|
|
timestamp_type stamp = 0;
|
|
|
|
for (u32 i = 0; i < cnt; i++) {
|
|
timestamp_type time = convert_to_final_stamp(items[i].stamp);
|
|
const char *func = items[i].func;
|
|
u32 line = items[i].line;
|
|
if (type == items[i].type) {
|
|
if (func != NULL) {
|
|
printf("time stamp[%-3u] = "TIMESTAMP_FMT" gap = "TIMESTAMP_FMT""
|
|
" type: %-5u line: %-5u func: %s\n",
|
|
i + 1, time, time - stamp,
|
|
items[i].type, line, func);
|
|
} else {
|
|
printf("time stamp[%-3u] = "TIMESTAMP_FMT" gap = "TIMESTAMP_FMT""
|
|
" type: %-5u line: %-5u\n",
|
|
i + 1, time, time - stamp,
|
|
items[i].type, line);
|
|
}
|
|
}
|
|
stamp = time;
|
|
if (i == 0) {
|
|
time0 = time;
|
|
}
|
|
if (i == (cnt - 1)) {
|
|
printf("total time from stamp[%-3d] to [%-3d] gap = "
|
|
TIMESTAMP_FMT"\n", 1, i + 1, time - time0);
|
|
}
|
|
}
|
|
}
|
|
|
|
static int do_timestamp(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
TIME_STAMP(0);
|
|
return 0;
|
|
}
|
|
U_BOOT_CMD(timestamp, 1, 1, do_timestamp,
|
|
"Mark a time stamp",
|
|
"");
|
|
|
|
/*---------------------------------
|
|
* stopwatch
|
|
*--------------------------------*/
|
|
static timestamp_type stopwatch_get(u32 point)
|
|
{
|
|
stopwatch_cfg cfg = {0};
|
|
|
|
cfg.timer_clear = 0; /* false */
|
|
cfg.timer_trigger = 0; /* false */
|
|
cfg.timer_sel = point;
|
|
writel(cfg.value, (STOPWATCH_CTRL_REG));
|
|
udelay(REG_OPERATION_DELAY_US);
|
|
timestamp_type value = readl(STOPWATCH_VALUE_REG);
|
|
value += (timestamp_type)readl(STOPWATCH_VALUE_REG_H) << 32;
|
|
return value;
|
|
}
|
|
|
|
static timestamp_type stopwatch_get_running_timer(void)
|
|
{
|
|
writel(1 << 16, STOPWATCH_CTRL_REG);
|
|
/* 4us at least to wait */
|
|
udelay(4);
|
|
timestamp_type value = readl(STOPWATCH_RUNNING_VALUE_REG);
|
|
value += (timestamp_type)readl(STOPWATCH_RUNNING_VALUE_REG_H) << 32;
|
|
return value;
|
|
}
|
|
|
|
void stopwatch_trigger(void)
|
|
{
|
|
stopwatch_cfg cfg = {0};
|
|
|
|
cfg.timer_clear = 0; /* false */
|
|
cfg.timer_trigger = 1; /* true */
|
|
writel(cfg.value, (STOPWATCH_CTRL_REG));
|
|
}
|
|
|
|
void stopwatch_clear(void)
|
|
{
|
|
stopwatch_cfg cfg = {0};
|
|
|
|
cfg.timer_clear = 1; /* true */
|
|
cfg.timer_trigger = 0; /* false */
|
|
writel(cfg.value, (STOPWATCH_CTRL_REG));
|
|
}
|
|
|
|
void stopwatch_print(void)
|
|
{
|
|
timestamp_type time;
|
|
u32 point;
|
|
printf("-----------------------------\n");
|
|
printf("STOPWATCH(boot)[0-%d]: \n", TIMESTAMP_STOPWATCH_POINT_MAX - 1);
|
|
for (point = 0; point < TIMESTAMP_STOPWATCH_POINT_MAX; point++) {
|
|
time = stopwatch_get(point);
|
|
printf("%-3d ", point);
|
|
printf(TIMESTAMP_FMT"\n", time);
|
|
}
|
|
printf("-----------------------------\n");
|
|
}
|
|
|
|
/* #define STOPWATCH_TEST */
|
|
#ifdef STOPWATCH_TEST
|
|
static int do_stopwatch_test(cmd_tbl_t *cmdtp, int flag, int argc,
|
|
char * const argv[])
|
|
{
|
|
#define __NUM 60
|
|
u32 value[__NUM];
|
|
int i;
|
|
|
|
for (i = 0; i < __NUM; i += 2) {
|
|
writel(1 << 16, STOPWATCH_CTRL_REG);
|
|
udelay(4);
|
|
value[i] = readl(STOPWATCH_RUNNING_VALUE_REG);
|
|
value[i + 1] = readl(STOPWATCH_RUNNING_VALUE_REG_H);
|
|
}
|
|
|
|
printf("------------------------------------------------\n");
|
|
printf("STOPWATCH RUNNING TIMER(boot)[0-%d]: \n", __NUM / 2);
|
|
for (i = 0; i < __NUM; i += 2) {
|
|
printf("%8u_%-8u us", value[i + 1], value[i]);
|
|
if (i == 0)
|
|
printf(", gap: 0 us\n");
|
|
else {
|
|
printf(", gap: %-8u us\n", value[i] - value[i - 2]);
|
|
if (value[i] - value[i - 2] > 10) {
|
|
printf("Gap Exception!!");
|
|
hang();
|
|
}
|
|
}
|
|
}
|
|
|
|
printf("------------------------------------------------\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
U_BOOT_CMD(stopwatch_test, 1, 1, do_stopwatch_test,
|
|
"stopwatch_test",
|
|
"");
|
|
#endif
|
|
|
|
#endif
|