diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/staging/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/android/Kconfig | 4 | ||||
-rw-r--r-- | drivers/staging/android/ion/Kconfig | 8 | ||||
-rw-r--r-- | drivers/staging/android/ion/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion.c | 38 | ||||
-rw-r--r-- | drivers/staging/android/ion/ion_priv.h | 6 | ||||
-rw-r--r-- | drivers/staging/android/ion/mxc/Makefile | 2 | ||||
-rw-r--r-- | drivers/staging/android/ion/mxc/mxc_ion.c | 308 | ||||
-rw-r--r-- | drivers/staging/android/uapi/ion.h | 25 |
9 files changed, 391 insertions, 4 deletions
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 2fa9745db614..27a8ba7ee973 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -22,7 +22,7 @@ obj-$(CONFIG_FB_XGI) += xgifb/ obj-$(CONFIG_USB_EMXX) += emxx_udc/ obj-$(CONFIG_SPEAKUP) += speakup/ obj-$(CONFIG_MFD_NVEC) += nvec/ -obj-$(CONFIG_ANDROID) += android/ +obj-y += android/ obj-$(CONFIG_STAGING_BOARD) += board/ obj-$(CONFIG_LTE_GDM724X) += gdm724x/ obj-$(CONFIG_FIREWIRE_SERIAL) += fwserial/ diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig index 6c00d6f765c6..6b2b942ebfc3 100644 --- a/drivers/staging/android/Kconfig +++ b/drivers/staging/android/Kconfig @@ -24,8 +24,8 @@ config ANDROID_LOW_MEMORY_KILLER scripts (/init.rc), and it defines priority values with minimum free memory size for each priority. -source "drivers/staging/android/ion/Kconfig" - endif # if ANDROID +source "drivers/staging/android/ion/Kconfig" + endmenu diff --git a/drivers/staging/android/ion/Kconfig b/drivers/staging/android/ion/Kconfig index c8fb4134c55d..22ab23074c16 100644 --- a/drivers/staging/android/ion/Kconfig +++ b/drivers/staging/android/ion/Kconfig @@ -42,6 +42,13 @@ config ION_HISI source "drivers/staging/android/ion/hisilicon/Kconfig" +config ION_MXC + tristate "Ion for imx platform" + depends on ION + select VIDEOBUF2_DMA_CONTIG + help + Choose this option if you wish to use ion on imx platform. + config ION_OF bool "Devicetree support for Ion" depends on ION && OF_ADDRESS @@ -52,3 +59,4 @@ config ION_OF extensions If using Ion and devicetree, you should say Y here + diff --git a/drivers/staging/android/ion/Makefile b/drivers/staging/android/ion/Makefile index 5d630a088381..724f014cb005 100644 --- a/drivers/staging/android/ion/Makefile +++ b/drivers/staging/android/ion/Makefile @@ -9,5 +9,5 @@ endif obj-$(CONFIG_ION_DUMMY) += ion_dummy_driver.o obj-$(CONFIG_ION_TEGRA) += tegra/ obj-$(CONFIG_ION_HISI) += hisilicon/ +obj-$(CONFIG_ION_MXC) += mxc/ obj-$(CONFIG_ION_OF) += ion_of.o - diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c index 6f9974cb0e15..d280d14a95e0 100644 --- a/drivers/staging/android/ion/ion.c +++ b/drivers/staging/android/ion/ion.c @@ -3,6 +3,7 @@ * drivers/staging/android/ion/ion.c * * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -364,6 +365,26 @@ struct ion_handle *ion_handle_get_by_id(struct ion_client *client, return handle; } +/* for used in mxc_ion.c */ +int ion_handle_put_wrap(struct ion_handle *handle) +{ + return ion_handle_put(handle); +} + +struct ion_handle *ion_handle_get_by_id_wrap(struct ion_client *client, + int id) +{ + return ion_handle_get_by_id(client, id); +} + +struct device *ion_device_get_by_client(struct ion_client *client) +{ + if (client) + return client->dev->dev.this_device; + else + return NULL; +} + static bool ion_handle_validate(struct ion_client *client, struct ion_handle *handle) { @@ -1016,6 +1037,21 @@ static int ion_dma_buf_end_cpu_access(struct dma_buf *dmabuf, return 0; } +static void *ion_dma_buf_vmap(struct dma_buf *dmabuf) +{ + struct ion_buffer *buffer = dmabuf->priv; + + if (ion_dma_buf_begin_cpu_access(dmabuf, DMA_NONE) != 0) + return NULL; + + return buffer->vaddr; +} + +static void ion_dma_buf_vunmap(struct dma_buf *dmabuf, void *vaddr) +{ + ion_dma_buf_end_cpu_access(dmabuf, DMA_NONE); +} + static struct dma_buf_ops dma_buf_ops = { .map_dma_buf = ion_map_dma_buf, .unmap_dma_buf = ion_unmap_dma_buf, @@ -1027,6 +1063,8 @@ static struct dma_buf_ops dma_buf_ops = { .kunmap_atomic = ion_dma_buf_kunmap, .kmap = ion_dma_buf_kmap, .kunmap = ion_dma_buf_kunmap, + .vmap = ion_dma_buf_vmap, + .vunmap = ion_dma_buf_vunmap, }; struct dma_buf *ion_share_dma_buf(struct ion_client *client, diff --git a/drivers/staging/android/ion/ion_priv.h b/drivers/staging/android/ion/ion_priv.h index 3c3b3245275d..2d4ef0d93d99 100644 --- a/drivers/staging/android/ion/ion_priv.h +++ b/drivers/staging/android/ion/ion_priv.h @@ -2,6 +2,7 @@ * drivers/staging/android/ion/ion_priv.h * * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2016 Freescale Semiconductor, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -470,4 +471,9 @@ int ion_handle_put(struct ion_handle *handle); int ion_query_heaps(struct ion_client *client, struct ion_heap_query *query); +int ion_handle_put_wrap(struct ion_handle *handle); +struct ion_handle *ion_handle_get_by_id_wrap(struct ion_client *client, + int id); +struct device *ion_device_get_by_client(struct ion_client *client); + #endif /* _ION_PRIV_H */ diff --git a/drivers/staging/android/ion/mxc/Makefile b/drivers/staging/android/ion/mxc/Makefile new file mode 100644 index 000000000000..df308e51837a --- /dev/null +++ b/drivers/staging/android/ion/mxc/Makefile @@ -0,0 +1,2 @@ +ccflags-y += -I../ +obj-y += mxc_ion.o diff --git a/drivers/staging/android/ion/mxc/mxc_ion.c b/drivers/staging/android/ion/mxc/mxc_ion.c new file mode 100644 index 000000000000..14ae747a5385 --- /dev/null +++ b/drivers/staging/android/ion/mxc/mxc_ion.c @@ -0,0 +1,308 @@ +/* + * drivers/gpu/mxc/mxc_ion.c + * + * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2012-2016 Freescale Semiconductor, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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/err.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_platform.h> +#include <linux/uaccess.h> +#include <media/videobuf2-dma-contig.h> +#include <linux/dma-buf.h> + +#include "../ion_priv.h" + +static struct ion_device *idev; +static int num_heaps = 1; +static struct ion_heap **heaps; +static int cacheable; + +struct ion_platform_data * +mxc_ion_parse_of(struct platform_device *pdev) +{ + struct ion_platform_data *pdata = 0; + const struct device_node *node = pdev->dev.of_node; + int ret = 0; + unsigned int val = 0; + struct ion_platform_heap *heap = NULL; + + pdata = kzalloc(sizeof(struct ion_platform_data), GFP_KERNEL); + if (!pdata) + return ERR_PTR(-ENOMEM); + + heap = kzalloc(sizeof(struct ion_platform_heap), GFP_KERNEL); + if (!heap) { + kfree(pdata); + return ERR_PTR(-ENOMEM); + } + + heap->type = ION_HEAP_TYPE_DMA; + heap->priv = &pdev->dev; + heap->name = "mxc_ion"; + + pdata->heaps = heap; + pdata->nr = num_heaps; + + ret = of_property_read_u32(node, "fsl,heap-cacheable", &val); + if (!ret) + cacheable = 1; + + val = 0; + ret = of_property_read_u32(node, "fsl,heap-id", &val); + if (!ret) + heap->id = val; + else + heap->id = 0; + + return pdata; +} + +static long +mxc_custom_ioctl(struct ion_client *client, unsigned int cmd, unsigned long arg) +{ + switch (cmd) { + case ION_IOC_PHYS: + { + struct ion_handle *handle; + struct ion_phys_data data; + struct device *dev; + void *vaddr; + + if (copy_from_user(&data, (void __user *) arg, + sizeof(struct ion_phys_data))) + return -EFAULT; + handle = ion_handle_get_by_id_wrap(client, data.handle); + if (IS_ERR(handle)) + return PTR_ERR(handle); + + vaddr = ion_map_kernel(client, handle); + ion_handle_put_wrap(handle); + + if (IS_ERR(vaddr)) + return PTR_ERR(vaddr); + + dev = ion_device_get_by_client(client); + data.phys = virt_to_dma(dev, vaddr); + + if (copy_to_user((void __user *) arg, &data, + sizeof(struct ion_phys_data))) + return -EFAULT; + return 0; + } + case ION_IOC_PHYS_DMA: + { + int ret = 0; + struct device *dev = NULL; + struct dma_buf *dmabuf = NULL; + unsigned long phys = 0; + u64 dma_mask = DMA_BIT_MASK(32); + size_t len = 0; + struct ion_phys_dma_data data; + const struct vb2_mem_ops *mem_ops = + &vb2_dma_contig_memops; + dma_addr_t *addr; + void *mem_priv; + + if (copy_from_user(&data, (void __user *) arg, + sizeof(struct ion_phys_dma_data))) + return -EFAULT; + + /* Get physical address from dmafd */ + dmabuf = dma_buf_get(data.dmafd); + if (!dmabuf) + return -1; + + dev = ion_device_get_by_client(client); + dev->dma_mask = &dma_mask; + + mem_priv = mem_ops->attach_dmabuf(dev, + dmabuf, dmabuf->size, + DMA_BIDIRECTIONAL); + if (IS_ERR(mem_priv)) + goto err1; + ret = mem_ops->map_dmabuf(mem_priv); + if (ret) + goto err0; + + addr = mem_ops->cookie(mem_priv); + phys = *addr; + len = dmabuf->size; + + data.phys = phys; + data.size = len; + if (copy_to_user((void __user *) arg, &data, + sizeof(struct ion_phys_dma_data))) { + ret = -EFAULT; + } + + /* unmap and detach */ + mem_ops->unmap_dmabuf(mem_priv); +err0: + mem_ops->detach_dmabuf(mem_priv); +err1: + dma_buf_put(dmabuf); + + if (ret < 0) + return ret; + return 0; + } + case ION_IOC_PHYS_VIRT: + { + struct device *dev = NULL; + u64 dma_mask = DMA_BIT_MASK(32); + struct ion_phys_virt_data data; + const struct vb2_mem_ops *mem_ops = + &vb2_dma_contig_memops; + dma_addr_t *addr; + void *mem_priv; + + if (copy_from_user(&data, (void __user *) arg, + sizeof(struct ion_phys_virt_data))) + return -EFAULT; + + /* Get physical address from virtual address */ + if (!data.virt) + return -1; + + dev = ion_device_get_by_client(client); + dev->dma_mask = &dma_mask; + + mem_priv = mem_ops->get_userptr(dev, + data.virt, data.size, + DMA_BIDIRECTIONAL); + if (IS_ERR(mem_priv)) + return -1; + + addr = mem_ops->cookie(mem_priv); + mem_ops->put_userptr(mem_priv); + + data.phys = *addr; + if (copy_to_user((void __user *) arg, &data, + sizeof(struct ion_phys_virt_data))) + return -EFAULT; + return 0; + } + default: + return -ENOTTY; + } + + return 0; +} + +int +mxc_ion_probe(struct platform_device *pdev) +{ + struct ion_platform_data *pdata = NULL; + int pdata_is_created = 0; + int err; + int i; + + if (pdev->dev.of_node) { + pdata = mxc_ion_parse_of(pdev); + pdata_is_created = 1; + } else { + pdata = pdev->dev.platform_data; + } + + if (IS_ERR_OR_NULL(pdata)) + return PTR_ERR(pdata); + + num_heaps = pdata->nr; + + heaps = kzalloc(sizeof(struct ion_heap *) * pdata->nr, GFP_KERNEL); + + idev = ion_device_create(mxc_custom_ioctl); + if (IS_ERR_OR_NULL(idev)) { + err = PTR_ERR(idev); + goto err; + } + + /* create the heaps as specified in the board file */ + for (i = 0; i < num_heaps; i++) { + struct ion_platform_heap *heap_data = &pdata->heaps[i]; + + heaps[i] = ion_heap_create(heap_data); + if (IS_ERR_OR_NULL(heaps[i])) { + err = PTR_ERR(heaps[i]); + heaps[i] = NULL; + goto err; + } + ion_device_add_heap(idev, heaps[i]); + } + platform_set_drvdata(pdev, idev); + return 0; +err: + for (i = 0; i < num_heaps; i++) { + if (heaps[i]) + ion_heap_destroy(heaps[i]); + } + kfree(heaps); + if (pdata_is_created) { + kfree(pdata->heaps); + kfree(pdata); + } + return err; +} + +int +mxc_ion_remove(struct platform_device *pdev) +{ + struct ion_device *idev = platform_get_drvdata(pdev); + int i; + + ion_device_destroy(idev); + for (i = 0; i < num_heaps; i++) + ion_heap_destroy(heaps[i]); + kfree(heaps); + return 0; +} + +static struct of_device_id ion_match_table[] = { + {.compatible = "fsl,mxc-ion"}, + {}, +}; + +static struct platform_driver ion_driver = { + .probe = mxc_ion_probe, + .remove = mxc_ion_remove, + .driver = { + .name = "ion-mxc", + .of_match_table = ion_match_table, + }, +}; + +static int __init +ion_init(void) +{ + return platform_driver_register(&ion_driver); +} + +static void __exit +ion_exit(void) +{ + platform_driver_unregister(&ion_driver); +} + +module_init(ion_init); +module_exit(ion_exit); + +MODULE_AUTHOR("Freescale Semiconductor, Inc."); +MODULE_DESCRIPTION("MXC ion allocator driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("fb"); diff --git a/drivers/staging/android/uapi/ion.h b/drivers/staging/android/uapi/ion.h index 14cd8738ecfc..401d59edcd0f 100644 --- a/drivers/staging/android/uapi/ion.h +++ b/drivers/staging/android/uapi/ion.h @@ -2,6 +2,7 @@ * drivers/staging/android/uapi/ion.h * * Copyright (C) 2011 Google, Inc. + * Copyright (C) 2016 Freescale Semiconductor, Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -46,6 +47,7 @@ enum ion_heap_type { */ }; +#define ION_CMA_HEAP_ID 0 #define ION_NUM_HEAP_IDS (sizeof(unsigned int) * 8) /** @@ -158,6 +160,23 @@ struct ion_heap_query { __u32 reserved2; }; +struct ion_phys_data { + ion_user_handle_t handle; + unsigned long phys; +}; + +struct ion_phys_dma_data { + unsigned long phys; + size_t size; + int dmafd; +}; + +struct ion_phys_virt_data { + unsigned long virt; + unsigned long phys; + size_t size; +}; + #define ION_IOC_MAGIC 'I' /** @@ -233,4 +252,10 @@ struct ion_heap_query { #define ION_IOC_HEAP_QUERY _IOWR(ION_IOC_MAGIC, 8, \ struct ion_heap_query) +#define ION_IOC_PHYS _IOWR(ION_IOC_MAGIC, 8, struct ion_phys_data) + +#define ION_IOC_PHYS_DMA _IOWR(ION_IOC_MAGIC, 9, struct ion_phys_dma_data) + +#define ION_IOC_PHYS_VIRT _IOWR(ION_IOC_MAGIC, 10, struct ion_phys_virt_data) + #endif /* _UAPI_LINUX_ION_H */ |