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

339 lines
6.9 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/module.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/printk.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <mt_emi.h>
#include "emi_ctrl_v1.h"
static void __iomem *CEN_EMI_BASE;
static void __iomem *CHN_EMI_BASE[MAX_CH];
#ifdef ENABLE_EMI_DEBUG_API
static void __iomem *EMI_DBG_BASE[MAX_DBG_NR];
#endif
static void __iomem *EMI_MPU_BASE;
static struct emi_info_t emi_info;
static unsigned int emi_dcm;
static int emi_probe(struct platform_device *pdev);
static int ddr_info_show(struct seq_file *m, void *v)
{
unsigned char buf[128];
ssize_t ret;
unsigned int density, rank, ddr_info;
ret = 0;
for (rank = 0, density = 0; rank < get_rk_num(); rank++)
density += get_rank_size(rank);
density *= 128;
ddr_info = ((density >> 2) & 0xF00) | get_dram_mr(5);
ret += snprintf(buf + ret, sizeof(buf) - ret,
"ddr_info: 0x%x\n", ddr_info);
ret += snprintf(buf + ret, sizeof(buf) - ret,
"DRAM density: %d MB\n", density);
ret += snprintf(buf + ret, sizeof(buf) - ret,
"vendor ID: 0x%x\n", get_dram_mr(5));
seq_write(m, buf, ret);
return 0;
}
static int ddr_info_open(struct inode *inode, struct file *file)
{
return single_open(file, ddr_info_show, NULL);
}
static const struct file_operations ddr_info_proc_fops = {
.open = ddr_info_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static int emi_remove(struct platform_device *dev)
{
return 0;
}
#ifdef CONFIG_OF
static const struct of_device_id emi_of_ids[] = {
{.compatible = "mediatek,emi",},
{}
};
#endif
#ifdef CONFIG_PM
static int emi_suspend_noirq(struct device *dev)
{
/* pr_info("[EMI] suspend\n"); */
#if ENABLE_ELM
suspend_elm();
#endif
return 0;
}
static int emi_resume_noirq(struct device *dev)
{
/* pr_info("[EMI] resume\n"); */
#if ENABLE_ELM
resume_elm();
#endif
#ifdef DECS_ON_SSPM
resume_decs(CEN_EMI_BASE);
#endif
return 0;
}
static const struct dev_pm_ops emi_pm_ops = {
.suspend_noirq = emi_suspend_noirq,
.resume_noirq = emi_resume_noirq,
};
#define EMI_PM_OPS (&emi_pm_ops)
#else
#define EMI_PM_OPS NULL
#endif
static struct platform_driver emi_ctrl = {
.probe = emi_probe,
.remove = emi_remove,
.driver = {
.name = "emi_ctrl",
.owner = THIS_MODULE,
.pm = EMI_PM_OPS,
#ifdef CONFIG_OF
.of_match_table = emi_of_ids,
#endif
},
};
__weak void plat_debug_api_init(void)
{
}
static int emi_probe(struct platform_device *pdev)
{
struct resource *res;
struct proc_dir_entry *proc_entry;
int i;
pr_info("[EMI] module probe.\n");
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
CEN_EMI_BASE = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(CEN_EMI_BASE)) {
pr_err("[EMI] unable to map CEN_EMI_BASE\n");
return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
EMI_MPU_BASE = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(EMI_MPU_BASE)) {
pr_err("[EMI] unable to map EMI_MPU_BASE\n");
return -EINVAL;
}
for (i = 0; i < MAX_CH; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM, 2 + i);
CHN_EMI_BASE[i] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(CHN_EMI_BASE[i])) {
pr_err("[EMI] unable to map CH%d_EMI_BASE\n", i);
return -EINVAL;
}
}
#ifdef ENABLE_EMI_DEBUG_API
for (i = 0; i < MAX_DBG_NR; i++) {
res = platform_get_resource(pdev, IORESOURCE_MEM,
2 + MAX_CH + i);
EMI_DBG_BASE[i] = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(EMI_DBG_BASE[i])) {
pr_debug("[EMI] unable to map dbg\n");
return -EINVAL;
}
}
of_property_read_u32(pdev->dev.of_node,
"emi_dcm", &emi_dcm);
plat_debug_api_init();
#endif
pr_info("[EMI] get CEN_EMI_BASE @ %p\n", mt_cen_emi_base_get());
pr_info("[EMI] get EMI_MPU_BASE @ %p\n", mt_emi_mpu_base_get());
for (i = 0; i < MAX_CH; i++)
pr_info("[EMI] get CH%d_EMI_BASE @ %p\n",
i, mt_chn_emi_base_get(i));
proc_entry = proc_create("ddr_info", 0444, NULL, &ddr_info_proc_fops);
#if ENABLE_BWL
bwl_init(&emi_ctrl);
#endif
#if ENABLE_MPU
mpu_init(&emi_ctrl, pdev);
#endif
#if ENABLE_ELM
elm_init(&emi_ctrl, pdev);
#endif
#if ENABLE_MBW
mbw_init(&emi_ctrl);
#endif
return 0;
}
/*
* emi_ctrl_init: module init function.
*/
static int __init emi_ctrl_init(void)
{
int ret;
int i;
struct device_node *node;
/* register EMI ctrl interface */
ret = platform_driver_register(&emi_ctrl);
if (ret)
pr_err("[EMI/BWL] fail to register emi_ctrl driver\n");
/* get EMI info from boot tags */
node = of_find_compatible_node(NULL, NULL, "mediatek,emi");
if (node) {
ret = of_property_read_u32(node,
"emi_info,dram_type", &(emi_info.dram_type));
if (ret)
pr_err("[EMI] fail to get dram_type\n");
ret = of_property_read_u32(node,
"emi_info,ch_num", &(emi_info.ch_num));
if (ret)
pr_err("[EMI] fail to get ch_num\n");
ret = of_property_read_u32(node,
"emi_info,rk_num", &(emi_info.rk_num));
if (ret)
pr_err("[EMI] fail to get rk_num\n");
ret = of_property_read_u32_array(node, "emi_info,rank_size",
emi_info.rank_size, MAX_RK);
if (ret)
pr_err("[EMI] fail to get rank_size\n");
}
pr_info("[EMI] dram_type(%d)\n", get_dram_type());
pr_info("[EMI] mr5(0x%x)\n", get_dram_mr(5));
pr_info("[EMI] ch_num(%d)\n", get_ch_num());
pr_info("[EMI] rk_num(%d)\n", get_rk_num());
for (i = 0; i < get_rk_num(); i++)
pr_info("[EMI] rank%d_size(0x%x)", i, get_rank_size(i));
return 0;
}
/*
* emi_ctrl_exit: module exit function.
*/
static void __exit emi_ctrl_exit(void)
{
}
postcore_initcall(emi_ctrl_init);
module_exit(emi_ctrl_exit);
unsigned int get_dram_type(void)
{
return (emi_info.dram_type & 0xF);
}
unsigned int get_dram_mr(unsigned int index)
{
switch (index) {
case 5:
return ((emi_info.dram_type >> 24) & 0xFF);
default:
return 0;
}
}
unsigned int get_ch_num(void)
{
return emi_info.ch_num;
}
unsigned int get_rk_num(void)
{
return emi_info.rk_num;
}
unsigned int get_rank_size(unsigned int rank_index)
{
if ((rank_index < emi_info.rk_num) && (rank_index < MAX_RK))
return emi_info.rank_size[rank_index];
return 0;
}
void __iomem *mt_cen_emi_base_get(void)
{
return CEN_EMI_BASE;
}
EXPORT_SYMBOL(mt_cen_emi_base_get);
/* for legacy use */
void __iomem *mt_emi_base_get(void)
{
return mt_cen_emi_base_get();
}
EXPORT_SYMBOL(mt_emi_base_get);
void __iomem *mt_chn_emi_base_get(unsigned int channel_index)
{
if (channel_index < MAX_CH)
return CHN_EMI_BASE[channel_index];
return NULL;
}
EXPORT_SYMBOL(mt_chn_emi_base_get);
#ifdef ENABLE_EMI_DEBUG_API
void __iomem *mt_emi_dbg_base_get(unsigned int index)
{
if (index < MAX_DBG_NR)
return EMI_DBG_BASE[index];
return NULL;
}
EXPORT_SYMBOL(mt_emi_dbg_base_get);
#endif
void __iomem *mt_emi_mpu_base_get(void)
{
return EMI_MPU_BASE;
}
EXPORT_SYMBOL(mt_emi_mpu_base_get);
unsigned int mt_emi_dcm_config(void)
{
return emi_dcm;
}
EXPORT_SYMBOL(mt_emi_dcm_config);