summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/video/b2r2/Makefile2
-rw-r--r--drivers/video/b2r2/b2r2_api.c1643
-rw-r--r--drivers/video/b2r2/b2r2_blt_main.c827
-rw-r--r--drivers/video/b2r2/b2r2_control.h33
-rw-r--r--drivers/video/b2r2/b2r2_core.c699
-rw-r--r--drivers/video/b2r2/b2r2_core.h192
-rw-r--r--drivers/video/b2r2/b2r2_input_validation.c98
-rw-r--r--drivers/video/b2r2/b2r2_input_validation.h2
-rw-r--r--drivers/video/b2r2/b2r2_internal.h89
-rw-r--r--drivers/video/b2r2/b2r2_node_split.c60
-rw-r--r--drivers/video/b2r2/b2r2_profiler_socket.c5
-rw-r--r--drivers/video/b2r2/b2r2_utils.c295
-rw-r--r--drivers/video/b2r2/b2r2_utils.h19
-rw-r--r--include/video/b2r2_blt.h51
14 files changed, 2779 insertions, 1236 deletions
diff --git a/drivers/video/b2r2/Makefile b/drivers/video/b2r2/Makefile
index 9900ebf8216..f271f4e7ea1 100644
--- a/drivers/video/b2r2/Makefile
+++ b/drivers/video/b2r2/Makefile
@@ -2,7 +2,7 @@
obj-$(CONFIG_FB_B2R2) += b2r2.o
-b2r2-objs = b2r2_blt_main.o b2r2_core.o b2r2_mem_alloc.o b2r2_generic.o b2r2_node_gen.o b2r2_node_split.o b2r2_profiler_socket.o b2r2_timing.o b2r2_filters.o b2r2_utils.o b2r2_input_validation.o b2r2_hw_convert.o
+b2r2-objs = b2r2_api.o b2r2_blt_main.o b2r2_core.o b2r2_mem_alloc.o b2r2_generic.o b2r2_node_gen.o b2r2_node_split.o b2r2_profiler_socket.o b2r2_timing.o b2r2_filters.o b2r2_utils.o b2r2_input_validation.o b2r2_hw_convert.o
ifdef CONFIG_B2R2_DEBUG
b2r2-objs += b2r2_debug.o
diff --git a/drivers/video/b2r2/b2r2_api.c b/drivers/video/b2r2/b2r2_api.c
new file mode 100644
index 00000000000..0361e85ebf3
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_api.c
@@ -0,0 +1,1643 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2010/2012
+ *
+ * ST-Ericsson B2R2 Blitter module API
+ *
+ * Author: Jorgen Nilsson <jorgen.nilsson@stericsson.com>
+ * Author: Robert Fekete <robert.fekete@stericsson.com>
+ * Author: Paul Wannback
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/file.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/miscdevice.h>
+#include <linux/list.h>
+#ifdef CONFIG_ANDROID_PMEM
+#include <linux/android_pmem.h>
+#endif
+#include <linux/fb.h>
+#include <linux/uaccess.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
+#include <asm/cacheflush.h>
+#include <linux/smp.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/err.h>
+#include <linux/hwmem.h>
+#include <linux/kref.h>
+
+#include "b2r2_internal.h"
+#include "b2r2_control.h"
+#include "b2r2_core.h"
+#include "b2r2_timing.h"
+#include "b2r2_utils.h"
+#include "b2r2_debug.h"
+#include "b2r2_input_validation.h"
+#include "b2r2_profiler_socket.h"
+#include "b2r2_hw.h"
+
+/*
+ * TODO:
+ * Implementation of query cap
+ * Support for user space virtual pointer to physically consecutive memory
+ * Support for user space virtual pointer to physically scattered memory
+ * Callback reads lagging behind in blt_api_stress app
+ * Store smaller items in the report list instead of the whole request
+ * Support read of many report records at once.
+ */
+
+#define DATAS_START_SIZE 10
+#define DATAS_GROW_SIZE 5
+
+/**
+ * @miscdev: The miscdev presenting b2r2 to the system
+ */
+struct b2r2_blt {
+ spinlock_t lock;
+ int next_job_id;
+ struct miscdevice miscdev;
+ struct device *dev;
+ struct mutex datas_lock;
+ /**
+ * datas - Stores the b2r2_blt_data mapped to the cliend handle
+ */
+ struct b2r2_blt_data **datas;
+ /**
+ * data_count - The current maximum of active datas
+ */
+ int data_count;
+};
+
+struct b2r2_blt_data {
+ struct b2r2_control_instance *ctl_instace[B2R2_MAX_NBR_DEVICES];
+};
+
+/**
+ * Used to keep track of coming and going b2r2 cores and
+ * the number of active instance references
+ */
+struct b2r2_control_ref {
+ struct b2r2_control *b2r2_control;
+ spinlock_t lock;
+};
+
+/**
+ * b2r2_blt - The blitter device, /dev/b2r2_blt
+ */
+struct kref blt_refcount;
+static struct b2r2_blt *b2r2_blt;
+
+/**
+ * b2r2_control - The core controls and synchronization mechanism
+ */
+static struct b2r2_control_ref b2r2_controls[B2R2_MAX_NBR_DEVICES];
+
+/**
+ * b2r2_blt_add_control - Add the b2r2 core control
+ */
+void b2r2_blt_add_control(struct b2r2_control *cont)
+{
+ unsigned long flags;
+ BUG_ON(cont->id < 0 || cont->id >= B2R2_MAX_NBR_DEVICES);
+
+ spin_lock_irqsave(&b2r2_controls[cont->id].lock, flags);
+ if (b2r2_controls[cont->id].b2r2_control == NULL)
+ b2r2_controls[cont->id].b2r2_control = cont;
+ spin_unlock_irqrestore(&b2r2_controls[cont->id].lock, flags);
+}
+
+/**
+ * b2r2_blt_remove_control - Remove the b2r2 core control
+ */
+void b2r2_blt_remove_control(struct b2r2_control *cont)
+{
+ unsigned long flags;
+ BUG_ON(cont->id < 0 || cont->id >= B2R2_MAX_NBR_DEVICES);
+
+ spin_lock_irqsave(&b2r2_controls[cont->id].lock, flags);
+ b2r2_controls[cont->id].b2r2_control = NULL;
+ spin_unlock_irqrestore(&b2r2_controls[cont->id].lock, flags);
+}
+
+/**
+ * b2r2_blt_get_control - Lock control for writing/removal
+ */
+static struct b2r2_control *b2r2_blt_get_control(int i)
+{
+ struct b2r2_control *cont;
+ unsigned long flags;
+ BUG_ON(i < 0 || i >= B2R2_MAX_NBR_DEVICES);
+
+ spin_lock_irqsave(&b2r2_controls[i].lock, flags);
+ cont = (struct b2r2_control *) b2r2_controls[i].b2r2_control;
+ if (cont != NULL) {
+ if (!cont->enabled)
+ cont = NULL;
+ else
+ kref_get(&cont->ref);
+ }
+ spin_unlock_irqrestore(&b2r2_controls[i].lock, flags);
+
+ return cont;
+}
+
+/**
+ * b2r2_blt_release_control - Unlock control for writing/removal
+ */
+static void b2r2_blt_release_control(int i)
+{
+ struct b2r2_control *cont;
+ unsigned long flags;
+ BUG_ON(i < 0 || i >= B2R2_MAX_NBR_DEVICES);
+
+ spin_lock_irqsave(&b2r2_controls[i].lock, flags);
+ cont = (struct b2r2_control *) b2r2_controls[i].b2r2_control;
+ spin_unlock_irqrestore(&b2r2_controls[i].lock, flags);
+ if (cont != NULL)
+ kref_put(&cont->ref, b2r2_core_release);
+}
+
+/**
+ * Increase size of array containing b2r2 handles
+ */
+static int grow_datas(void)
+{
+ struct b2r2_blt_data **new_datas = NULL;
+ int new_data_count = b2r2_blt->data_count + DATAS_GROW_SIZE;
+ int ret = 0;
+
+ new_datas = kzalloc(new_data_count * sizeof(*new_datas), GFP_KERNEL);
+ if (new_datas == NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ memcpy(new_datas, b2r2_blt->datas,
+ b2r2_blt->data_count * sizeof(*b2r2_blt->datas));
+
+ kfree(b2r2_blt->datas);
+
+ b2r2_blt->data_count = new_data_count;
+ b2r2_blt->datas = new_datas;
+exit:
+ return ret;
+}
+
+/**
+ * Allocate and/or reserve a b2r2 handle
+ */
+static int alloc_handle(struct b2r2_blt_data *blt_data)
+{
+ int handle;
+ int ret;
+
+ mutex_lock(&b2r2_blt->datas_lock);
+
+ if (b2r2_blt->datas == NULL) {
+ b2r2_blt->datas = kzalloc(
+ DATAS_START_SIZE * sizeof(*b2r2_blt->datas),
+ GFP_KERNEL);
+ if (b2r2_blt->datas == NULL) {
+ ret = -ENOMEM;
+ goto exit;
+ }
+ b2r2_blt->data_count = DATAS_START_SIZE;
+ }
+
+ for (handle = 0; handle < b2r2_blt->data_count; handle++) {
+ if (b2r2_blt->datas[handle] == NULL) {
+ b2r2_blt->datas[handle] = blt_data;
+ break;
+ }
+
+ if (handle == b2r2_blt->data_count - 1) {
+ ret = grow_datas();
+ if (ret < 0)
+ goto exit;
+ }
+ }
+ ret = handle;
+exit:
+ mutex_unlock(&b2r2_blt->datas_lock);
+
+ return ret;
+}
+
+/**
+ * Get b2r2 data from b2r2 handle
+ */
+static struct b2r2_blt_data *get_data(int handle)
+{
+ if (handle >= b2r2_blt->data_count || handle < 0)
+ return NULL;
+ else
+ return b2r2_blt->datas[handle];
+}
+
+/**
+ * Unreserve b2r2 handle
+ */
+static void free_handle(int handle)
+{
+ if (handle < b2r2_blt->data_count && handle >= 0)
+ b2r2_blt->datas[handle] = NULL;
+}
+
+/**
+ * Get the next job number. This is the one returned to the client
+ * if the blit request was successful.
+ */
+static int get_next_job_id(void)
+{
+ int job_id;
+ unsigned long flags;
+
+ spin_lock_irqsave(&b2r2_blt->lock, flags);
+ if (b2r2_blt->next_job_id < 1)
+ b2r2_blt->next_job_id = 1;
+ job_id = b2r2_blt->next_job_id++;
+ spin_unlock_irqrestore(&b2r2_blt->lock, flags);
+
+ return job_id;
+}
+
+/**
+ * Limit the number of cores used in some "easy" and impossible cases
+ */
+static int limit_blits(int n_split, struct b2r2_blt_req *user_req)
+{
+ if (n_split <= 1)
+ return n_split;
+
+ if (user_req->dst_rect.width < 24 && user_req->dst_rect.height < 24)
+ return 1;
+
+ if (user_req->src_rect.width < n_split &&
+ user_req->src_rect.height < n_split)
+ return 1;
+
+ return n_split;
+}
+
+/**
+ * Check if the format inherently requires the b2r2 scaling engine to be active
+ */
+static bool is_scaling_fmt(enum b2r2_blt_fmt fmt)
+{
+ /* Plane separated formats must be treated as scaling */
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YVU420_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YVU422_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV444_PACKED_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YVU420_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YVU422_PACKED_SEMI_PLANAR:
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Check for macroblock formats
+ */
+static bool is_mb_fmt(enum b2r2_blt_fmt fmt)
+{
+ switch (fmt) {
+ case B2R2_BLT_FMT_YUV420_PACKED_SEMIPLANAR_MB_STE:
+ case B2R2_BLT_FMT_YUV422_PACKED_SEMIPLANAR_MB_STE:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * Split a request rectangle on available cores
+ */
+static int b2r2_blt_split_request(struct b2r2_blt_data *blt_data,
+ struct b2r2_blt_req *user_req,
+ struct b2r2_blt_request **split_requests,
+ struct b2r2_control_instance **ctl,
+ int *n_split)
+{
+ int sstep_x, sstep_y, dstep_x, dstep_y;
+ int dstart_x, dstart_y;
+ int bstart_x, bstart_y;
+ int dpos_x, dpos_y;
+ int bpos_x, bpos_y;
+ int dso_x = 1;
+ int dso_y = 1;
+ int sf_x, sf_y;
+ int i;
+ int srw, srh;
+ int drw, drh;
+ bool ssplit_x = true;
+ bool dsplit_x = true;
+ enum b2r2_blt_transform transform;
+ bool is_rotation = false;
+ bool is_scaling = false;
+ bool bg_blend = false;
+ u32 core_mask = 0;
+
+ srw = user_req->src_rect.width;
+ srh = user_req->src_rect.height;
+ drw = user_req->dst_rect.width;
+ drh = user_req->dst_rect.height;
+ transform = user_req->transform;
+
+ /* Early exit in the basic cases */
+ if (*n_split == 0) {
+ return -ENOSYS;
+ } else if (*n_split == 1 ||
+ (srw < *n_split && srh < *n_split) ||
+ (drw < *n_split && drh < *n_split) ||
+ is_mb_fmt(user_req->src_img.fmt)) {
+ /* Handle macroblock formats with one
+ * core for now since there seems to be some bug
+ * related to macroblock access patterns
+ */
+ memcpy(&split_requests[0]->user_req,
+ user_req,
+ sizeof(*user_req));
+ split_requests[0]->core_mask = 1;
+ *n_split = 1;
+ return 0;
+ }
+
+ /*
+ * TODO: fix the load balancing algorithm
+ */
+
+ is_rotation = (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) != 0;
+
+ /* Check for scaling */
+ if (is_rotation) {
+ is_scaling = (user_req->src_rect.width !=
+ user_req->dst_rect.height) ||
+ (user_req->src_rect.height !=
+ user_req->dst_rect.width);
+ } else {
+ is_scaling = (user_req->src_rect.width !=
+ user_req->dst_rect.width) ||
+ (user_req->src_rect.height !=
+ user_req->dst_rect.height);
+ }
+
+ is_scaling = is_scaling ||
+ is_scaling_fmt(user_req->src_img.fmt) ||
+ is_scaling_fmt(user_req->dst_img.fmt);
+
+ bg_blend = ((user_req->flags & B2R2_BLT_FLAG_BG_BLEND) != 0);
+
+ /*
+ * Split the request
+ */
+
+ b2r2_log_info(b2r2_blt->dev, "%s: In (t:0x%08X, f:0x%08X):\n"
+ "\tsrc_rect x:%d, y:%d, w:%d, h:%d src fmt:0x%x\n"
+ "\tdst_rect x:%d, y:%d, w:%d, h:%d dst fmt:0x%x\n",
+ __func__,
+ user_req->transform,
+ user_req->flags,
+ user_req->src_rect.x,
+ user_req->src_rect.y,
+ user_req->src_rect.width,
+ user_req->src_rect.height,
+ user_req->src_img.fmt,
+ user_req->dst_rect.x,
+ user_req->dst_rect.y,
+ user_req->dst_rect.width,
+ user_req->dst_rect.height,
+ user_req->dst_img.fmt);
+
+ /* TODO: We need sub pixel precision here,
+ * or a better way to split rects */
+ dstart_x = user_req->dst_rect.x;
+ dstart_y = user_req->dst_rect.y;
+ if (bg_blend) {
+ bstart_x = user_req->bg_rect.x;
+ bstart_y = user_req->bg_rect.y;
+ }
+
+ if (srw && srh) {
+ if ((srw < srh) && !is_scaling) {
+ ssplit_x = false;
+ sstep_y = srh / *n_split;
+ /* Round up */
+ if (srh % (*n_split))
+ sstep_y++;
+
+ if (srh > 16)
+ sstep_y = ((sstep_y + 16) >> 4) << 4;
+
+ if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ sf_y = (drw << 10) / srh;
+ dstep_x = (sf_y * sstep_y) >> 10;
+ } else {
+ dsplit_x = false;
+ sf_y = (drh << 10) / srh;
+ dstep_y = (sf_y * sstep_y) >> 10;
+ }
+ } else {
+ sstep_x = srw / *n_split;
+ /* Round up */
+ if (srw % (*n_split))
+ sstep_x++;
+
+ if (is_scaling) {
+ int scale_step_size =
+ B2R2_RESCALE_MAX_WIDTH - 1;
+ int pad = (scale_step_size -
+ (sstep_x % scale_step_size));
+ if ((sstep_x + pad) < srw)
+ sstep_x += pad;
+ } else {
+ /* Aim for even 16px multiples */
+ if ((sstep_x & 0xF) && ((sstep_x + 16) < srw))
+ sstep_x = ((sstep_x + 16) >> 4) << 4;
+ }
+
+ if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
+ dsplit_x = false;
+ sf_x = (drh << 10) / srw;
+ dstep_y = (sf_x * sstep_x) >> 10;
+ } else {
+ sf_x = (drw << 10) / srw;
+ dstep_x = (sf_x * sstep_x) >> 10;
+ }
+ }
+
+ } else {
+ sstep_x = sstep_y = 0;
+
+ if (drw < drh) {
+ dsplit_x = false;
+ dstep_y = drh / *n_split;
+ /* Round up */
+ if (drh % *n_split)
+ dstep_y++;
+
+ /* Aim for even 16px multiples */
+ if ((dstep_y & 0xF) && ((dstep_y + 16) < drh))
+ dstep_y = ((dstep_y + 16) >> 4) << 4;
+ } else {
+ dstep_x = drw / *n_split;
+ /* Round up */
+ if (drw % *n_split)
+ dstep_x++;
+
+ /* Aim for even 16px multiples */
+ if ((dstep_x & 0xF) && ((dstep_x + 16) < drw))
+ dstep_x = ((dstep_x + 16) >> 4) << 4;
+ }
+ }
+
+ /* Check for flip and rotate to establish destination
+ * step order */
+ if (transform & B2R2_BLT_TRANSFORM_FLIP_H) {
+ dstart_x += drw;
+ if (bg_blend)
+ bstart_x += drw;
+ dso_x = -1;
+ }
+ if ((transform & B2R2_BLT_TRANSFORM_FLIP_V) ||
+ (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90)) {
+ dstart_y += drh;
+ if (bg_blend)
+ bstart_y += drh;
+ dso_y = -1;
+ }
+
+ /* Set scan starting position */
+ dpos_x = dstart_x;
+ dpos_y = dstart_y;
+ if (bg_blend) {
+ bpos_x = bstart_x;
+ bpos_y = bstart_y;
+ }
+
+ for (i = 0; i < *n_split; i++) {
+ struct b2r2_blt_req *sreq =
+ &split_requests[i]->user_req;
+
+ /* First mimic all */
+ memcpy(sreq, user_req, sizeof(*user_req));
+
+ /* Then change the rects */
+ if (srw && srh) {
+ if (ssplit_x) {
+ if (sstep_x > 0) {
+ sreq->src_rect.width =
+ min(sstep_x, srw);
+ sreq->src_rect.x += i*sstep_x;
+ srw -= sstep_x;
+ } else {
+ sreq->src_rect.width = srw;
+ }
+ } else {
+ if (sstep_y > 0) {
+ sreq->src_rect.y += i*sstep_y;
+ sreq->src_rect.height =
+ min(sstep_y, srh);
+ srh -= sstep_y;
+ } else {
+ sreq->src_rect.height = srh;
+ }
+ }
+ }
+
+ if (dsplit_x) {
+ int sx = min(dstep_x, drw);
+ if (dso_x < 0) {
+ dpos_x += dso_x * sx;
+ if (bg_blend)
+ bpos_x += dso_x * sx;
+ }
+ sreq->dst_rect.width = sx;
+ sreq->dst_rect.x = dpos_x;
+ if (bg_blend) {
+ sreq->bg_rect.width = sx;
+ sreq->bg_rect.x = bpos_x;
+ }
+ if (dso_x > 0) {
+ dpos_x += dso_x * sx;
+ if (bg_blend)
+ bpos_x += dso_x * sx;
+ }
+ drw -= sx;
+ } else {
+ int sy = min(dstep_y, drh);
+ if (dso_y < 0) {
+ dpos_y += dso_y * sy;
+ if (bg_blend)
+ bpos_y += dso_y * sy;
+ }
+ sreq->dst_rect.height = sy;
+ sreq->dst_rect.y = dpos_y;
+ if (bg_blend) {
+ sreq->bg_rect.height = sy;
+ sreq->bg_rect.y = bpos_y;
+ }
+ if (dso_y > 0) {
+ dpos_y += dso_y * sy;
+ if (bg_blend)
+ bpos_y += dso_y * sy;
+ }
+ drh -= sy;
+ }
+
+ b2r2_log_info(b2r2_blt->dev, "%s: Out:\n"
+ "\tsrc_rect x:%d, y:%d, w:%d, h:%d\n"
+ "\tdst_rect x:%d, y:%d, w:%d, h:%d\n"
+ "\tbg_rect x:%d, y:%d, w:%d, h:%d\n",
+ __func__,
+ sreq->src_rect.x,
+ sreq->src_rect.y,
+ sreq->src_rect.width,
+ sreq->src_rect.height,
+ sreq->dst_rect.x,
+ sreq->dst_rect.y,
+ sreq->dst_rect.width,
+ sreq->dst_rect.height,
+ sreq->bg_rect.x,
+ sreq->bg_rect.y,
+ sreq->bg_rect.width,
+ sreq->bg_rect.height);
+
+ core_mask |= (1 << i);
+ }
+
+ for (i = 0; i < *n_split; i++)
+ split_requests[i]->core_mask = core_mask;
+
+ return 0;
+}
+
+/**
+ * Get available b2r2 control instances. It will be limited
+ * to the number of cores available at the current point in time.
+ * It will also cause the cores to stay active during the time until
+ * release_control_instances is called.
+ */
+static void get_control_instances(struct b2r2_blt_data *blt_data,
+ struct b2r2_control_instance **ctl, int max_size,
+ int *count)
+{
+ int i;
+
+ *count = 0;
+ for (i = 0; i < max_size; i++) {
+ struct b2r2_control_instance *ci = blt_data->ctl_instace[i];
+ if (ci) {
+ struct b2r2_control *cont =
+ b2r2_blt_get_control(ci->control_id);
+ if (cont) {
+ ctl[*count] = ci;
+ *count += 1;
+ }
+ }
+ }
+}
+
+/**
+ * Release b2r2 control instances. The cores allocated for the request
+ * are given back.
+ */
+static void release_control_instances(struct b2r2_control_instance **ctl,
+ int count)
+{
+ int i;
+
+ /* Release the handles to the core controls */
+ for (i = 0; i < count; i++) {
+ if (ctl[i])
+ b2r2_blt_release_control(ctl[i]->control_id);
+ }
+}
+
+/**
+ * Free b2r2 request
+ */
+static void b2r2_free_request(struct b2r2_blt_request *request)
+{
+ if (request) {
+ /* Free requests in split_requests */
+ if (request->clut)
+ dma_free_coherent(b2r2_blt->dev,
+ CLUT_SIZE,
+ request->clut,
+ request->clut_phys_addr);
+ request->clut = NULL;
+ request->clut_phys_addr = 0;
+ kfree(request);
+ }
+}
+
+/**
+ * Allocate internal b2r2 request based on user input.
+ */
+static int b2r2_alloc_request(struct b2r2_blt_req *user_req,
+ bool us_req, struct b2r2_blt_request **request_out)
+{
+ int ret = 0;
+ struct b2r2_blt_request *request =
+ kzalloc(sizeof(*request), GFP_KERNEL);
+ if (!request)
+ return -ENOMEM;
+
+ /* Initialize the structure */
+ INIT_LIST_HEAD(&request->list);
+
+ /*
+ * If the user specified a color look-up table,
+ * make a copy that the HW can use.
+ */
+ if ((user_req->flags &
+ B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) {
+ request->clut = dma_alloc_coherent(
+ b2r2_blt->dev,
+ CLUT_SIZE,
+ &(request->clut_phys_addr),
+ GFP_DMA | GFP_KERNEL);
+ if (request->clut == NULL) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s CLUT allocation "
+ "failed.\n", __func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ if (us_req) {
+ if (copy_from_user(request->clut,
+ user_req->clut, CLUT_SIZE)) {
+ b2r2_log_err(b2r2_blt->dev, "%s: CLUT "
+ "copy_from_user failed\n",
+ __func__);
+ ret = -EFAULT;
+ goto exit;
+ }
+ } else {
+ memcpy(request->clut, user_req->clut,
+ CLUT_SIZE);
+ }
+ }
+
+ request->profile = is_profiler_registered_approx();
+
+ *request_out = request;
+exit:
+ if (ret != 0)
+ b2r2_free_request(request);
+
+ return ret;
+}
+
+/**
+ * Do the blit job split on available cores.
+ */
+static int b2r2_blt_blit_internal(int handle,
+ struct b2r2_blt_req *user_req,
+ bool us_req)
+{
+ int request_id;
+ int i;
+ int n_instance = 0;
+ int n_blit = 0;
+ int ret = 0;
+ struct b2r2_blt_data *blt_data;
+ struct b2r2_blt_req ureq;
+
+ /* The requests and the designated workers */
+ struct b2r2_blt_request *split_requests[B2R2_MAX_NBR_DEVICES];
+ struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES];
+
+ blt_data = get_data(handle);
+ if (blt_data == NULL) {
+ b2r2_log_warn(b2r2_blt->dev,
+ "%s, blitter instance not found (handle=%d)\n",
+ __func__, handle);
+ return -ENOSYS;
+ }
+
+ /* Get the b2r2 core controls for the job */
+ get_control_instances(blt_data, ctl, B2R2_MAX_NBR_DEVICES, &n_instance);
+ if (n_instance == 0) {
+ b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n",
+ __func__);
+ return -ENOSYS;
+ }
+
+ /* Get the user data */
+ if (us_req) {
+ if (copy_from_user(&ureq, user_req, sizeof(ureq))) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: copy_from_user failed\n",
+ __func__);
+ ret = -EFAULT;
+ goto exit;
+ }
+ } else {
+ memcpy(&ureq, user_req, sizeof(ureq));
+ }
+
+ /*
+ * B2R2 cannot handle destination clipping on buffers
+ * allocated close to 64MiB bank boundaries.
+ * recalculate src_ and dst_rect to avoid clipping.
+ *
+ * Also this is needed to ensure the request split
+ * operates on visible areas
+ */
+ b2r2_recalculate_rects(b2r2_blt->dev, &ureq);
+
+ if (!b2r2_validate_user_req(b2r2_blt->dev, &ureq)) {
+ b2r2_log_warn(b2r2_blt->dev,
+ "%s: b2r2_validate_user_req failed.\n",
+ __func__);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ /* Don't split small requests */
+ n_blit = limit_blits(n_instance, &ureq);
+
+ /* The id needs to be universal on
+ * all cores */
+ request_id = get_next_job_id();
+
+#ifdef CONFIG_B2R2_GENERIC_ONLY
+ /* Limit the generic only solution to one core (for now) */
+ n_blit = 1;
+#endif
+
+ for (i = 0; i < n_blit; i++) {
+ ret = b2r2_alloc_request(&ureq, us_req, &split_requests[i]);
+ if (ret < 0 || !split_requests[i]) {
+ b2r2_log_err(b2r2_blt->dev, "%s: Failed to alloc mem\n",
+ __func__);
+ ret = -ENOMEM;
+ break;
+ }
+ split_requests[i]->instance = ctl[i];
+ split_requests[i]->job.job_id = request_id;
+ split_requests[i]->job.data = (int) ctl[i]->control->data;
+ }
+
+ /* Split the request */
+ if (ret >= 0)
+ ret = b2r2_blt_split_request(blt_data, &ureq,
+ &split_requests[0], &ctl[0], &n_blit);
+
+ /* If anything failed, clean up allocated memory */
+ if (ret < 0) {
+ for (i = 0; i < n_blit; i++)
+ b2r2_free_request(split_requests[i]);
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: b2r2_blt_split_request failed.\n",
+ __func__);
+ goto exit;
+ }
+
+#ifdef CONFIG_B2R2_GENERIC_ONLY
+ if (ureq.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ /* No support for BG BLEND in generic
+ * implementation yet */
+ b2r2_log_warn(b2r2_blt->dev, "%s: Unsupported: "
+ "Background blend in b2r2_generic_blt\n",
+ __func__);
+ ret = -ENOSYS;
+ b2r2_free_request(split_requests[0]);
+ goto exit;
+ }
+ /* Use the generic path for all operations */
+ ret = b2r2_generic_blt(split_requests[0]);
+#else
+ /* Call each blitter control */
+ for (i = 0; i < n_blit; i++) {
+ ret = b2r2_control_blt(split_requests[i]);
+ if (ret < 0) {
+ b2r2_log_warn(b2r2_blt->dev,
+ "%s: b2r2_control_blt failed.\n", __func__);
+ break;
+ }
+ }
+ if (ret != -ENOSYS) {
+ int j;
+ /* TODO: if one blitter fails then cancel the jobs added */
+
+ /* Call waitjob for successful jobs
+ * (synchs if specified in request) */
+ if (ureq.flags & B2R2_BLT_FLAG_DRY_RUN)
+ goto exit;
+
+ for (j = 0; j < i; j++) {
+ int rtmp;
+
+ rtmp = b2r2_control_waitjob(split_requests[j]);
+ if (rtmp < 0) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: b2r2_control_waitjob failed.\n",
+ __func__);
+ }
+
+ /* Save just the one error */
+ ret = (ret >= 0) ? rtmp : ret;
+ }
+ }
+#endif
+#ifdef CONFIG_B2R2_GENERIC_FALLBACK
+ if (ret == -ENOSYS) {
+ struct b2r2_blt_request *request_gen = NULL;
+ if (ureq.flags & B2R2_BLT_FLAG_BG_BLEND) {
+ /* No support for BG BLEND in generic
+ * implementation yet */
+ b2r2_log_warn(b2r2_blt->dev, "%s: Unsupported: "
+ "Background blend in b2r2_generic_blt\n",
+ __func__);
+ goto exit;
+ }
+
+ b2r2_log_info(b2r2_blt->dev,
+ "b2r2_blt=%d Going generic.\n", ret);
+ ret = b2r2_alloc_request(&ureq, us_req, &request_gen);
+ if (ret < 0 || !request_gen) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: Failed to alloc mem for "
+ "request_gen\n", __func__);
+ ret = -ENOMEM;
+ goto exit;
+ }
+
+ /* Initialize the structure */
+ request_gen->instance = ctl[0];
+ memcpy(&request_gen->user_req, &ureq,
+ sizeof(request_gen->user_req));
+ request_gen->core_mask = 1;
+ request_gen->job.job_id = request_id;
+ request_gen->job.data = (int) ctl[0]->control->data;
+
+ ret = b2r2_generic_blt(request_gen);
+ b2r2_log_info(b2r2_blt->dev, "\nb2r2_generic_blt=%d "
+ "Generic done.\n", ret);
+ }
+#endif
+exit:
+ release_control_instances(ctl, n_instance);
+
+ ret = ret >= 0 ? request_id : ret;
+
+ return ret;
+}
+
+/**
+ * Free the memory used for the b2r2_blt device
+ */
+static void b2r2_blt_release(struct kref *ref)
+{
+ BUG_ON(b2r2_blt == NULL);
+ if (b2r2_blt == NULL)
+ return;
+ kfree(b2r2_blt->datas);
+ kfree(b2r2_blt);
+ b2r2_blt = NULL;
+}
+
+int b2r2_blt_open(void)
+{
+ int ret = 0;
+ struct b2r2_blt_data *blt_data = NULL;
+ int i;
+
+ if (!atomic_inc_not_zero(&blt_refcount.refcount))
+ return -ENOSYS;
+
+ /* Allocate blitter instance data structure */
+ blt_data = (struct b2r2_blt_data *)
+ kzalloc(sizeof(*blt_data), GFP_KERNEL);
+ if (!blt_data) {
+ b2r2_log_err(b2r2_blt->dev, "%s: Failed to alloc\n", __func__);
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) {
+ struct b2r2_control *control = b2r2_blt_get_control(i);
+ if (control != NULL) {
+ struct b2r2_control_instance *ci;
+
+ /* Allocate and initialize the control instance */
+ ci = kzalloc(sizeof(*ci), GFP_KERNEL);
+ if (!ci) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: Failed to alloc\n",
+ __func__);
+ ret = -ENOMEM;
+ b2r2_blt_release_control(i);
+ goto err;
+ }
+ ci->control_id = i;
+ ci->control = control;
+ ret = b2r2_control_open(ci);
+ if (ret < 0) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: Failed to open b2r2 control %d\n",
+ __func__, i);
+ kfree(ci);
+ b2r2_blt_release_control(i);
+ goto err;
+ }
+ blt_data->ctl_instace[i] = ci;
+ b2r2_blt_release_control(i);
+ } else {
+ blt_data->ctl_instace[i] = NULL;
+ }
+ }
+
+ /* TODO: Create kernel worker kthread */
+
+ ret = alloc_handle(blt_data);
+ if (ret < 0)
+ goto err;
+
+ kref_put(&blt_refcount, b2r2_blt_release);
+
+ return ret;
+
+err:
+ /* Destroy the blitter instance data structure */
+ if (blt_data) {
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++)
+ kfree(blt_data->ctl_instace[i]);
+ kfree(blt_data);
+ }
+
+ kref_put(&blt_refcount, b2r2_blt_release);
+
+ return ret;
+}
+EXPORT_SYMBOL(b2r2_blt_open);
+
+int b2r2_blt_close(int handle)
+{
+ int i;
+ struct b2r2_blt_data *blt_data;
+ int ret = 0;
+
+ if (!atomic_inc_not_zero(&blt_refcount.refcount))
+ return -ENOSYS;
+
+ b2r2_log_info(b2r2_blt->dev, "%s\n", __func__);
+
+ blt_data = get_data(handle);
+ if (blt_data == NULL) {
+ b2r2_log_warn(b2r2_blt->dev,
+ "%s, blitter data not found (handle=%d)\n",
+ __func__, handle);
+ ret = -ENOSYS;
+ goto exit;
+ }
+ free_handle(handle);
+
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) {
+ struct b2r2_control_instance *ci =
+ blt_data->ctl_instace[i];
+ if (ci != NULL) {
+ struct b2r2_control *cont =
+ b2r2_blt_get_control(ci->control_id);
+ if (cont) {
+ /* Release the instance */
+ b2r2_control_release(ci);
+ b2r2_blt_release_control(ci->control_id);
+ }
+ kfree(ci);
+ }
+ }
+ kfree(blt_data);
+
+exit:
+ kref_put(&blt_refcount, b2r2_blt_release);
+
+ return ret;
+}
+EXPORT_SYMBOL(b2r2_blt_close);
+
+int b2r2_blt_request(int handle,
+ struct b2r2_blt_req *user_req)
+{
+ int ret = 0;
+
+ if (!atomic_inc_not_zero(&blt_refcount.refcount))
+ return -ENOSYS;
+
+ /* Exclude some currently unsupported cases */
+ if ((user_req->flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) ||
+ (user_req->flags & B2R2_BLT_FLAG_REPORT_PERFORMANCE) ||
+ (user_req->report1 != 0)) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s No callback support in the kernel API\n",
+ __func__);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ ret = b2r2_blt_blit_internal(handle, user_req, false);
+
+exit:
+ kref_put(&blt_refcount, b2r2_blt_release);
+
+ return ret;
+}
+EXPORT_SYMBOL(b2r2_blt_request);
+
+int b2r2_blt_synch(int handle, int request_id)
+{
+ int ret = 0;
+ int i;
+ int n_synch = 0;
+ struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES];
+ struct b2r2_blt_data *blt_data;
+
+ if (!atomic_inc_not_zero(&blt_refcount.refcount))
+ return -ENOSYS;
+
+ b2r2_log_info(b2r2_blt->dev, "%s\n", __func__);
+
+ blt_data = get_data(handle);
+ if (blt_data == NULL) {
+ b2r2_log_warn(b2r2_blt->dev,
+ "%s, blitter data not found (handle=%d)\n",
+ __func__, handle);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ /* Get the b2r2 core controls for the job */
+ get_control_instances(blt_data, ctl, B2R2_MAX_NBR_DEVICES, &n_synch);
+ if (n_synch == 0) {
+ b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n",
+ __func__);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ for (i = 0; i < n_synch; i++) {
+ ret = b2r2_control_synch(ctl[i], request_id);
+ if (ret != 0) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: b2r2_control_synch failed.\n",
+ __func__);
+ break;
+ }
+ }
+
+ /* Release the handles to the core controls */
+ release_control_instances(ctl, n_synch);
+
+exit:
+ kref_put(&blt_refcount, b2r2_blt_release);
+
+ b2r2_log_info(b2r2_blt->dev,
+ "%s, request_id=%d, returns %d\n", __func__, request_id, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(b2r2_blt_synch);
+
+/**
+ * The user space API
+ */
+
+/**
+ * b2r2_blt_open_us - Implements file open on the b2r2_blt device
+ *
+ * @inode: File system inode
+ * @filp: File pointer
+ *
+ * A b2r2_blt_data handle is created and stored in the file structure.
+ */
+static int b2r2_blt_open_us(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ int handle;
+
+ handle = b2r2_blt_open();
+ if (handle < 0) {
+ b2r2_log_err(b2r2_blt->dev, "%s: Failed to open handle\n",
+ __func__);
+ ret = handle;
+ goto exit;
+ }
+ filp->private_data = (void *) handle;
+exit:
+ return ret;
+}
+
+/**
+ * b2r2_blt_release_us - Implements last close on an instance of
+ * the b2r2_blt device
+ *
+ * @inode: File system inode
+ * @filp: File pointer
+ *
+ * All active jobs are finished or cancelled and allocated data
+ * is released.
+ */
+static int b2r2_blt_release_us(struct inode *inode, struct file *filp)
+{
+ int ret;
+ ret = b2r2_blt_close((int) filp->private_data);
+ return ret;
+}
+
+/**
+ * Query B2R2 capabilities
+ *
+ * @blt_data: The B2R2 BLT instance
+ * @query_cap: The structure receiving the capabilities
+ */
+static int b2r2_blt_query_cap(struct b2r2_blt_data *blt_data,
+ struct b2r2_blt_query_cap *query_cap)
+{
+ /* FIXME: Not implemented yet */
+ return -ENOSYS;
+}
+
+/**
+ * b2r2_blt_ioctl_us - This routine implements b2r2_blt ioctl interface
+ *
+ * @file: file pointer.
+ * @cmd :ioctl command.
+ * @arg: input argument for ioctl.
+ *
+ * Returns 0 if OK else negative error code
+ */
+static long b2r2_blt_ioctl_us(struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int ret = 0;
+ int handle = (int) file->private_data;
+
+ /** Process actual ioctl */
+ b2r2_log_info(b2r2_blt->dev, "%s\n", __func__);
+
+ /* Get the instance from the file structure */
+ switch (cmd) {
+ case B2R2_BLT_IOC: {
+ /* arg is user pointer to struct b2r2_blt_request */
+ ret = b2r2_blt_blit_internal(handle,
+ (struct b2r2_blt_req *) arg, true);
+ break;
+ }
+
+ case B2R2_BLT_SYNCH_IOC:
+ /* arg is request_id */
+ ret = b2r2_blt_synch(handle, (int) arg);
+ break;
+
+ case B2R2_BLT_QUERY_CAP_IOC: {
+ /* Arg is struct b2r2_blt_query_cap */
+ struct b2r2_blt_query_cap query_cap;
+ struct b2r2_blt_data *blt_data = get_data(handle);
+
+ /* Get the user data */
+ if (copy_from_user(&query_cap, (void *)arg,
+ sizeof(query_cap))) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: copy_from_user failed\n",
+ __func__);
+ ret = -EFAULT;
+ goto exit;
+ }
+
+ /* Fill in our capabilities */
+ ret = b2r2_blt_query_cap(blt_data, &query_cap);
+
+ /* Return data to user */
+ if (copy_to_user((void *)arg, &query_cap,
+ sizeof(query_cap))) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: copy_to_user failed\n",
+ __func__);
+ ret = -EFAULT;
+ goto exit;
+ }
+ break;
+ }
+
+ default:
+ /* Unknown command */
+ b2r2_log_err(b2r2_blt->dev, "%s: Unknown cmd %d\n",
+ __func__, cmd);
+ ret = -EINVAL;
+ break;
+
+ }
+
+exit:
+ if (ret < 0)
+ b2r2_log_err(b2r2_blt->dev, "%s: Return with error %d!\n",
+ __func__, -ret);
+
+ return ret;
+}
+
+/**
+ * b2r2_blt_poll - Support for user-space poll, select & epoll.
+ * Used for user-space callback
+ *
+ * @filp: File to poll on
+ * @wait: Poll table to wait on
+ *
+ * This function checks if there are anything to read
+ */
+static unsigned b2r2_blt_poll_us(struct file *filp, poll_table *wait)
+{
+ struct b2r2_blt_data *blt_data =
+ (struct b2r2_blt_data *) filp->private_data;
+ struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES];
+ unsigned int ret = POLLIN | POLLRDNORM;
+ int n_poll = 0;
+ int i;
+
+ b2r2_log_info(b2r2_blt->dev, "%s\n", __func__);
+
+ /* Get the b2r2 core controls for the job */
+ get_control_instances(blt_data, ctl, B2R2_MAX_NBR_DEVICES, &n_poll);
+ if (n_poll == 0) {
+ b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n",
+ __func__);
+ ret = -ENOSYS;
+ goto exit;
+ }
+
+ /* Poll each core control instance */
+ for (i = 0; i < n_poll && ret != 0; i++) {
+ poll_wait(filp, &ctl[i]->report_list_waitq, wait);
+ mutex_lock(&ctl[i]->lock);
+ if (list_empty(&ctl[i]->report_list))
+ ret = 0; /* No reports */
+ mutex_unlock(&ctl[i]->lock);
+ }
+
+ /* Release the handles to the core controls */
+ release_control_instances(ctl, n_poll);
+
+exit:
+ b2r2_log_info(b2r2_blt->dev, "%s: returns %d, n_poll: %d\n",
+ __func__, ret, n_poll);
+
+ return ret;
+}
+
+/**
+ * b2r2_blt_read - Read report data, user for user-space callback
+ *
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static ssize_t b2r2_blt_read_us(struct file *filp,
+ char __user *buf, size_t count, loff_t *f_pos)
+{
+ int ret = 0;
+ int n_read = 0;
+ int i;
+ int first_index = 0;
+ struct b2r2_blt_report report;
+ struct b2r2_blt_request *requests[B2R2_MAX_NBR_DEVICES];
+ struct b2r2_blt_data *blt_data =
+ (struct b2r2_blt_data *) filp->private_data;
+ struct b2r2_control_instance *ctl[B2R2_MAX_NBR_DEVICES];
+ struct b2r2_control_instance *first = NULL;
+ bool block = ((filp->f_flags & O_NONBLOCK) == 0);
+ u32 core_mask = 0;
+
+ b2r2_log_info(b2r2_blt->dev, "%s\n", __func__);
+
+ /*
+ * We return only complete report records, one at a time.
+ * Might be more efficient to support read of many.
+ */
+ count = (count / sizeof(struct b2r2_blt_report)) *
+ sizeof(struct b2r2_blt_report);
+ if (count > sizeof(struct b2r2_blt_report))
+ count = sizeof(struct b2r2_blt_report);
+ if (count == 0)
+ return count;
+
+ memset(ctl, 0, sizeof(*ctl) * B2R2_MAX_NBR_DEVICES);
+ /* Get the b2r2 core controls for the job */
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) {
+ struct b2r2_control_instance *ci = blt_data->ctl_instace[i];
+ if (ci) {
+ struct b2r2_control *cont =
+ b2r2_blt_get_control(ci->control_id);
+ if (cont) {
+ ctl[i] = ci;
+ n_read++;
+ }
+ }
+ }
+ if (n_read == 0) {
+ b2r2_log_err(b2r2_blt->dev, "%s: No b2r2 cores available.\n",
+ __func__);
+ return -ENOSYS;
+ }
+
+ /* Find which control to ask for a report first */
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) {
+ if (ctl[i] != NULL) {
+ first = ctl[i];
+ first_index = i;
+ break;
+ }
+ }
+ if (!first) {
+ b2r2_log_err(b2r2_blt->dev, "%s: Internal error.\n",
+ __func__);
+ return -ENOSYS;
+ }
+
+ memset(requests, 0, sizeof(*requests) * B2R2_MAX_NBR_DEVICES);
+ /* Read report from core 0 */
+ ret = b2r2_control_read(first, &requests[first_index], block);
+ if (ret <= 0 || requests[0] == NULL) {
+ b2r2_log_err(b2r2_blt->dev, "%s: b2r2_control_read failed.\n",
+ __func__);
+ ret = -EFAULT;
+ goto exit;
+ }
+ core_mask = requests[first_index]->core_mask >> 1;
+ core_mask &= ~(1 << first_index);
+
+ /* If there are any more cores, try reading the report
+ * with the specific ID from the other cores */
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++) {
+ if ((core_mask & 1) && (ctl[i] != NULL)) {
+ /* TODO: Do we need to wait here? */
+ ret = b2r2_control_read_id(ctl[i], &requests[i], block,
+ requests[first_index]->request_id);
+ if (ret <= 0 || requests[i] == NULL) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: b2r2_control_read failed.\n",
+ __func__);
+ break;
+ }
+ }
+ core_mask = core_mask >> 1;
+ }
+
+ if (ret > 0) {
+ /* Construct a report and copy to userland */
+ report.request_id = requests[0]->request_id;
+ report.report1 = requests[0]->user_req.report1;
+ report.report2 = requests[0]->user_req.report2;
+ report.usec_elapsed = 0; /* TBD */
+
+ if (copy_to_user(buf, &report, sizeof(report))) {
+ b2r2_log_err(b2r2_blt->dev,
+ "%s: copy_to_user failed.\n",
+ __func__);
+ ret = -EFAULT;
+ }
+ }
+
+ if (ret > 0) {
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++)
+ /*
+ * Release matching the addref when the job was put
+ * into the report list
+ */
+ if (requests[i] != NULL)
+ b2r2_core_job_release(&requests[i]->job,
+ __func__);
+ } else {
+ /* We failed at one core or copy to user failed */
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++)
+ if (requests[i] != NULL)
+ list_add(&requests[i]->list,
+ &ctl[i]->report_list);
+ goto exit;
+ }
+
+ ret = count;
+
+exit:
+ /* Release the handles to the core controls */
+ release_control_instances(ctl, n_read);
+
+ return ret;
+}
+
+/**
+ * b2r2_blt_fops - File operations for b2r2_blt
+ */
+static const struct file_operations b2r2_blt_fops = {
+ .owner = THIS_MODULE,
+ .open = b2r2_blt_open_us,
+ .release = b2r2_blt_release_us,
+ .unlocked_ioctl = b2r2_blt_ioctl_us,
+ .poll = b2r2_blt_poll_us,
+ .read = b2r2_blt_read_us,
+};
+
+
+/**
+ * b2r2_probe() - This routine loads the B2R2 core driver
+ *
+ * @pdev: platform device.
+ */
+static int b2r2_blt_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+ int i;
+
+ BUG_ON(pdev == NULL);
+
+ dev_info(&pdev->dev, "%s start.\n", __func__);
+
+ if (!b2r2_blt) {
+ b2r2_blt = kzalloc(sizeof(*b2r2_blt), GFP_KERNEL);
+ if (!b2r2_blt) {
+ dev_err(&pdev->dev, "b2r2_blt alloc failed\n");
+ ret = -EINVAL;
+ goto error_exit;
+ }
+
+ /* Init b2r2 core control reference counters */
+ for (i = 0; i < B2R2_MAX_NBR_DEVICES; i++)
+ spin_lock_init(&b2r2_controls[i].lock);
+ }
+
+ mutex_init(&b2r2_blt->datas_lock);
+ spin_lock_init(&b2r2_blt->lock);
+ b2r2_blt->dev = &pdev->dev;
+
+ /* Register b2r2 driver */
+ b2r2_blt->miscdev.parent = b2r2_blt->dev;
+ b2r2_blt->miscdev.minor = MISC_DYNAMIC_MINOR;
+ b2r2_blt->miscdev.name = "b2r2_blt";
+ b2r2_blt->miscdev.fops = &b2r2_blt_fops;
+
+ ret = misc_register(&b2r2_blt->miscdev);
+ if (ret != 0) {
+ printk(KERN_WARNING "%s: registering misc device fails\n",
+ __func__);
+ goto error_exit;
+ }
+
+ b2r2_blt->dev = b2r2_blt->miscdev.this_device;
+ b2r2_blt->dev->coherent_dma_mask = 0xFFFFFFFF;
+
+ kref_init(&blt_refcount);
+
+ dev_info(&pdev->dev, "%s done.\n", __func__);
+
+ return ret;
+
+/** Recover from any error if something fails */
+error_exit:
+
+ kfree(b2r2_blt);
+
+ dev_info(&pdev->dev, "%s done with errors (%d).\n", __func__, ret);
+
+ return ret;
+}
+
+/**
+ * b2r2_blt_remove - This routine unloads b2r2_blt driver
+ *
+ * @pdev: platform device.
+ */
+static int b2r2_blt_remove(struct platform_device *pdev)
+{
+ BUG_ON(pdev == NULL);
+ dev_info(&pdev->dev, "%s started.\n", __func__);
+ misc_deregister(&b2r2_blt->miscdev);
+ kref_put(&blt_refcount, b2r2_blt_release);
+ return 0;
+}
+
+/**
+ * b2r2_blt_suspend() - This routine puts the B2R2 blitter in to sustend state.
+ * @pdev: platform device.
+ *
+ * This routine stores the current state of the b2r2 device and puts in to
+ * suspend state.
+ *
+ */
+int b2r2_blt_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+/**
+ * b2r2_blt_resume() - This routine resumes the B2R2 blitter from sustend state.
+ * @pdev: platform device.
+ *
+ * This routine restore back the current state of the b2r2 device resumes.
+ *
+ */
+int b2r2_blt_resume(struct platform_device *pdev)
+{
+ return 0;
+}
+
+/**
+ * struct platform_b2r2_driver - Platform driver configuration for the
+ * B2R2 core driver
+ */
+static struct platform_driver platform_b2r2_blt_driver = {
+ .remove = b2r2_blt_remove,
+ .driver = {
+ .name = "b2r2_blt",
+ },
+ .suspend = b2r2_blt_suspend,
+ .resume = b2r2_blt_resume,
+};
+
+/**
+ * b2r2_init() - Module init function for the B2R2 core module
+ */
+static int __init b2r2_blt_init(void)
+{
+ printk(KERN_INFO "%s\n", __func__);
+ return platform_driver_probe(&platform_b2r2_blt_driver, b2r2_blt_probe);
+}
+module_init(b2r2_blt_init);
+
+/**
+ * b2r2_exit() - Module exit function for the B2R2 core module
+ */
+static void __exit b2r2_blt_exit(void)
+{
+ printk(KERN_INFO "%s\n", __func__);
+ platform_driver_unregister(&platform_b2r2_blt_driver);
+ return;
+}
+module_exit(b2r2_blt_exit);
+
+MODULE_AUTHOR("Robert Fekete <robert.fekete@stericsson.com>");
+MODULE_DESCRIPTION("ST-Ericsson B2R2 Blitter module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/video/b2r2/b2r2_blt_main.c b/drivers/video/b2r2/b2r2_blt_main.c
index 919de1ef0ee..3727f742bf1 100644
--- a/drivers/video/b2r2/b2r2_blt_main.c
+++ b/drivers/video/b2r2/b2r2_blt_main.c
@@ -36,6 +36,7 @@
#include <linux/hwmem.h>
#include "b2r2_internal.h"
+#include "b2r2_control.h"
#include "b2r2_node_split.h"
#include "b2r2_generic.h"
#include "b2r2_mem_alloc.h"
@@ -60,28 +61,11 @@
* Support read of many report records at once.
*/
-/**
- * b2r2_blt_dev - Our device(s), /dev/b2r2_blt
- */
-static struct b2r2_control *b2r2_ctl[B2R2_MAX_NBR_DEVICES];
-
-/* Debug file system support */
-#ifdef CONFIG_DEBUG_FS
-static int sprintf_req(struct b2r2_blt_request *request, char *buf, int size);
-#endif
-
/* Local functions */
static void inc_stat(struct b2r2_control *cont, unsigned long *stat);
static void dec_stat(struct b2r2_control *cont, unsigned long *stat);
-static int b2r2_blt_synch(struct b2r2_blt_instance *instance,
- int request_id);
-static int b2r2_blt_query_cap(struct b2r2_blt_instance *instance,
- struct b2r2_blt_query_cap *query_cap);
#ifndef CONFIG_B2R2_GENERIC_ONLY
-static int b2r2_blt(struct b2r2_blt_instance *instance,
- struct b2r2_blt_request *request);
-
static void job_callback(struct b2r2_core_job *job);
static void job_release(struct b2r2_core_job *job);
static int job_acquire_resources(struct b2r2_core_job *job, bool atomic);
@@ -89,9 +73,6 @@ static void job_release_resources(struct b2r2_core_job *job, bool atomic);
#endif
#ifdef CONFIG_B2R2_GENERIC
-static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
- struct b2r2_blt_request *request);
-
static void job_callback_gen(struct b2r2_core_job *job);
static void job_release_gen(struct b2r2_core_job *job);
static int job_acquire_resources_gen(struct b2r2_core_job *job, bool atomic);
@@ -109,8 +90,8 @@ static void unresolve_buf(struct b2r2_control *cont,
static void sync_buf(struct b2r2_control *cont, struct b2r2_blt_img *img,
struct b2r2_resolved_buf *resolved, bool is_dst,
struct b2r2_blt_rect *rect);
-static bool is_report_list_empty(struct b2r2_blt_instance *instance);
-static bool is_synching(struct b2r2_blt_instance *instance);
+static bool is_report_list_empty(struct b2r2_control_instance *instance);
+static bool is_synching(struct b2r2_control_instance *instance);
static void get_actual_dst_rect(struct b2r2_blt_req *req,
struct b2r2_blt_rect *actual_dst_rect);
static void set_up_hwmem_region(struct b2r2_control *cont,
@@ -196,39 +177,18 @@ static void clean_l1_cache_range_all_cpus(struct sync_args *sa)
*
* A B2R2 BLT instance is created and stored in the file structure.
*/
-static int b2r2_blt_open(struct inode *inode, struct file *filp)
+int b2r2_control_open(struct b2r2_control_instance *instance)
{
int ret = 0;
- struct b2r2_blt_instance *instance;
- struct b2r2_control *cont = filp->private_data;
+ struct b2r2_control *cont = instance->control;
b2r2_log_info(cont->dev, "%s\n", __func__);
-
inc_stat(cont, &cont->stat_n_in_open);
- /* Allocate and initialize the instance */
- instance = (struct b2r2_blt_instance *)
- kmalloc(sizeof(*instance), GFP_KERNEL);
- if (!instance) {
- b2r2_log_err(cont->dev, "%s: Failed to alloc\n", __func__);
- goto instance_alloc_failed;
- }
- memset(instance, 0, sizeof(*instance));
INIT_LIST_HEAD(&instance->report_list);
mutex_init(&instance->lock);
init_waitqueue_head(&instance->report_list_waitq);
init_waitqueue_head(&instance->synch_done_waitq);
- instance->control = cont;
-
- /*
- * Remember the instance so that we can retrieve it in
- * other functions
- */
- filp->private_data = instance;
- goto out;
-
-instance_alloc_failed:
-out:
dec_stat(cont, &cont->stat_n_in_open);
return ret;
@@ -244,11 +204,9 @@ out:
* All active jobs are finished or cancelled and allocated data
* is released.
*/
-static int b2r2_blt_release(struct inode *inode, struct file *filp)
+int b2r2_control_release(struct b2r2_control_instance *instance)
{
int ret;
- struct b2r2_blt_instance *instance =
- (struct b2r2_blt_instance *) filp->private_data;
struct b2r2_control *cont = instance->control;
b2r2_log_info(cont->dev, "%s\n", __func__);
@@ -256,7 +214,7 @@ static int b2r2_blt_release(struct inode *inode, struct file *filp)
inc_stat(cont, &cont->stat_n_in_release);
/* Finish all outstanding requests */
- ret = b2r2_blt_synch(instance, 0);
+ ret = b2r2_control_synch(instance, 0);
if (ret < 0)
b2r2_log_warn(cont->dev, "%s: b2r2_blt_sync failed with %d\n",
__func__, ret);
@@ -301,296 +259,68 @@ static int b2r2_blt_release(struct inode *inode, struct file *filp)
}
mutex_unlock(&instance->lock);
- /* Release our instance */
- kfree(instance);
-
dec_stat(cont, &cont->stat_n_in_release);
return 0;
}
-/**
- * b2r2_blt_ioctl - This routine implements b2r2_blt ioctl interface
- *
- * @file: file pointer.
- * @cmd :ioctl command.
- * @arg: input argument for ioctl.
- *
- * Returns 0 if OK else negative error code
- */
-static long b2r2_blt_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
+size_t b2r2_control_read(struct b2r2_control_instance *instance,
+ struct b2r2_blt_request **request_out, bool block)
{
- int ret = 0;
- struct b2r2_blt_instance *instance =
- (struct b2r2_blt_instance *) file->private_data;
+ struct b2r2_blt_request *request = NULL;
+#ifdef CONFIG_B2R2_DEBUG
struct b2r2_control *cont = instance->control;
-
- /** Process actual ioctl */
- b2r2_log_info(cont->dev, "%s\n", __func__);
-
- /* Get the instance from the file structure */
- switch (cmd) {
- case B2R2_BLT_IOC: {
- /* This is the "blit" command */
-
- /* arg is user pointer to struct b2r2_blt_request */
- struct b2r2_blt_request *request =
- kmalloc(sizeof(*request), GFP_KERNEL);
- if (!request) {
- b2r2_log_err(cont->dev, "%s: Failed to alloc mem\n",
- __func__);
- return -ENOMEM;
- }
-
- /* Initialize the structure */
- memset(request, 0, sizeof(*request));
- INIT_LIST_HEAD(&request->list);
- request->instance = instance;
-
- /*
- * The user request is a sub structure of the
- * kernel request structure.
- */
-
- /* Get the user data */
- if (copy_from_user(&request->user_req, (void *)arg,
- sizeof(request->user_req))) {
- b2r2_log_err(cont->dev, "%s: copy_from_user failed\n",
- __func__);
- kfree(request);
- return -EFAULT;
- }
-
- if (!b2r2_validate_user_req(cont, &request->user_req)) {
- kfree(request);
- return -EINVAL;
- }
-
- request->profile = is_profiler_registered_approx();
-
- /*
- * If the user specified a color look-up table,
- * make a copy that the HW can use.
- */
- if ((request->user_req.flags &
- B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION) != 0) {
- request->clut = dma_alloc_coherent(cont->dev,
- CLUT_SIZE, &(request->clut_phys_addr),
- GFP_DMA | GFP_KERNEL);
- if (request->clut == NULL) {
- b2r2_log_err(cont->dev, "%s CLUT allocation "
- "failed.\n", __func__);
- kfree(request);
- return -ENOMEM;
- }
-
- if (copy_from_user(request->clut,
- request->user_req.clut, CLUT_SIZE)) {
- b2r2_log_err(cont->dev, "%s: CLUT "
- "copy_from_user failed\n",
- __func__);
- dma_free_coherent(cont->dev, CLUT_SIZE,
- request->clut,
- request->clut_phys_addr);
- request->clut = NULL;
- request->clut_phys_addr = 0;
- kfree(request);
- return -EFAULT;
- }
- }
-
- /* Perform the blit */
-
-#ifdef CONFIG_B2R2_GENERIC_ONLY
- /* Use the generic path for all operations */
- ret = b2r2_generic_blt(instance, request);
-#else
- /* Use the optimized path */
- ret = b2r2_blt(instance, request);
#endif
-#ifdef CONFIG_B2R2_GENERIC_FALLBACK
- /* Fall back to generic path if operation was not supported */
- if (ret == -ENOSYS) {
- struct b2r2_blt_request *request_gen;
-
- if (request->user_req.flags & B2R2_BLT_FLAG_BG_BLEND) {
- /* No support for BG BLEND in generic
- * implementation yet */
- b2r2_log_warn(cont->dev, "%s: Unsupported: "
- "Background blend in b2r2_generic_blt\n",
- __func__);
- return ret;
- }
-
- b2r2_log_info(cont->dev,
- "b2r2_blt=%d Going generic.\n", ret);
- request_gen = kmalloc(sizeof(*request_gen), GFP_KERNEL);
- if (!request_gen) {
- b2r2_log_err(cont->dev,
- "%s: Failed to alloc mem for "
- "request_gen\n", __func__);
- return -ENOMEM;
- }
-
- /* Initialize the structure */
- memset(request_gen, 0, sizeof(*request_gen));
- INIT_LIST_HEAD(&request_gen->list);
- request_gen->instance = instance;
-
- /*
- * The user request is a sub structure of the
- * kernel request structure.
- */
-
- /* Get the user data */
- if (copy_from_user(&request_gen->user_req, (void *)arg,
- sizeof(request_gen->user_req))) {
- b2r2_log_err(cont->dev, "%s: copy_from_user "
- "failed\n", __func__);
- kfree(request_gen);
- return -EFAULT;
- }
+ b2r2_log_info(cont->dev, "%s\n", __func__);
- /*
- * If the user specified a color look-up table,
- * make a copy that the HW can use.
- */
- if ((request_gen->user_req.flags &
- B2R2_BLT_FLAG_CLUT_COLOR_CORRECTION)
- != 0) {
- request_gen->clut = dma_alloc_coherent(
- cont->dev, CLUT_SIZE,
- &(request_gen->clut_phys_addr),
- GFP_DMA | GFP_KERNEL);
- if (request_gen->clut == NULL) {
- b2r2_log_err(cont->dev, "%s CLUT "
- "allocation failed.\n",
- __func__);
- kfree(request_gen);
- return -ENOMEM;
- }
-
- if (copy_from_user(request_gen->clut,
- request_gen->user_req.clut,
- CLUT_SIZE)) {
- b2r2_log_err(cont->dev, "%s: CLUT"
- " copy_from_user failed\n",
- __func__);
- dma_free_coherent(cont->dev, CLUT_SIZE,
- request_gen->clut,
- request_gen->clut_phys_addr);
- request_gen->clut = NULL;
- request_gen->clut_phys_addr = 0;
- kfree(request_gen);
- return -EFAULT;
- }
- }
+ /*
+ * Loop and wait here until we have anything to return or
+ * until interrupted
+ */
+ mutex_lock(&instance->lock);
+ while (list_empty(&instance->report_list)) {
+ mutex_unlock(&instance->lock);
- request_gen->profile = is_profiler_registered_approx();
+ /* Return if non blocking read */
+ if (!block)
+ return -EAGAIN;
- ret = b2r2_generic_blt(instance, request_gen);
- b2r2_log_info(cont->dev, "\nb2r2_generic_blt=%d "
- "Generic done.\n", ret);
- }
-#endif /* CONFIG_B2R2_GENERIC_FALLBACK */
+ b2r2_log_info(cont->dev, "%s - Going to sleep\n", __func__);
+ if (wait_event_interruptible(
+ instance->report_list_waitq,
+ !is_report_list_empty(instance)))
+ /* signal: tell the fs layer to handle it */
+ return -ERESTARTSYS;
- break;
+ /* Otherwise loop, but first reaquire the lock */
+ mutex_lock(&instance->lock);
}
- case B2R2_BLT_SYNCH_IOC:
- /* arg is request_id */
- ret = b2r2_blt_synch(instance, (int) arg);
- break;
-
- case B2R2_BLT_QUERY_CAP_IOC:
- {
- /* Arg is struct b2r2_blt_query_cap */
- struct b2r2_blt_query_cap query_cap;
-
- /* Get the user data */
- if (copy_from_user(&query_cap, (void *)arg,
- sizeof(query_cap))) {
- b2r2_log_err(cont->dev, "%s: copy_from_user failed\n",
- __func__);
- return -EFAULT;
- }
-
- /* Fill in our capabilities */
- ret = b2r2_blt_query_cap(instance, &query_cap);
-
- /* Return data to user */
- if (copy_to_user((void *)arg, &query_cap,
- sizeof(query_cap))) {
- b2r2_log_err(cont->dev, "%s: copy_to_user failed\n",
- __func__);
- return -EFAULT;
- }
- break;
- }
+ if (!list_empty(&instance->report_list))
+ request = list_first_entry(
+ &instance->report_list, struct b2r2_blt_request, list);
- default:
- /* Unknown command */
- b2r2_log_err(cont->dev, "%s: Unknown cmd %d\n", __func__, cmd);
- ret = -EINVAL;
- break;
+ if (request) {
+ /* Remove from list to avoid reading twice */
+ list_del_init(&request->list);
+ *request_out = request;
}
-
- if (ret < 0)
- b2r2_log_err(cont->dev, "EC %d OK!\n", -ret);
-
- return ret;
-}
-
-/**
- * b2r2_blt_poll - Support for user-space poll, select & epoll.
- * Used for user-space callback
- *
- * @filp: File to poll on
- * @wait: Poll table to wait on
- *
- * This function checks if there are anything to read
- */
-static unsigned b2r2_blt_poll(struct file *filp, poll_table *wait)
-{
- struct b2r2_blt_instance *instance =
- (struct b2r2_blt_instance *) filp->private_data;
- unsigned int mask = 0;
-#ifdef CONFIG_B2R2_DEBUG
- struct b2r2_control *cont = instance->control;
-#endif
-
- b2r2_log_info(cont->dev, "%s\n", __func__);
-
- poll_wait(filp, &instance->report_list_waitq, wait);
- mutex_lock(&instance->lock);
- if (!list_empty(&instance->report_list))
- mask |= POLLIN | POLLRDNORM;
mutex_unlock(&instance->lock);
- return mask;
+ if (request)
+ return 1;
+
+ /* No report returned */
+ return 0;
}
-/**
- * b2r2_blt_read - Read report data, user for user-space callback
- *
- * @filp: File pointer
- * @buf: User space buffer
- * @count: Number of bytes to read
- * @f_pos: File position
- *
- * Returns number of bytes read or negative error code
- */
-static ssize_t b2r2_blt_read(struct file *filp, char __user *buf, size_t count,
- loff_t *f_pos)
+size_t b2r2_control_read_id(struct b2r2_control_instance *instance,
+ struct b2r2_blt_request **request_out, bool block,
+ int request_id)
{
- int ret = 0;
struct b2r2_blt_request *request = NULL;
- struct b2r2_blt_report report;
- struct b2r2_blt_instance *instance =
- (struct b2r2_blt_instance *) filp->private_data;
#ifdef CONFIG_B2R2_DEBUG
struct b2r2_control *cont = instance->control;
#endif
@@ -598,17 +328,6 @@ static ssize_t b2r2_blt_read(struct file *filp, char __user *buf, size_t count,
b2r2_log_info(cont->dev, "%s\n", __func__);
/*
- * We return only complete report records, one at a time.
- * Might be more efficient to support read of many.
- */
- count = (count / sizeof(struct b2r2_blt_report)) *
- sizeof(struct b2r2_blt_report);
- if (count > sizeof(struct b2r2_blt_report))
- count = sizeof(struct b2r2_blt_report);
- if (count == 0)
- return count;
-
- /*
* Loop and wait here until we have anything to return or
* until interrupted
*/
@@ -617,7 +336,7 @@ static ssize_t b2r2_blt_read(struct file *filp, char __user *buf, size_t count,
mutex_unlock(&instance->lock);
/* Return if non blocking read */
- if (filp->f_flags & O_NONBLOCK)
+ if (!block)
return -EAGAIN;
b2r2_log_info(cont->dev, "%s - Going to sleep\n", __func__);
@@ -631,55 +350,28 @@ static ssize_t b2r2_blt_read(struct file *filp, char __user *buf, size_t count,
mutex_lock(&instance->lock);
}
- if (!list_empty(&instance->report_list))
- request = list_first_entry(
- &instance->report_list, struct b2r2_blt_request, list);
+ if (!list_empty(&instance->report_list)) {
+ struct b2r2_blt_request *pos;
+ list_for_each_entry(pos, &instance->report_list, list) {
+ if (pos->request_id)
+ request = pos;
+ }
+ }
if (request) {
/* Remove from list to avoid reading twice */
list_del_init(&request->list);
-
- report.request_id = request->request_id;
- report.report1 = request->user_req.report1;
- report.report2 = request->user_req.report2;
- report.usec_elapsed = 0; /* TBD */
-
- mutex_unlock(&instance->lock);
- if (copy_to_user(buf, &report, sizeof(report)))
- ret = -EFAULT;
- mutex_lock(&instance->lock);
-
- if (ret < 0) {
- /* copy to user failed, re-insert into list */
- list_add(&request->list,
- &request->instance->report_list);
- request = NULL;
- }
+ *request_out = request;
}
mutex_unlock(&instance->lock);
if (request)
- /*
- * Release matching the addref when the job was put into
- * the report list
- */
- b2r2_core_job_release(&request->job, __func__);
+ return 1;
- return count;
+ /* No report returned */
+ return 0;
}
-/**
- * b2r2_blt_fops - File operations for b2r2_blt
- */
-static const struct file_operations b2r2_blt_fops = {
- .owner = THIS_MODULE,
- .open = b2r2_blt_open,
- .release = b2r2_blt_release,
- .unlocked_ioctl = b2r2_blt_ioctl,
- .poll = b2r2_blt_poll,
- .read = b2r2_blt_read,
-};
-
#ifndef CONFIG_B2R2_GENERIC_ONLY
/**
* b2r2_blt - Implementation of the B2R2 blit request
@@ -687,14 +379,14 @@ static const struct file_operations b2r2_blt_fops = {
* @instance: The B2R2 BLT instance
* @request; The request to perform
*/
-static int b2r2_blt(struct b2r2_blt_instance *instance,
- struct b2r2_blt_request *request)
+int b2r2_control_blt(struct b2r2_blt_request *request)
{
int ret = 0;
struct b2r2_blt_rect actual_dst_rect;
int request_id = 0;
struct b2r2_node *last_node = request->first_node;
int node_count;
+ struct b2r2_control_instance *instance = request->instance;
struct b2r2_control *cont = instance->control;
u32 thread_runtime_at_start = 0;
@@ -918,6 +610,7 @@ static int b2r2_blt(struct b2r2_blt_instance *instance,
last_node = last_node->next;
request->job.tag = (int) instance;
+ request->job.data = (int) cont->data;
request->job.prio = request->user_req.prio;
request->job.first_node_address =
request->first_node->physical_address;
@@ -1010,33 +703,6 @@ static int b2r2_blt(struct b2r2_blt_instance *instance,
instance->no_of_active_requests++;
mutex_unlock(&instance->lock);
- /* Wait for the job to be done if synchronous */
- if ((request->user_req.flags & B2R2_BLT_FLAG_ASYNCH) == 0) {
- b2r2_log_info(cont->dev, "%s: Synchronous, waiting\n",
- __func__);
-
- inc_stat(cont, &cont->stat_n_in_blt_wait);
-
- ret = b2r2_core_job_wait(&request->job);
-
- dec_stat(cont, &cont->stat_n_in_blt_wait);
-
- if (ret < 0 && ret != -ENOENT)
- b2r2_log_warn(cont->dev, "%s: Failed to wait job,"
- " ret = %d\n", __func__, ret);
- else
- b2r2_log_info(cont->dev, "%s: Synchronous wait done\n",
- __func__);
- ret = 0;
- }
-
- /*
- * Release matching the addref in b2r2_core_job_add,
- * the request must not be accessed after this call
- */
- b2r2_core_job_release(&request->job, __func__);
- dec_stat(cont, &cont->stat_n_in_blt);
-
return ret >= 0 ? request_id : ret;
job_add_failed:
@@ -1057,17 +723,52 @@ resolve_bg_buf_failed:
&request->src_resolved);
resolve_src_buf_failed:
synch_interrupted:
- job_release(&request->job);
- dec_stat(cont, &cont->stat_n_jobs_released);
if ((request->user_req.flags & B2R2_BLT_FLAG_DRY_RUN) == 0 || ret)
b2r2_log_warn(cont->dev, "%s returns with error %d\n",
__func__, ret);
+ job_release(&request->job);
+ dec_stat(cont, &cont->stat_n_jobs_released);
dec_stat(cont, &cont->stat_n_in_blt);
return ret;
}
+int b2r2_control_waitjob(struct b2r2_blt_request *request)
+{
+ int ret = 0;
+ struct b2r2_control_instance *instance = request->instance;
+ struct b2r2_control *cont = instance->control;
+
+ /* Wait for the job to be done if synchronous */
+ if ((request->user_req.flags & B2R2_BLT_FLAG_ASYNCH) == 0) {
+ b2r2_log_info(cont->dev, "%s: Synchronous, waiting\n",
+ __func__);
+
+ inc_stat(cont, &cont->stat_n_in_blt_wait);
+
+ ret = b2r2_core_job_wait(&request->job);
+
+ dec_stat(cont, &cont->stat_n_in_blt_wait);
+
+ if (ret < 0 && ret != -ENOENT)
+ b2r2_log_warn(cont->dev, "%s: Failed to wait job,"
+ " ret = %d\n", __func__, ret);
+ else
+ b2r2_log_info(cont->dev, "%s: Synchronous wait done\n",
+ __func__);
+ }
+
+ /*
+ * Release matching the addref in b2r2_core_job_add,
+ * the request must not be accessed after this call
+ */
+ b2r2_core_job_release(&request->job, __func__);
+ dec_stat(cont, &cont->stat_n_in_blt);
+
+ return ret;
+}
+
/**
* Called when job is done or cancelled
*
@@ -1075,9 +776,13 @@ synch_interrupted:
*/
static void job_callback(struct b2r2_core_job *job)
{
- struct b2r2_blt_request *request =
- container_of(job, struct b2r2_blt_request, job);
- struct b2r2_control *cont = request->instance->control;
+ struct b2r2_blt_request *request = NULL;
+ struct b2r2_core *core = NULL;
+ struct b2r2_control *cont = NULL;
+
+ request = container_of(job, struct b2r2_blt_request, job);
+ core = (struct b2r2_core *) job->data;
+ cont = core->control;
if (cont->dev)
b2r2_log_info(cont->dev, "%s\n", __func__);
@@ -1098,6 +803,8 @@ static void job_callback(struct b2r2_core_job *job)
/* Move to report list if the job shall be reported */
/* FIXME: Use a smaller struct? */
+ /* TODO: In the case of kernel API call, feed an asynch task to the
+ * instance worker (kthread) instead of polling for a report */
mutex_lock(&request->instance->lock);
if (request->user_req.flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) {
/* Move job to report list */
@@ -1163,9 +870,13 @@ static void job_callback(struct b2r2_core_job *job)
*/
static void job_release(struct b2r2_core_job *job)
{
- struct b2r2_blt_request *request =
- container_of(job, struct b2r2_blt_request, job);
- struct b2r2_control *cont = request->instance->control;
+ struct b2r2_blt_request *request = NULL;
+ struct b2r2_core *core = NULL;
+ struct b2r2_control *cont = NULL;
+
+ request = container_of(job, struct b2r2_blt_request, job);
+ core = (struct b2r2_core *) job->data;
+ cont = core->control;
inc_stat(cont, &cont->stat_n_jobs_released);
@@ -1206,7 +917,8 @@ static int job_acquire_resources(struct b2r2_core_job *job, bool atomic)
{
struct b2r2_blt_request *request =
container_of(job, struct b2r2_blt_request, job);
- struct b2r2_control *cont = request->instance->control;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
+ struct b2r2_control *cont = core->control;
int ret;
int i;
@@ -1280,7 +992,8 @@ static void job_release_resources(struct b2r2_core_job *job, bool atomic)
{
struct b2r2_blt_request *request =
container_of(job, struct b2r2_blt_request, job);
- struct b2r2_control *cont = request->instance->control;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
+ struct b2r2_control *cont = core->control;
int i;
b2r2_log_info(cont->dev, "%s\n", __func__);
@@ -1323,9 +1036,9 @@ static void job_release_resources(struct b2r2_core_job *job, bool atomic)
static void tile_job_callback_gen(struct b2r2_core_job *job)
{
#ifdef CONFIG_B2R2_DEBUG
- struct b2r2_blt_instance *instance =
- (struct b2r2_blt_instance *) job->tag;
- struct b2r2_control *cont = instance->control;
+ struct b2r2_core *core =
+ (struct b2r2_core *) job->data;
+ struct b2r2_control *cont = core->control;
#endif
b2r2_log_info(cont->dev, "%s\n", __func__);
@@ -1355,7 +1068,8 @@ static void job_callback_gen(struct b2r2_core_job *job)
{
struct b2r2_blt_request *request =
container_of(job, struct b2r2_blt_request, job);
- struct b2r2_control *cont = request->instance->control;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
+ struct b2r2_control *cont = core->control;
b2r2_log_info(cont->dev, "%s\n", __func__);
@@ -1372,8 +1086,9 @@ static void job_callback_gen(struct b2r2_core_job *job)
/* Move to report list if the job shall be reported */
/* FIXME: Use a smaller struct? */
+ /* TODO: In the case of kernel API call, feed an asynch task to the
+ * instance worker (kthread) instead of polling for a report */
mutex_lock(&request->instance->lock);
-
if (request->user_req.flags & B2R2_BLT_FLAG_REPORT_WHEN_DONE) {
/* Move job to report list */
list_add_tail(&request->list,
@@ -1398,7 +1113,7 @@ static void job_callback_gen(struct b2r2_core_job *job)
BUG_ON(request->instance->no_of_active_requests == 0);
request->instance->no_of_active_requests--;
if (request->instance->synching &&
- request->instance->no_of_active_requests == 0) {
+ request->instance->no_of_active_requests == 0) {
request->instance->synching = false;
/* Wake up all syncing */
@@ -1438,9 +1153,9 @@ static void job_callback_gen(struct b2r2_core_job *job)
static void tile_job_release_gen(struct b2r2_core_job *job)
{
- struct b2r2_blt_instance *instance =
- (struct b2r2_blt_instance *) job->tag;
- struct b2r2_control *cont = instance->control;
+ struct b2r2_core *core =
+ (struct b2r2_core *) job->data;
+ struct b2r2_control *cont = core->control;
inc_stat(cont, &cont->stat_n_jobs_released);
@@ -1462,7 +1177,8 @@ static void job_release_gen(struct b2r2_core_job *job)
{
struct b2r2_blt_request *request =
container_of(job, struct b2r2_blt_request, job);
- struct b2r2_control *cont = request->instance->control;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
+ struct b2r2_control *cont = core->control;
inc_stat(cont, &cont->stat_n_jobs_released);
@@ -1503,11 +1219,9 @@ static void job_release_resources_gen(struct b2r2_core_job *job, bool atomic)
/**
* b2r2_generic_blt - Generic implementation of the B2R2 blit request
*
- * @instance: The B2R2 BLT instance
* @request; The request to perform
*/
-static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
- struct b2r2_blt_request *request)
+int b2r2_generic_blt(struct b2r2_blt_request *request)
{
int ret = 0;
struct b2r2_blt_rect actual_dst_rect;
@@ -1527,6 +1241,7 @@ static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
struct b2r2_work_buf work_bufs[4];
struct b2r2_blt_rect dst_rect_tile;
int i;
+ struct b2r2_control_instance *instance = request->instance;
struct b2r2_control *cont = instance->control;
u32 thread_runtime_at_start = 0;
@@ -1754,6 +1469,7 @@ static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
last_node = last_node->next;
request->job.tag = (int) instance;
+ request->job.data = (int) cont->data;
request->job.prio = request->user_req.prio;
request->job.first_node_address =
request->first_node->physical_address;
@@ -1860,7 +1576,9 @@ static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
"(%d, %d)\n", __func__, x, y);
continue;
}
+ tile_job->job_id = request->job.job_id;
tile_job->tag = request->job.tag;
+ tile_job->data = request->job.data;
tile_job->prio = request->job.prio;
tile_job->first_node_address =
request->job.first_node_address;
@@ -1976,7 +1694,9 @@ static int b2r2_generic_blt(struct b2r2_blt_instance *instance,
"(%d, %d)\n", __func__, x, y);
continue;
}
+ tile_job->job_id = request->job.job_id;
tile_job->tag = request->job.tag;
+ tile_job->data = request->job.data;
tile_job->prio = request->job.prio;
tile_job->first_node_address =
request->job.first_node_address;
@@ -2177,7 +1897,7 @@ zero_blt:
* @request_id: If 0, wait for all requests on this instance to finish.
* Else wait for request with given request id to finish.
*/
-static int b2r2_blt_synch(struct b2r2_blt_instance *instance,
+int b2r2_control_synch(struct b2r2_control_instance *instance,
int request_id)
{
int ret = 0;
@@ -2223,19 +1943,6 @@ static int b2r2_blt_synch(struct b2r2_blt_instance *instance,
return ret;
}
-/**
- * Query B2R2 capabilities
- *
- * @instance: The B2R2 BLT instance
- * @query_cap: The structure receiving the capabilities
- */
-static int b2r2_blt_query_cap(struct b2r2_blt_instance *instance,
- struct b2r2_blt_query_cap *query_cap)
-{
- /* FIXME: Not implemented yet */
- return -ENOSYS;
-}
-
static void get_actual_dst_rect(struct b2r2_blt_req *req,
struct b2r2_blt_rect *actual_dst_rect)
{
@@ -2261,12 +1968,12 @@ static void set_up_hwmem_region(struct b2r2_control *cont,
if (b2r2_is_zero_area_rect(rect))
return;
- img_size = b2r2_get_img_size(cont, img);
+ img_size = b2r2_get_img_size(cont->dev, img);
if (b2r2_is_single_plane_fmt(img->fmt) &&
b2r2_is_independent_pixel_fmt(img->fmt)) {
- int img_fmt_bpp = b2r2_get_fmt_bpp(cont, img->fmt);
- u32 img_pitch = b2r2_get_img_pitch(cont, img);
+ int img_fmt_bpp = b2r2_get_fmt_bpp(cont->dev, img->fmt);
+ u32 img_pitch = b2r2_get_img_pitch(cont->dev, img);
region->offset = (u32)(img->buf.offset + (rect->y *
img_pitch));
@@ -2319,8 +2026,9 @@ static int resolve_hwmem(struct b2r2_control *cont,
required_access = (is_dst ? HWMEM_ACCESS_WRITE : HWMEM_ACCESS_READ) |
HWMEM_ACCESS_IMPORT;
if ((required_access & access) != required_access) {
- b2r2_log_info(cont->dev, "%s: Insufficient access to hwmem "
- "buffer.\n", __func__);
+ b2r2_log_info(cont->dev,
+ "%s: Insufficient access to hwmem (%d, requires %d)"
+ "buffer.\n", __func__, access, required_access);
return_value = -EACCES;
goto access_check_failed;
}
@@ -2333,11 +2041,12 @@ static int resolve_hwmem(struct b2r2_control *cont,
}
if (resolved_buf->file_len <
- img->buf.offset + (__u32)b2r2_get_img_size(cont, img)) {
+ img->buf.offset +
+ (__u32)b2r2_get_img_size(cont->dev, img)) {
b2r2_log_info(cont->dev, "%s: Hwmem buffer too small. (%d < "
"%d)\n", __func__, resolved_buf->file_len,
img->buf.offset +
- (__u32)b2r2_get_img_size(cont, img));
+ (__u32)b2r2_get_img_size(cont->dev, img));
return_value = -EINVAL;
goto size_check_failed;
}
@@ -2714,7 +2423,7 @@ static void sync_buf(struct b2r2_control *cont,
*
* @instance: The B2R2 BLT instance
*/
-static bool is_report_list_empty(struct b2r2_blt_instance *instance)
+static bool is_report_list_empty(struct b2r2_control_instance *instance)
{
bool is_empty;
@@ -2730,7 +2439,7 @@ static bool is_report_list_empty(struct b2r2_blt_instance *instance)
*
* @instance: The B2R2 BLT instance
*/
-static bool is_synching(struct b2r2_blt_instance *instance)
+static bool is_synching(struct b2r2_control_instance *instance)
{
bool is_synching;
@@ -2768,213 +2477,6 @@ static void dec_stat(struct b2r2_control *cont, unsigned long *stat)
#ifdef CONFIG_DEBUG_FS
/**
- * sprintf_req() - Builds a string representing the request, for debug
- *
- * @request:Request that should be encoded into a string
- * @buf: Receiving buffer
- * @size: Size of receiving buffer
- *
- * Returns number of characters in string, excluding null terminator
- */
-static int sprintf_req(struct b2r2_blt_request *request, char *buf, int size)
-{
- size_t dev_size = 0;
-
- /* generic request info */
- dev_size += sprintf(buf + dev_size,
- "instance : 0x%08lX\n",
- (unsigned long) request->instance);
- dev_size += sprintf(buf + dev_size,
- "size : %d bytes\n", request->user_req.size);
- dev_size += sprintf(buf + dev_size,
- "flags : 0x%08lX\n",
- (unsigned long) request->user_req.flags);
- dev_size += sprintf(buf + dev_size,
- "transform : %d\n",
- (int) request->user_req.transform);
- dev_size += sprintf(buf + dev_size,
- "prio : %d\n", request->user_req.transform);
- dev_size += sprintf(buf + dev_size,
- "global_alpha : %d\n",
- (int) request->user_req.global_alpha);
- dev_size += sprintf(buf + dev_size,
- "report1 : 0x%08lX\n",
- (unsigned long) request->user_req.report1);
- dev_size += sprintf(buf + dev_size,
- "report2 : 0x%08lX\n",
- (unsigned long) request->user_req.report2);
- dev_size += sprintf(buf + dev_size,
- "request_id : 0x%08lX\n\n",
- (unsigned long) request->request_id);
-
- /* src info */
- dev_size += sprintf(buf + dev_size,
- "src_img.fmt : %#010x\n",
- request->user_req.src_img.fmt);
- dev_size += sprintf(buf + dev_size,
- "src_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d, "
- "offset=%d, len=%d}\n",
- request->user_req.src_img.buf.type,
- request->user_req.src_img.buf.hwmem_buf_name,
- request->user_req.src_img.buf.fd,
- request->user_req.src_img.buf.offset,
- request->user_req.src_img.buf.len);
- dev_size += sprintf(buf + dev_size,
- "src_img : {width=%d, height=%d, pitch=%d}\n",
- request->user_req.src_img.width,
- request->user_req.src_img.height,
- request->user_req.src_img.pitch);
- dev_size += sprintf(buf + dev_size,
- "src_mask.fmt : %#010x\n",
- request->user_req.src_mask.fmt);
- dev_size += sprintf(buf + dev_size,
- "src_mask.buf : {type=%d, hwmem_buf_name=%d, fd=%d,"
- " offset=%d, len=%d}\n",
- request->user_req.src_mask.buf.type,
- request->user_req.src_mask.buf.hwmem_buf_name,
- request->user_req.src_mask.buf.fd,
- request->user_req.src_mask.buf.offset,
- request->user_req.src_mask.buf.len);
- dev_size += sprintf(buf + dev_size,
- "src_mask : {width=%d, height=%d, pitch=%d}\n",
- request->user_req.src_mask.width,
- request->user_req.src_mask.height,
- request->user_req.src_mask.pitch);
- dev_size += sprintf(buf + dev_size,
- "src_rect : {x=%d, y=%d, width=%d, height=%d}\n",
- request->user_req.src_rect.x,
- request->user_req.src_rect.y,
- request->user_req.src_rect.width,
- request->user_req.src_rect.height);
- dev_size += sprintf(buf + dev_size,
- "src_color : 0x%08lX\n\n",
- (unsigned long) request->user_req.src_color);
-
- /* bg info */
- dev_size += sprintf(buf + dev_size,
- "bg_img.fmt : %#010x\n",
- request->user_req.bg_img.fmt);
- dev_size += sprintf(buf + dev_size,
- "bg_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d,"
- " offset=%d, len=%d}\n",
- request->user_req.bg_img.buf.type,
- request->user_req.bg_img.buf.hwmem_buf_name,
- request->user_req.bg_img.buf.fd,
- request->user_req.bg_img.buf.offset,
- request->user_req.bg_img.buf.len);
- dev_size += sprintf(buf + dev_size,
- "bg_img : {width=%d, height=%d, pitch=%d}\n",
- request->user_req.bg_img.width,
- request->user_req.bg_img.height,
- request->user_req.bg_img.pitch);
- dev_size += sprintf(buf + dev_size,
- "bg_rect : {x=%d, y=%d, width=%d, height=%d}\n\n",
- request->user_req.bg_rect.x,
- request->user_req.bg_rect.y,
- request->user_req.bg_rect.width,
- request->user_req.bg_rect.height);
-
- /* dst info */
- dev_size += sprintf(buf + dev_size,
- "dst_img.fmt : %#010x\n",
- request->user_req.dst_img.fmt);
- dev_size += sprintf(buf + dev_size,
- "dst_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d,"
- " offset=%d, len=%d}\n",
- request->user_req.dst_img.buf.type,
- request->user_req.dst_img.buf.hwmem_buf_name,
- request->user_req.dst_img.buf.fd,
- request->user_req.dst_img.buf.offset,
- request->user_req.dst_img.buf.len);
- dev_size += sprintf(buf + dev_size,
- "dst_img : {width=%d, height=%d, pitch=%d}\n",
- request->user_req.dst_img.width,
- request->user_req.dst_img.height,
- request->user_req.dst_img.pitch);
- dev_size += sprintf(buf + dev_size,
- "dst_rect : {x=%d, y=%d, width=%d, height=%d}\n",
- request->user_req.dst_rect.x,
- request->user_req.dst_rect.y,
- request->user_req.dst_rect.width,
- request->user_req.dst_rect.height);
- dev_size += sprintf(buf + dev_size,
- "dst_clip_rect : {x=%d, y=%d, width=%d, height=%d}\n",
- request->user_req.dst_clip_rect.x,
- request->user_req.dst_clip_rect.y,
- request->user_req.dst_clip_rect.width,
- request->user_req.dst_clip_rect.height);
- dev_size += sprintf(buf + dev_size,
- "dst_color : 0x%08lX\n\n",
- (unsigned long) request->user_req.dst_color);
-
- dev_size += sprintf(buf + dev_size,
- "src_resolved.physical : 0x%08lX\n",
- (unsigned long) request->src_resolved.
- physical_address);
- dev_size += sprintf(buf + dev_size,
- "src_resolved.virtual : 0x%08lX\n",
- (unsigned long) request->src_resolved.virtual_address);
- dev_size += sprintf(buf + dev_size,
- "src_resolved.filep : 0x%08lX\n",
- (unsigned long) request->src_resolved.filep);
- dev_size += sprintf(buf + dev_size,
- "src_resolved.filep_physical_start : 0x%08lX\n",
- (unsigned long) request->src_resolved.
- file_physical_start);
- dev_size += sprintf(buf + dev_size,
- "src_resolved.filep_virtual_start : 0x%08lX\n",
- (unsigned long) request->src_resolved.file_virtual_start);
- dev_size += sprintf(buf + dev_size,
- "src_resolved.file_len : %d\n\n",
- request->src_resolved.file_len);
-
- dev_size += sprintf(buf + dev_size,
- "src_mask_resolved.physical : 0x%08lX\n",
- (unsigned long) request->src_mask_resolved.
- physical_address);
- dev_size += sprintf(buf + dev_size,
- "src_mask_resolved.virtual : 0x%08lX\n",
- (unsigned long) request->src_mask_resolved.virtual_address);
- dev_size += sprintf(buf + dev_size,
- "src_mask_resolved.filep : 0x%08lX\n",
- (unsigned long) request->src_mask_resolved.filep);
- dev_size += sprintf(buf + dev_size,
- "src_mask_resolved.filep_physical_start : 0x%08lX\n",
- (unsigned long) request->src_mask_resolved.
- file_physical_start);
- dev_size += sprintf(buf + dev_size,
- "src_mask_resolved.filep_virtual_start : 0x%08lX\n",
- (unsigned long) request->src_mask_resolved.
- file_virtual_start);
- dev_size += sprintf(buf + dev_size,
- "src_mask_resolved.file_len : %d\n\n",
- request->src_mask_resolved.file_len);
-
- dev_size += sprintf(buf + dev_size,
- "dst_resolved.physical : 0x%08lX\n",
- (unsigned long) request->dst_resolved.
- physical_address);
- dev_size += sprintf(buf + dev_size,
- "dst_resolved.virtual : 0x%08lX\n",
- (unsigned long) request->dst_resolved.virtual_address);
- dev_size += sprintf(buf + dev_size,
- "dst_resolved.filep : 0x%08lX\n",
- (unsigned long) request->dst_resolved.filep);
- dev_size += sprintf(buf + dev_size,
- "dst_resolved.filep_physical_start : 0x%08lX\n",
- (unsigned long) request->dst_resolved.
- file_physical_start);
- dev_size += sprintf(buf + dev_size,
- "dst_resolved.filep_virtual_start : 0x%08lX\n",
- (unsigned long) request->dst_resolved.file_virtual_start);
- dev_size += sprintf(buf + dev_size,
- "dst_resolved.file_len : %d\n\n",
- request->dst_resolved.file_len);
-
- return dev_size;
-}
-
-/**
* debugfs_b2r2_blt_request_read() - Implements debugfs read for B2R2 register
*
* @filp: File pointer
@@ -3246,27 +2748,12 @@ static void destroy_tmp_bufs(struct b2r2_control *cont)
*
* Returns 0 if OK else negative error code
*/
-int b2r2_blt_module_init(struct b2r2_control *cont)
+int b2r2_control_init(struct b2r2_control *cont)
{
int ret;
mutex_init(&cont->stat_lock);
- /* Register b2r2 driver */
- cont->miscdev.minor = MISC_DYNAMIC_MINOR;
- cont->miscdev.name = cont->name;
- cont->miscdev.fops = &b2r2_blt_fops;
-
- ret = misc_register(&cont->miscdev);
- if (ret) {
- printk(KERN_WARNING "%s: registering misc device fails\n",
- __func__);
- goto b2r2_misc_register_fail;
- }
-
- cont->dev = cont->miscdev.this_device;
- dev_set_drvdata(cont->dev, cont);
-
#ifdef CONFIG_B2R2_GENERIC
/* Initialize generic path */
b2r2_generic_init(cont);
@@ -3280,11 +2767,6 @@ int b2r2_blt_module_init(struct b2r2_control *cont)
b2r2_log_info(cont->dev, "%s: device registered\n", __func__);
- /*
- * FIXME: This stuff should be done before the first requests i.e.
- * before misc_register, but they need the device which is not
- * available until after misc_register.
- */
cont->dev->coherent_dma_mask = 0xFFFFFFFF;
init_tmp_bufs(cont);
ret = b2r2_filters_init(cont);
@@ -3315,7 +2797,6 @@ int b2r2_blt_module_init(struct b2r2_control *cont)
}
#endif
- b2r2_ctl[cont->id] = cont;
b2r2_log_info(cont->dev, "%s: done\n", __func__);
return ret;
@@ -3328,15 +2809,13 @@ b2r2_node_split_init_fail:
#ifdef CONFIG_B2R2_GENERIC
b2r2_generic_exit(cont);
#endif
- misc_deregister(&cont->miscdev);
-b2r2_misc_register_fail:
return ret;
}
/**
- * b2r2_module_exit() - Module exit function
+ * b2r2_control_exit() - Module exit function
*/
-void b2r2_blt_module_exit(struct b2r2_control *cont)
+void b2r2_control_exit(struct b2r2_control *cont)
{
if (cont) {
b2r2_log_info(cont->dev, "%s\n", __func__);
@@ -3348,8 +2827,6 @@ void b2r2_blt_module_exit(struct b2r2_control *cont)
#endif
b2r2_mem_exit(cont);
destroy_tmp_bufs(cont);
- b2r2_ctl[cont->id] = NULL;
- misc_deregister(&cont->miscdev);
b2r2_node_split_exit(cont);
#if defined(CONFIG_B2R2_GENERIC)
b2r2_generic_exit(cont);
diff --git a/drivers/video/b2r2/b2r2_control.h b/drivers/video/b2r2/b2r2_control.h
new file mode 100644
index 00000000000..d13d2188618
--- /dev/null
+++ b/drivers/video/b2r2/b2r2_control.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) ST-Ericsson SA 2012
+ *
+ * ST-Ericsson B2R2 internal definitions
+ *
+ * Author: Jorgen Nilsson <jorgen.nilsson@stericsson.com>
+ * for ST-Ericsson.
+ *
+ * License terms: GNU General Public License (GPL), version 2.
+ */
+
+#ifndef _LINUX_DRIVERS_VIDEO_B2R2_CONTROL_H_
+#define _LINUX_DRIVERS_VIDEO_B2R2_CONTROL_H_
+
+#include "b2r2_internal.h"
+
+int b2r2_control_init(struct b2r2_control *cont);
+void b2r2_control_exit(struct b2r2_control *cont);
+int b2r2_control_open(struct b2r2_control_instance *instance);
+int b2r2_control_release(struct b2r2_control_instance *instance);
+
+int b2r2_control_blt(struct b2r2_blt_request *request);
+int b2r2_generic_blt(struct b2r2_blt_request *request);
+int b2r2_control_waitjob(struct b2r2_blt_request *request);
+int b2r2_control_synch(struct b2r2_control_instance *instance,
+ int request_id);
+size_t b2r2_control_read(struct b2r2_control_instance *instance,
+ struct b2r2_blt_request **request_out, bool block);
+size_t b2r2_control_read_id(struct b2r2_control_instance *instance,
+ struct b2r2_blt_request **request_out, bool block,
+ int request_id);
+
+#endif
diff --git a/drivers/video/b2r2/b2r2_core.c b/drivers/video/b2r2/b2r2_core.c
index ed5f52598da..02071d5f989 100644
--- a/drivers/video/b2r2/b2r2_core.c
+++ b/drivers/video/b2r2/b2r2_core.c
@@ -48,73 +48,18 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/kref.h>
#include "b2r2_internal.h"
#include "b2r2_core.h"
#include "b2r2_global.h"
#include "b2r2_structures.h"
-#include "b2r2_internal.h"
+#include "b2r2_control.h"
#include "b2r2_profiler_api.h"
#include "b2r2_timing.h"
#include "b2r2_debug.h"
/**
- * B2R2_DRIVER_TIMEOUT_VALUE - Busy loop timeout after soft reset
- */
-#define B2R2_DRIVER_TIMEOUT_VALUE (1500)
-
-/**
- * B2R2_CLK_FLAG - Value to write into clock reg to turn clock on
- */
-#define B2R2_CLK_FLAG (0x125)
-
-/**
- * DEBUG_CHECK_ADDREF_RELEASE - Define this to enable addref / release debug
- */
-#define DEBUG_CHECK_ADDREF_RELEASE 1
-
-#ifdef CONFIG_DEBUG_FS
-/**
- * HANDLE_TIMEOUTED_JOBS - Define this to check jobs for timeout and cancel them
- */
-#define HANDLE_TIMEOUTED_JOBS 1
-#endif
-
-/**
- * B2R2_CLOCK_ALWAYS_ON - Define this to disable power save clock turn off
- */
-/* #define B2R2_CLOCK_ALWAYS_ON 1 */
-
-/**
- * START_SENTINEL - Watch guard to detect job overwrites
- */
-#define START_SENTINEL 0xBABEDEEA
-
-/**
- * STOP_SENTINEL - Watch guard to detect job overwrites
- */
-#define END_SENTINEL 0xDADBDCDD
-
-/**
- * B2R2_CORE_LOWEST_PRIO - Lowest prio allowed
- */
-#define B2R2_CORE_LOWEST_PRIO -19
-/**
- * B2R2_CORE_HIGHEST_PRIO - Highest prio allowed
- */
-#define B2R2_CORE_HIGHEST_PRIO 20
-
-/**
- * B2R2_DOMAIN_DISABLE -
- */
-#define B2R2_DOMAIN_DISABLE_TIMEOUT (HZ/100)
-
-/**
- * B2R2_REGULATOR_RETRY_COUNT -
- */
-#define B2R2_REGULATOR_RETRY_COUNT 10
-
-/**
* B2R2 Hardware defines below
*/
@@ -179,134 +124,6 @@
#define B2R2BLT_STA1AccessType (INITIAL_TEST)
#define B2R2BLT_STA1 (0xa08)
-
-#ifdef DEBUG_CHECK_ADDREF_RELEASE
-
-/**
- * struct addref_release - Represents one addref or release. Used
- * to debug addref / release problems
- *
- * @addref: true if this represents an addref else it represents
- * a release.
- * @job: The job that was referenced
- * @caller: The caller of the addref or release
- * @ref_count: The job reference count after addref / release
- */
-struct addref_release {
- bool addref;
- struct b2r2_core_job *job;
- const char *caller;
- int ref_count;
-};
-
-#endif
-
-/**
- * struct b2r2_core - Administration data for B2R2 core
- *
- * @lock: Spin lock protecting the b2r2_core structure and the B2R2 HW
- * @hw: B2R2 registers memory mapped
- * @pmu_b2r2_clock: Control of B2R2 clock
- * @log_dev: Device used for logging via dev_... functions
- *
- * @prio_queue: Queue of jobs sorted in priority order
- * @active_jobs: Array containing pointer to zero or one job per queue
- * @n_active_jobs: Number of active jobs
- * @jiffies_last_active: jiffie value when adding last active job
- * @jiffies_last_irq: jiffie value when last irq occured
- * @timeout_work: Work structure for timeout work
- *
- * @next_job_id: Contains the job id that will be assigned to the next
- * added job.
- *
- * @clock_request_count: When non-zero, clock is on
- * @clock_off_timer: Kernel timer to handle delayed turn off of clock
- *
- * @work_queue: Work queue to handle done jobs (callbacks) and timeouts in
- * non-interrupt context.
- *
- * @stat_n_irq: Number of interrupts (statistics)
- * @stat_n_jobs_added: Number of jobs added (statistics)
- * @stat_n_jobs_removed: Number of jobs removed (statistics)
- * @stat_n_jobs_in_prio_list: Number of jobs in prio list (statistics)
- *
- * @debugfs_root_dir: Root directory for B2R2 debugfs
- *
- * @ar: Circular array of addref / release debug structs
- * @ar_write: Where next write will occur
- * @ar_read: First valid place to read. When ar_read == ar_write then
- * the array is empty.
- */
-struct b2r2_core {
- spinlock_t lock;
-
- struct b2r2_memory_map *hw;
-
- u8 op_size;
- u8 ch_size;
- u8 pg_size;
- u8 mg_size;
- u16 min_req_time;
- int irq;
-
- char name[16];
- struct device *dev;
-
- struct list_head prio_queue;
-
- struct b2r2_core_job *active_jobs[B2R2_CORE_QUEUE_NO_OF];
- unsigned long n_active_jobs;
-
- unsigned long jiffies_last_active;
- unsigned long jiffies_last_irq;
-#ifdef HANDLE_TIMEOUTED_JOBS
- struct delayed_work timeout_work;
-#endif
- int next_job_id;
-
- unsigned long clock_request_count;
- struct timer_list clock_off_timer;
-
- struct workqueue_struct *work_queue;
-
- /* Statistics */
- unsigned long stat_n_irq;
- unsigned long stat_n_jobs_added;
- unsigned long stat_n_jobs_removed;
-
- unsigned long stat_n_jobs_in_prio_list;
-
-#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs_root_dir;
- struct dentry *debugfs_core_root_dir;
- struct dentry *debugfs_regs_dir;
-#endif
-
-#ifdef DEBUG_CHECK_ADDREF_RELEASE
- /* Tracking release bug...*/
- struct addref_release ar[100];
- int ar_write;
- int ar_read;
-#endif
-
- /* Power management variables */
- struct mutex domain_lock;
- struct delayed_work domain_disable_work;
-
- /*
- * We need to keep track of both the number of domain_enable/disable()
- * calls and whether the power was actually turned off, since the
- * power off is done in a delayed job.
- */
- bool domain_enabled;
- int domain_request_count;
-
- struct clk *b2r2_clock;
- struct regulator *b2r2_reg;
-
- struct b2r2_control *control;
-};
-
/**
* b2r2_core - Quick link to administration data for B2R2
*/
@@ -318,7 +135,6 @@ static void clear_interrupts(struct b2r2_core *core);
static void trigger_job(struct b2r2_core *core, struct b2r2_core_job *job);
static void exit_job_list(struct b2r2_core *core,
struct list_head *job_list);
-static int get_next_job_id(struct b2r2_core *core);
static void job_work_function(struct work_struct *ptr);
static void init_job(struct b2r2_core_job *job);
static void insert_into_prio_list(struct b2r2_core *core,
@@ -439,19 +255,21 @@ static void internal_job_addref(struct b2r2_core *core,
{
u32 ref_count;
- b2r2_log_info(core->dev, "%s (%p, %p) (from %s)\n",
- __func__, core, job, caller);
-
/* Sanity checks */
+ BUG_ON(core == NULL);
BUG_ON(job == NULL);
+ b2r2_log_info(core->dev, "%s (core: %p, job: %p) (from %s)\n",
+ __func__, core, job, caller);
+
+
if (job->start_sentinel != START_SENTINEL ||
job->end_sentinel != END_SENTINEL ||
job->ref_count == 0 || job->ref_count > 10) {
- b2r2_log_info(core->dev, "%s: (%p, %p) start=%X end=%X "
- "ref_count=%d\n", __func__, core, job,
- job->start_sentinel, job->end_sentinel,
- job->ref_count);
+ b2r2_log_info(core->dev, "%s: (core: %p, job: %p) "
+ "start=%X end=%X ref_count=%d\n",
+ __func__, core, job, job->start_sentinel,
+ job->end_sentinel, job->ref_count);
/* Something is wrong, print the addref / release array */
#ifdef DEBUG_CHECK_ADDREF_RELEASE
@@ -471,8 +289,8 @@ static void internal_job_addref(struct b2r2_core *core,
ar_add(core, job, caller, true);
#endif
- b2r2_log_info(core->dev, "%s called from %s (%p, %p): Ref Count is "
- "%d\n", __func__, caller, core, job, job->ref_count);
+ b2r2_log_info(core->dev, "%s called from %s (core: %p, job: %p): Ref "
+ "Count is %d\n", __func__, caller, core, job, job->ref_count);
}
/**
@@ -496,14 +314,14 @@ static bool internal_job_release(struct b2r2_core *core,
/* Sanity checks */
BUG_ON(job == NULL);
- b2r2_log_info(core->dev, "%s (%p, %p) (from %s)\n",
+ b2r2_log_info(core->dev, "%s (core: %p, job: %p) (from %s)\n",
__func__, core, job, caller);
if (job->start_sentinel != START_SENTINEL ||
job->end_sentinel != END_SENTINEL ||
job->ref_count == 0 || job->ref_count > 10) {
- b2r2_log_info(core->dev, "%s: (%p, %p) start=%X end=%X "
- "ref_count=%d\n", __func__, core, job,
+ b2r2_log_info(core->dev, "%s: (core: %p, job: %p) start=%X "
+ "end=%X ref_count=%d\n", __func__, core, job,
job->start_sentinel, job->end_sentinel,
job->ref_count);
@@ -521,8 +339,8 @@ static bool internal_job_release(struct b2r2_core *core,
#ifdef DEBUG_CHECK_ADDREF_RELEASE
ar_add(core, job, caller, false);
#endif
- b2r2_log_info(core->dev, "%s called from %s (%p, %p) Ref Count is "
- "%d\n", __func__, caller, core, job, ref_count);
+ b2r2_log_info(core->dev, "%s called from %s (core: %p, job: %p) "
+ "Ref Count is %d\n", __func__, caller, core, job, ref_count);
if (!ref_count && job->release) {
call_release = true;
@@ -543,11 +361,10 @@ static bool internal_job_release(struct b2r2_core *core,
void b2r2_core_job_addref(struct b2r2_core_job *job, const char *caller)
{
unsigned long flags;
- struct b2r2_blt_instance *instance;
struct b2r2_core *core;
- instance = (struct b2r2_blt_instance *) job->tag;
- core = instance->control->data;
+ BUG_ON(job == NULL || job->data == 0);
+ core = (struct b2r2_core *) job->data;
spin_lock_irqsave(&core->lock, flags);
internal_job_addref(core, job, caller);
@@ -561,11 +378,10 @@ void b2r2_core_job_release(struct b2r2_core_job *job, const char *caller)
{
unsigned long flags;
bool call_release = false;
- struct b2r2_blt_instance *instance;
struct b2r2_core *core;
- instance = (struct b2r2_blt_instance *) job->tag;
- core = instance->control->data;
+ BUG_ON(job == NULL || job->data == 0);
+ core = (struct b2r2_core *) job->data;
spin_lock_irqsave(&core->lock, flags);
call_release = internal_job_release(core, job, caller);
@@ -584,12 +400,19 @@ int b2r2_core_job_add(struct b2r2_control *control,
unsigned long flags;
struct b2r2_core *core = control->data;
- b2r2_log_info(core->dev, "%s (%p, %p)\n", __func__, control, job);
+ b2r2_log_info(core->dev, "%s (core: %p, job: %p)\n",
+ __func__, core, job);
/* Enable B2R2 */
domain_enable(core);
spin_lock_irqsave(&core->lock, flags);
+ /* Check that we have not been powered down */
+ if (!core->domain_enabled) {
+ spin_unlock_irqrestore(&core->lock, flags);
+ return -ENOSYS;
+ }
+
core->stat_n_jobs_added++;
/* Initialise internal job data */
@@ -605,7 +428,7 @@ int b2r2_core_job_add(struct b2r2_control *control,
check_prio_list(core, false);
spin_unlock_irqrestore(&core->lock, flags);
- return 0;
+ return job->job_id;
}
/**
@@ -618,7 +441,8 @@ struct b2r2_core_job *b2r2_core_job_find(struct b2r2_control *control,
struct b2r2_core_job *job;
struct b2r2_core *core = control->data;
- b2r2_log_info(core->dev, "%s (%p, %d)\n", __func__, control, job_id);
+ b2r2_log_info(core->dev, "%s (core: %p, job_id: %d)\n",
+ __func__, core, job_id);
spin_lock_irqsave(&core->lock, flags);
/* Look through prio queue */
@@ -642,7 +466,8 @@ struct b2r2_core_job *b2r2_core_job_find_first_with_tag(
struct b2r2_core_job *job;
struct b2r2_core *core = control->data;
- b2r2_log_info(core->dev, "%s (%p, %d)\n", __func__, control, tag);
+ b2r2_log_info(core->dev,
+ "%s (core: %p, tag: %d)\n", __func__, core, tag);
spin_lock_irqsave(&core->lock, flags);
/* Look through prio queue */
@@ -669,11 +494,7 @@ static bool is_job_done(struct b2r2_core_job *job)
{
unsigned long flags;
bool job_is_done;
- struct b2r2_blt_instance *instance;
- struct b2r2_core *core;
-
- instance = (struct b2r2_blt_instance *) job->tag;
- core = instance->control->data;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
spin_lock_irqsave(&core->lock, flags);
job_is_done =
@@ -694,13 +515,12 @@ static bool is_job_done(struct b2r2_core_job *job)
int b2r2_core_job_wait(struct b2r2_core_job *job)
{
int ret = 0;
- struct b2r2_blt_instance *instance;
- struct b2r2_core *core;
-
- instance = (struct b2r2_blt_instance *) job->tag;
- core = instance->control->data;
+#ifdef CONFIG_B2R2_DEBUG
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
+#endif
- b2r2_log_info(core->dev, "%s (%p)\n", __func__, job);
+ b2r2_log_info(core->dev, "%s (core: %p, job: %p)\n",
+ __func__, core, job);
/* Check that we have the job */
if (job->job_state == B2R2_CORE_JOB_IDLE) {
/* Never or not queued */
@@ -779,14 +599,10 @@ int b2r2_core_job_cancel(struct b2r2_core_job *job)
{
unsigned long flags;
int ret = 0;
- struct b2r2_blt_instance *instance;
- struct b2r2_core *core;
-
- instance = (struct b2r2_blt_instance *) job->tag;
- core = instance->control->data;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
- b2r2_log_info(core->dev, "%s (%p) (%d)\n",
- __func__, job, job->job_state);
+ b2r2_log_info(core->dev, "%s (core: %p, job: %p) (st: %d)\n",
+ __func__, core, job, job->job_state);
/* Check that we have the job */
if (job->job_state == B2R2_CORE_JOB_IDLE) {
/* Never or not queued */
@@ -819,6 +635,7 @@ static void domain_disable_work_function(struct work_struct *work)
return;
if (core->domain_request_count == 0) {
+ core->valid = false;
exit_hw(core);
clk_disable(core->b2r2_clock);
regulator_disable(core->b2r2_reg);
@@ -853,10 +670,16 @@ again:
else if (ret < 0)
goto regulator_enable_failed;
- clk_enable(core->b2r2_clock);
+ ret = clk_enable(core->b2r2_clock);
+ if (ret < 0) {
+ b2r2_log_err(core->dev,
+ "%s: Could not enable clock\n", __func__);
+ goto enable_clk_failed;
+ }
if (init_hw(core) < 0)
goto init_hw_failed;
core->domain_enabled = true;
+ core->valid = true;
}
mutex_unlock(&core->domain_lock);
@@ -866,9 +689,9 @@ again:
init_hw_failed:
b2r2_log_err(core->dev,
"%s: Could not initialize hardware!\n", __func__);
-
clk_disable(core->b2r2_clock);
+enable_clk_failed:
if (regulator_disable(core->b2r2_reg) < 0)
b2r2_log_err(core->dev, "%s: regulator_disable failed!\n",
__func__);
@@ -946,22 +769,6 @@ static void exit_job_list(struct b2r2_core *core,
}
/**
- * get_next_job_id() - Return a new job id.
- *
- * @core: The b2r2 core entity
- */
-static int get_next_job_id(struct b2r2_core *core)
-{
- int job_id;
-
- if (core->next_job_id < 1)
- core->next_job_id = 1;
- job_id = core->next_job_id++;
-
- return job_id;
-}
-
-/**
* job_work_function() - Work queue function that calls callback(s) and
* checks if B2R2 can accept a new job
*
@@ -972,11 +779,7 @@ static void job_work_function(struct work_struct *ptr)
unsigned long flags;
struct b2r2_core_job *job =
container_of(ptr, struct b2r2_core_job, work);
- struct b2r2_blt_instance *instance;
- struct b2r2_core *core;
-
- instance = (struct b2r2_blt_instance *) job->tag;
- core = instance->control->data;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
/* Disable B2R2 */
domain_disable(core);
@@ -1025,10 +828,12 @@ static void timeout_work_function(struct work_struct *ptr)
if (core->n_active_jobs > 0) {
unsigned long diff =
(long) jiffies - (long) core->jiffies_last_irq;
- if (diff > HZ/2) {
+ if (diff > JOB_TIMEOUT) {
/* Active jobs and more than a second since last irq! */
int i;
+ b2r2_core_print_stats(core);
+
/* Look for timeout:ed jobs and put them in tmp list.
* It's important that the application queues are
* killed in order of decreasing priority */
@@ -1077,7 +882,7 @@ static void timeout_work_function(struct work_struct *ptr)
if (core->n_active_jobs)
queue_delayed_work(
core->work_queue,
- &core->timeout_work, HZ/2);
+ &core->timeout_work, JOB_TIMEOUT);
spin_unlock_irqrestore(&core->lock, flags);
}
@@ -1194,18 +999,10 @@ static void stop_hw_timer(struct b2r2_core *core, struct b2r2_core_job *job)
*/
static void init_job(struct b2r2_core_job *job)
{
- struct b2r2_blt_instance *instance;
- struct b2r2_core *core;
-
- instance = (struct b2r2_blt_instance *) job->tag;
- core = instance->control->data;
job->start_sentinel = START_SENTINEL;
job->end_sentinel = END_SENTINEL;
- /* Get a job id*/
- job->job_id = get_next_job_id(core);
-
/* Job is idle, never queued */
job->job_state = B2R2_CORE_JOB_IDLE;
@@ -1361,7 +1158,7 @@ static void check_prio_list(struct b2r2_core *core, bool atomic)
#ifdef HANDLE_TIMEOUTED_JOBS
/* Check in one half second if it hangs */
queue_delayed_work(core->work_queue,
- &core->timeout_work, HZ/2);
+ &core->timeout_work, JOB_TIMEOUT);
#endif
} else {
/* No resources */
@@ -1395,9 +1192,7 @@ static struct b2r2_core_job *find_job_in_list(int job_id,
struct b2r2_core_job *job = list_entry(
ptr, struct b2r2_core_job, list);
if (job->job_id == job_id) {
- struct b2r2_blt_instance *instance =
- (struct b2r2_blt_instance *) job->tag;
- struct b2r2_core *core = instance->control->data;
+ struct b2r2_core *core = (struct b2r2_core *) job->data;
/* Increase reference count, should be released by
the caller of b2r2_core_job_find */
internal_job_addref(core, job, __func__);
@@ -1503,7 +1298,7 @@ static struct b2r2_core_job *find_tag_in_active_jobs(struct b2r2_core *core,
*/
static int hw_reset(struct b2r2_core *core)
{
- u32 uTimeOut = B2R2_DRIVER_TIMEOUT_VALUE;
+ u32 uTimeOut = B2R2_RESET_TIMEOUT_VALUE;
/* Tell B2R2 to reset */
writel(readl(&core->hw->BLT_CTL) | B2R2BLT_CTLGLOBAL_soft_reset,
@@ -1761,17 +1556,23 @@ static void process_events(struct b2r2_core *core, u32 status)
* b2r2_irq_handler() - B2R2 interrupt handler
*
* @irq: Interrupt number (not used)
- * @x: ??? (Not used)
+ * @dev_id: A pointer to the b2r2 core entity
*/
-static irqreturn_t b2r2_irq_handler(int irq, void *x)
+static irqreturn_t b2r2_irq_handler(int irq, void *dev_id)
{
unsigned long flags;
- struct b2r2_core* core = (struct b2r2_core *) x;
+ struct b2r2_core* core = (struct b2r2_core *) dev_id;
/* Spin lock is need in irq handler (SMP) */
spin_lock_irqsave(&core->lock, flags);
- /* Make sure that we have a clock */
+ /* Make a quick exit if this device was not interrupting */
+ if (!core->valid ||
+ ((readl(&core->hw->BLT_ITS) & B2R2_ITS_MASK) == 0)) {
+ core->stat_n_irq_skipped++;
+ spin_unlock_irqrestore(&core->lock, flags);
+ return IRQ_NONE;
+ }
/* Remember time for last irq (for timeout mgmt) */
core->jiffies_last_irq = jiffies;
@@ -1783,6 +1584,8 @@ static irqreturn_t b2r2_irq_handler(int irq, void *x)
/* Check if we can dispatch new jobs */
check_prio_list(core, true);
+ core->stat_n_irq_exit++;
+
spin_unlock_irqrestore(&core->lock, flags);
return IRQ_HANDLED;
@@ -2032,9 +1835,9 @@ static int debugfs_b2r2_reg_read(struct file *filp, char __user *buf,
size_t dev_size;
int ret = 0;
unsigned long value;
- char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+ char *tmpbuf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
- if (Buf == NULL) {
+ if (tmpbuf == NULL) {
ret = -ENOMEM;
goto out;
}
@@ -2044,7 +1847,7 @@ static int debugfs_b2r2_reg_read(struct file *filp, char __user *buf,
filp->f_dentry->d_inode->i_private);
/* Build the string */
- dev_size = sprintf(Buf, "%8lX\n", value);
+ dev_size = sprintf(tmpbuf, "%8lX\n", value);
/* No more to read if offset != 0 */
if (*f_pos > dev_size)
@@ -2054,14 +1857,14 @@ static int debugfs_b2r2_reg_read(struct file *filp, char __user *buf,
count = dev_size - *f_pos;
/* Return it to user space */
- if (copy_to_user(buf, Buf, count))
+ if (copy_to_user(buf, tmpbuf, count))
ret = -EINVAL;
*f_pos += count;
ret = count;
out:
- if (Buf != NULL)
- kfree(Buf);
+ if (tmpbuf != NULL)
+ kfree(tmpbuf);
return ret;
}
@@ -2078,19 +1881,19 @@ out:
static int debugfs_b2r2_reg_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
- char Buf[80];
+ char tmpbuf[80];
u32 reg_value;
int ret = 0;
/* Adjust count */
- if (count >= sizeof(Buf))
- count = sizeof(Buf) - 1;
+ if (count >= sizeof(tmpbuf))
+ count = sizeof(tmpbuf) - 1;
/* Get it from user space */
- if (copy_from_user(Buf, buf, count))
+ if (copy_from_user(tmpbuf, buf, count))
return -EINVAL;
- Buf[count] = 0;
+ tmpbuf[count] = 0;
/* Convert from hex string */
- if (sscanf(Buf, "%8lX", (unsigned long *) &reg_value) != 1)
+ if (sscanf(tmpbuf, "%8lX", (unsigned long *) &reg_value) != 1)
return -EINVAL;
writel(reg_value, (u32 *)
@@ -2127,9 +1930,9 @@ static int debugfs_b2r2_regs_read(struct file *filp, char __user *buf,
size_t dev_size = 0;
int ret = 0;
int i;
- char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+ char *tmpbuf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
- if (Buf == NULL) {
+ if (tmpbuf == NULL) {
ret = -ENOMEM;
goto out;
}
@@ -2140,7 +1943,7 @@ static int debugfs_b2r2_regs_read(struct file *filp, char __user *buf,
readl((u32 *) (((u8 *)
filp->f_dentry->d_inode->i_private) +
debugfs_regs[i].offset));
- dev_size += sprintf(Buf + dev_size, "%s: %08lX\n",
+ dev_size += sprintf(tmpbuf + dev_size, "%s: %08lX\n",
debugfs_regs[i].name,
value);
}
@@ -2152,14 +1955,14 @@ static int debugfs_b2r2_regs_read(struct file *filp, char __user *buf,
if (*f_pos + count > dev_size)
count = dev_size - *f_pos;
- if (copy_to_user(buf, Buf, count))
+ if (copy_to_user(buf, tmpbuf, count))
ret = -EINVAL;
*f_pos += count;
ret = count;
out:
- if (Buf != NULL)
- kfree(Buf);
+ if (tmpbuf != NULL)
+ kfree(tmpbuf);
return ret;
}
@@ -2187,30 +1990,30 @@ static int debugfs_b2r2_stat_read(struct file *filp, char __user *buf,
size_t dev_size = 0;
int ret = 0;
int i = 0;
- char *Buf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
+ char *tmpbuf = kmalloc(sizeof(char) * 4096, GFP_KERNEL);
struct b2r2_core *core = filp->f_dentry->d_inode->i_private;
- if (Buf == NULL) {
+ if (tmpbuf == NULL) {
ret = -ENOMEM;
goto out;
}
/* Build a string containing all statistics */
- dev_size += sprintf(Buf + dev_size, "Interrupts : %lu\n",
+ dev_size += sprintf(tmpbuf + dev_size, "Interrupts : %lu\n",
core->stat_n_irq);
- dev_size += sprintf(Buf + dev_size, "Added jobs : %lu\n",
+ dev_size += sprintf(tmpbuf + dev_size, "Added jobs : %lu\n",
core->stat_n_jobs_added);
- dev_size += sprintf(Buf + dev_size, "Removed jobs : %lu\n",
+ dev_size += sprintf(tmpbuf + dev_size, "Removed jobs : %lu\n",
core->stat_n_jobs_removed);
- dev_size += sprintf(Buf + dev_size, "Jobs in prio list : %lu\n",
+ dev_size += sprintf(tmpbuf + dev_size, "Jobs in prio list : %lu\n",
core->stat_n_jobs_in_prio_list);
- dev_size += sprintf(Buf + dev_size, "Active jobs : %lu\n",
+ dev_size += sprintf(tmpbuf + dev_size, "Active jobs : %lu\n",
core->n_active_jobs);
for (i = 0; i < ARRAY_SIZE(core->active_jobs); i++)
- dev_size += sprintf(Buf + dev_size,
+ dev_size += sprintf(tmpbuf + dev_size,
" Job in queue %d : 0x%08lx\n",
i, (unsigned long) core->active_jobs[i]);
- dev_size += sprintf(Buf + dev_size, "Clock requests : %lu\n",
+ dev_size += sprintf(tmpbuf + dev_size, "Clock requests : %lu\n",
core->clock_request_count);
/* No more to read if offset != 0 */
@@ -2220,14 +2023,14 @@ static int debugfs_b2r2_stat_read(struct file *filp, char __user *buf,
if (*f_pos + count > dev_size)
count = dev_size - *f_pos;
- if (copy_to_user(buf, Buf, count))
+ if (copy_to_user(buf, tmpbuf, count))
ret = -EINVAL;
*f_pos += count;
ret = count;
out:
- if (Buf != NULL)
- kfree(Buf);
+ if (tmpbuf != NULL)
+ kfree(tmpbuf);
return ret;
}
@@ -2254,14 +2057,14 @@ static int debugfs_b2r2_clock_read(struct file *filp, char __user *buf,
size_t count, loff_t *f_pos)
{
/* 10 characters hex number + newline + string terminator; */
- char Buf[10+2];
+ char tmpbuf[10+2];
size_t dev_size;
int ret = 0;
struct b2r2_core *core = filp->f_dentry->d_inode->i_private;
unsigned long value = clk_get_rate(core->b2r2_clock);
- dev_size = sprintf(Buf, "%#010lx\n", value);
+ dev_size = sprintf(tmpbuf, "%#010lx\n", value);
/* No more to read if offset != 0 */
if (*f_pos > dev_size)
@@ -2270,7 +2073,7 @@ static int debugfs_b2r2_clock_read(struct file *filp, char __user *buf,
if (*f_pos + count > dev_size)
count = dev_size - *f_pos;
- if (copy_to_user(buf, Buf, count))
+ if (copy_to_user(buf, tmpbuf, count))
ret = -EINVAL;
*f_pos += count;
ret = count;
@@ -2292,16 +2095,16 @@ out:
static int debugfs_b2r2_clock_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
- char Buf[80];
+ char tmpbuf[80];
u32 reg_value;
int ret = 0;
- if (count >= sizeof(Buf))
- count = sizeof(Buf) - 1;
- if (copy_from_user(Buf, buf, count))
+ if (count >= sizeof(tmpbuf))
+ count = sizeof(tmpbuf) - 1;
+ if (copy_from_user(tmpbuf, buf, count))
return -EINVAL;
- Buf[count] = 0;
- if (sscanf(Buf, "%8lX", (unsigned long *) &reg_value) != 1)
+ tmpbuf[count] = 0;
+ if (sscanf(tmpbuf, "%8lX", (unsigned long *) &reg_value) != 1)
return -EINVAL;
/*not working yet*/
@@ -2322,6 +2125,88 @@ static const struct file_operations debugfs_b2r2_clock_fops = {
.write = debugfs_b2r2_clock_write,
};
+/**
+ * debugfs_b2r2_enabled_read() - Implements debugfs read for
+ * B2R2 Core Enable/Disable
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to read
+ * @f_pos: File position
+ *
+ * Returns number of bytes read or negative error code
+ */
+static int debugfs_b2r2_enabled_read(struct file *filp, char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ /* 4 characters hex number + newline + string terminator; */
+ char tmpbuf[4+2];
+ size_t dev_size;
+ int ret = 0;
+ struct b2r2_core *core = filp->f_dentry->d_inode->i_private;
+
+ dev_size = sprintf(tmpbuf, "%02X\n", core->control->enabled);
+
+ /* No more to read if offset != 0 */
+ if (*f_pos > dev_size)
+ goto out;
+
+ if (*f_pos + count > dev_size)
+ count = dev_size - *f_pos;
+
+ if (copy_to_user(buf, tmpbuf, count))
+ ret = -EINVAL;
+ *f_pos += count;
+ ret = count;
+out:
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_enabled_write() - Implements debugfs write for
+ * B2R2 Core Enable/Disable
+ * @filp: File pointer
+ * @buf: User space buffer
+ * @count: Number of bytes to write
+ * @f_pos: File position
+ *
+ * Returns number of bytes written or negative error code
+ */
+static int debugfs_b2r2_enabled_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *f_pos)
+{
+ char tmpbuf[80];
+ unsigned int enable;
+ int ret = 0;
+ struct b2r2_core *core = filp->f_dentry->d_inode->i_private;
+
+ if (count >= sizeof(tmpbuf))
+ count = sizeof(tmpbuf) - 1;
+ if (copy_from_user(tmpbuf, buf, count))
+ return -EINVAL;
+ tmpbuf[count] = 0;
+ if (sscanf(tmpbuf, "%02X", &enable) != 1)
+ return -EINVAL;
+
+ if (enable)
+ core->control->enabled = true;
+ else
+ core->control->enabled = false;
+
+ *f_pos += count;
+ ret = count;
+
+ return ret;
+}
+
+/**
+ * debugfs_b2r2_enabled_fops() - File operations for B2R2 Core Enable/Disable debugfs
+ */
+static const struct file_operations debugfs_b2r2_enabled_fops = {
+ .owner = THIS_MODULE,
+ .read = debugfs_b2r2_enabled_read,
+ .write = debugfs_b2r2_enabled_write,
+};
+
#endif
/**
@@ -2348,7 +2233,7 @@ static const struct file_operations debugfs_b2r2_clock_fops = {
static int init_hw(struct b2r2_core *core)
{
int result = 0;
- u32 uTimeOut = B2R2_DRIVER_TIMEOUT_VALUE;
+ u32 uTimeOut = B2R2_RESET_TIMEOUT_VALUE;
/* Put B2R2 into reset */
clear_interrupts(core);
@@ -2357,7 +2242,7 @@ static int init_hw(struct b2r2_core *core)
&core->hw->BLT_CTL);
/* Set up interrupt handler */
- result = request_irq(core->irq, b2r2_irq_handler, 0,
+ result = request_irq(core->irq, b2r2_irq_handler, IRQF_SHARED,
"b2r2-interrupt", core);
if (result) {
b2r2_log_err(core->dev,
@@ -2400,7 +2285,7 @@ static int init_hw(struct b2r2_core *core)
debugfs_create_file(debugfs_regs[i].name, 0666,
core->debugfs_regs_dir,
(void *)(((u8 *) core->hw) +
- debugfs_regs[i].offset),
+ debugfs_regs[i].offset),
&debugfs_b2r2_reg_fops);
}
#endif
@@ -2474,18 +2359,22 @@ static void exit_hw(struct b2r2_core *core)
static int b2r2_probe(struct platform_device *pdev)
{
int ret = 0;
- struct resource *res;
- struct b2r2_core *core;
- struct b2r2_control *control;
+ struct resource *res = NULL;
+ struct b2r2_core *core = NULL;
+ struct b2r2_control *control = NULL;
+ struct b2r2_platform_data *pdata = NULL;
+ int debug_init = 0;
BUG_ON(pdev == NULL);
BUG_ON(pdev->id < 0 || pdev->id >= B2R2_MAX_NBR_DEVICES);
+ pdata = pdev->dev.platform_data;
+
core = kzalloc(sizeof(*core), GFP_KERNEL);
if (!core) {
dev_err(&pdev->dev, "b2r2 core alloc failed\n");
ret = -EINVAL;
- goto b2r2_probe_core_alloc_fail;
+ goto error_exit;
}
core->dev = &pdev->dev;
@@ -2512,24 +2401,25 @@ static int b2r2_probe(struct platform_device *pdev)
core->work_queue = create_workqueue("B2R2");
if (!core->work_queue) {
ret = -ENOMEM;
- goto b2r2_probe_no_work_queue;
+ goto error_exit;
}
/* Get the clock for B2R2 */
- core->b2r2_clock = clk_get(core->dev, "b2r2");
+ core->b2r2_clock = clk_get(core->dev, pdata->clock_id);
if (IS_ERR(core->b2r2_clock)) {
ret = PTR_ERR(core->b2r2_clock);
- dev_err(&pdev->dev, "clk_get b2r2 failed\n");
- goto b2r2_probe_no_clk;
+ dev_err(&pdev->dev, "clk_get %s failed\n", pdata->clock_id);
+ goto error_exit;
}
/* Get the B2R2 regulator */
- core->b2r2_reg = regulator_get(core->dev, "vsupply");
+ core->b2r2_reg = regulator_get(core->dev, pdata->regulator_id);
if (IS_ERR(core->b2r2_reg)) {
ret = PTR_ERR(core->b2r2_reg);
- dev_err(&pdev->dev, "regulator_get vsupply failed "
- "(dev_name=%s)\n", dev_name(core->dev));
- goto b2r2_probe_no_reg;
+ dev_err(&pdev->dev, "regulator_get %s failed "
+ "(dev_name=%s)\n", pdata->regulator_id,
+ dev_name(core->dev));
+ goto error_exit;
}
/* Init power management */
@@ -2537,18 +2427,19 @@ static int b2r2_probe(struct platform_device *pdev)
INIT_DELAYED_WORK_DEFERRABLE(&core->domain_disable_work,
domain_disable_work_function);
core->domain_enabled = false;
+ core->valid = false;
/* Map B2R2 into kernel virtual memory space */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL)
- goto b2r2_probe_no_res;
+ goto error_exit;
/* Hook up irq */
core->irq = platform_get_irq(pdev, 0);
if (core->irq <= 0) {
dev_err(&pdev->dev, "%s: Failed to request irq (irq=%d)\n",
__func__, core->irq);
- goto b2r2_failed_irq_get;
+ goto error_exit;
}
core->hw = (struct b2r2_memory_map *) ioremap(res->start,
@@ -2556,7 +2447,7 @@ static int b2r2_probe(struct platform_device *pdev)
if (core->hw == NULL) {
dev_err(&pdev->dev, "%s: ioremap failed\n", __func__);
ret = -ENOMEM;
- goto b2r2_probe_ioremap_failed;
+ goto error_exit;
}
dev_dbg(core->dev, "b2r2 structure address %p\n", core->hw);
@@ -2565,14 +2456,12 @@ static int b2r2_probe(struct platform_device *pdev)
if (!control) {
dev_err(&pdev->dev, "b2r2 control alloc failed\n");
ret = -EINVAL;
- goto b2r2_probe_control_alloc_fail;
+ goto error_exit;
}
- control->miscdev.parent = core->dev;
control->data = (void *)core;
control->id = pdev->id;
control->dev = &pdev->dev; /* Temporary device */
- snprintf(control->name, sizeof(control->name), "%s_blt", core->name);
core->op_size = B2R2_PLUG_OPCODE_SIZE_DEFAULT;
core->ch_size = B2R2_PLUG_CHUNK_SIZE_DEFAULT;
@@ -2598,6 +2487,9 @@ static int b2r2_probe(struct platform_device *pdev)
core, &debugfs_b2r2_stat_fops);
debugfs_create_file("clock", 0666, core->debugfs_core_root_dir,
core, &debugfs_b2r2_clock_fops);
+ debugfs_create_file("enabled", 0666,
+ core->debugfs_core_root_dir,
+ core, &debugfs_b2r2_enabled_fops);
debugfs_create_u8("op_size", 0666, core->debugfs_core_root_dir,
&core->op_size);
debugfs_create_u8("ch_size", 0666, core->debugfs_core_root_dir,
@@ -2614,39 +2506,44 @@ static int b2r2_probe(struct platform_device *pdev)
ret = b2r2_debug_init(control);
if (ret < 0) {
dev_err(&pdev->dev, "b2r2_debug_init failed\n");
- goto b2r2_probe_debug_init_failed;
+ goto error_exit;
}
+ debug_init = 1;
- /* Initialize b2r2_blt module. FIXME: Module of it's own
- or perhaps a dedicated module init c file? */
- ret = b2r2_blt_module_init(control);
+ /* Initialize b2r2_control */
+ ret = b2r2_control_init(control);
if (ret < 0) {
- b2r2_log_err(&pdev->dev, "b2r2_blt_module_init failed\n");
- goto b2r2_probe_blt_init_fail;
+ b2r2_log_err(&pdev->dev, "b2r2_control_init failed\n");
+ goto error_exit;
}
-
core->control = control;
+
+ /* Add the control to the blitter */
+ kref_init(&control->ref);
+ control->enabled = true;
+ b2r2_blt_add_control(control);
+
b2r2_core[pdev->id] = core;
- dev_info(&pdev->dev, "init done.\n");
+ dev_info(&pdev->dev, "%s done.\n", __func__);
return ret;
/** Recover from any error if something fails */
-b2r2_probe_blt_init_fail:
+error_exit:
kfree(control);
-b2r2_probe_control_alloc_fail:
-b2r2_probe_ioremap_failed:
-b2r2_failed_irq_get:
-b2r2_probe_no_res:
- regulator_put(core->b2r2_reg);
-b2r2_probe_no_reg:
- clk_put(core->b2r2_clock);
-b2r2_probe_no_clk:
- destroy_workqueue(core->work_queue);
- core->work_queue = NULL;
-b2r2_probe_no_work_queue:
- b2r2_debug_exit();
-b2r2_probe_debug_init_failed:
+
+ if (!IS_ERR_OR_NULL(core->b2r2_reg))
+ regulator_put(core->b2r2_reg);
+
+ if (!IS_ERR_OR_NULL(core->b2r2_clock))
+ clk_put(core->b2r2_clock);
+
+ if (!IS_ERR_OR_NULL(core->work_queue))
+ destroy_workqueue(core->work_queue);
+
+ if (debug_init)
+ b2r2_debug_exit();
+
#ifdef CONFIG_DEBUG_FS
if (!IS_ERR_OR_NULL(core->debugfs_root_dir)) {
debugfs_remove_recursive(core->debugfs_root_dir);
@@ -2654,44 +2551,29 @@ b2r2_probe_debug_init_failed:
}
#endif
kfree(core);
-b2r2_probe_core_alloc_fail:
- dev_info(&pdev->dev, "init done with errors.\n");
+
+ dev_info(&pdev->dev, "%s done with errors (%d).\n", __func__, ret);
return ret;
}
-
-
-/**
- * b2r2_remove - This routine unloads b2r2 driver
- *
- * @pdev: platform device.
- */
-static int b2r2_remove(struct platform_device *pdev)
+void b2r2_core_release(struct kref *control_ref)
{
+ struct b2r2_control *control = container_of(
+ control_ref, struct b2r2_control, ref);
+ struct b2r2_core *core = control->data;
+ int id = control->id;
unsigned long flags;
- struct b2r2_core *core;
-
- BUG_ON(pdev == NULL);
-
- core = dev_get_drvdata(&pdev->dev);
- BUG_ON(core == NULL);
- b2r2_log_info(&pdev->dev, "%s: Started\n", __func__);
-
-#ifdef CONFIG_DEBUG_FS
- if (!IS_ERR_OR_NULL(core->debugfs_root_dir)) {
- debugfs_remove_recursive(core->debugfs_root_dir);
- core->debugfs_root_dir = NULL;
- }
+#ifdef CONFIG_B2R2_DEBUG
+ struct device *dev = core->dev;
#endif
- /* Flush B2R2 work queue (call all callbacks) */
- flush_workqueue(core->work_queue);
-
- /* Exit b2r2 blt module */
- b2r2_blt_module_exit(core->control);
+ b2r2_log_info(dev, "%s: enter\n", __func__);
- kfree(core->control);
+ /* Exit b2r2 control module */
+ b2r2_control_exit(control);
+ kfree(control);
+ b2r2_debug_exit();
#ifdef HANDLE_TIMEOUTED_JOBS
cancel_delayed_work(&core->timeout_work);
@@ -2705,7 +2587,7 @@ static int b2r2_remove(struct platform_device *pdev)
cancel_delayed_work_sync(&core->domain_disable_work);
/** Unmap B2R2 registers */
- b2r2_log_info(&pdev->dev, "unmap b2r2 registers..\n");
+ b2r2_log_info(dev, "%s: unmap b2r2 registers..\n", __func__);
if (core->hw) {
iounmap(core->hw);
core->hw = NULL;
@@ -2723,9 +2605,41 @@ static int b2r2_remove(struct platform_device *pdev)
core->dev = NULL;
kfree(core);
- b2r2_core[pdev->id] = NULL;
+ b2r2_core[id] = NULL;
- b2r2_debug_exit();
+ b2r2_log_info(dev, "%s: exit\n", __func__);
+}
+
+
+/**
+ * b2r2_remove - This routine unloads b2r2 driver
+ *
+ * @pdev: platform device.
+ */
+static int b2r2_remove(struct platform_device *pdev)
+{
+ struct b2r2_core *core;
+
+ BUG_ON(pdev == NULL);
+
+ core = dev_get_drvdata(&pdev->dev);
+ BUG_ON(core == NULL);
+ b2r2_log_info(&pdev->dev, "%s: Started\n", __func__);
+
+#ifdef CONFIG_DEBUG_FS
+ if (!IS_ERR_OR_NULL(core->debugfs_root_dir)) {
+ debugfs_remove_recursive(core->debugfs_root_dir);
+ core->debugfs_root_dir = NULL;
+ }
+#endif
+
+ /* Flush B2R2 work queue (call all callbacks) */
+ flush_workqueue(core->work_queue);
+
+ /* Remove control from blitter */
+ core->control->enabled = false;
+ b2r2_blt_remove_control(core->control);
+ kref_put(&core->control->ref, b2r2_core_release);
b2r2_log_info(&pdev->dev, "%s: Ended\n", __func__);
@@ -2785,6 +2699,23 @@ int b2r2_resume(struct platform_device *pdev)
return 0;
}
+void b2r2_core_print_stats(struct b2r2_core *core)
+{
+ b2r2_log_info(core->dev,
+ "%s: n_irq %ld, n_irq_exit %ld, n_irq_skipped %ld,\n"
+ "n_jobs_added %ld, n_active_jobs %ld, "
+ "n_jobs_in_prio_list %ld,\n"
+ "n_jobs_removed %ld\n",
+ __func__,
+ core->stat_n_irq,
+ core->stat_n_irq_exit,
+ core->stat_n_irq_skipped,
+ core->stat_n_jobs_added,
+ core->n_active_jobs,
+ core->stat_n_jobs_in_prio_list,
+ core->stat_n_jobs_removed);
+}
+
/**
* struct platform_b2r2_driver - Platform driver configuration for the
* B2R2 core driver
diff --git a/drivers/video/b2r2/b2r2_core.h b/drivers/video/b2r2/b2r2_core.h
index 991dd9d9d1b..5b9fdcdc2bb 100644
--- a/drivers/video/b2r2/b2r2_core.h
+++ b/drivers/video/b2r2/b2r2_core.h
@@ -18,6 +18,194 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
+/**
+ * B2R2_RESET_TIMEOUT_VALUE - The number of times to read the status register
+ * waiting for b2r2 to go idle after soft reset.
+ */
+#define B2R2_RESET_TIMEOUT_VALUE (1500)
+
+/**
+ * B2R2_CLK_FLAG - Value to write into clock reg to turn clock on
+ */
+#define B2R2_CLK_FLAG (0x125)
+
+/**
+ * DEBUG_CHECK_ADDREF_RELEASE - Define this to enable addref / release debug
+ */
+#define DEBUG_CHECK_ADDREF_RELEASE 1
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * HANDLE_TIMEOUTED_JOBS - Define this to check jobs for timeout and cancel them
+ */
+#define HANDLE_TIMEOUTED_JOBS
+#define JOB_TIMEOUT (HZ/2)
+#endif
+
+/**
+ * B2R2_CLOCK_ALWAYS_ON - Define this to disable power save clock turn off
+ */
+/* #define B2R2_CLOCK_ALWAYS_ON 1 */
+
+/**
+ * START_SENTINEL - Watch guard to detect job overwrites
+ */
+#define START_SENTINEL 0xBABEDEEA
+
+/**
+ * STOP_SENTINEL - Watch guard to detect job overwrites
+ */
+#define END_SENTINEL 0xDADBDCDD
+
+/**
+ * B2R2_CORE_LOWEST_PRIO - Lowest prio allowed
+ */
+#define B2R2_CORE_LOWEST_PRIO -19
+/**
+ * B2R2_CORE_HIGHEST_PRIO - Highest prio allowed
+ */
+#define B2R2_CORE_HIGHEST_PRIO 20
+
+/**
+ * B2R2_DOMAIN_DISABLE -
+ */
+#define B2R2_DOMAIN_DISABLE_TIMEOUT (HZ/100)
+
+/**
+ * B2R2_REGULATOR_RETRY_COUNT -
+ */
+#define B2R2_REGULATOR_RETRY_COUNT 10
+
+
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+
+/**
+ * struct addref_release - Represents one addref or release. Used
+ * to debug addref / release problems
+ *
+ * @addref: true if this represents an addref else it represents
+ * a release.
+ * @job: The job that was referenced
+ * @caller: The caller of the addref or release
+ * @ref_count: The job reference count after addref / release
+ */
+struct addref_release {
+ bool addref;
+ struct b2r2_core_job *job;
+ const char *caller;
+ int ref_count;
+};
+
+#endif
+
+/**
+ * struct b2r2_core - Administration data for B2R2 core
+ *
+ * @lock: Spin lock protecting the b2r2_core structure and the B2R2 HW
+ * @hw: B2R2 registers memory mapped
+ * @pmu_b2r2_clock: Control of B2R2 clock
+ * @log_dev: Device used for logging via dev_... functions
+ *
+ * @prio_queue: Queue of jobs sorted in priority order
+ * @active_jobs: Array containing pointer to zero or one job per queue
+ * @n_active_jobs: Number of active jobs
+ * @jiffies_last_active: jiffie value when adding last active job
+ * @jiffies_last_irq: jiffie value when last irq occured
+ * @timeout_work: Work structure for timeout work
+ *
+ * @next_job_id: Contains the job id that will be assigned to the next
+ * added job.
+ *
+ * @clock_request_count: When non-zero, clock is on
+ * @clock_off_timer: Kernel timer to handle delayed turn off of clock
+ *
+ * @work_queue: Work queue to handle done jobs (callbacks) and timeouts in
+ * non-interrupt context.
+ *
+ * @stat_n_irq: Number of interrupts (statistics)
+ * @stat_n_jobs_added: Number of jobs added (statistics)
+ * @stat_n_jobs_removed: Number of jobs removed (statistics)
+ * @stat_n_jobs_in_prio_list: Number of jobs in prio list (statistics)
+ *
+ * @debugfs_root_dir: Root directory for B2R2 debugfs
+ *
+ * @ar: Circular array of addref / release debug structs
+ * @ar_write: Where next write will occur
+ * @ar_read: First valid place to read. When ar_read == ar_write then
+ * the array is empty.
+ */
+struct b2r2_core {
+ spinlock_t lock;
+
+ struct b2r2_memory_map *hw;
+
+ u8 op_size;
+ u8 ch_size;
+ u8 pg_size;
+ u8 mg_size;
+ u16 min_req_time;
+ int irq;
+
+ char name[16];
+ struct device *dev;
+
+ struct list_head prio_queue;
+
+ struct b2r2_core_job *active_jobs[B2R2_CORE_QUEUE_NO_OF];
+ unsigned long n_active_jobs;
+
+ unsigned long jiffies_last_active;
+ unsigned long jiffies_last_irq;
+#ifdef HANDLE_TIMEOUTED_JOBS
+ struct delayed_work timeout_work;
+#endif
+ int next_job_id;
+
+ unsigned long clock_request_count;
+ struct timer_list clock_off_timer;
+
+ struct workqueue_struct *work_queue;
+
+ /* Statistics */
+ unsigned long stat_n_irq_exit;
+ unsigned long stat_n_irq_skipped;
+ unsigned long stat_n_irq;
+ unsigned long stat_n_jobs_added;
+ unsigned long stat_n_jobs_removed;
+
+ unsigned long stat_n_jobs_in_prio_list;
+
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs_root_dir;
+ struct dentry *debugfs_core_root_dir;
+ struct dentry *debugfs_regs_dir;
+#endif
+
+#ifdef DEBUG_CHECK_ADDREF_RELEASE
+ /* Tracking release bug...*/
+ struct addref_release ar[100];
+ int ar_write;
+ int ar_read;
+#endif
+
+ /* Power management variables */
+ struct mutex domain_lock;
+ struct delayed_work domain_disable_work;
+
+ /*
+ * We need to keep track of both the number of domain_enable/disable()
+ * calls and whether the power was actually turned off, since the
+ * power off is done in a delayed job.
+ */
+ bool domain_enabled;
+ volatile bool valid;
+ int domain_request_count;
+
+ struct clk *b2r2_clock;
+ struct regulator *b2r2_reg;
+
+ struct b2r2_control *control;
+};
/**
* b2r2_core_job_add() - Adds a job to B2R2 job queues
@@ -105,4 +293,8 @@ void b2r2_core_job_addref(struct b2r2_core_job *job, const char *caller);
*/
void b2r2_core_job_release(struct b2r2_core_job *job, const char *caller);
+void b2r2_core_print_stats(struct b2r2_core *core);
+
+void b2r2_core_release(struct kref *control_ref);
+
#endif /* !defined(__B2R2_CORE_JOB_H__) */
diff --git a/drivers/video/b2r2/b2r2_input_validation.c b/drivers/video/b2r2/b2r2_input_validation.c
index ac8b5728847..c8eb2f7b025 100644
--- a/drivers/video/b2r2/b2r2_input_validation.c
+++ b/drivers/video/b2r2/b2r2_input_validation.c
@@ -32,7 +32,7 @@
static bool is_valid_format(enum b2r2_blt_fmt fmt);
static bool is_valid_bg_format(enum b2r2_blt_fmt fmt);
-static bool is_valid_pitch_for_fmt(struct b2r2_control *cont,
+static bool is_valid_pitch_for_fmt(struct device *dev,
u32 pitch, s32 width, enum b2r2_blt_fmt fmt);
static bool is_aligned_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt);
@@ -40,9 +40,9 @@ static s32 width_2_complete_width(s32 width, enum b2r2_blt_fmt fmt);
static bool is_complete_width_for_fmt(s32 width, enum b2r2_blt_fmt fmt);
static bool is_valid_height_for_fmt(s32 height, enum b2r2_blt_fmt fmt);
-static bool validate_img(struct b2r2_control *cont,
+static bool validate_img(struct device *dev,
struct b2r2_blt_img *img);
-static bool validate_rect(struct b2r2_control *cont,
+static bool validate_rect(struct device *dev,
struct b2r2_blt_rect *rect);
@@ -103,7 +103,7 @@ static bool is_valid_bg_format(enum b2r2_blt_fmt fmt)
}
-static bool is_valid_pitch_for_fmt(struct b2r2_control *cont,
+static bool is_valid_pitch_for_fmt(struct device *dev,
u32 pitch, s32 width, enum b2r2_blt_fmt fmt)
{
s32 complete_width;
@@ -111,7 +111,7 @@ static bool is_valid_pitch_for_fmt(struct b2r2_control *cont,
complete_width = width_2_complete_width(width, fmt);
- pitch_derived_from_width = b2r2_calc_pitch_from_width(cont,
+ pitch_derived_from_width = b2r2_calc_pitch_from_width(dev,
complete_width, fmt);
if (pitch < pitch_derived_from_width)
@@ -263,7 +263,7 @@ static bool is_valid_height_for_fmt(s32 height, enum b2r2_blt_fmt fmt)
return true;
}
-static bool validate_img(struct b2r2_control *cont,
+static bool validate_img(struct device *dev,
struct b2r2_blt_img *img)
{
/*
@@ -276,14 +276,14 @@ static bool validate_img(struct b2r2_control *cont,
s32 img_size;
if (!is_valid_format(img->fmt)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!is_valid_format(img->fmt)\n");
return false;
}
if (img->width < 0 || img->width > max_img_width_height ||
img->height < 0 || img->height > max_img_width_height) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"img->width < 0 || "
"img->width > max_img_width_height || "
"img->height < 0 || "
@@ -293,7 +293,7 @@ static bool validate_img(struct b2r2_control *cont,
if (b2r2_is_mb_fmt(img->fmt)) {
if (!is_complete_width_for_fmt(img->width, img->fmt)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!is_complete_width_for_fmt(img->width,"
" img->fmt)\n");
return false;
@@ -302,7 +302,7 @@ static bool validate_img(struct b2r2_control *cont,
if (0 == img->pitch &&
(!is_aligned_width_for_fmt(img->width, img->fmt) ||
!is_complete_width_for_fmt(img->width, img->fmt))) {
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"Validation Error: "
"0 == img->pitch && "
"(!is_aligned_width_for_fmt(img->width,"
@@ -313,24 +313,24 @@ static bool validate_img(struct b2r2_control *cont,
}
if (img->pitch != 0 &&
- !is_valid_pitch_for_fmt(cont, img->pitch, img->width,
+ !is_valid_pitch_for_fmt(dev, img->pitch, img->width,
img->fmt)) {
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"Validation Error: "
"img->pitch != 0 && "
- "!is_valid_pitch_for_fmt(cont, "
+ "!is_valid_pitch_for_fmt(dev, "
"img->pitch, img->width, img->fmt)\n");
return false;
}
}
if (!is_valid_height_for_fmt(img->width, img->fmt)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!is_valid_height_for_fmt(img->width, img->fmt)\n");
return false;
}
- img_size = b2r2_get_img_size(cont, img);
+ img_size = b2r2_get_img_size(dev, img);
/*
* To keep the entire image inside s32 range.
@@ -338,7 +338,7 @@ static bool validate_img(struct b2r2_control *cont,
if ((B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == img->buf.type ||
B2R2_BLT_PTR_FD_OFFSET == img->buf.type) &&
img->buf.offset > (u32)b2r2_s32_max - (u32)img_size) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"(B2R2_BLT_PTR_HWMEM_BUF_NAME_OFFSET == "
"img->buf.type || B2R2_BLT_PTR_FD_OFFSET == "
"img->buf.type) && img->buf.offset > "
@@ -349,11 +349,11 @@ static bool validate_img(struct b2r2_control *cont,
return true;
}
-static bool validate_rect(struct b2r2_control *cont,
+static bool validate_rect(struct device *dev,
struct b2r2_blt_rect *rect)
{
if (rect->width < 0 || rect->height < 0) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"rect->width < 0 || rect->height < 0\n");
return false;
}
@@ -361,7 +361,7 @@ static bool validate_rect(struct b2r2_control *cont,
return true;
}
-bool b2r2_validate_user_req(struct b2r2_control *cont,
+bool b2r2_validate_user_req(struct device *dev,
struct b2r2_blt_req *req)
{
bool is_src_img_used;
@@ -370,7 +370,7 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
bool is_dst_clip_rect_used;
if (req->size != sizeof(struct b2r2_blt_req)) {
- b2r2_log_err(cont->dev, "Validation Error: "
+ b2r2_log_err(dev, "Validation Error: "
"req->size != sizeof(struct b2r2_blt_req)\n");
return false;
}
@@ -382,31 +382,31 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
is_dst_clip_rect_used = req->flags & B2R2_BLT_FLAG_DESTINATION_CLIP;
if (is_src_img_used || is_src_mask_used) {
- if (!validate_rect(cont, &req->src_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_rect(cont, &req->src_rect)\n");
+ if (!validate_rect(dev, &req->src_rect)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_rect(dev, &req->src_rect)\n");
return false;
}
}
- if (!validate_rect(cont, &req->dst_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_rect(cont, &req->dst_rect)\n");
+ if (!validate_rect(dev, &req->dst_rect)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_rect(dev, &req->dst_rect)\n");
return false;
}
if (is_bg_img_used) {
- if (!validate_rect(cont, &req->bg_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_rect(cont, &req->bg_rect)\n");
+ if (!validate_rect(dev, &req->bg_rect)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_rect(dev, &req->bg_rect)\n");
return false;
}
}
if (is_dst_clip_rect_used) {
- if (!validate_rect(cont, &req->dst_clip_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_rect(cont, &req->dst_clip_rect)\n");
+ if (!validate_rect(dev, &req->dst_clip_rect)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_rect(dev, &req->dst_clip_rect)\n");
return false;
}
}
@@ -414,9 +414,9 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
if (is_src_img_used) {
struct b2r2_blt_rect src_img_bounding_rect;
- if (!validate_img(cont, &req->src_img)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_img(cont, &req->src_img)\n");
+ if (!validate_img(dev, &req->src_img)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_img(dev, &req->src_img)\n");
return false;
}
@@ -424,7 +424,7 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
&src_img_bounding_rect);
if (!b2r2_is_rect_inside_rect(&req->src_rect,
&src_img_bounding_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!b2r2_is_rect_inside_rect(&req->src_rect, "
"&src_img_bounding_rect)\n");
return false;
@@ -434,14 +434,14 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
if (is_bg_img_used) {
struct b2r2_blt_rect bg_img_bounding_rect;
- if (!validate_img(cont, &req->bg_img)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_img(cont, &req->bg_img)\n");
+ if (!validate_img(dev, &req->bg_img)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_img(dev, &req->bg_img)\n");
return false;
}
if (!is_valid_bg_format(req->bg_img.fmt)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!is_valid_bg_format(req->bg_img->fmt)\n");
return false;
}
@@ -450,7 +450,7 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
&bg_img_bounding_rect);
if (!b2r2_is_rect_inside_rect(&req->bg_rect,
&bg_img_bounding_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!b2r2_is_rect_inside_rect(&req->bg_rect, "
"&bg_img_bounding_rect)\n");
return false;
@@ -460,9 +460,9 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
if (is_src_mask_used) {
struct b2r2_blt_rect src_mask_bounding_rect;
- if (!validate_img(cont, &req->src_mask)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_img(cont, &req->src_mask)\n");
+ if (!validate_img(dev, &req->src_mask)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_img(dev, &req->src_mask)\n");
return false;
}
@@ -470,22 +470,22 @@ bool b2r2_validate_user_req(struct b2r2_control *cont,
&src_mask_bounding_rect);
if (!b2r2_is_rect_inside_rect(&req->src_rect,
&src_mask_bounding_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!b2r2_is_rect_inside_rect(&req->src_rect, "
"&src_mask_bounding_rect)\n");
return false;
}
}
- if (!validate_img(cont, &req->dst_img)) {
- b2r2_log_info(cont->dev, "Validation Error: "
- "!validate_img(cont, &req->dst_img)\n");
+ if (!validate_img(dev, &req->dst_img)) {
+ b2r2_log_info(dev, "Validation Error: "
+ "!validate_img(dev, &req->dst_img)\n");
return false;
}
if (is_bg_img_used) {
if (!b2r2_is_rect_gte_rect(&req->bg_rect, &req->dst_rect)) {
- b2r2_log_info(cont->dev, "Validation Error: "
+ b2r2_log_info(dev, "Validation Error: "
"!b2r2_is_rect_gte_rect(&req->bg_rect, "
"&req->dst_rect)\n");
return false;
diff --git a/drivers/video/b2r2/b2r2_input_validation.h b/drivers/video/b2r2/b2r2_input_validation.h
index d3c6ae1b296..25f022a45ab 100644
--- a/drivers/video/b2r2/b2r2_input_validation.h
+++ b/drivers/video/b2r2/b2r2_input_validation.h
@@ -25,7 +25,7 @@
#include "b2r2_internal.h"
-bool b2r2_validate_user_req(struct b2r2_control *cont,
+bool b2r2_validate_user_req(struct device *dev,
struct b2r2_blt_req *req);
#endif
diff --git a/drivers/video/b2r2/b2r2_internal.h b/drivers/video/b2r2/b2r2_internal.h
index c46e814df14..329d644e5e1 100644
--- a/drivers/video/b2r2/b2r2_internal.h
+++ b/drivers/video/b2r2/b2r2_internal.h
@@ -23,7 +23,7 @@
/**
* B2R2_MAX_NBR_DEVICES - The maximum number of B2R2s handled
*/
-#define B2R2_MAX_NBR_DEVICES 1
+#define B2R2_MAX_NBR_DEVICES 2
/* The maximum possible number of temporary buffers needed */
#define MAX_TMP_BUFS_NEEDED 2
@@ -31,6 +31,9 @@
/* Size of the color look-up table */
#define CLUT_SIZE 1024
+/* The defined bits of the Interrupt Status Register */
+#define B2R2_ITS_MASK 0x0FFFF0FF
+
/**
* b2r2_op_type - the type of B2R2 operation to configure
*/
@@ -127,9 +130,12 @@ struct tmp_buf {
};
/**
- * struct b2r2_blt_instance - Represents the B2R2 instance (one per open)
+ * struct b2r2_control_instance - Represents the B2R2 instance
+ * (one per open and blitter core)
*
* @lock: Lock to protect the instance
+ * @control_id: The b2r2 core core control identifier
+ * @control: The b2r2 core control entity
*
* @report_list: Ready requests that should be reported,
* @report_list_waitq: Wait queue for report list
@@ -137,10 +143,11 @@ struct tmp_buf {
* in callback.
* @synching: true if any client is waiting for b2r2_blt_synch(0)
* @synch_done_waitq: Wait queue to handle synching on request_id 0
- * @control: The b2r2 control entity
*/
-struct b2r2_blt_instance {
+struct b2r2_control_instance {
struct mutex lock;
+ int control_id;
+ struct b2r2_control *control;
/* Requests to be reported */
struct list_head report_list;
@@ -150,8 +157,6 @@ struct b2r2_blt_instance {
u32 no_of_active_requests;
bool synching;
wait_queue_head_t synch_done_waitq;
-
- struct b2r2_control *control;
};
/**
@@ -370,6 +375,7 @@ struct b2r2_core_job {
/* Data to be filled in by client */
int tag;
+ int data;
int prio;
u32 first_node_address;
u32 last_node_address;
@@ -419,6 +425,7 @@ struct b2r2_core_job {
* @node_split_job: The administration structure for the B2R2 node split job
* @first_node: Pointer to the first B2R2 node
* @request_id: Request id for this job
+ * @core_mask: Bit mask with the cores doing part of the job
* @node_split_handle: Handle of the node split
* @src_resolved: Calculated info about the source buffer
* @src_mask_resolved: Calculated info about the source mask buffer
@@ -427,13 +434,14 @@ struct b2r2_core_job {
* @profile: True if the blit shall be profiled, false otherwise
*/
struct b2r2_blt_request {
- struct b2r2_blt_instance *instance;
+ struct b2r2_control_instance *instance;
struct list_head list;
struct b2r2_blt_req user_req;
struct b2r2_core_job job;
struct b2r2_node_split_job node_split_job;
struct b2r2_node *first_node;
int request_id;
+ u32 core_mask;
/* Resolved buffer addresses */
struct b2r2_resolved_buf src_resolved;
@@ -491,7 +499,6 @@ struct b2r2_mem_heap {
/**
*
- * @miscdev: The miscdev presenting b2r2 to the system
* @dev: The device handle of the b2r2 instance
* @id: The id of the b2r2 instance
* @name: The name of the b2r2 instance
@@ -525,36 +532,36 @@ struct b2r2_mem_heap {
* @prev_node_count: Node cound of last_job
*/
struct b2r2_control {
- struct miscdevice miscdev;
- struct device *dev;
- int id;
- char name[16];
- void *data;
- struct tmp_buf tmp_bufs[MAX_TMP_BUFS_NEEDED];
- int filters_initialized;
- struct b2r2_mem_heap mem_heap;
+ struct device *dev;
+ void *data;
+ int id;
+ struct kref ref;
+ bool enabled;
+ struct tmp_buf tmp_bufs[MAX_TMP_BUFS_NEEDED];
+ int filters_initialized;
+ struct b2r2_mem_heap mem_heap;
#ifdef CONFIG_DEBUG_FS
- struct b2r2_blt_request debugfs_latest_request;
- struct dentry *debugfs_root_dir;
- struct dentry *debugfs_debug_root_dir;
+ struct b2r2_blt_request debugfs_latest_request;
+ struct dentry *debugfs_root_dir;
+ struct dentry *debugfs_debug_root_dir;
#endif
- struct mutex stat_lock;
- unsigned long stat_n_jobs_added;
- unsigned long stat_n_jobs_released;
- unsigned long stat_n_jobs_in_report_list;
- unsigned long stat_n_in_blt;
- unsigned long stat_n_in_blt_synch;
- unsigned long stat_n_in_blt_add;
- unsigned long stat_n_in_blt_wait;
- unsigned long stat_n_in_synch_0;
- unsigned long stat_n_in_synch_job;
- unsigned long stat_n_in_query_cap;
- unsigned long stat_n_in_open;
- unsigned long stat_n_in_release;
- struct mutex last_job_lock;
- struct b2r2_node *last_job;
- char *last_job_chars;
- int prev_node_count;
+ struct mutex stat_lock;
+ unsigned long stat_n_jobs_added;
+ unsigned long stat_n_jobs_released;
+ unsigned long stat_n_jobs_in_report_list;
+ unsigned long stat_n_in_blt;
+ unsigned long stat_n_in_blt_synch;
+ unsigned long stat_n_in_blt_add;
+ unsigned long stat_n_in_blt_wait;
+ unsigned long stat_n_in_synch_0;
+ unsigned long stat_n_in_synch_job;
+ unsigned long stat_n_in_query_cap;
+ unsigned long stat_n_in_open;
+ unsigned long stat_n_in_release;
+ struct mutex last_job_lock;
+ struct b2r2_node *last_job;
+ char *last_job_chars;
+ int prev_node_count;
};
/* FIXME: The functions below should be removed when we are
@@ -590,4 +597,14 @@ int b2r2_blt_module_init(struct b2r2_control *cont);
*/
void b2r2_blt_module_exit(struct b2r2_control *cont);
+/**
+ * b2r2_blt_add_control() - Add the b2r2 core control
+ */
+void b2r2_blt_add_control(struct b2r2_control *cont);
+
+/**
+ * b2r2_blt_remove_control() - Remove the b2r2 core control
+ */
+void b2r2_blt_remove_control(struct b2r2_control *cont);
+
#endif
diff --git a/drivers/video/b2r2/b2r2_node_split.c b/drivers/video/b2r2/b2r2_node_split.c
index d773865223b..b2fb07580ca 100644
--- a/drivers/video/b2r2/b2r2_node_split.c
+++ b/drivers/video/b2r2/b2r2_node_split.c
@@ -21,9 +21,6 @@
/*
* Macros and constants
*/
-#define ABS(x) ((x) < 0 ? -(x) : (x))
-#define MAX(x, y) ((x) > (y) ? (x) : (y))
-#define MIN(x, y) ((x) < (y) ? (x) : (y))
#define INSTANCES_DEFAULT_SIZE 10
#define INSTANCES_GROW_SIZE 5
@@ -111,9 +108,6 @@ static int configure_rot_scale(struct b2r2_control *cont,
struct b2r2_node_split_job *this, struct b2r2_node *node,
struct b2r2_node **next);
-static void recalculate_rects(struct b2r2_control *cont,
- struct b2r2_blt_req *req);
-
static int check_rect(struct b2r2_control *cont,
const struct b2r2_blt_img *img,
const struct b2r2_blt_rect *rect,
@@ -255,13 +249,6 @@ int b2r2_node_split_analyze(const struct b2r2_blt_request *req,
color_fill = (this->flags & (B2R2_BLT_FLAG_SOURCE_FILL |
B2R2_BLT_FLAG_SOURCE_FILL_RAW)) != 0;
- /*
- * B2R2 cannot handle destination clipping on buffers
- * allocated close to 64MiB bank boundaries.
- * recalculate src_ and dst_rect to avoid clipping.
- */
- recalculate_rects(cont, (struct b2r2_blt_req *) &req->user_req);
-
/* Configure the source and destination buffers */
set_buf(cont, &this->src, req->src_resolved.physical_address,
&req->user_req.src_img, &req->user_req.src_rect,
@@ -579,25 +566,6 @@ void b2r2_node_split_cancel(struct b2r2_control *cont,
return;
}
-/*
- * Private functions
- */
-
-static void recalculate_rects(struct b2r2_control *cont,
- struct b2r2_blt_req *req)
-{
- struct b2r2_blt_rect new_dst_rect;
- struct b2r2_blt_rect new_src_rect;
- struct b2r2_blt_rect new_bg_rect;
-
- b2r2_trim_rects(cont,
- req, &new_bg_rect, &new_dst_rect, &new_src_rect);
-
- req->dst_rect = new_dst_rect;
- req->src_rect = new_src_rect;
- req->bg_rect = new_bg_rect;
-}
-
static int check_rect(struct b2r2_control *cont,
const struct b2r2_blt_img *img,
const struct b2r2_blt_rect *rect,
@@ -619,10 +587,10 @@ static int check_rect(struct b2r2_control *cont,
/* If we are using clip we should only look at the intersection of the
rects */
if (clip) {
- l = MAX(rect->x, clip->x);
- t = MAX(rect->y, clip->y);
- r = MIN(rect->x + rect->width, clip->x + clip->width);
- b = MIN(rect->y + rect->height, clip->y + clip->height);
+ l = max(rect->x, clip->x);
+ t = max(rect->y, clip->y);
+ r = min(rect->x + rect->width, clip->x + clip->width);
+ b = min(rect->y + rect->height, clip->y + clip->height);
} else {
l = rect->x;
t = rect->y;
@@ -1338,22 +1306,22 @@ static int analyze_scale_factors(struct b2r2_control *cont,
u16 vsf;
if (this->rotation) {
- ret = calculate_scale_factor(cont, this->src.rect.width,
+ ret = calculate_scale_factor(cont->dev, this->src.rect.width,
this->dst.rect.height, &hsf);
if (ret < 0)
goto error;
- ret = calculate_scale_factor(cont, this->src.rect.height,
+ ret = calculate_scale_factor(cont->dev, this->src.rect.height,
this->dst.rect.width, &vsf);
if (ret < 0)
goto error;
} else {
- ret = calculate_scale_factor(cont, this->src.rect.width,
+ ret = calculate_scale_factor(cont->dev, this->src.rect.width,
this->dst.rect.width, &hsf);
if (ret < 0)
goto error;
- ret = calculate_scale_factor(cont, this->src.rect.height,
+ ret = calculate_scale_factor(cont->dev, this->src.rect.height,
this->dst.rect.height, &vsf);
if (ret < 0)
goto error;
@@ -2791,9 +2759,9 @@ static int setup_tmp_buf(struct b2r2_control *cont,
if (size > max_size) {
/* We need to limit the size, so we choose a different width */
- width = MIN(width, B2R2_RESCALE_MAX_WIDTH);
+ width = min(width, (u32) B2R2_RESCALE_MAX_WIDTH);
pitch = b2r2_fmt_byte_pitch(fmt, width);
- height = MIN(height, max_size / pitch);
+ height = min(height, max_size / pitch);
size = pitch * height;
}
@@ -2918,10 +2886,10 @@ static void set_target(struct b2r2_node *node, u32 addr,
/* Clip to the destination buffer to prevent memory overwrites */
if ((l < 0) || (r > buf->width) || (t < 0) || (b > buf->height)) {
/* The clip rectangle is including the borders */
- l = MAX(l, 0);
- r = MIN(r, buf->width) - 1;
- t = MAX(t, 0);
- b = MIN(b, buf->height) - 1;
+ l = max(l, 0);
+ r = min(r, (s32) buf->width) - 1;
+ t = max(t, 0);
+ b = min(b, (s32) buf->height) - 1;
node->node.GROUP0.B2R2_CIC |= B2R2_CIC_CLIP_WINDOW;
node->node.GROUP0.B2R2_INS |= B2R2_INS_RECT_CLIP_ENABLED;
diff --git a/drivers/video/b2r2/b2r2_profiler_socket.c b/drivers/video/b2r2/b2r2_profiler_socket.c
index ffa7f2870c8..cb95af9380e 100644
--- a/drivers/video/b2r2/b2r2_profiler_socket.c
+++ b/drivers/video/b2r2/b2r2_profiler_socket.c
@@ -16,7 +16,7 @@
#include "b2r2_profiler_api.h"
#include "b2r2_internal.h"
-
+#include "b2r2_core.h"
/*
* TODO: Call the profiler in a seperate thread and have a circular buffer
@@ -81,7 +81,8 @@ void b2r2_call_profiler_blt_done(const struct b2r2_blt_request * const request)
{
int return_value;
struct b2r2_blt_profiling_info blt_profiling_info;
- struct b2r2_control *cont = request->instance->control;
+ struct b2r2_core *core = (struct b2r2_core *) request->job.data;
+ struct b2r2_control *cont = core->control;
return_value = down_interruptible(&b2r2_profiler_lock);
if (return_value != 0) {
diff --git a/drivers/video/b2r2/b2r2_utils.c b/drivers/video/b2r2/b2r2_utils.c
index d482701089e..44c738b5aab 100644
--- a/drivers/video/b2r2/b2r2_utils.c
+++ b/drivers/video/b2r2/b2r2_utils.c
@@ -24,19 +24,19 @@ const s32 b2r2_s32_max = 2147483647;
* calculate_scale_factor() - calculates the scale factor between the given
* values
*/
-int calculate_scale_factor(struct b2r2_control *cont,
+int calculate_scale_factor(struct device *dev,
u32 from, u32 to, u16 *sf_out)
{
int ret;
u32 sf;
- b2r2_log_info(cont->dev, "%s\n", __func__);
+ b2r2_log_info(dev, "%s\n", __func__);
if (to == from) {
*sf_out = 1 << 10;
return 0;
} else if (to == 0) {
- b2r2_log_err(cont->dev, "%s: To is 0!\n", __func__);
+ b2r2_log_err(dev, "%s: To is 0!\n", __func__);
BUG_ON(1);
}
@@ -44,12 +44,12 @@ int calculate_scale_factor(struct b2r2_control *cont,
if ((sf & 0xffff0000) != 0) {
/* Overflow error */
- b2r2_log_warn(cont->dev, "%s: "
+ b2r2_log_warn(dev, "%s: "
"Scale factor too large\n", __func__);
ret = -EINVAL;
goto error;
} else if (sf == 0) {
- b2r2_log_warn(cont->dev, "%s: "
+ b2r2_log_warn(dev, "%s: "
"Scale factor too small\n", __func__);
ret = -EINVAL;
goto error;
@@ -57,12 +57,12 @@ int calculate_scale_factor(struct b2r2_control *cont,
*sf_out = (u16)sf;
- b2r2_log_info(cont->dev, "%s exit\n", __func__);
+ b2r2_log_info(dev, "%s exit\n", __func__);
return 0;
error:
- b2r2_log_warn(cont->dev, "%s: Exit...\n", __func__);
+ b2r2_log_warn(dev, "%s: Exit...\n", __func__);
return ret;
}
@@ -127,7 +127,7 @@ void b2r2_intersect_rects(struct b2r2_blt_rect *rect1,
* the old source rectangle corresponds to
* to the new part of old destination rectangle.
*/
-void b2r2_trim_rects(struct b2r2_control *cont,
+void b2r2_trim_rects(struct device *dev,
const struct b2r2_blt_req *req,
struct b2r2_blt_rect *new_bg_rect,
struct b2r2_blt_rect *new_dst_rect,
@@ -150,11 +150,11 @@ void b2r2_trim_rects(struct b2r2_control *cont,
s16 hsf;
s16 vsf;
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"%s\nold_dst_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__,
old_dst_rect->x, old_dst_rect->y,
old_dst_rect->width, old_dst_rect->height);
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"%s\nold_src_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__,
old_src_rect->x, old_src_rect->y,
old_src_rect->width, old_src_rect->height);
@@ -167,7 +167,7 @@ void b2r2_trim_rects(struct b2r2_control *cont,
goto keep_rects;
b2r2_intersect_rects(old_dst_rect, &dst_img_bounds, new_dst_rect);
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"%s\nnew_dst_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__,
new_dst_rect->x, new_dst_rect->y,
new_dst_rect->width, new_dst_rect->height);
@@ -181,13 +181,13 @@ void b2r2_trim_rects(struct b2r2_control *cont,
if (transform & B2R2_BLT_TRANSFORM_CCW_ROT_90) {
int res = 0;
- res = calculate_scale_factor(cont, old_src_rect->width,
+ res = calculate_scale_factor(dev, old_src_rect->width,
old_dst_rect->height, &hsf);
/* invalid dimensions, leave them to validation */
if (res < 0)
goto keep_rects;
- res = calculate_scale_factor(cont, old_src_rect->height,
+ res = calculate_scale_factor(dev, old_src_rect->height,
old_dst_rect->width, &vsf);
if (res < 0)
goto keep_rects;
@@ -207,12 +207,12 @@ void b2r2_trim_rects(struct b2r2_control *cont,
src_h = new_dst_rect->width * vsf;
} else {
int res = 0;
- res = calculate_scale_factor(cont, old_src_rect->width,
+ res = calculate_scale_factor(dev, old_src_rect->width,
old_dst_rect->width, &hsf);
if (res < 0)
goto keep_rects;
- res = calculate_scale_factor(cont, old_src_rect->height,
+ res = calculate_scale_factor(dev, old_src_rect->height,
old_dst_rect->height, &vsf);
if (res < 0)
goto keep_rects;
@@ -270,7 +270,7 @@ void b2r2_trim_rects(struct b2r2_control *cont,
new_src_rect->width = src_w;
new_src_rect->height = src_h;
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"%s\nnew_src_rect(x,y,w,h)=(%d, %d, %d, %d)\n", __func__,
new_src_rect->x, new_src_rect->y,
new_src_rect->width, new_src_rect->height);
@@ -279,7 +279,7 @@ void b2r2_trim_rects(struct b2r2_control *cont,
/* Modify bg_rect in the same way as dst_rect */
s32 dw = new_dst_rect->width - old_dst_rect->width;
s32 dh = new_dst_rect->height - old_dst_rect->height;
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"%s\nold bg_rect(x,y,w,h)=(%d, %d, %d, %d)\n",
__func__, old_bg_rect->x, old_bg_rect->y,
old_bg_rect->width, old_bg_rect->height);
@@ -287,7 +287,7 @@ void b2r2_trim_rects(struct b2r2_control *cont,
new_bg_rect->y = old_bg_rect->y + dy;
new_bg_rect->width = old_bg_rect->width + dw;
new_bg_rect->height = old_bg_rect->height + dh;
- b2r2_log_info(cont->dev,
+ b2r2_log_info(dev,
"%s\nnew bg_rect(x,y,w,h)=(%d, %d, %d, %d)\n",
__func__, new_bg_rect->x, new_bg_rect->y,
new_bg_rect->width, new_bg_rect->height);
@@ -301,11 +301,11 @@ keep_rects:
*new_src_rect = *old_src_rect;
*new_dst_rect = *old_dst_rect;
*new_bg_rect = *old_bg_rect;
- b2r2_log_info(cont->dev, "%s original rectangles preserved.\n", __func__);
+ b2r2_log_info(dev, "%s original rectangles preserved.\n", __func__);
return;
}
-int b2r2_get_fmt_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt)
+int b2r2_get_fmt_bpp(struct device *dev, enum b2r2_blt_fmt fmt)
{
/*
* Currently this function is not used that often but if that changes a
@@ -351,14 +351,14 @@ int b2r2_get_fmt_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt)
return 32;
default:
- b2r2_log_err(cont->dev,
+ b2r2_log_err(dev,
"%s: Internal error! Format %#x not recognized.\n",
__func__, fmt);
return 32;
}
}
-int b2r2_get_fmt_y_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt)
+int b2r2_get_fmt_y_bpp(struct device *dev, enum b2r2_blt_fmt fmt)
{
switch (fmt) {
case B2R2_BLT_FMT_YUV420_PACKED_PLANAR:
@@ -381,7 +381,7 @@ int b2r2_get_fmt_y_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt)
return 8;
default:
- b2r2_log_err(cont->dev,
+ b2r2_log_err(dev,
"%s: Internal error! Non YCbCr format supplied.\n",
__func__);
return 8;
@@ -542,40 +542,40 @@ bool b2r2_is_mb_fmt(enum b2r2_blt_fmt fmt)
}
}
-u32 b2r2_calc_pitch_from_width(struct b2r2_control *cont,
+u32 b2r2_calc_pitch_from_width(struct device *dev,
s32 width, enum b2r2_blt_fmt fmt)
{
if (b2r2_is_single_plane_fmt(fmt)) {
return (u32)b2r2_div_round_up(width *
- b2r2_get_fmt_bpp(cont, fmt), 8);
+ b2r2_get_fmt_bpp(dev, fmt), 8);
} else if (b2r2_is_ycbcrsp_fmt(fmt) || b2r2_is_ycbcrp_fmt(fmt)) {
return (u32)b2r2_div_round_up(width *
- b2r2_get_fmt_y_bpp(cont, fmt), 8);
+ b2r2_get_fmt_y_bpp(dev, fmt), 8);
} else {
- b2r2_log_err(cont->dev, "%s: Internal error! "
+ b2r2_log_err(dev, "%s: Internal error! "
"Pitchless format supplied.\n",
__func__);
return 0;
}
}
-u32 b2r2_get_img_pitch(struct b2r2_control *cont, struct b2r2_blt_img *img)
+u32 b2r2_get_img_pitch(struct device *dev, struct b2r2_blt_img *img)
{
if (img->pitch != 0)
return img->pitch;
else
- return b2r2_calc_pitch_from_width(cont, img->width, img->fmt);
+ return b2r2_calc_pitch_from_width(dev, img->width, img->fmt);
}
-s32 b2r2_get_img_size(struct b2r2_control *cont, struct b2r2_blt_img *img)
+s32 b2r2_get_img_size(struct device *dev, struct b2r2_blt_img *img)
{
if (b2r2_is_single_plane_fmt(img->fmt)) {
- return (s32)b2r2_get_img_pitch(cont, img) * img->height;
+ return (s32)b2r2_get_img_pitch(dev, img) * img->height;
} else if (b2r2_is_ycbcrsp_fmt(img->fmt) ||
b2r2_is_ycbcrp_fmt(img->fmt)) {
s32 y_plane_size;
- y_plane_size = (s32)b2r2_get_img_pitch(cont, img) * img->height;
+ y_plane_size = (s32)b2r2_get_img_pitch(dev, img) * img->height;
if (b2r2_is_ycbcr420_fmt(img->fmt)) {
return y_plane_size + y_plane_size / 2;
@@ -584,16 +584,16 @@ s32 b2r2_get_img_size(struct b2r2_control *cont, struct b2r2_blt_img *img)
} else if (b2r2_is_ycbcr444_fmt(img->fmt)) {
return y_plane_size * 3;
} else {
- b2r2_log_err(cont->dev, "%s: Internal error!"
+ b2r2_log_err(dev, "%s: Internal error!"
" Format %#x not recognized.\n",
__func__, img->fmt);
return 0;
}
} else if (b2r2_is_mb_fmt(img->fmt)) {
return (img->width * img->height *
- b2r2_get_fmt_bpp(cont, img->fmt)) / 8;
+ b2r2_get_fmt_bpp(dev, img->fmt)) / 8;
} else {
- b2r2_log_err(cont->dev, "%s: Internal error! "
+ b2r2_log_err(dev, "%s: Internal error! "
"Format %#x not recognized.\n",
__func__, img->fmt);
return 0;
@@ -1097,3 +1097,228 @@ enum b2r2_fmt_type b2r2_get_fmt_type(enum b2r2_blt_fmt fmt)
return B2R2_FMT_TYPE_RASTER;
}
}
+
+#ifdef CONFIG_DEBUG_FS
+/**
+ * sprintf_req() - Builds a string representing the request, for debug
+ *
+ * @request:Request that should be encoded into a string
+ * @buf: Receiving buffer
+ * @size: Size of receiving buffer
+ *
+ * Returns number of characters in string, excluding null terminator
+ */
+int sprintf_req(struct b2r2_blt_request *request, char *buf, int size)
+{
+ size_t dev_size = 0;
+
+ /* generic request info */
+ dev_size += sprintf(buf + dev_size,
+ "instance : 0x%08lX\n",
+ (unsigned long) request->instance);
+ dev_size += sprintf(buf + dev_size,
+ "size : %d bytes\n", request->user_req.size);
+ dev_size += sprintf(buf + dev_size,
+ "flags : 0x%08lX\n",
+ (unsigned long) request->user_req.flags);
+ dev_size += sprintf(buf + dev_size,
+ "transform : %d\n",
+ (int) request->user_req.transform);
+ dev_size += sprintf(buf + dev_size,
+ "prio : %d\n", request->user_req.transform);
+ dev_size += sprintf(buf + dev_size,
+ "global_alpha : %d\n",
+ (int) request->user_req.global_alpha);
+ dev_size += sprintf(buf + dev_size,
+ "report1 : 0x%08lX\n",
+ (unsigned long) request->user_req.report1);
+ dev_size += sprintf(buf + dev_size,
+ "report2 : 0x%08lX\n",
+ (unsigned long) request->user_req.report2);
+ dev_size += sprintf(buf + dev_size,
+ "request_id : 0x%08lX\n\n",
+ (unsigned long) request->request_id);
+
+ /* src info */
+ dev_size += sprintf(buf + dev_size,
+ "src_img.fmt : %#010x\n",
+ request->user_req.src_img.fmt);
+ dev_size += sprintf(buf + dev_size,
+ "src_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d, "
+ "offset=%d, len=%d}\n",
+ request->user_req.src_img.buf.type,
+ request->user_req.src_img.buf.hwmem_buf_name,
+ request->user_req.src_img.buf.fd,
+ request->user_req.src_img.buf.offset,
+ request->user_req.src_img.buf.len);
+ dev_size += sprintf(buf + dev_size,
+ "src_img : {width=%d, height=%d, pitch=%d}\n",
+ request->user_req.src_img.width,
+ request->user_req.src_img.height,
+ request->user_req.src_img.pitch);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask.fmt : %#010x\n",
+ request->user_req.src_mask.fmt);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask.buf : {type=%d, hwmem_buf_name=%d, fd=%d,"
+ " offset=%d, len=%d}\n",
+ request->user_req.src_mask.buf.type,
+ request->user_req.src_mask.buf.hwmem_buf_name,
+ request->user_req.src_mask.buf.fd,
+ request->user_req.src_mask.buf.offset,
+ request->user_req.src_mask.buf.len);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask : {width=%d, height=%d, pitch=%d}\n",
+ request->user_req.src_mask.width,
+ request->user_req.src_mask.height,
+ request->user_req.src_mask.pitch);
+ dev_size += sprintf(buf + dev_size,
+ "src_rect : {x=%d, y=%d, width=%d, height=%d}\n",
+ request->user_req.src_rect.x,
+ request->user_req.src_rect.y,
+ request->user_req.src_rect.width,
+ request->user_req.src_rect.height);
+ dev_size += sprintf(buf + dev_size,
+ "src_color : 0x%08lX\n\n",
+ (unsigned long) request->user_req.src_color);
+
+ /* bg info */
+ dev_size += sprintf(buf + dev_size,
+ "bg_img.fmt : %#010x\n",
+ request->user_req.bg_img.fmt);
+ dev_size += sprintf(buf + dev_size,
+ "bg_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d,"
+ " offset=%d, len=%d}\n",
+ request->user_req.bg_img.buf.type,
+ request->user_req.bg_img.buf.hwmem_buf_name,
+ request->user_req.bg_img.buf.fd,
+ request->user_req.bg_img.buf.offset,
+ request->user_req.bg_img.buf.len);
+ dev_size += sprintf(buf + dev_size,
+ "bg_img : {width=%d, height=%d, pitch=%d}\n",
+ request->user_req.bg_img.width,
+ request->user_req.bg_img.height,
+ request->user_req.bg_img.pitch);
+ dev_size += sprintf(buf + dev_size,
+ "bg_rect : {x=%d, y=%d, width=%d, height=%d}\n\n",
+ request->user_req.bg_rect.x,
+ request->user_req.bg_rect.y,
+ request->user_req.bg_rect.width,
+ request->user_req.bg_rect.height);
+
+ /* dst info */
+ dev_size += sprintf(buf + dev_size,
+ "dst_img.fmt : %#010x\n",
+ request->user_req.dst_img.fmt);
+ dev_size += sprintf(buf + dev_size,
+ "dst_img.buf : {type=%d, hwmem_buf_name=%d, fd=%d,"
+ " offset=%d, len=%d}\n",
+ request->user_req.dst_img.buf.type,
+ request->user_req.dst_img.buf.hwmem_buf_name,
+ request->user_req.dst_img.buf.fd,
+ request->user_req.dst_img.buf.offset,
+ request->user_req.dst_img.buf.len);
+ dev_size += sprintf(buf + dev_size,
+ "dst_img : {width=%d, height=%d, pitch=%d}\n",
+ request->user_req.dst_img.width,
+ request->user_req.dst_img.height,
+ request->user_req.dst_img.pitch);
+ dev_size += sprintf(buf + dev_size,
+ "dst_rect : {x=%d, y=%d, width=%d, height=%d}\n",
+ request->user_req.dst_rect.x,
+ request->user_req.dst_rect.y,
+ request->user_req.dst_rect.width,
+ request->user_req.dst_rect.height);
+ dev_size += sprintf(buf + dev_size,
+ "dst_clip_rect : {x=%d, y=%d, width=%d, height=%d}\n",
+ request->user_req.dst_clip_rect.x,
+ request->user_req.dst_clip_rect.y,
+ request->user_req.dst_clip_rect.width,
+ request->user_req.dst_clip_rect.height);
+ dev_size += sprintf(buf + dev_size,
+ "dst_color : 0x%08lX\n\n",
+ (unsigned long) request->user_req.dst_color);
+
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.physical : 0x%08lX\n",
+ (unsigned long) request->src_resolved.
+ physical_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.virtual : 0x%08lX\n",
+ (unsigned long) request->src_resolved.virtual_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.filep : 0x%08lX\n",
+ (unsigned long) request->src_resolved.filep);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.filep_physical_start : 0x%08lX\n",
+ (unsigned long) request->src_resolved.
+ file_physical_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.filep_virtual_start : 0x%08lX\n",
+ (unsigned long) request->src_resolved.file_virtual_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_resolved.file_len : %d\n\n",
+ request->src_resolved.file_len);
+
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.physical : 0x%08lX\n",
+ (unsigned long) request->src_mask_resolved.
+ physical_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.virtual : 0x%08lX\n",
+ (unsigned long) request->src_mask_resolved.virtual_address);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.filep : 0x%08lX\n",
+ (unsigned long) request->src_mask_resolved.filep);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.filep_physical_start : 0x%08lX\n",
+ (unsigned long) request->src_mask_resolved.
+ file_physical_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.filep_virtual_start : 0x%08lX\n",
+ (unsigned long) request->src_mask_resolved.
+ file_virtual_start);
+ dev_size += sprintf(buf + dev_size,
+ "src_mask_resolved.file_len : %d\n\n",
+ request->src_mask_resolved.file_len);
+
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.physical : 0x%08lX\n",
+ (unsigned long) request->dst_resolved.
+ physical_address);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.virtual : 0x%08lX\n",
+ (unsigned long) request->dst_resolved.virtual_address);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.filep : 0x%08lX\n",
+ (unsigned long) request->dst_resolved.filep);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.filep_physical_start : 0x%08lX\n",
+ (unsigned long) request->dst_resolved.
+ file_physical_start);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.filep_virtual_start : 0x%08lX\n",
+ (unsigned long) request->dst_resolved.file_virtual_start);
+ dev_size += sprintf(buf + dev_size,
+ "dst_resolved.file_len : %d\n\n",
+ request->dst_resolved.file_len);
+
+ return dev_size;
+}
+#endif
+
+void b2r2_recalculate_rects(struct device *dev,
+ struct b2r2_blt_req *req)
+{
+ struct b2r2_blt_rect new_dst_rect;
+ struct b2r2_blt_rect new_src_rect;
+ struct b2r2_blt_rect new_bg_rect;
+
+ b2r2_trim_rects(dev,
+ req, &new_bg_rect, &new_dst_rect, &new_src_rect);
+
+ req->dst_rect = new_dst_rect;
+ req->src_rect = new_src_rect;
+ if (req->flags & B2R2_BLT_FLAG_BG_BLEND)
+ req->bg_rect = new_bg_rect;
+}
diff --git a/drivers/video/b2r2/b2r2_utils.h b/drivers/video/b2r2/b2r2_utils.h
index e639e454121..081ac1f4848 100644
--- a/drivers/video/b2r2/b2r2_utils.h
+++ b/drivers/video/b2r2/b2r2_utils.h
@@ -17,7 +17,7 @@
extern const s32 b2r2_s32_max;
-int calculate_scale_factor(struct b2r2_control *cont,
+int calculate_scale_factor(struct device *dev,
u32 from, u32 to, u16 *sf_out);
void b2r2_get_img_bounding_rect(struct b2r2_blt_img *img,
struct b2r2_blt_rect *bounding_rect);
@@ -30,14 +30,14 @@ bool b2r2_is_rect_gte_rect(struct b2r2_blt_rect *rect1,
void b2r2_intersect_rects(struct b2r2_blt_rect *rect1,
struct b2r2_blt_rect *rect2,
struct b2r2_blt_rect *intersection);
-void b2r2_trim_rects(struct b2r2_control *cont,
+void b2r2_trim_rects(struct device *dev,
const struct b2r2_blt_req *req,
struct b2r2_blt_rect *new_bg_rect,
struct b2r2_blt_rect *new_dst_rect,
struct b2r2_blt_rect *new_src_rect);
-int b2r2_get_fmt_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt);
-int b2r2_get_fmt_y_bpp(struct b2r2_control *cont, enum b2r2_blt_fmt fmt);
+int b2r2_get_fmt_bpp(struct device *dev, enum b2r2_blt_fmt fmt);
+int b2r2_get_fmt_y_bpp(struct device *dev, enum b2r2_blt_fmt fmt);
bool b2r2_is_single_plane_fmt(enum b2r2_blt_fmt fmt);
bool b2r2_is_independent_pixel_fmt(enum b2r2_blt_fmt fmt);
@@ -52,11 +52,11 @@ bool b2r2_is_mb_fmt(enum b2r2_blt_fmt fmt);
/*
* Rounds up if an invalid width causes the pitch to be non byte aligned.
*/
-u32 b2r2_calc_pitch_from_width(struct b2r2_control *cont,
+u32 b2r2_calc_pitch_from_width(struct device *dev,
s32 width, enum b2r2_blt_fmt fmt);
-u32 b2r2_get_img_pitch(struct b2r2_control *cont,
+u32 b2r2_get_img_pitch(struct device *dev,
struct b2r2_blt_img *img);
-s32 b2r2_get_img_size(struct b2r2_control *cont,
+s32 b2r2_get_img_size(struct device *dev,
struct b2r2_blt_img *img);
s32 b2r2_div_round_up(s32 dividend, s32 divisor);
@@ -80,5 +80,10 @@ int b2r2_fmt_byte_pitch(enum b2r2_blt_fmt fmt, u32 width);
enum b2r2_native_fmt b2r2_to_native_fmt(enum b2r2_blt_fmt fmt);
u32 b2r2_to_RGB888(u32 color, const enum b2r2_blt_fmt fmt);
enum b2r2_fmt_type b2r2_get_fmt_type(enum b2r2_blt_fmt fmt);
+#ifdef CONFIG_DEBUG_FS
+int sprintf_req(struct b2r2_blt_request *request, char *buf, int size);
+#endif
+void b2r2_recalculate_rects(struct device *dev,
+ struct b2r2_blt_req *req);
#endif
diff --git a/include/video/b2r2_blt.h b/include/video/b2r2_blt.h
index 0964c95af36..4fdc40ab3b9 100644
--- a/include/video/b2r2_blt.h
+++ b/include/video/b2r2_blt.h
@@ -636,4 +636,55 @@ struct b2r2_blt_report {
#define B2R2_BLT_QUERY_CAP_IOC _IOWR(B2R2_BLT_IOC_MAGIC, 3, \
struct b2r2_blt_query_cap)
+/**
+ * struct b2r2_platform_data - The b2r2 core hardware configuration
+ *
+ * @regulator_id: The name of the b2r2 power source
+ * @clock_id: The name of the b2r2 clock
+ *
+ */
+struct b2r2_platform_data {
+ const char *regulator_id;
+ const char *clock_id;
+};
+
+/**
+ * b2r2_blt_open - Opening a handle for use with the blitter interface
+ *
+ * Returns a handle (0 or greater) to a B2R2 blitter intance on success
+ */
+int b2r2_blt_open(void);
+
+/**
+ * b2r2_blt_close - Free the blitter instance and its resources
+ *
+ * @handle: The B2R2 BLT instance handle
+ *
+ * All active jobs are finished or cancelled and allocated data
+ * is released.
+ *
+ * Returns 0 on success
+ */
+int b2r2_blt_close(int handle);
+
+/**
+ * b2r2_blt_request - Request a blit operation
+ *
+ * @handle: The B2R2 BLT instance handle
+ *
+ * Returns 0 on success
+ */
+int b2r2_blt_request(int handle, struct b2r2_blt_req *user_req);
+
+/**
+ * b2r2_blt_synch - Wait for all or a specified job
+ *
+ * @handle: The B2R2 BLT instance handle
+ * @request_id: If 0, wait for all requests on this instance to finish.
+ * Else wait for the request with the given request id to finish.
+ *
+ * Returns 0 on success
+ */
+int b2r2_blt_synch(int handle, int request_id);
+
#endif /* #ifdef _LINUX_VIDEO_B2R2_BLT_H */