Files
kernel_common_drivers/drivers/debug/uboot_log.c
T
benlong.zhou 2d120bb920 kernel: read boot log same as kernel5.15 [1/1]
PD#SWPL-237927

Problem:
kernel can't get boot log

Solution:
kernel get boot log that they are blx's log
same as below CL
https://scgit.amlogic.com/#/c/527327/
https://scgit.amlogic.com/#/c/568160/
https://scgit.amlogic.com/#/c/580089/

Verify:
s7d_bm201

Change-Id: I786569565b2b5effde66d620e3b9b014ec6f8a2c
Signed-off-by: benlong.zhou <benlong.zhou@amlogic.com>
2025-12-03 21:58:50 -08:00

363 lines
8.4 KiB
C

// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2019 Amlogic, Inc. All rights reserved.
*/
#include <linux/export.h>
#include <linux/cdev.h>
#include <linux/types.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/platform_device.h>
#include <linux/amlogic/iomap.h>
#include <linux/amlogic/secmon.h>
#include <linux/of.h>
#include <linux/of_fdt.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/upstream_version.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/of_reserved_mem.h>
#include <linux/mailbox_client.h>
#include <linux/amlogic/aml_mbox.h>
#include <linux/mailbox_controller.h>
#include "ring_buffer.h"
#define LOG_MEM_MAX_REGION_COUNT 2
struct log_operations_t {
unsigned int (*read)(unsigned int *timer, unsigned char *buf,
unsigned int size, unsigned int *state);
};
struct log_mem_t {
unsigned long log_base;
unsigned long log_size;
};
struct uboot_log_t {
struct log_mem_t mem[LOG_MEM_MAX_REGION_COUNT];
struct log_operations_t operations[LOG_MEM_MAX_REGION_COUNT];
void __iomem *timer_reg;
void __iomem *bl30_log_base;
};
struct uboot_log_t *uboot_log;
struct mbox_chan *bl30log_mbox_chan;
static struct proc_dir_entry *proc_uboot_log;
#define LOG_MEM_INDEX_UBOOT 0
#define LOG_MEM_INDEX_BL30 1
#define DATA_BUF_MAX_SIZE 100
#define TIME_BUF_MAX_SIZE 16
#define TOTAL_BUF_MAX_SIZE (DATA_BUF_MAX_SIZE + TIME_BUF_MAX_SIZE)
static unsigned int get_show_data(unsigned char *buf, int size)
{
unsigned char r_buf[DATA_BUF_MAX_SIZE];
unsigned int timer = 0;
unsigned int status;
unsigned int count;
struct log_operations_t *op;
int i;
if (!uboot_log)
return 0;
if (!buf || size < TOTAL_BUF_MAX_SIZE)
return 0;
count = 0;
memset(buf, 0, size);
for (i = 0; i < LOG_MEM_MAX_REGION_COUNT; i++) {
memset(r_buf, 0, sizeof(r_buf));
timer = 0;
status = 0;
op = &uboot_log->operations[i];
if (op->read) {
count = op->read(&timer, r_buf, sizeof(r_buf), &status);
if (count > 0) {
switch (status & 3) {
case 1:
case 3:
snprintf(buf, size, "[%10d]:%s", timer, r_buf);
pr_notice("%s", buf);
break;
case 0:
case 2:
snprintf(buf, size, "%s", r_buf);
pr_notice("%s", r_buf);
break;
}
break; //exit for loop
}
}
}
return count;
}
static int uboot_log_show(struct seq_file *m, void *arg)
{
unsigned char *p = (unsigned char *)arg;
if (!p)
return -EINVAL;
// dump_stack();
seq_printf(m, "%s", p);
return 0;
}
static void *uboot_log_start(struct seq_file *m, loff_t *pos)
{
unsigned int count;
unsigned char *spos = kmalloc(TOTAL_BUF_MAX_SIZE, GFP_KERNEL);
if (!spos)
return NULL;
count = get_show_data(spos, TOTAL_BUF_MAX_SIZE);
if (count == 0) {
/*when count is 0, there is no data*/
kfree(spos);
return NULL;
}
return spos;
}
static void *uboot_log_next(struct seq_file *m, void *v, loff_t *pos)
{
unsigned int count;
unsigned char *spos = (unsigned char *)v;
(*pos)++;
count = get_show_data(spos, TOTAL_BUF_MAX_SIZE);
if (count == 0) {
/*when count is 0, there is no data*/
return NULL;
}
return spos;
}
static void uboot_log_stop(struct seq_file *m, void *v)
{
kfree(v);
}
static const struct seq_operations uboot_log_seq_ops = {
.start = uboot_log_start,
.next = uboot_log_next,
.stop = uboot_log_stop,
.show = uboot_log_show,
};
static int uboot_log_open(struct inode *inode, struct file *file)
{
second_read_ring_buffer_set();
return seq_open(file, &uboot_log_seq_ops);
}
#define BL30_RECEIVE_STATUS_START 0
#define BL30_RECEIVE_STATUS_FINISHED 1
static void send_refresh_cmd_to_bl30(void)
{
unsigned long log_base, log_size;
unsigned int bl30_recive_status = BL30_RECEIVE_STATUS_START;
if (!uboot_log)
return;
if (!IS_ERR_OR_NULL(bl30log_mbox_chan)) {
aml_mbox_transfer_data(bl30log_mbox_chan,
MBOX_CMD_REFRESH_BL30_LOG,
NULL, 0,
&bl30_recive_status, sizeof(bl30_recive_status),
MBOX_SYNC);
if (bl30_recive_status == BL30_RECEIVE_STATUS_FINISHED) {
log_base = uboot_log->mem[LOG_MEM_INDEX_BL30].log_base;
log_size = uboot_log->mem[LOG_MEM_INDEX_BL30].log_size;
bl30_log_update(log_base, log_size);
}
}
}
static ssize_t bl30_log_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
char cmd;
if (copy_from_user(&cmd, buf, 1))
return -EFAULT;
if (cmd == '1') {
send_refresh_cmd_to_bl30();
return count;
}
return -EINVAL;
}
static const struct proc_ops uboot_log_ops = {
.proc_open = uboot_log_open,
.proc_read = seq_read,
.proc_write = bl30_log_write,
.proc_lseek = seq_lseek,
.proc_release = seq_release,
};
long get_raw_time_from_timer_e(void)
{
long time;
if (!uboot_log || !uboot_log->timer_reg) {
pr_notice("uboot log get time error\n");
return 0;
}
time = readl(uboot_log->timer_reg);
return time;
}
static void uboot_log_reserved_memory(struct platform_device *pdev, struct uboot_log_t *log)
{
struct device_node *node;
struct reserved_mem *rmem;
int i;
for (i = 0; i < LOG_MEM_MAX_REGION_COUNT; i++) {
node = of_parse_phandle(pdev->dev.of_node, "memory-region", i);
if (!node) {
pr_err("uboot log don't have memory-region\n");
return;
}
rmem = of_reserved_mem_lookup(node);
if (!rmem) {
pr_err("uboot log don't have reserved mem\n");
return;
}
if (!rmem->size) {
pr_err("uboot log reserved mem size is 0\n");
return;
}
if (i == LOG_MEM_INDEX_BL30) {
/*bl30 is sram memory*/
log->bl30_log_base = ioremap(rmem->base, rmem->size);
if (!log->bl30_log_base) {
pr_err("bl30 log sram ioremap fail,rmem->base:0x%lx,size:0x%lx\n",
(long)rmem->base, (long)rmem->size);
return;
}
log->mem[i].log_base = (unsigned long)log->bl30_log_base;
} else {
log->mem[i].log_base = __phys_to_virt(rmem->base);
}
log->mem[i].log_size = rmem->size;
pr_notice("uboot log rmem->base:0x%lx,log->mem[%d].log_base:0x%lx,size: 0x%lx\n",
(long)rmem->base, i, log->mem[i].log_base, log->mem[i].log_size);
}
}
static int uboot_log_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct resource res;
int ret = 0;
unsigned long start, size;
pr_notice("uboot log probe\n");
if (of_property_read_bool(np, "mboxes"))
bl30log_mbox_chan = aml_mbox_request_channel_byidx(&pdev->dev, 0);
uboot_log = kmalloc(sizeof(*uboot_log), GFP_KERNEL);
if (!uboot_log)
return -ENOMEM;
uboot_log_reserved_memory(pdev, uboot_log);
ret = of_address_to_resource(np, 0, &res);
if (ret) {
pr_notice("uboot log get timer E failed\n");
kfree(uboot_log);
return -EINVAL;
}
//pr_notice("uboot log timer E start:0x%lx, size: 0x%lx\n",
// (long)res.start, (long)resource_size(&res));
uboot_log->timer_reg = ioremap(res.start, resource_size(&res));
if (!uboot_log->timer_reg) {
pr_notice("uboot log timer_reg remap failed\n");
kfree(uboot_log);
return -EINVAL;
}
start = res.start;
size = res.end - res.start + 1;
pr_notice("uboot log timer E timer_reg:0x%lx,start = %lx, size = %lx\n",
(long)uboot_log->timer_reg, start, size);
blx_init_uboot_log(uboot_log->mem[0].log_base, uboot_log->mem[0].log_size);
bl30_init_log(uboot_log->mem[1].log_base, uboot_log->mem[1].log_size);
uboot_log->operations[0].read = read_ring_buffer;
uboot_log->operations[1].read = bl30_read_ring_buffer;
proc_uboot_log = proc_create("uboot_log", 0444, NULL, &uboot_log_ops);
if (IS_ERR_OR_NULL(proc_uboot_log)) {
iounmap(uboot_log->timer_reg);
kfree(uboot_log);
pr_err("create uboot_log proc failed\n");
return -EINVAL;
}
pr_notice("uboot log probe successful\n");
return ret;
}
static const struct of_device_id uboot_log_dt_match[] = {
{ .compatible = "amlogic, uboot_log" },
{ /* sentinel */ }
};
static struct platform_driver uboot_log_platform_driver = {
.probe = uboot_log_probe,
.driver = {
.owner = THIS_MODULE,
.name = "uboot_log",
.of_match_table = uboot_log_dt_match,
},
};
int __init meson_uboot_log_init(void)
{
pr_notice("uboot log init\n");
return platform_driver_register(&uboot_log_platform_driver);
}
void __exit meson_uboot_log_exit(void)
{
if (proc_uboot_log)
proc_remove(proc_uboot_log);
if (uboot_log && uboot_log->timer_reg) {
iounmap(uboot_log->timer_reg);
if (uboot_log->bl30_log_base)
iounmap(uboot_log->bl30_log_base);
kfree(uboot_log);
}
platform_driver_unregister(&uboot_log_platform_driver);
}