kernel_samsung_a34x-permissive/drivers/misc/mediatek/dramc/mtk_rshmoo.c
2024-04-28 15:51:13 +02:00

250 lines
5.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2019 MediaTek Inc.
* Author: Sagy Shih <sagy.shih@mediatek.com>
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/kallsyms.h>
#include <linux/cpu.h>
#include <linux/smp.h>
#include <linux/vmalloc.h>
#include <linux/memblock.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <asm/cacheflush.h>
/* #include <mach/mtk_clkmgr.h> */
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_fdt.h>
#include <linux/debugfs.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
#include <asm/setup.h>
#include <mt-plat/sync_write.h>
#include <mt-plat/mtk_chip.h>
#include <mt-plat/aee.h>
#ifdef CONFIG_MTK_WATCHDOG
#include <mtk_wd_api.h>
#endif
#include <dramc_io.h>
#include "mtk_dramc.h"
#include "dramc.h"
#ifdef RUNTIME_SHMOO
static unsigned int rshmoo_test_rank;
static unsigned int rshmoo_test_ch;
static unsigned int rshmoo_test_byte;
static unsigned int rshmoo_test_txvrange;
static unsigned int rshmoo_test_txvref;
static unsigned int rshmoo_test_delay;
static unsigned int rshmoo_test_ongoing;
static unsigned int rshmoo_test_done;
static struct timer_list rshmoo_timer;
static unsigned int rshmoo_timer_counter;
#define KEY_RSHMOO_STORE 0x9487
#define RSHMOO_STORE_MAGIC 0x04879487
#define RSHMOO_REBOOT_TIME 30
#define TIMER_INTERVAL 500
#define TIMER_EXPIRE_MINUTES(m) ((m)*60*1000/TIMER_INTERVAL)
struct rshmoo_store_info {
unsigned int magic;
unsigned int last_result;
unsigned int pass_cnt;
};
void __iomem *get_dbg_info_base(unsigned int key);
static ssize_t rshmoo_test_done_show(struct device_driver *driver, char *buf)
{
return snprintf(buf, PAGE_SIZE, "%u\n", rshmoo_test_done);
}
DRIVER_ATTR(rshmoo_test_done, 0444,
rshmoo_test_done_show, NULL);
static ssize_t rshmoo_test_info_show(struct device_driver *driver, char *buf)
{
return snprintf(buf, PAGE_SIZE,
"CH %c,RANK %u,BYTE %u,VRANGE %u,VREF %u,PI %u\n",
(rshmoo_test_ch == 0) ? 'A' : 'B', rshmoo_test_rank,
rshmoo_test_byte, rshmoo_test_txvrange,
rshmoo_test_txvref, rshmoo_test_delay);
}
DRIVER_ATTR(rshmoo_test_info, 0444,
rshmoo_test_info_show, NULL);
int dram_rshmoo_mark_pass(void)
{
struct rshmoo_store_info *ptr = (struct rshmoo_store_info *)
get_dbg_info_base(KEY_RSHMOO_STORE);
if (ptr && ptr->magic == RSHMOO_STORE_MAGIC) {
ptr->last_result = 1;
return 0;
}
return -1;
}
void dram_rshmoo_timer_callback(unsigned long data)
{
unsigned int expire = TIMER_EXPIRE_MINUTES(RSHMOO_REBOOT_TIME);
#ifdef CONFIG_MTK_WATCHDOG
int res;
struct wd_api *wd_api = NULL;
#endif
rshmoo_timer_counter++;
if (rshmoo_timer_counter < expire) {
mod_timer(&rshmoo_timer, jiffies +
msecs_to_jiffies(TIMER_INTERVAL));
return;
}
#ifdef CONFIG_MTK_WATCHDOG
res = get_wd_api(&wd_api);
if (res < 0) {
pr_info("arch_reset, get wd api error %d\n", res);
while (1)
cpu_relax();
} else {
pr_info("exception reboot\n");
wd_api->wd_sw_reset(WD_SW_RESET_BYPASS_PWR_KEY);
}
#else
emergency_restart();
#endif
}
static int dram_rshmoo_probe(struct platform_device *pdev)
{
int ret = 0;
pr_debug("[DRAMC] rshmoo module probe.\n");
ret = of_property_read_u32(pdev->dev.of_node, "rank",
&rshmoo_test_rank);
if (ret < 0) {
pr_info("Fail to find rank information\n");
return ret;
}
ret = of_property_read_u32(pdev->dev.of_node, "ch", &rshmoo_test_ch);
if (ret < 0) {
pr_info("Fail to find ch information\n");
return ret;
}
ret = of_property_read_u32(pdev->dev.of_node, "byte",
&rshmoo_test_byte);
if (ret < 0) {
pr_info("Fail to find byte information\n");
return ret;
}
ret = of_property_read_u32(pdev->dev.of_node, "txvrange",
&rshmoo_test_txvrange);
if (ret < 0) {
pr_info("Fail to find txvrange information\n");
return ret;
}
ret = of_property_read_u32(pdev->dev.of_node, "txvref",
&rshmoo_test_txvref);
if (ret < 0) {
pr_info("Fail to find txvref information\n");
return ret;
}
ret = of_property_read_u32(pdev->dev.of_node, "delay",
&rshmoo_test_delay);
if (ret < 0) {
pr_info("Fail to find delay information\n");
return ret;
}
ret = of_property_read_u32(pdev->dev.of_node, "ongoing",
&rshmoo_test_ongoing);
if (ret < 0) {
pr_info("Fail to find ongoing information\n");
return ret;
}
ret = of_property_read_u32(pdev->dev.of_node, "done",
&rshmoo_test_done);
if (ret < 0) {
pr_info("Fail to find done information\n");
return ret;
}
ret = driver_create_file(pdev->dev.driver,
&driver_attr_rshmoo_test_done);
if (ret) {
pr_info("fail to create the rshmoo_test_done sysfs files\n");
return ret;
}
ret = driver_create_file(pdev->dev.driver,
&driver_attr_rshmoo_test_info);
if (ret) {
pr_info("fail to create the rshmoo_test_info sysfs files\n");
return ret;
}
init_timer(&rshmoo_timer);
rshmoo_timer.function = dram_rshmoo_timer_callback;
rshmoo_timer.data = 0;
mod_timer(&rshmoo_timer, jiffies + msecs_to_jiffies(TIMER_INTERVAL));
return 0;
}
static int dram_rshmoo_remove(struct platform_device *dev)
{
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id dram_of_ids[] = {
{.compatible = "mediatek,dram_rshmoo_info",},
{}
};
#endif
static struct platform_driver dram_rshmoo_drv = {
.probe = dram_rshmoo_probe,
.remove = dram_rshmoo_remove,
.driver = {
.name = "dram_rshmoo",
.owner = THIS_MODULE,
#ifdef CONFIG_OF
.of_match_table = dram_of_ids,
#endif
},
};
static int __init dram_rshmoo_init(void)
{
int ret = 0;
ret = platform_driver_register(&dram_rshmoo_drv);
if (ret) {
pr_info("[DRAMC] init fail, ret 0x%x\n", ret);
return ret;
}
return 0;
}
late_initcall(dram_rshmoo_init);
#endif