Initial commit: Linux kernel 4.19 for Unplugged OS

This commit is contained in:
ziv committed 2025-10-06 13:52:42 +00:00
commit d30235b04c
80519 files changed
+35800681

No files matched your search

+14
View File
@@ -0,0 +1,14 @@
config MTK_PLAT_SRAM_FLAG
bool "MediaTek PLATFORM SRAM FLAG"
help
PLAT_SRAM_FLAG provides APIs to access debugging flags.
Which are kept after exception occurs, and we can dump
these flags as hints or inputs to post-processing scripts
for further analyze.
config MTK_LASTBUS_INTERFACE
bool "MTK_LASTBUS"
help
LASTBUS is a tool to get the snapshot of peri and infra bus.
Enable this feature, you can dump LASTBUS status for peri and
infra bus for debug purpose.
@@ -0,0 +1,3 @@
obj-y += plat_dbg_info/
obj-$(CONFIG_MTK_LASTBUS_INTERFACE) += lastbus/
@@ -0,0 +1,6 @@
obj-y += lastbus.o
ifeq ($(CONFIG_MACH_MT6781),y)
obj-y += mt6781/
else
obj-y += $(subst ",,$(CONFIG_MTK_PLATFORM))/
endif
@@ -0,0 +1,217 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/printk.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include "lastbus.h"
struct plt_cfg_bus_latch *lastbus_ctrl;
static int lastbus_probe(struct platform_device *pdev);
#define NUM_INFRA_EVENT_REG (lastbus_ctrl->num_infra_event_reg)
#define NUM_PERI_EVENT_REG (lastbus_ctrl->num_peri_event_reg)
int lastbus_setup(struct plt_cfg_bus_latch *p)
{
lastbus_ctrl = p;
return 0;
}
static const struct of_device_id lastbus_of_ids[] = {
{ .compatible = "mediatek,lastbus-v1", },
{}
};
static struct platform_driver lastbus_drv = {
.driver = {
.name = "lastbus",
.bus = &platform_bus_type,
.owner = THIS_MODULE,
.of_match_table = lastbus_of_ids,
},
.probe = lastbus_probe,
};
static ssize_t lastbus_dump_show(struct device_driver *driver, char *buf)
{
unsigned int wp = 0;
if (lastbus_ctrl->perisys_ops.dump)
wp += lastbus_ctrl->perisys_ops.dump(lastbus_ctrl, buf, &wp);
if (lastbus_ctrl->infrasys_ops.dump)
wp += lastbus_ctrl->infrasys_ops.dump(lastbus_ctrl, buf, &wp);
return strlen(buf);
}
DRIVER_ATTR_RO(lastbus_dump);
static ssize_t
infra_event_store(struct device_driver *driver, const char *buf, size_t count)
{
int ret = 0;
if (lastbus_ctrl->infrasys_ops.set_event)
ret = lastbus_ctrl->infrasys_ops.set_event(lastbus_ctrl, buf);
if (ret < 0)
pr_notice("lastbus: peri-event set error\n");
return count;
}
static ssize_t infra_event_show(struct device_driver *driver, char *buf)
{
ssize_t len = 0;
if (lastbus_ctrl->infrasys_ops.get_event)
len = lastbus_ctrl->infrasys_ops.get_event(lastbus_ctrl, buf);
if (len < 0)
pr_notice("lastbus: peri-event get event error\n");
return len;
}
DRIVER_ATTR_RW(infra_event);
static ssize_t
lastbus_timeout_store(struct device_driver *driver,
const char *buf, size_t count)
{
int ret = 0;
if (lastbus_ctrl->infrasys_ops.set_timeout)
ret = lastbus_ctrl->infrasys_ops.set_timeout(lastbus_ctrl, buf);
if (ret < 0)
pr_notice("lastbus: set timeout error\n");
return count;
}
static ssize_t lastbus_timeout_show(struct device_driver *driver, char *buf)
{
ssize_t len = 0;
if (lastbus_ctrl->infrasys_ops.get_timeout)
len = lastbus_ctrl->infrasys_ops.get_timeout(lastbus_ctrl, buf);
if (len < 0)
pr_notice("lastbus: get timeout error\n");
return len;
}
DRIVER_ATTR_RW(lastbus_timeout);
static ssize_t
peri_event_store(struct device_driver *driver,
const char *buf, size_t count)
{
int ret = 0;
if (lastbus_ctrl->perisys_ops.set_event)
ret = lastbus_ctrl->perisys_ops.set_event(lastbus_ctrl, buf);
if (ret < 0)
pr_notice("lastbus: peri-event set error\n");
return count;
}
static ssize_t peri_event_show(struct device_driver *driver, char *buf)
{
int len = 0;
if (lastbus_ctrl->perisys_ops.get_event)
len = lastbus_ctrl->perisys_ops.get_event(lastbus_ctrl, buf);
if (len < 0)
pr_notice("lastbus: peri-event get event error\n");
return len;
}
DRIVER_ATTR_RW(peri_event);
static int lastbus_probe(struct platform_device *pdev)
{
int ret = 0;
pr_debug("%s:%d: enter\n", __func__, __LINE__);
if (lastbus_ctrl->init)
lastbus_ctrl->init(lastbus_ctrl);
else {
lastbus_ctrl->infra_base = of_iomap(pdev->dev.of_node, 0);
if (!lastbus_ctrl->infra_base) {
pr_info("can't of_iomap for infra lastbus!!\n");
return -ENOMEM;
}
lastbus_ctrl->peri_base = of_iomap(pdev->dev.of_node, 1);
if (!lastbus_ctrl->peri_base) {
pr_info("can't of_iomap for peri lastbus!!\n");
return -ENOMEM;
}
lastbus_ctrl->spm_flag_base = of_iomap(pdev->dev.of_node, 2);
if (!lastbus_ctrl->peri_base) {
pr_info("can't of_iomap for peri lastbus!!\n");
return -ENOMEM;
}
}
ret = driver_create_file(&lastbus_drv.driver,
&driver_attr_lastbus_dump);
ret |= driver_create_file(&lastbus_drv.driver,
&driver_attr_infra_event);
ret |= driver_create_file(&lastbus_drv.driver,
&driver_attr_peri_event);
ret |= driver_create_file(&lastbus_drv.driver,
&driver_attr_lastbus_timeout);
if (ret)
pr_info("last bus create file failed\n");
return 0;
}
static int __init lastbus_init(void)
{
int err = 0;
if (lastbus_ctrl == NULL) {
pr_notice("kernel lastbus dump not support");
return -1;
}
err = platform_driver_register(&lastbus_drv);
if (err)
return err;
return 0;
}
late_initcall_sync(lastbus_init);
@@ -0,0 +1,62 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#ifndef _LASTBUS_H__
#define _LASTBUS_H__
#include <linux/sizes.h>
#include <linux/io.h>
#define LATCH_BUF_LENGTH SZ_4K
struct lastbus_perisys_offsets {
unsigned int bus_peri_r0;
unsigned int bus_peri_r1;
unsigned int bus_peri_mon;
};
struct lastbus_infrasys_offsets {
unsigned int bus_infra_ctrl;
unsigned int bus_infra_mask_l;
unsigned int bus_infra_mask_h;
unsigned int bus_infra_snapshot;
};
struct plt_cfg_bus_latch;
struct lastbus_ops {
int (*init)(const struct plt_cfg_bus_latch *self);
int (*is_timeout)(const struct plt_cfg_bus_latch *self);
int (*dump)(const struct plt_cfg_bus_latch *self, char *buf, int *wp);
int (*set_event)(const struct plt_cfg_bus_latch *self,
const char *buf);
int (*get_event)(const struct plt_cfg_bus_latch *self, char *buf);
int (*set_timeout)(const struct plt_cfg_bus_latch *self,
const char *buf);
int (*get_timeout)(const struct plt_cfg_bus_latch *self, char *buf);
};
struct plt_cfg_bus_latch {
unsigned int supported;
unsigned int num_perisys_mon;
unsigned int num_infrasys_mon;
unsigned int num_infra_event_reg;
unsigned int num_peri_event_reg;
unsigned int secure_perisys;
unsigned int perisys_enable;
unsigned int perisys_timeout;
unsigned int perisys_eventmask;
unsigned int infrasys_enable;
unsigned int infrasys_config;
struct lastbus_ops perisys_ops;
struct lastbus_ops infrasys_ops;
void __iomem *peri_base;
void __iomem *infra_base;
void __iomem *spm_flag_base;
struct lastbus_perisys_offsets perisys_offsets;
struct lastbus_infrasys_offsets infrasys_offsets;
int (*init)(const struct plt_cfg_bus_latch *self);
};
int lastbus_setup(struct plt_cfg_bus_latch *p);
#endif
@@ -0,0 +1 @@
obj-y += plat_lastbus.o
@@ -0,0 +1,296 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "./../lastbus.h"
#include "plat_lastbus.h"
#include <linux/seqlock.h>
#include <linux/irqflags.h>
static DEFINE_SPINLOCK(lastbus_spin_lock);
/*
* Usage: echo 0 0 {infra} {peri} >
* /sys/bus/platform/drivers/lastbus/lastbus_timeout
*/
int infra_set_timeout(const struct plt_cfg_bus_latch *self, const char *buf)
{
int i;
char *arg;
char *p = (char *)buf;
unsigned long input;
unsigned int settings[4];
unsigned int infra_timeout;
unsigned int peri_timeout;
for (i = 0; i < 4; i++) {
arg = strsep(&p, " ");
if (arg == NULL)
return -EINVAL;
if (kstrtoul(arg, 16, &input) != 0) {
pr_info("%s:%d: kstrtoul fail for %s\n",
__func__, __LINE__, p);
return -1;
}
settings[i] = (unsigned int)input;
}
infra_timeout = readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl) & ~(0xffff);
infra_timeout |= settings[2];
writel(infra_timeout, self->infra_base +
self->infrasys_offsets.bus_infra_ctrl);
peri_timeout = readl(self->peri_base +
self->perisys_offsets.bus_peri_r0) & ~0xffff;
peri_timeout |= settings[3];
writel(peri_timeout, self->peri_base +
self->perisys_offsets.bus_peri_r0);
return 0;
}
int infra_get_timeout(const struct plt_cfg_bus_latch *self, char *buf)
{
return snprintf(buf, PAGE_SIZE,
"infra_config=0x%x, peri_config=0x%x\n",
readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl),
readl(self->peri_base +
self->perisys_offsets.bus_peri_r0));
}
int infra_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *infra_base = self->infra_base;
unsigned int ctrl;
if (self->num_infrasys_mon != 0) {
ctrl = readl(infra_base +
self->infrasys_offsets.bus_infra_ctrl);
if (ctrl & 0x1) {
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS BUS DUMP:\n");
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS_CTRL = %04x\n", ctrl);
for (i = 0; i <= self->num_infrasys_mon-1; ++i)
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"INFRA SNAPSHOT%d = %04x\n",
i, readl(infra_base +
self->infrasys_offsets.bus_infra_snapshot
+ 4*i));
} else {
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS NO TIMEOUT\n");
}
}
return 0;
}
static unsigned long preisys_dump_offset[] = {
0x500, /* PERIBUS_DBG0 */
0x504, /* PERIBUS_DBG1 */
0x508, /* PERIBUS_DBG2 */
0x50C, /* PERIBUS_DBG3 */
0x510, /* PERIBUS_DBG4 */
0x514, /* PERIBUS_DBG5 */
0x518, /* PERIBUS_DBG6 */
0x51C, /* PERIBUS_DBG7 */
0x520, /* PERIBUS_DBG8 */
0x524, /* PERIBUS_DBG9 */
0x528, /* PERIBUS_DBG10 */
0x52C, /* PERIBUS_DBG11 */
0x530, /* PERIBUS_DBG12 */
0x534, /* PERIBUS_DBG13 */
0x538, /* PERIBUS_DBG14 */
0x53C, /* PERIBUS_DBG15 */
0x580, /* PERIBUS_DBG16 */
0x584, /* PERIBUS_DBG17 */
};
int peri_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *peri_base = self->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] PERISYS BUS DUMP:\n");
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"PERIBUS_DBG%d(%p) = %04x\n",
i, reg, data);
}
return 0;
}
struct plt_cfg_bus_latch cfg_bus_latch = {
.supported = 1,
.num_perisys_mon = 18,
.num_infrasys_mon = 17,
.perisys_offsets = {
.bus_peri_r0 = 0x0500,
.bus_peri_r1 = 0x0504,
.bus_peri_mon = 0x0500,
},
.infrasys_offsets = {
.bus_infra_ctrl = 0x0d04,
.bus_infra_snapshot = 0x0d00,
},
.perisys_ops = {
.dump = peri_dump,
},
.infrasys_ops = {
.dump = infra_dump,
.set_timeout = infra_set_timeout,
.get_timeout = infra_get_timeout,
},
};
struct plt_cfg_bus_latch *lb = &cfg_bus_latch;
int infra_timeout_dump(void)
{
unsigned int i;
void __iomem *infra_base = lb->infra_base;
pr_info("[LAST BUS] PERISYS BUS & INFRA BUS DUMP:\n");
pr_info("%08x\n", readl(infra_base +
lb->infrasys_offsets.bus_infra_ctrl));
if (lb->num_infrasys_mon != 0) {
for (i = 0; i <= lb->num_infrasys_mon-1; ++i)
pr_info("%08x\n",
readl(infra_base +
lb->infrasys_offsets.bus_infra_snapshot
+ 4*i));
}
return 0;
}
int peri_timeout_dump(void)
{
unsigned int i;
void __iomem *peri_base = lb->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
/* peribus_dbg_in_0 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r0));
/* peribus_dbg_in_1 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r1));
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
pr_info("%08x\n", data);
}
return 0;
}
int is_infra_timeout(void)
{
int ctrl = 0;
if (!lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return 0;
}
ctrl = (readl(lb->infra_base +
lb->infrasys_offsets.bus_infra_ctrl)) & 0x1;
return ctrl;
}
int is_peri_timeout(void)
{
int ctrl = 0;
if (!lb->peri_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return 0;
}
ctrl = (readl(lb->peri_base +
lb->perisys_offsets.bus_peri_r1)) & 0x1;
return ctrl;
}
void reset_infra(void)
{
writel(0x8, lb->infra_base + lb->infrasys_offsets.bus_infra_ctrl);
writel(0xffff000c,
lb->infra_base + lb->infrasys_offsets.bus_infra_ctrl);
}
void reset_peri(void)
{
writel(0x0, lb->peri_base + lb->perisys_offsets.bus_peri_r0);
writel(0x8, lb->peri_base + lb->perisys_offsets.bus_peri_r1);
writel(0x3fff, lb->peri_base + lb->perisys_offsets.bus_peri_r0);
writel(0xc, lb->peri_base + lb->perisys_offsets.bus_peri_r1);
}
int lastbus_timeout_dump(void)
{
int infra = 0, peri = 0;
unsigned long flags;
spin_lock_irqsave(&lastbus_spin_lock, flags);
if (!lb->peri_base || !lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return -1;
}
infra = is_infra_timeout();
peri = is_peri_timeout();
if (infra | peri) {
infra_timeout_dump();
peri_timeout_dump();
reset_infra();
reset_peri();
}
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return infra | peri;
}
static int __init plt_lastbus_init(void)
{
lastbus_setup(&cfg_bus_latch);
return 0;
}
late_initcall(plt_lastbus_init);
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __PLAT_LAST_BUS_H__
#define __PLAT_LAST_BUS_H__
#define PLAT_NUM_INFRA_EVENT_REG 2
#define PLAT_NUM_PERI_EVENT_REG 1
/*
* [31:16]peri,[15:0]infra
*/
#define FLAG_26 0xE24
#define FLAG_133 0xE34
#endif
@@ -0,0 +1 @@
obj-y += plat_lastbus.o
@@ -0,0 +1,395 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#include "./../lastbus.h"
#include "plat_lastbus.h"
#include <linux/seqlock.h>
#include <linux/irqflags.h>
static DEFINE_SPINLOCK(lastbus_spin_lock);
int infra_set_event(const struct plt_cfg_bus_latch *self, const char *buf)
{
int i;
char *arg;
char *p = (char *)buf;
unsigned long input;
unsigned int settings[PLAT_NUM_INFRA_EVENT_REG];
for (i = 0; i < self->num_infra_event_reg; i++) {
arg = strsep(&p, " ");
if (arg == NULL)
return -EINVAL;
if (kstrtoul(arg, 16, &input) != 0) {
pr_info("%s:%d: kstrtoul fail for %s\n",
__func__, __LINE__, p);
return -1;
}
settings[i] = (unsigned int)input;
}
writel(settings[0],
self->infra_base + self->infrasys_offsets.bus_infra_mask_l);
writel(settings[1],
self->infra_base + self->infrasys_offsets.bus_infra_mask_h);
return 0;
}
int infra_get_event(const struct plt_cfg_bus_latch *self, char *buf)
{
int ret;
ret = snprintf(buf, PAGE_SIZE,
"INFRA_MASKL = 0x%x, INFRA_MASKH = 0x%x\n",
readl(self->infra_base +
self->infrasys_offsets.bus_infra_mask_l),
readl(self->infra_base +
self->infrasys_offsets.bus_infra_mask_h));
return ret;
}
int infra_set_timeout(const struct plt_cfg_bus_latch *self, const char *buf)
{
int i;
char *arg;
char *p = (char *)buf;
unsigned long input;
unsigned int settings[4];
unsigned int infra_timeout;
unsigned int peri_timeout;
for (i = 0; i < 4; i++) {
arg = strsep(&p, " ");
if (arg == NULL)
return -EINVAL;
if (kstrtoul(arg, 16, &input) != 0) {
pr_info("%s:%d: kstrtoul fail for %s\n",
__func__, __LINE__, p);
return -1;
}
settings[i] = (unsigned int)input;
}
infra_timeout = readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl) & ~(0xffff);
infra_timeout = infra_timeout | settings[2];
writel(infra_timeout, self->infra_base +
self->infrasys_offsets.bus_infra_ctrl);
peri_timeout = readl(self->peri_base +
self->perisys_offsets.bus_peri_r0) & ~0xffff;
peri_timeout = peri_timeout | settings[3];
writel(peri_timeout, self->peri_base +
self->perisys_offsets.bus_peri_r0);
return 0;
}
int infra_get_timeout(const struct plt_cfg_bus_latch *self, char *buf)
{
return snprintf(buf, PAGE_SIZE,
"infra_config=0x%x, peri_config=0x%x\n",
readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl),
readl(self->peri_base +
self->perisys_offsets.bus_peri_r0));
}
int peri_set_event(const struct plt_cfg_bus_latch *self, const char *buf)
{
char *p = (char *)buf;
unsigned long input;
if (kstrtoul(p, 16, &input) != 0) {
pr_info("%s:%d: kstrtoul fail for %s\n",
__func__, __LINE__, p);
return -1;
}
writel(input, self->peri_base +
self->perisys_offsets.bus_peri_r1);
return 0;
}
int peri_get_event(const struct plt_cfg_bus_latch *self, char *buf)
{
int ret;
ret = snprintf(buf, PAGE_SIZE, "PERI_MASK = 0x%x\n",
readl(self->peri_base +
self->perisys_offsets.bus_peri_r1));
return ret;
}
int infra_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *infra_base = self->infra_base;
unsigned int ctrl;
if (self->num_infrasys_mon != 0) {
ctrl = readl(infra_base +
self->infrasys_offsets.bus_infra_ctrl);
if (ctrl & 0xFF000000) {
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS TIMEOUT:\n");
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS_CTRL = %04x\n", ctrl);
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS_MASKL = %04x\n",
readl(infra_base +
self->infrasys_offsets.bus_infra_ctrl));
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS_MASKH = %04x\n",
readl(infra_base +
self->infrasys_offsets.bus_infra_ctrl));
for (i = 0; i <= self->num_infrasys_mon-1; ++i)
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"INFRA SNAPSHOT%d = %04x\n",
i, readl(infra_base +
self->infrasys_offsets.bus_infra_snapshot
+ 4*i));
} else {
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS NO TIMEOUT:\n");
}
}
return 0;
}
static unsigned long preisys_dump_offset[] = {
0x508, /* PERIBUS_DBG0 */
0x50c, /* PERIBUS_DBG1 */
0x510, /* PERIBUS_DBG2 */
0x514, /* PERIBUS_DBG3 */
0x518, /* PERIBUS_DBG4 */
0x51c, /* PERIBUS_DBG5 */
0x520, /* PERIBUS_DBG6 */
0x524, /* PERIBUS_DBG7 */
0x528, /* PERIBUS_DBG8 */
0x52c, /* PERIBUS_DBG9 */
0x530, /* PERIBUS_DBG10 */
0x534, /* PERIBUS_DBG11 */
0x538, /* PERIBUS_DBG12 */
0x53c, /* PERIBUS_DBG13 */
0x580, /* PERIBUS_DBG14 */
0x584, /* PERIBUS_DBG15 */
0x588, /* PERIBUS_DBG16 */
0x58c, /* PERIBUS_DBG17 */
0x590, /* PERIBUS_DBG18 */
0x594, /* PERIBUS_DBG19 */
0x598, /* PERIBUS_DBG20 */
};
int peri_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *peri_base = self->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] PERISYS BUS DUMP:\n");
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"PERIBUS_DBG%d(%p) = %04x\n",
i, reg, data);
}
return 0;
}
struct plt_cfg_bus_latch cfg_bus_latch = {
.supported = 1,
.num_perisys_mon = 21,
.num_infrasys_mon = 48,
.num_infra_event_reg = PLAT_NUM_INFRA_EVENT_REG,
.num_peri_event_reg = PLAT_NUM_PERI_EVENT_REG,
.perisys_offsets = {
.bus_peri_r0 = 0x0500,
.bus_peri_r1 = 0x0504,
.bus_peri_mon = 0x0508,
},
.infrasys_offsets = {
.bus_infra_ctrl = 0x0d04,
.bus_infra_mask_l = 0x0d00,
.bus_infra_mask_h = 0x0df0,
.bus_infra_snapshot = 0x0d08,
},
.perisys_ops = {
.dump = peri_dump,
.set_event = peri_set_event,
.get_event = peri_get_event,
},
.infrasys_ops = {
.dump = infra_dump,
.set_event = infra_set_event,
.get_event = infra_get_event,
.set_timeout = infra_set_timeout,
.get_timeout = infra_get_timeout,
},
};
struct plt_cfg_bus_latch *lb = &cfg_bus_latch;
int infra_timeout_dump(void)
{
unsigned int i;
void __iomem *infra_base = lb->infra_base;
pr_info("[LAST BUS] PERISYS BUS & INFRA BUS DUMP:\n");
/* infrabus_dbg_in_0 */
pr_info("%08x\n", readl(infra_base +
lb->infrasys_offsets.bus_infra_mask_l));
/* infrabus_dbg_mask_2 */
pr_info("%08x\n", readl(infra_base +
lb->infrasys_offsets.bus_infra_mask_h));
/* infrabus_dbg_in_1 */
pr_info("%08x\n", readl(infra_base +
lb->infrasys_offsets.bus_infra_ctrl));
if (lb->num_infrasys_mon != 0) {
for (i = 0; i <= lb->num_infrasys_mon-1; ++i)
pr_info("%08x\n",
readl(infra_base +
lb->infrasys_offsets.bus_infra_snapshot
+ 4*i));
}
return 0;
}
int peri_timeout_dump(void)
{
unsigned int i;
void __iomem *peri_base = lb->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
/* peribus_dbg_in_0 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r0));
/* peribus_dbg_in_1 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r1));
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
pr_info("%08x\n", data);
}
return 0;
}
int is_infra_timeout(void)
{
int ctrl = 0;
if (!lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return 0;
}
ctrl = readl(lb->infra_base +
lb->infrasys_offsets.bus_infra_ctrl);
return ctrl & 0x1;
}
int is_peri_timeout(void)
{
int ctrl = 0;
if (!lb->peri_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return 0;
}
ctrl = readl(lb->peri_base +
lb->perisys_offsets.bus_peri_r1);
return ctrl & 0x1;
}
void reset_infra(void)
{
writel(0x8, lb->infra_base + lb->infrasys_offsets.bus_infra_ctrl);
writel(0xffff000c,
lb->infra_base + lb->infrasys_offsets.bus_infra_ctrl);
}
void reset_peri(void)
{
writel(0x0, lb->peri_base + lb->perisys_offsets.bus_peri_r0);
writel(0x8, lb->peri_base + lb->perisys_offsets.bus_peri_r1);
writel(0x3fff, lb->peri_base + lb->perisys_offsets.bus_peri_r0);
writel(0xc, lb->peri_base + lb->perisys_offsets.bus_peri_r1);
}
int lastbus_timeout_dump(void)
{
int infra = 0, peri = 0;
unsigned long flags;
spin_lock_irqsave(&lastbus_spin_lock, flags);
if (!lb->peri_base || !lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return -1;
}
infra = is_infra_timeout();
peri = is_peri_timeout();
if (infra | peri) {
infra_timeout_dump();
peri_timeout_dump();
reset_infra();
reset_peri();
}
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return infra | peri;
}
static int __init plt_lastbus_init(void)
{
lastbus_setup(&cfg_bus_latch);
return 0;
}
late_initcall(plt_lastbus_init);
@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 MediaTek Inc.
*/
#ifndef __PLAT_LAST_BUS_H__
#define __PLAT_LAST_BUS_H__
#define PLAT_NUM_INFRA_EVENT_REG 2
#define PLAT_NUM_PERI_EVENT_REG 1
/*
* [31:16]peri,[15:0]infra
*/
#define FLAG_26 0xE24
#define FLAG_133 0xE34
#endif
@@ -0,0 +1 @@
obj-y += plat_lastbus.o
@@ -0,0 +1,278 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2016 MediaTek Inc.
*/
#include "./../lastbus.h"
#include "plat_lastbus.h"
#include <linux/seqlock.h>
#include <linux/irqflags.h>
static DEFINE_SPINLOCK(lastbus_spin_lock);
/*
* Usage: echo 0 0 {infra} {peri} >
* /sys/bus/platform/drivers/lastbus/lastbus_timeout
*/
int infra_set_timeout(const struct plt_cfg_bus_latch *self, const char *buf)
{
int i;
char *arg;
char *p = (char *)buf;
unsigned long input;
unsigned int settings[4];
unsigned int infra_timeout;
unsigned int peri_timeout;
for (i = 0; i < 4; i++) {
arg = strsep(&p, " ");
if (arg == NULL)
return -EINVAL;
if (kstrtoul(arg, 16, &input) != 0) {
pr_info("%s:%d: kstrtoul fail for %s\n",
__func__, __LINE__, p);
return -1;
}
settings[i] = (unsigned int)input;
}
infra_timeout = readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl) & 0x0000FFFF;
infra_timeout |= (settings[2] << 16);
writel(infra_timeout, self->infra_base +
self->infrasys_offsets.bus_infra_ctrl);
peri_timeout = readl(self->peri_base +
self->perisys_offsets.bus_peri_r0) & 0xFFFF0000;
peri_timeout |= settings[3];
writel(peri_timeout, self->peri_base +
self->perisys_offsets.bus_peri_r0);
return 0;
}
int infra_get_timeout(const struct plt_cfg_bus_latch *self, char *buf)
{
return snprintf(buf, PAGE_SIZE,
"infra_config=0x%x, peri_config=0x%x\n",
readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl),
readl(self->peri_base +
self->perisys_offsets.bus_peri_r0));
}
int infra_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *infra_base = self->infra_base;
unsigned int ctrl;
if (self->num_infrasys_mon != 0) {
ctrl = readl(infra_base +
self->infrasys_offsets.bus_infra_ctrl);
if (ctrl & 0x1) {
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS BUS DUMP:\n");
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS_CTRL = %04x\n", ctrl);
for (i = 0; i <= self->num_infrasys_mon-1; ++i)
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"INFRA SNAPSHOT%d = %04x\n",
i, readl(infra_base +
self->infrasys_offsets.bus_infra_snapshot
+ 4*i));
} else {
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS NO TIMEOUT\n");
}
}
return 0;
}
static unsigned long preisys_dump_offset[] = {
0x500, /* PERIBUS_DBG0 */
0x504, /* PERIBUS_DBG1 */
0x508, /* PERIBUS_DBG2 */
0x50C, /* PERIBUS_DBG3 */
0x510, /* PERIBUS_DBG4 */
0x514, /* PERIBUS_DBG5 */
0x518, /* PERIBUS_DBG6 */
0x51C, /* PERIBUS_DBG7 */
0x520, /* PERIBUS_DBG8 */
0x524, /* PERIBUS_DBG9 */
0x528, /* PERIBUS_DBG10 */
0x52C, /* PERIBUS_DBG11 */
0x530, /* PERIBUS_DBG12 */
0x534, /* PERIBUS_DBG13 */
0x538, /* PERIBUS_DBG14 */
0x53C, /* PERIBUS_DBG15 */
0x580, /* PERIBUS_DBG16 */
};
int peri_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *peri_base = self->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] PERISYS BUS DUMP:\n");
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"PERIBUS_DBG%d(%p) = %04x\n",
i, reg, data);
}
return 0;
}
struct plt_cfg_bus_latch cfg_bus_latch = {
.supported = 1,
.num_perisys_mon = 15,
.num_infrasys_mon = 15,
.perisys_offsets = {
.bus_peri_r0 = 0x0500,
.bus_peri_r1 = 0x0504,
.bus_peri_mon = 0x0508,
},
.infrasys_offsets = {
.bus_infra_ctrl = 0x0d04,
.bus_infra_snapshot = 0x0d08,
},
.perisys_ops = {
.dump = peri_dump,
},
.infrasys_ops = {
.dump = infra_dump,
.set_timeout = infra_set_timeout,
.get_timeout = infra_get_timeout,
},
};
struct plt_cfg_bus_latch *lb = &cfg_bus_latch;
int infra_timeout_dump(void)
{
unsigned int i;
void __iomem *infra_base = lb->infra_base;
pr_info("[LAST BUS] PERISYS BUS & INFRA BUS DUMP:\n");
pr_info("%08x\n", readl(infra_base +
lb->infrasys_offsets.bus_infra_ctrl));
if (lb->num_infrasys_mon != 0) {
for (i = 0; i <= lb->num_infrasys_mon-1; ++i)
pr_info("%08x\n",
readl(infra_base +
lb->infrasys_offsets.bus_infra_snapshot
+ 4*i));
}
return 0;
}
int peri_timeout_dump(void)
{
unsigned int i;
void __iomem *peri_base = lb->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
/* peribus_dbg_in_0 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r0));
/* peribus_dbg_in_1 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r1));
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
pr_info("%08x\n", data);
}
return 0;
}
int is_infra_timeout(void)
{
int ctrl = 0;
if (!lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return -1;
}
ctrl = (readl(lb->infra_base +
lb->infrasys_offsets.bus_infra_ctrl)) & 0x1;
return ctrl;
}
int is_peri_timeout(void)
{
int ctrl = 0;
if (!lb->peri_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return -1;
}
ctrl = (readl(lb->peri_base +
lb->perisys_offsets.bus_peri_r1)) & 0x1;
return ctrl;
}
int lastbus_timeout_dump(void)
{
int infra = 0, peri = 0;
unsigned long flags;
spin_lock_irqsave(&lastbus_spin_lock, flags);
if (!lb->peri_base || !lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return -1;
}
infra = is_infra_timeout();
peri = is_peri_timeout();
if (infra | peri) {
infra_timeout_dump();
peri_timeout_dump();
}
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return infra | peri;
}
static int __init plt_lastbus_init(void)
{
lastbus_setup(&cfg_bus_latch);
return 0;
}
late_initcall(plt_lastbus_init);
@@ -0,0 +1,10 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2016 MediaTek Inc.
*/
#ifndef __PLAT_LAST_BUS_H__
#define __PLAT_LAST_BUS_H__
#endif
@@ -0,0 +1 @@
obj-y += plat_lastbus.o
@@ -0,0 +1,283 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#include "./../lastbus.h"
#include "plat_lastbus.h"
#include <linux/seqlock.h>
#include <linux/irqflags.h>
static DEFINE_SPINLOCK(lastbus_spin_lock);
/*
* Usage: echo 0 0 {infra} {peri} >
* /sys/bus/platform/drivers/lastbus/lastbus_timeout
*/
int infra_set_timeout(const struct plt_cfg_bus_latch *self, const char *buf)
{
int i;
char *arg;
char *p = (char *)buf;
unsigned long input;
unsigned int settings[4];
unsigned int infra_timeout;
unsigned int peri_timeout;
for (i = 0; i < 4; i++) {
arg = strsep(&p, " ");
if (arg == NULL)
return -EINVAL;
if (kstrtoul(arg, 16, &input) != 0) {
pr_info("%s:%d: kstrtoul fail for %s\n",
__func__, __LINE__, p);
return -1;
}
settings[i] = (unsigned int)input;
}
infra_timeout = readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl) & 0x0000FFFF;
infra_timeout |= (settings[2] << 16);
writel(infra_timeout, self->infra_base +
self->infrasys_offsets.bus_infra_ctrl);
peri_timeout = readl(self->peri_base +
self->perisys_offsets.bus_peri_r0) & 0xFFFF0000;
peri_timeout |= settings[3];
writel(peri_timeout, self->peri_base +
self->perisys_offsets.bus_peri_r0);
return 0;
}
int infra_get_timeout(const struct plt_cfg_bus_latch *self, char *buf)
{
return snprintf(buf, PAGE_SIZE,
"infra_config=0x%x, peri_config=0x%x\n",
readl(self->infra_base +
self->infrasys_offsets.bus_infra_ctrl),
readl(self->peri_base +
self->perisys_offsets.bus_peri_r1));
}
int infra_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *infra_base = self->infra_base;
unsigned int ctrl;
if (self->num_infrasys_mon != 0) {
ctrl = readl(infra_base +
self->infrasys_offsets.bus_infra_ctrl);
if (ctrl & 0x1) {
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS BUS DUMP:\n");
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS_CTRL = %04x\n", ctrl);
for (i = 0; i <= self->num_infrasys_mon-1; ++i)
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"INFRA SNAPSHOT%d = %04x\n",
i, readl(infra_base +
self->infrasys_offsets.bus_infra_snapshot
+ 4*i));
} else {
*wp += snprintf(buf + *wp,
LATCH_BUF_LENGTH - *wp,
"[LAST BUS] INFRASYS NO TIMEOUT\n");
}
}
return 0;
}
static unsigned long preisys_dump_offset[] = {
0x500, /* PERIBUS_DBG0 */
0x504, /* PERIBUS_DBG1 */
0x508, /* PERIBUS_DBG2 */
0x50C, /* PERIBUS_DBG3 */
0x510, /* PERIBUS_DBG4 */
0x514, /* PERIBUS_DBG5 */
0x518, /* PERIBUS_DBG6 */
0x51C, /* PERIBUS_DBG7 */
0x520, /* PERIBUS_DBG8 */
0x524, /* PERIBUS_DBG9 */
0x528, /* PERIBUS_DBG10 */
0x52C, /* PERIBUS_DBG11 */
0x530, /* PERIBUS_DBG12 */
0x534, /* PERIBUS_DBG13 */
0x538, /* PERIBUS_DBG14 */
0x53C, /* PERIBUS_DBG15 */
0x580, /* PERIBUS_DBG16 */
0x584, /* PERIBUS_DBG17 */
0x588, /* PERIBUS_DBG18 */
0x58C, /* PERIBUS_DBG19 */
0x590, /* PERIBUS_DBG20 */
0x594, /* PERIBUS_DBG21 */
0x598, /* PERIBUS_DBG22 */
};
int peri_dump(const struct plt_cfg_bus_latch *self, char *buf, int *wp)
{
unsigned int i;
void __iomem *peri_base = self->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"[LAST BUS] PERISYS BUS DUMP:\n");
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
*wp += snprintf(buf + *wp, LATCH_BUF_LENGTH - *wp,
"PERIBUS_DBG%d(%p) = %04x\n",
i, reg, data);
}
return 0;
}
struct plt_cfg_bus_latch cfg_bus_latch = {
.supported = 1,
.num_perisys_mon = 21,
.num_infrasys_mon = 48,
.perisys_offsets = {
.bus_peri_r0 = 0x0500,
.bus_peri_r1 = 0x0504,
.bus_peri_mon = 0x0508,
},
.infrasys_offsets = {
.bus_infra_ctrl = 0x0d04,
.bus_infra_snapshot = 0x0d08,
},
.perisys_ops = {
.dump = peri_dump,
},
.infrasys_ops = {
.dump = infra_dump,
.set_timeout = infra_set_timeout,
.get_timeout = infra_get_timeout,
},
};
struct plt_cfg_bus_latch *lb = &cfg_bus_latch;
int infra_timeout_dump(void)
{
unsigned int i;
void __iomem *infra_base = lb->infra_base;
pr_info("[LAST BUS] PERISYS BUS & INFRA BUS DUMP:\n");
pr_info("%08x\n", readl(infra_base +
lb->infrasys_offsets.bus_infra_ctrl));
if (lb->num_infrasys_mon != 0) {
for (i = 0; i <= lb->num_infrasys_mon-1; ++i)
pr_info("%08x\n",
readl(infra_base +
lb->infrasys_offsets.bus_infra_snapshot
+ 4*i));
}
return 0;
}
int peri_timeout_dump(void)
{
unsigned int i;
void __iomem *peri_base = lb->peri_base;
unsigned long dump_size =
sizeof(preisys_dump_offset) / sizeof(unsigned long);
unsigned __iomem *reg;
unsigned int data;
/* peribus_dbg_in_0 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r0));
/* peribus_dbg_in_1 */
pr_info("%08x\n", readl(peri_base +
lb->perisys_offsets.bus_peri_r1));
for (i = 0; i < dump_size; ++i) {
reg = peri_base + preisys_dump_offset[i];
data = readl(reg);
pr_info("%08x\n", data);
}
return 0;
}
int is_infra_timeout(void)
{
int ctrl = 0;
if (!lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return -1;
}
ctrl = (readl(lb->infra_base +
lb->infrasys_offsets.bus_infra_ctrl)) & 0x1;
return ctrl;
}
int is_peri_timeout(void)
{
int ctrl = 0;
if (!lb->peri_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
return -1;
}
ctrl = (readl(lb->peri_base +
lb->perisys_offsets.bus_peri_r1)) & 0x1;
return ctrl;
}
int lastbus_timeout_dump(void)
{
int infra = 0, peri = 0;
unsigned long flags;
spin_lock_irqsave(&lastbus_spin_lock, flags);
if (!lb->peri_base || !lb->infra_base) {
pr_info("%s:%d: not ready\n", __func__, __LINE__);
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return -1;
}
infra = is_infra_timeout();
peri = is_peri_timeout();
if (infra | peri) {
infra_timeout_dump();
peri_timeout_dump();
}
spin_unlock_irqrestore(&lastbus_spin_lock, flags);
return infra | peri;
}
static int __init plt_lastbus_init(void)
{
lastbus_setup(&cfg_bus_latch);
return 0;
}
late_initcall(plt_lastbus_init);
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2019 MediaTek Inc.
*/
#ifndef __PLAT_LAST_BUS_H__
#define __PLAT_LAST_BUS_H__
#endif
@@ -0,0 +1,19 @@
#
# Copyright (C) 2016 MediaTek Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Do not change the following order
obj-y += plat_dbg_info.o
obj-y += plat_sram_flag.o
# timesync to get boot time
ccflags-y += -I$(srctree)/drivers/misc/mediatek/timer/timesync
@@ -0,0 +1,119 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/printk.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/slab.h>
#include <plat_dbg_info.h>
static void __iomem **plat_dbg_info_base;
static unsigned int *plat_dbg_info_size;
static unsigned int *plat_dbg_info_key;
static unsigned int plat_dbg_info_max;
static int __init plat_dbg_info_init(void)
{
unsigned int *temp_base;
unsigned int i;
int ret;
if (of_chosen) {
ret = of_property_read_u32(
of_chosen, "plat_dbg_info,max", &plat_dbg_info_max);
temp_base = kmalloc_array(
plat_dbg_info_max, sizeof(unsigned int), GFP_KERNEL);
plat_dbg_info_key = kmalloc_array(
plat_dbg_info_max, sizeof(unsigned int), GFP_KERNEL);
plat_dbg_info_size = kmalloc_array(
plat_dbg_info_max, sizeof(unsigned int), GFP_KERNEL);
plat_dbg_info_base = kmalloc_array(
plat_dbg_info_max, sizeof(void __iomem *), GFP_KERNEL);
if ((temp_base == NULL) ||
(plat_dbg_info_key == NULL) ||
(plat_dbg_info_size == NULL) ||
(plat_dbg_info_base == NULL)) {
pr_debug("[PLAT DBG INFO] cannot allocate memory\n");
ret = -ENOMEM;
goto alloc_fail;
}
ret |= of_property_read_u32_array(
of_chosen, "plat_dbg_info,key",
plat_dbg_info_key, plat_dbg_info_max);
ret |= of_property_read_u32_array(
of_chosen, "plat_dbg_info,base",
temp_base, plat_dbg_info_max);
ret |= of_property_read_u32_array(
of_chosen, "plat_dbg_info,size",
plat_dbg_info_size, plat_dbg_info_max);
if (ret != 0) {
pr_debug("[PLAT DBG INFO] cannot find property\n");
ret = -ENODEV;
goto alloc_fail;
}
for (i = 0; i < plat_dbg_info_max; i++) {
if (temp_base[i] != 0)
plat_dbg_info_base[i] =
ioremap(temp_base[i], plat_dbg_info_size[i]);
else
plat_dbg_info_base[i] = NULL;
pr_debug("[PLAT DBG INFO] 0x%x: 0x%x(%p), %d\n",
plat_dbg_info_key[i], temp_base[i],
plat_dbg_info_base[i], plat_dbg_info_size[i]);
}
kfree(temp_base);
} else {
pr_debug("[PLAT DBG INFO] cannot find node \"of_chosen\"\n");
return -ENODEV;
}
return 0;
alloc_fail:
kfree(temp_base);
kfree(plat_dbg_info_key);
kfree(plat_dbg_info_size);
kfree(plat_dbg_info_base);
return ret;
}
void __iomem *get_dbg_info_base(unsigned int key)
{
unsigned int i;
for (i = 0; i < plat_dbg_info_max; i++) {
if (plat_dbg_info_key[i] == key)
return plat_dbg_info_base[i];
}
return NULL;
}
EXPORT_SYMBOL(get_dbg_info_base);
unsigned int get_dbg_info_size(unsigned int key)
{
unsigned int i;
for (i = 0; i < plat_dbg_info_max; i++) {
if (plat_dbg_info_key[i] == key)
return plat_dbg_info_size[i];
}
return 0;
}
EXPORT_SYMBOL(get_dbg_info_size);
core_initcall(plat_dbg_info_init);
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 MediaTek Inc.
*/
#ifndef __PLAT_DBG_INFO_H__
#define __PLAT_DBG_INFO_H__
void __iomem *get_dbg_info_base(unsigned int key);
unsigned int get_dbg_info_size(unsigned int key);
#endif
@@ -0,0 +1,210 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2019 MediaTek Inc.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/printk.h>
#include <linux/platform_device.h>
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/sched/clock.h>
#include "archcounter_timesync.h"
#include "plat_sram_flag.h"
#ifdef CONFIG_MTK_BUS_TRACER
#include <asm/arch_timer.h>
#endif
static struct plat_sram_flag *plat;
static inline unsigned int extract_n2mbits(unsigned int input,
unsigned int n, unsigned int m)
{
/*
* 1. ~0 = 1111 1111 1111 1111 1111 1111 1111 1111
* 2. ~0 << (m - n + 1) = 1111 1111 1111 1111 1100 0000 0000 0000
* assuming we are extracting 14 bits,
* the +1 is added for inclusive selection
* 3. ~(~0 << (m - n + 1)) = 0000 0000 0000 0000 0011 1111 1111 1111
*/
int mask;
if (n > m) {
n = n + m;
m = n - m;
n = n - m;
}
mask = ~(~0 << (m - n + 1));
return (input >> n) & mask;
}
static int check_sram_base(void)
{
if (plat)
return 0;
pr_notice("%s:%d: sram_base == 0x0\n", __func__, __LINE__);
return -1;
}
/* return negative integer if fails */
int set_sram_flag_lastpc_valid(void)
{
if (check_sram_base() < 0)
return -1;
plat->plat_sram_flag0 =
(plat->plat_sram_flag0 | (1 << OFFSET_LASTPC_VALID));
return 0;
}
EXPORT_SYMBOL(set_sram_flag_lastpc_valid);
/* return negative integer if fails */
int set_sram_flag_etb_user(unsigned int etb_id, unsigned int user_id)
{
if (check_sram_base() < 0)
return -1;
if (etb_id >= MAX_ETB_NUM) {
pr_notice("%s:%d: etb_id > MAX_ETB_NUM\n",
__func__, __LINE__);
return -1;
}
if (user_id >= MAX_ETB_USER_NUM) {
pr_notice("%s:%d: user_id > MAX_ETB_USER_NUM\n",
__func__, __LINE__);
return -1;
}
plat->plat_sram_flag0 =
(plat->plat_sram_flag0 & ~(0x7 << (OFFSET_ETB_0 + etb_id*3)))
| ((user_id & 0x7) << (OFFSET_ETB_0 + etb_id*3));
return 0;
}
EXPORT_SYMBOL(set_sram_flag_etb_user);
#ifdef CONFIG_MTK_BUS_TRACER
int set_sram_flag_timestamp(void)
{
u64 tick, ts, boot_time;
if (check_sram_base() < 0)
return -1;
ts = sched_clock_get_cyc(&tick);
pr_notice("%s: tick=0x%llx, ts=%llu\n", __func__, tick, ts);
ts = sched_clock();
boot_time = mtk_get_archcounter_time(arch_counter_get_cntvct());
boot_time -= ts;
#if BITS_PER_LONG == 32
boot_time = div_u64((boot_time*13), 1000);
#else
boot_time = (boot_time*13)/1000;
#endif
plat->plat_sram_flag0 = boot_time;
pr_notice("%s: kernel_start_tick = 0x%x\n", __func__,
plat->plat_sram_flag0);
return 0;
}
EXPORT_SYMBOL(set_sram_flag_timestamp);
#endif
/* return negative integer if fails */
int set_sram_flag_dfd_valid(void)
{
if (check_sram_base() < 0)
return -1;
plat->plat_sram_flag1 =
(plat->plat_sram_flag1 | (1 << OFFSET_DFD_VALID));
return 0;
}
EXPORT_SYMBOL(set_sram_flag_dfd_valid);
static struct platform_driver plat_sram_flag_drv = {
.driver = {
.name = "plat_sram_flag",
.bus = &platform_bus_type,
.owner = THIS_MODULE,
},
};
static ssize_t plat_sram_flag_dump_show(struct device_driver *driver,
char *buf)
{
unsigned int i;
char *wp = buf;
if (!plat) {
pr_notice("%s:%d: sram_base == 0x0\n", __func__, __LINE__);
return snprintf(buf, PAGE_SIZE, "sram_base == 0x0\n");
}
wp += snprintf(wp, PAGE_SIZE,
"plat_sram_flag0 = 0x%x\n", plat->plat_sram_flag0);
wp += snprintf(wp, PAGE_SIZE,
"plat_sram_flag1 = 0x%x\nplat_sram_flag2 = 0x%x\n",
plat->plat_sram_flag1, plat->plat_sram_flag2);
wp += snprintf(wp, PAGE_SIZE, "\n-------------\n");
wp += snprintf(wp, PAGE_SIZE, "lastpc_valid = 0x%x\n",
extract_n2mbits(plat->plat_sram_flag0,
OFFSET_LASTPC_VALID, OFFSET_LASTPC_VALID));
wp += snprintf(wp, PAGE_SIZE, "lastpc_valid_before_reboot = 0x%x\n",
extract_n2mbits(plat->plat_sram_flag0,
OFFSET_LASTPC_VALID_BEFORE_REBOOT,
OFFSET_LASTPC_VALID_BEFORE_REBOOT));
for (i = 0; i <= MAX_ETB_NUM-1; ++i)
wp += snprintf(wp, PAGE_SIZE,
"user_id_of_multi_user_etb_%d = 0x%03x\n",
i, extract_n2mbits(plat->plat_sram_flag0,
OFFSET_ETB_0 + i*3, OFFSET_ETB_0 + i*3 + 2));
wp += snprintf(wp, PAGE_SIZE, "dfd_valid = 0x%x\n",
extract_n2mbits(plat->plat_sram_flag1,
OFFSET_DFD_VALID, OFFSET_DFD_VALID));
wp += snprintf(wp, PAGE_SIZE, "dfd_valid_before_reboot = 0x%x\n",
extract_n2mbits(plat->plat_sram_flag1,
OFFSET_DFD_VALID_BEFORE_REBOOT,
OFFSET_DFD_VALID_BEFORE_REBOOT));
return strlen(buf);
}
static DRIVER_ATTR_RO(plat_sram_flag_dump);
static int __init plat_sram_flag_init(void)
{
int ret = 0;
unsigned int size;
plat = (struct plat_sram_flag *)get_dbg_info_base(PLAT_SRAM_FLAG_KEY);
if (!plat)
return -EINVAL;
size = get_dbg_info_size(PLAT_SRAM_FLAG_KEY);
if (size != sizeof(struct plat_sram_flag)) {
pr_debug("[SRAM FLAG] Can't match plat_sram_flag size\n");
return -EINVAL;
}
ret = platform_driver_register(&plat_sram_flag_drv);
if (ret)
return -ENODEV;
ret = driver_create_file(&plat_sram_flag_drv.driver,
&driver_attr_plat_sram_flag_dump);
if (ret)
pr_notice("%s:%d: driver_create_file failed.\n",
__func__, __LINE__);
return 0;
}
core_initcall(plat_sram_flag_init);
@@ -0,0 +1,72 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (C) 2019 MediaTek Inc.
*/
#ifndef __PLAT_SRAM_FLAG_H__
#define __PLAT_SRAM_FLAG_H__
/* each flag is a word */
struct plat_sram_flag {
unsigned int plat_magic;
unsigned int plat_sram_flag0;
unsigned int plat_sram_flag1;
unsigned int plat_sram_flag2;
};
#define DEF_PLAT_SRAM_FLAG PLAT_SRAM_FLAG_T
#define PLAT_SRAM_FLAG_KEY 0xDB45
/*
* PLAT_FLAG0:
* bit[0:0] = lastpc_valid,
* bit[1:1] = lastpc_valid_before_reboot,
* bit[2:4] = user_id_of_multi_user_etb_0,
* bit[5:7] = user_id_of_multi_user_etb_1,
* bit[8:10] = user_id_of_multi_user_etb_2,
* bit[11:13] = user_id_of_multi_user_etb_3,
* bit[14:16] = user_id_of_multi_user_etb_4,
* bit[17:19] = user_id_of_multi_user_etb_5,
* bit[20:22] = user_id_of_multi_user_etb_6,
* bit[23:25] = user_id_of_multi_user_etb_7,
* bit[26:28] = user_id_of_multi_user_etb_8,
* bit[29:31] = user_id_of_multi_user_etb_9,
*/
#define OFFSET_LASTPC_VALID 0
#define OFFSET_LASTPC_VALID_BEFORE_REBOOT 1
#define OFFSET_ETB_0 2
/* available multi-user ETB number
* (only count for ETB that supports multi-user)
*/
#define MAX_ETB_NUM 10
/* available user type is 0x0~0x7 */
#define MAX_ETB_USER_NUM 8
/*
* PLAT_FLAG1:
* bit[0:0] = dfd_valid,
* bit[1:1] = dfd_before_reboot,
*/
#define OFFSET_DFD_VALID 0
#define OFFSET_DFD_VALID_BEFORE_REBOOT 1
/*
* PLAT_FLAG2:
* bit[0:0] = base_address_for_dfd[32:32],
* bit[1:31] = base_address_for_dfd[1:31],
*
* XXX: due to alignment, base_address_for_dfd[0:0] is always 0
*/
int set_sram_flag_lastpc_valid(void);
int set_sram_flag_dfd_valid(void);
int set_sram_flag_etb_user(unsigned int utb_id, unsigned int user_id);
int set_sram_flag_timestamp(void);
extern void __iomem *get_dbg_info_base(unsigned int key);
extern unsigned int get_dbg_info_size(unsigned int key);
#endif