blob: 15d6aa325d6361a776f4a48bcb757592e019b7dc [file] [log] [blame]
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only 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.
*/
#include <linux/export.h>
#include <linux/err.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include <linux/dma-contiguous.h>
#include <soc/qcom/scm.h>
#define SHARED_HEAP_SVC_ID 0x2
#define SHARED_HEAP_CMD_ID 0xB
#define SHARED_HEAP_TYPE_READ 0x1
#define SHARED_HEAP_TYPE_WRITE 0x2
static int msm_shared_heap_unlock(dma_addr_t base,
size_t size, unsigned int proc_type)
{
int rc;
struct shared_heap_unlock {
u32 start;
u32 size;
u32 proc;
u32 share_type;
} request;
int resp = 0;
struct scm_desc desc = {0};
desc.arginfo = SCM_ARGS(4);
desc.args[0] = request.start = base;
desc.args[1] = request.size = size;
desc.args[2] = request.proc = proc_type;
desc.args[3] = request.share_type = SHARED_HEAP_TYPE_READ |
SHARED_HEAP_TYPE_WRITE;
if (!is_scm_armv8())
rc = scm_call(SHARED_HEAP_SVC_ID, SHARED_HEAP_CMD_ID, &request,
sizeof(request), &resp, 1);
else
rc = scm_call2(SCM_SIP_FNID(SHARED_HEAP_SVC_ID,
SHARED_HEAP_CMD_ID), &desc);
if (rc)
pr_err("shared_heap: Failed to unlock the shared heap %d\n",
rc);
return rc;
}
static int msm_shared_heap_populate_base_and_size
(struct device_node *node, size_t *size,
dma_addr_t *base, struct device *priv)
{
int ret = 0;
struct device_node *pnode;
pnode = of_parse_phandle(node, "linux,contiguous-region", 0);
if (pnode != NULL) {
const u32 *addr;
u64 len;
addr = of_get_address(pnode, 0, &len, NULL);
if (!addr) {
of_node_put(pnode);
ret = -EINVAL;
goto out;
}
*size = cma_get_size(priv);
*base = cma_get_base(priv);
of_node_put(pnode);
} else {
pr_err("%s: Unable to parse phandle\n", __func__);
ret = -EINVAL;
}
out:
return ret;
}
static int get_heap_and_unlock(struct platform_device *pdev)
{
struct device_node *node = pdev->dev.of_node;
struct device *priv;
dma_addr_t base;
size_t size;
int proc_type;
int ret = 0;
priv = &pdev->dev;
ret = msm_shared_heap_populate_base_and_size(node, &size, &base, priv);
if (ret)
return ret;
ret = of_property_read_u32(node, "qcom,proc-id", &proc_type);
if (ret) {
pr_err("Unable to find the proc_type\n");
return ret;
}
ret = msm_shared_heap_unlock(base, size, proc_type);
if (ret)
pr_err("%s: Cannot unlock memory %pa of size %zx, error = %d\n",
__func__, &base, size, ret);
else
pr_info("shared_mem: Unlocked memory %pa of size %zx\n",
&base, size);
return ret;
}
static int msm_shared_memory_probe(struct platform_device *pdev)
{
int ret = 0;
if (pdev->dev.of_node)
ret = get_heap_and_unlock(pdev);
if (ret)
pr_err("%s: Unable to unlock heap due to error %d\n",
__func__, ret);
return ret;
}
static int msm_shared_memory_remove(struct platform_device *pdev)
{
return 0;
}
static struct of_device_id msm_shared_memory_table[] = {
{.compatible = "qcom,msm-shared-memory",
},
{}
};
static struct platform_driver msm_shared_memory = {
.probe = msm_shared_memory_probe,
.remove = msm_shared_memory_remove,
.driver = {
.name = "msm-shared-memory",
.of_match_table = msm_shared_memory_table,
},
};
static int __init msm_shared_memory_init(void)
{
return platform_driver_register(&msm_shared_memory);
}
static void __exit msm_shared_memory_exit(void)
{
platform_driver_unregister(&msm_shared_memory);
};
subsys_initcall(msm_shared_memory_init);
module_exit(msm_shared_memory_exit);