-obj-$(CONFIG_EXYNOS_GRAPHICS_G2D) += g2d_drv.o
+obj-$(CONFIG_EXYNOS_GRAPHICS_G2D) += g2d_drv.o g2d_task.o
#include <linux/device.h>
#include <linux/miscdevice.h>
+struct g2d_task; /* defined in g2d_task.h */
+
struct g2d_device {
struct miscdevice misc;
struct device *dev;
struct clk *clock;
void __iomem *reg;
+
+ /* task management */
+ spinlock_t lock_task;
+ struct g2d_task *tasks;
+ struct list_head tasks_free;
+ struct list_head tasks_prepared;
+ struct list_head tasks_active;
};
struct g2d_context {
struct g2d_device *g2d_dev;
};
+/* job mask (hwfc or not) */
+#define G2D_JOBMASK_HWFC 0x7
+#define G2D_JOBMASK_DEFAULT 0xFFF8
+#define g2d_job_full(id, job_mask) ((id & job_mask) == job_mask)
+#define g2d_job_empty(id, job_mask) ((id & job_mask) == 0)
+
#endif /* __EXYNOS_G2D_H__ */
#include <linux/pm_runtime.h>
#include <linux/exynos_iovmm.h>
#include <linux/interrupt.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/slab.h>
#include "g2d.h"
#include "g2d_regs.h"
+#include "g2d_task.h"
#define MODULE_NAME "exynos-g2d"
goto err;
}
+ spin_lock_init(&g2d_dev->lock_task);
+
+ INIT_LIST_HEAD(&g2d_dev->tasks_free);
+ INIT_LIST_HEAD(&g2d_dev->tasks_prepared);
+ INIT_LIST_HEAD(&g2d_dev->tasks_active);
+
+ ret = g2d_create_tasks(g2d_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to create tasks");
+ goto err_task;
+ }
+
dev_info(&pdev->dev, "Probed FIMG2D version %#010x\n", version);
return 0;
+err_task:
+ misc_deregister(&g2d_dev->misc);
err:
pm_runtime_disable(&pdev->dev);
iovmm_deactivate(g2d_dev->dev);
{
struct g2d_device *g2d_dev = platform_get_drvdata(pdev);
+ g2d_destroy_tasks(g2d_dev);
+
misc_deregister(&g2d_dev->misc);
pm_runtime_disable(&pdev->dev);
--- /dev/null
+/*
+ * linux/drivers/gpu/exynos/g2d/g2d_format.h
+ *
+ * Copyright (c) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Samsung Graphics 2D driver
+ *
+ * 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 __G2D_FORMAT_H__
+#define __G2D_FORMAT_H__
+
+/* TODO: check the ARGB order */
+#define G2D_SWZ_MASK 0xFFFF
+
+#define G2D_SWZ_ARGB (0x3210)
+#define G2D_SWZ_ABGR (0x3012)
+#define G2D_SWZ_xBGR (0x5012)
+#define G2D_SWZ_xRGB (0x5210)
+
+#define G2D_YUVORDER_MASK (0x3 << 24)
+
+#define G2D_YUV_UV ((0 << 24) | G2D_SWZ_ARGB)
+#define G2D_YUV_VU ((1 << 24) | G2D_SWZ_ARGB)
+#define G2D_YUV_YC (0 << 25)
+#define G2D_YUV_CY (1 << 25)
+
+#define G2D_DATAFMT_SHIFT 16
+#define G2D_DATAFMT_MASK (0xF << G2D_DATAFMT_SHIFT)
+
+#define G2D_DATAFMT_8888 (0 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_565 (1 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_4444 (2 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_888 (3 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_1555 (4 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_5551 (5 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_8 (6 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_RESERVED (7 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_YUV420SP (8 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_YUV420P (9 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_YUV422I (10 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_YUV422SP (11 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_P010 (12 << G2D_DATAFMT_SHIFT)
+#define G2D_DATAFMT_YUV420SP82 (13 << G2D_DATAFMT_SHIFT)
+
+#define G2D_FMT_ARGB8888 (G2D_DATAFMT_8888 | G2D_SWZ_ARGB)
+#define G2D_FMT_ABGR8888 (G2D_DATAFMT_8888 | G2D_SWZ_ABGR)
+#define G2D_FMT_XBGR8888 (G2D_DATAFMT_8888 | G2D_SWZ_xBGR)
+#define G2D_FMT_XRGB8888 (G2D_DATAFMT_8888 | G2D_SWZ_xRGB)
+#define G2D_FMT_ARGB4444 (G2D_DATAFMT_4444 | G2D_SWZ_ARGB)
+#define G2D_FMT_ARGB1555 (G2D_DATAFMT_1555 | G2D_SWZ_ARGB)
+#define G2D_FMT_RGB565 (G2D_DATAFMT_565 | G2D_SWZ_xBGR)
+#define G2D_FMT_RGB888 (G2D_DATAFMT_888 | G2D_SWZ_xRGB)
+#define G2D_FMT_BGR888 (G2D_DATAFMT_888 | G2D_SWZ_BGR)
+#define G2D_FMT_NV12 (G2D_DATAFMT_YUV420SP | G2D_YUV_UV)
+#define G2D_FMT_NV21 (G2D_DATAFMT_YUV420SP | G2D_YUV_VU)
+#define G2D_FMT_YV12 (G2D_DATAFMT_YUV420P | G2D_YUV_VU)
+#define G2D_FMT_YUYV (G2D_DATAFMT_YUV422I | G2D_YUV_YC | G2D_YUV_UV)
+#define G2D_FMT_YVYU (G2D_DATAFMT_YUV422I | G2D_YUV_YC | G2D_YUV_VU)
+#define G2D_FMT_UYVY (G2D_DATAFMT_YUV422I | G2D_YUV_CY | G2D_YUV_UV)
+#define G2D_FMT_VYUY (G2D_DATAFMT_YUV422I | G2D_YUV_CY | G2D_YUV_VU)
+#define G2D_FMT_NV16 (G2D_DATAFMT_YUV422SP | G2D_YUV_UV)
+#define G2D_FMT_NV61 (G2D_DATAFMT_YUV422SP | G2D_YUV_VU)
+#define G2D_FMT_NV12_82 (G2D_DATAFMT_YUV420SP82 | G2D_YUV_UV)
+#define G2D_FMT_NV21_82 (G2D_DATAFMT_YUV420SP82 | G2D_YUV_VU)
+#define G2D_FMT_NV12_P010 (G2D_DATAFMT_P010 | G2D_YUV_UV)
+#define G2D_FMT_NV21_P010 (G2D_DATAFMT_P010 | G2D_YUV_VU)
+
+#define G2D_DATAFORMAT_AFBC (1 << 20)
+#define G2D_DATAFORMAT_UORDER (1 << 21)
+
+#define IS_AFBC(fmt) ((fmt & G2D_DATAFORMAT_AFBC) != 0)
+#define IS_UORDER(fmt) ((fmt & G2D_DATAFORMAT_UORDER) != 0)
+#define IS_YUV(fmt) (((fmt) & G2D_DATAFMT_MASK) > G2D_DATAFMT_RESERVED)
+#define IS_YUV422(fmt) ((((fmt) >> G2D_DATAFMT_SHIFT) & 0xE) == 0xA)
+#define IS_RGB(fmt) (((fmt) & G2D_DATAFMT_MASK) < G2D_DATAFMT_8)
+#define IS_YUV420_82(fmt) (((fmt) & G2D_DATAFMT_MASK) == G2D_DATAFMT_YUV420SP82)
+
+#define IS_AFBC_WIDTH_ALIGNED(width) IS_ALIGNED((width), 16)
+#define IS_AFBC_HEIGHT_ALIGNED(height) IS_ALIGNED((height), 4)
+
+#define G2D_IMGFMT(value) ((value) & \
+ (G2D_DATAFMT_MASK | G2D_YUVORDER_MASK | G2D_SWZ_MASK))
+
+#define G2D_MAX_PLANES 4
+
+#define G2D_MAX_SIZE 8192
+
+#endif /* __G2D_FORMAT_H__ */
--- /dev/null
+/*
+ * linux/drivers/gpu/exynos/g2d/g2d_task.c
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/exynos_iovmm.h>
+
+#include "g2d.h"
+#include "g2d_task.h"
+
+void g2d_destroy_tasks(struct g2d_device *g2d_dev)
+{
+ struct g2d_task *task, *next;
+ unsigned long flags;
+
+ spin_lock_irqsave(&g2d_dev->lock_task, flags);
+
+ task = g2d_dev->tasks;
+ while (task != NULL) {
+ next = task->next;
+
+ list_del(&task->node);
+
+ iovmm_unmap(g2d_dev->dev, task->cmd_addr);
+
+ __free_pages(task->cmd_page, get_order(G2D_CMD_LIST_SIZE));
+
+ kfree(task);
+
+ task = next;
+ }
+
+ spin_unlock_irqrestore(&g2d_dev->lock_task, flags);
+}
+
+static struct g2d_task *g2d_create_task(struct g2d_device *g2d_dev)
+{
+ struct g2d_task *task;
+ struct scatterlist sgl;
+ int i;
+
+ task = kzalloc(sizeof(*task), GFP_KERNEL);
+ if (!task)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&task->node);
+
+ task->cmd_page = alloc_pages(GFP_KERNEL, get_order(G2D_CMD_LIST_SIZE));
+ if (!task->cmd_page)
+ goto err_page;
+
+ /* mapping the command data */
+ sg_init_table(&sgl, 1);
+ sg_set_page(&sgl, task->cmd_page, G2D_CMD_LIST_SIZE, 0);
+ task->cmd_addr = iovmm_map(g2d_dev->dev, &sgl, 0, G2D_CMD_LIST_SIZE,
+ DMA_TO_DEVICE, IOMMU_READ | IOMMU_CACHE);
+
+ for (i = 0; i < G2D_MAX_IMAGES; i++)
+ task->source[i].task = task;
+ task->target.task = task;
+
+ task->g2d_dev = g2d_dev;
+
+ return task;
+err_page:
+ kfree(task);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+int g2d_create_tasks(struct g2d_device *g2d_dev)
+{
+ struct g2d_task *task;
+ unsigned int i;
+
+ for (i = 0; i < G2D_MAX_JOBS; i++) {
+ task = g2d_create_task(g2d_dev);
+
+ if (IS_ERR(task)) {
+ g2d_destroy_tasks(g2d_dev);
+ return PTR_ERR(task);
+ }
+
+ task->job_id = i;
+
+ task->next = g2d_dev->tasks;
+ g2d_dev->tasks = task;
+ list_add(&task->node, &g2d_dev->tasks_free);
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ * linux/drivers/gpu/exynos/g2d/g2d_task.h
+ *
+ * Copyright (C) 2017 Samsung Electronics Co., Ltd.
+ *
+ * Contact: Hyesoo Yu <hyesoo.yu@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.
+ *
+ * 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.
+ */
+
+#ifndef __EXYNOS_G2D_TASK_H__
+#define __EXYNOS_G2D_TASK_H__
+
+#include <linux/dma-buf.h>
+
+#include "g2d_format.h"
+
+#define G2D_MAX_IMAGES 16
+#define G2D_MAX_JOBS 16
+#define G2D_CMD_LIST_SIZE 8192
+
+struct g2d_buffer {
+ union {
+ struct {
+ unsigned int offset;
+ struct dma_buf *dmabuf;
+ struct dma_buf_attachment *attachment;
+ struct sg_table *sgt;
+ } dmabuf;
+ struct {
+ unsigned long addr;
+ struct vm_area_struct *vma;
+ } userptr;
+ };
+ unsigned int length;
+ unsigned int payload;
+ dma_addr_t dma_addr;
+};
+
+struct g2d_layer {
+ struct g2d_task *task;
+ int flags;
+ int buffer_type;
+ int num_buffers;
+ struct g2d_buffer buffer[G2D_MAX_PLANES];
+};
+
+#define G2D_TASKSTATE_WAITING 1
+#define G2D_TASKSTATE_UNPREPARED 2
+#define G2D_TASKSTATE_PREPARED 3
+#define G2D_TASKSTATE_ACTIVE 4
+#define G2D_TASKSTATE_PROCESSED 5
+#define G2D_TASKSTATE_ERROR 6
+#define G2D_TASKSTATE_KILLED 7
+#define G2D_TASKSTATE_TIMEOUT 8
+
+struct g2d_context;
+struct g2d_device;
+
+struct g2d_task {
+ struct list_head node;
+ struct g2d_task *next;
+ struct g2d_device *g2d_dev;
+
+ unsigned int job_id;
+
+ struct g2d_layer source[G2D_MAX_IMAGES];
+ struct g2d_layer target;
+ unsigned int num_source;
+
+ /* Command list */
+ struct page *cmd_page;
+ dma_addr_t cmd_addr;
+ unsigned int cmd_count;
+
+ unsigned int priority;
+};
+
+void g2d_destroy_tasks(struct g2d_device *g2d_dev);
+int g2d_create_tasks(struct g2d_device *g2d_dev);
+
+#endif /*__EXYNOS_G2D_TASK_H__*/