blob: 110fbd489d67c6b54de59f617dda6ba35b05b147 [file] [log] [blame]
/*
* Copyright (c) 2018 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* 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.
*
*/
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/vmalloc.h>
#include <linux/of_reserved_mem.h>
static unsigned long rmem_addr;
static unsigned rmem_size;
static void __iomem *request_rmem(unsigned long addr, unsigned size)
{
int i;
unsigned int num_pages = (size >> PAGE_SHIFT);
pgprot_t prot = pgprot_writecombine(PAGE_KERNEL);
struct page **pages;
void *v_addr;
if (!addr)
return NULL;
if (size > (num_pages << PAGE_SHIFT))
num_pages++;
pages = kmalloc(sizeof(struct page*) * num_pages, GFP_ATOMIC);
if (!pages) {
pr_err("%s: pages allocation fail!\n", __func__);
return NULL;
}
for (i = 0; i < (num_pages); i++) {
pages[i] = phys_to_page(addr);
addr += PAGE_SIZE;
}
v_addr = vmap(pages, num_pages, VM_MAP, prot);
if (v_addr == NULL)
pr_err("%s: Failed to vmap pages\n", __func__);
kfree(pages);
return (void __iomem *)v_addr;
}
static int __init cp_linear_rmem_setup(struct reserved_mem *rmem)
{
rmem_addr = rmem->base;
rmem_size = rmem->size;
pr_info("%s: memory reserved: addr=0x%08x, size=0x%08x\n",
__func__, (u32)rmem_addr, (u32)rmem_size);
return 0;
}
RESERVEDMEM_OF_DECLARE(cp_linear, "exynos,cp_linear", cp_linear_rmem_setup);
static int __init exynos_cpmem_probe(struct platform_device *pdev)
{
void __iomem *rmem_base;
if (!rmem_addr || !rmem_size)
return 0;
rmem_base = request_rmem(rmem_addr, rmem_size);
if (rmem_base) {
vunmap(rmem_base);
rmem_base = NULL;
pr_err("%s: rmem allocation fail\n", __func__);
}
return 0;
}
static int exynos_cpmem_remove(struct platform_device *pdev)
{
platform_set_drvdata(pdev, NULL);
pr_info("%s: exynos-cpmem is removed", __func__);
return 0;
}
static struct platform_device_id exynos_cpmem_driver_ids[] = {
{ .name = "exynos-cpmem", },
{},
};
MODULE_DEVICE_TABLE(platform, exynos_cpmem_driver_ids);
static const struct of_device_id exynos_cpmem_match[] = {
{ .compatible = "samsung,exynos-cpmem", },
{},
};
static struct platform_driver exynos_cpmem_driver = {
.remove = exynos_cpmem_remove,
.id_table = exynos_cpmem_driver_ids,
.driver = {
.name = "exynos-cpmem",
.owner = THIS_MODULE,
.of_match_table = exynos_cpmem_match,
},
};
module_platform_driver_probe(exynos_cpmem_driver, exynos_cpmem_probe);
MODULE_AUTHOR("");
MODULE_DESCRIPTION("Samsung CP memory reserve");
MODULE_LICENSE("GPL");