--- /dev/null
+/*
+ * drivers/soc/samsung/secmem.c
+ *
+ * Copyright (c) 2015 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/device.h>
+#include <linux/uaccess.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/dma-mapping.h>
+#include <linux/export.h>
+#include <linux/pm_qos.h>
+#include <linux/dma-contiguous.h>
+#include <linux/ion_exynos.h>
+#include <linux/smc.h>
+#include <linux/dma-buf.h>
+
+#include <asm/memory.h>
+#include <asm/cacheflush.h>
+
+#include <soc/samsung/secmem.h>
+
+#define SECMEM_DEV_NAME "s5p-smem"
+
+
+#define DRM_PROT_VER_CHUNK_BASED_PROT 0
+#define DRM_PROT_VER_BUFFER_BASED_PROT 1
+
+struct miscdevice secmem;
+struct secmem_crypto_driver_ftn *crypto_driver;
+
+uint32_t instance_count;
+
+#if defined(CONFIG_SOC_EXYNOS5433)
+static uint32_t secmem_regions[] = {
+ ION_EXYNOS_ID_G2D_WFD,
+ ION_EXYNOS_ID_VIDEO,
+ ION_EXYNOS_ID_SECTBL,
+ ION_EXYNOS_ID_MFC_FW,
+ ION_EXYNOS_ID_MFC_NFW,
+};
+
+static char *secmem_regions_name[] = {
+ "g2d_wfd", /* 0 */
+ "video", /* 1 */
+ "sectbl", /* 2 */
+ "mfc_fw", /* 3 */
+ "mfc_nfw", /* 4 */
+ NULL
+};
+#elif defined(CONFIG_SOC_EXYNOS7420)
+static uint32_t secmem_regions[] = {
+ ION_EXYNOS_ID_G2D_WFD,
+ ION_EXYNOS_ID_VIDEO,
+ ION_EXYNOS_ID_VIDEO_EXT,
+ ION_EXYNOS_ID_MFC_FW,
+ ION_EXYNOS_ID_MFC_NFW,
+};
+
+static char *secmem_regions_name[] = {
+ "g2d_wfd", /* 0 */
+ "video", /* 1 */
+ "video_ext", /* 2 */
+ "mfc_fw", /* 3 */
+ "mfc_nfw", /* 4 */
+ NULL
+};
+#endif
+
+static bool drm_onoff;
+static DEFINE_MUTEX(drm_lock);
+static DEFINE_MUTEX(smc_lock);
+
+struct secmem_info {
+ struct device *dev;
+ bool drm_enabled;
+};
+
+struct protect_info {
+ uint32_t dev;
+ uint32_t enable;
+};
+
+#define SECMEM_IS_PAGE_ALIGNED(addr) (!((addr) & (~PAGE_MASK)))
+
+int drm_enable_locked(struct secmem_info *info, bool enable)
+{
+ if (drm_onoff == enable) {
+ pr_err("%s: DRM is already %s\n", __func__, drm_onoff ? "on" : "off");
+ return -EINVAL;
+ }
+
+ drm_onoff = enable;
+ /*
+ * this will only allow this instance to turn drm_off either by
+ * calling the ioctl or by closing the fd
+ */
+ info->drm_enabled = enable;
+
+ return 0;
+}
+
+static int secmem_open(struct inode *inode, struct file *file)
+{
+ struct miscdevice *miscdev = file->private_data;
+ struct device *dev = miscdev->this_device;
+ struct secmem_info *info;
+
+ info = kzalloc(sizeof(struct secmem_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ info->dev = dev;
+ file->private_data = info;
+
+ mutex_lock(&drm_lock);
+ instance_count++;
+ mutex_unlock(&drm_lock);
+
+ return 0;
+}
+
+static int secmem_release(struct inode *inode, struct file *file)
+{
+ struct secmem_info *info = file->private_data;
+
+ /* disable drm if we were the one to turn it on */
+ mutex_lock(&drm_lock);
+ instance_count--;
+ if (instance_count == 0) {
+ if (info->drm_enabled) {
+ int ret;
+ ret = drm_enable_locked(info, false);
+ if (ret < 0)
+ pr_err("fail to lock/unlock drm status. lock = %d\n", false);
+ }
+ }
+
+ mutex_unlock(&drm_lock);
+
+ kfree(info);
+ return 0;
+}
+
+static long secmem_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct secmem_info *info = filp->private_data;
+
+ switch (cmd) {
+#if defined(CONFIG_ION) || defined(CONFIG_ION_EXYNOS)
+ case (uint32_t)SECMEM_IOC_GET_FD_PHYS_ADDR:
+ {
+ struct secfd_info fd_info;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attachment;
+ struct sg_table *sgt;
+
+ if (copy_from_user(&fd_info, (int __user *)arg,
+ sizeof(fd_info)))
+ return -EFAULT;
+
+ dmabuf = dma_buf_get(fd_info.fd);
+ if (IS_ERR_OR_NULL(dmabuf)) {
+ pr_err("smem ioctl error(%d)\n", __LINE__);
+ return -ENOMEM;
+ }
+
+ attachment = dma_buf_attach(dmabuf, info->dev);
+ if (!attachment) {
+ pr_err("smem ioctl error(%d)\n", __LINE__);
+ dma_buf_put(dmabuf);
+ return -ENOMEM;
+ }
+
+ sgt = dma_buf_map_attachment(attachment, DMA_TO_DEVICE);
+ if (!sgt) {
+ pr_err("smem ioctl error(%d)\n", __LINE__);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+ return -ENOMEM;
+ }
+
+ fd_info.phys = sg_phys(sgt->sgl);
+ pr_debug("%s: physical addr from kernel space = 0x%08x\n",
+ __func__, (unsigned int)fd_info.phys);
+
+ dma_buf_unmap_attachment(attachment, sgt, DMA_TO_DEVICE);
+ dma_buf_detach(dmabuf, attachment);
+ dma_buf_put(dmabuf);
+
+ if (copy_to_user((void __user *)arg, &fd_info, sizeof(fd_info)))
+ return -EFAULT;
+ break;
+ }
+#endif
+ case (uint32_t)SECMEM_IOC_GET_DRM_ONOFF:
+ smp_rmb();
+ if (copy_to_user((void __user *)arg, &drm_onoff, sizeof(bool)))
+ return -EFAULT;
+ break;
+ case (uint32_t)SECMEM_IOC_SET_DRM_ONOFF:
+ {
+ int ret, val = 0;
+
+ if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ mutex_lock(&drm_lock);
+ if ((info->drm_enabled && !val) ||
+ (!info->drm_enabled && val)) {
+ /*
+ * 1. if we enabled drm, then disable it
+ * 2. if we don't already hdrm enabled,
+ * try to enable it.
+ */
+ ret = drm_enable_locked(info, val);
+ if (ret < 0)
+ pr_err("fail to lock/unlock drm status. lock = %d\n", val);
+ }
+ mutex_unlock(&drm_lock);
+ break;
+ }
+ case (uint32_t)SECMEM_IOC_GET_CRYPTO_LOCK:
+ {
+ break;
+ }
+ case (uint32_t)SECMEM_IOC_RELEASE_CRYPTO_LOCK:
+ {
+ break;
+ }
+ case (uint32_t)SECMEM_IOC_SET_TZPC:
+ {
+ break;
+ }
+ case (uint32_t)SECMEM_IOC_SET_VIDEO_EXT_PROC:
+ {
+ int val, ret;
+
+ if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+ mutex_lock(&smc_lock);
+ ret = exynos_smc((uint32_t)(SMC_DRM_VIDEO_PROC), val, 0, 0);
+ if (ret) {
+ pr_err("Failed to control VIDEO EXT region protection. prot = %d\n", val);
+ mutex_unlock(&smc_lock);
+ return -ENOMEM;
+ }
+
+ mutex_unlock(&smc_lock);
+ break;
+ }
+ case (uint32_t)SECMEM_IOC_GET_DRM_PROT_VER:
+ {
+ int val;
+
+ val = DRM_PROT_VER_BUFFER_BASED_PROT;
+ if (copy_to_user((void __user *)arg, &val, sizeof(int)))
+ return -EFAULT;
+
+ break;
+ }
+ default:
+ return -ENOTTY;
+ }
+
+ return 0;
+}
+
+#if 0
+void secmem_crypto_register(struct secmem_crypto_driver_ftn *ftn)
+{
+ crypto_driver = ftn;
+}
+EXPORT_SYMBOL(secmem_crypto_register);
+
+void secmem_crypto_deregister(void)
+{
+ crypto_driver = NULL;
+}
+EXPORT_SYMBOL(secmem_crypto_deregister);
+#endif
+
+static const struct file_operations secmem_fops = {
+ .owner = THIS_MODULE,
+ .open = secmem_open,
+ .release = secmem_release,
+ .compat_ioctl = secmem_ioctl,
+ .unlocked_ioctl = secmem_ioctl,
+};
+
+struct miscdevice secmem = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = SECMEM_DEV_NAME,
+ .fops = &secmem_fops,
+};
+
+static int __init secmem_init(void)
+{
+ int ret;
+
+ ret = misc_register(&secmem);
+ if (ret) {
+ pr_err("%s: SECMEM can't register misc on minor=%d\n",
+ __func__, MISC_DYNAMIC_MINOR);
+ return ret;
+ }
+
+ crypto_driver = NULL;
+
+ return 0;
+}
+
+static void __exit secmem_exit(void)
+{
+ misc_deregister(&secmem);
+}
+
+module_init(secmem_init);
+module_exit(secmem_exit);
--- /dev/null
+/* include/soc/samsung/secmem.h
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - Secure memory support
+ *
+ * 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.
+*/
+
+#ifndef __ASM_ARCH_SECMEM_H
+#define __ASM_ARCH_SECMEM_H __FILE__
+
+#define MAX_NAME_LEN 20
+
+struct secchunk_info {
+ int index;
+ char name[MAX_NAME_LEN];
+ phys_addr_t base;
+ size_t size;
+};
+
+#if defined(CONFIG_ION)
+struct secfd_info {
+ int fd;
+ unsigned long phys;
+};
+#endif
+
+struct secmem_crypto_driver_ftn {
+ int (*lock) (void);
+ int (*release) (void);
+};
+
+struct secmem_region {
+ char *virt_addr;
+ unsigned long phys_addr;
+ unsigned long len;
+};
+
+#if defined(CONFIG_EXYNOS_CONTENT_PATH_PROTECTION)
+void secmem_crypto_register(struct secmem_crypto_driver_ftn *ftn);
+void secmem_crypto_deregister(void);
+#else
+#define secmem_crypto_register(ftn)
+#define secmem_crypto_deregister()
+#endif
+
+int drm_gsc_enable_locked(bool enable);
+
+#define SECMEM_IOC_CHUNKINFO _IOWR('S', 1, struct secchunk_info)
+#define SECMEM_IOC_SET_DRM_ONOFF _IOWR('S', 2, int)
+#define SECMEM_IOC_GET_DRM_ONOFF _IOWR('S', 3, int)
+#define SECMEM_IOC_GET_CRYPTO_LOCK _IOR('S', 4, int)
+#define SECMEM_IOC_RELEASE_CRYPTO_LOCK _IOR('S', 5, int)
+#if defined(CONFIG_ION)
+#define SECMEM_IOC_GET_FD_PHYS_ADDR _IOWR('S', 8, struct secfd_info)
+#endif
+#define SECMEM_IOC_GET_CHUNK_NUM _IOWR('S', 9, int)
+#define SECMEM_IOC_SET_TZPC _IOWR('S', 11, struct protect_info)
+#define SECMEM_IOC_SET_PROTECT _IOWR('S', 12, int)
+#define SECMEM_IOC_SET_VIDEO_EXT_PROC _IOWR('S', 13, int)
+#define SECMEM_IOC_GET_DRM_PROT_VER _IOWR('S', 14, int)
+
+#endif /* __ASM_ARCH_SECMEM_H */