1004 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1004 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0
 | |
| /*
 | |
|  * Copyright (C) Rockchip Electronics Co., Ltd.
 | |
|  *
 | |
|  * Author:
 | |
|  *	Cerf Yu <cerf.yu@rock-chips.com>
 | |
|  *	Huang Lee <Putin.li@rock-chips.com>
 | |
|  */
 | |
| 
 | |
| #include <linux/slab.h>
 | |
| #include <linux/delay.h>
 | |
| #include <linux/syscalls.h>
 | |
| #include <linux/kernel.h>
 | |
| #include <linux/debugfs.h>
 | |
| #include <linux/proc_fs.h>
 | |
| #include <linux/seq_file.h>
 | |
| 
 | |
| #include "rga.h"
 | |
| #include "rga_debugger.h"
 | |
| #include "rga_drv.h"
 | |
| #include "rga_mm.h"
 | |
| #include "rga_common.h"
 | |
| #include "rga_job.h"
 | |
| 
 | |
| #define RGA_DEBUGGER_ROOT_NAME "rkrga"
 | |
| 
 | |
| #define STR_ENABLE(en) (en ? "EN" : "DIS")
 | |
| 
 | |
| int RGA_DEBUG_REG;
 | |
| int RGA_DEBUG_MSG;
 | |
| int RGA_DEBUG_TIME;
 | |
| int RGA_DEBUG_INT_FLAG;
 | |
| int RGA_DEBUG_MM;
 | |
| int RGA_DEBUG_CHECK_MODE;
 | |
| int RGA_DEBUG_INTERNAL_MODE;
 | |
| int RGA_DEBUG_NONUSE;
 | |
| int RGA_DEBUG_DEBUG_MODE;
 | |
| int RGA_DEBUG_DUMP_IMAGE;
 | |
| 
 | |
| #ifdef CONFIG_NO_GKI
 | |
| static char g_dump_path[100] = "/data";
 | |
| #endif
 | |
| 
 | |
| static int rga_debug_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	seq_printf(m, "REG [%s]\n"
 | |
| 		 "MSG [%s]\n"
 | |
| 		 "TIME [%s]\n"
 | |
| 		 "INT [%s]\n"
 | |
| 		 "MM [%s]\n"
 | |
| 		 "CHECK [%s]\n"
 | |
| 		 "INTL [%s]\n"
 | |
| 		 "STOP [%s]\n",
 | |
| 		 STR_ENABLE(RGA_DEBUG_REG),
 | |
| 		 STR_ENABLE(RGA_DEBUG_MSG),
 | |
| 		 STR_ENABLE(RGA_DEBUG_TIME),
 | |
| 		 STR_ENABLE(RGA_DEBUG_INT_FLAG),
 | |
| 		 STR_ENABLE(RGA_DEBUG_MM),
 | |
| 		 STR_ENABLE(RGA_DEBUG_CHECK_MODE),
 | |
| 		 STR_ENABLE(RGA_DEBUG_INTERNAL_MODE),
 | |
| 		 STR_ENABLE(RGA_DEBUG_NONUSE));
 | |
| 
 | |
| 	seq_puts(m, "\nhelp:\n");
 | |
| 	seq_puts(m, " 'echo reg > debug' to enable/disable register log printing.\n");
 | |
| 	seq_puts(m, " 'echo msg > debug' to enable/disable message log printing.\n");
 | |
| 	seq_puts(m, " 'echo time > debug' to enable/disable time log printing.\n");
 | |
| 	seq_puts(m, " 'echo int > debug' to enable/disable interruppt log printing.\n");
 | |
| 	seq_puts(m, " 'echo mm > debug' to enable/disable memory manager log printing.\n");
 | |
| 	seq_puts(m, " 'echo check > debug' to enable/disable check mode.\n");
 | |
| 	seq_puts(m, " 'echo intl > debug' to enable/disable internal mode.\n");
 | |
| 	seq_puts(m, " 'echo stop > debug' to enable/disable stop using hardware\n");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static ssize_t rga_debug_write(struct file *file, const char __user *ubuf,
 | |
| 				 size_t len, loff_t *offp)
 | |
| {
 | |
| 	char buf[14];
 | |
| 
 | |
| 	if (len > sizeof(buf) - 1)
 | |
| 		return -EINVAL;
 | |
| 	if (copy_from_user(buf, ubuf, len))
 | |
| 		return -EFAULT;
 | |
| 	buf[len - 1] = '\0';
 | |
| 
 | |
| 	if (strncmp(buf, "reg", 4) == 0) {
 | |
| 		if (RGA_DEBUG_REG) {
 | |
| 			RGA_DEBUG_REG = 0;
 | |
| 			pr_info("close rga reg!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_REG = 1;
 | |
| 			pr_info("open rga reg!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "msg", 3) == 0) {
 | |
| 		if (RGA_DEBUG_MSG) {
 | |
| 			RGA_DEBUG_MSG = 0;
 | |
| 			pr_info("close rga test MSG!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_MSG = 1;
 | |
| 			pr_info("open rga test MSG!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "time", 4) == 0) {
 | |
| 		if (RGA_DEBUG_TIME) {
 | |
| 			RGA_DEBUG_TIME = 0;
 | |
| 			pr_info("close rga test time!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_TIME = 1;
 | |
| 			pr_info("open rga test time!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "intl", 4) == 0) {
 | |
| 		if (RGA_DEBUG_INTERNAL_MODE) {
 | |
| 			RGA_DEBUG_INTERNAL_MODE = 0;
 | |
| 			pr_info("close rga internal flag!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_INTERNAL_MODE = 1;
 | |
| 			pr_info("open rga internal flag!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "int", 3) == 0) {
 | |
| 		if (RGA_DEBUG_INT_FLAG) {
 | |
| 			RGA_DEBUG_INT_FLAG = 0;
 | |
| 			pr_info("close inturrupt MSG!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_INT_FLAG = 1;
 | |
| 			pr_info("open inturrupt MSG!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "mm", 2) == 0) {
 | |
| 		if (RGA_DEBUG_MM) {
 | |
| 			RGA_DEBUG_MM = 0;
 | |
| 			pr_info("close rga mm log!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_MM = 1;
 | |
| 			pr_info("open rga mm log!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "check", 5) == 0) {
 | |
| 		if (RGA_DEBUG_CHECK_MODE) {
 | |
| 			RGA_DEBUG_CHECK_MODE = 0;
 | |
| 			pr_info("close rga check flag!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_CHECK_MODE = 1;
 | |
| 			pr_info("open rga check flag!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "stop", 4) == 0) {
 | |
| 		if (RGA_DEBUG_NONUSE) {
 | |
| 			RGA_DEBUG_NONUSE = 0;
 | |
| 			pr_info("using rga hardware!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_NONUSE = 1;
 | |
| 			pr_info("stop using rga hardware!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "debug", 3) == 0) {
 | |
| 		if (RGA_DEBUG_DEBUG_MODE) {
 | |
| 			RGA_DEBUG_REG = 0;
 | |
| 			RGA_DEBUG_MSG = 0;
 | |
| 			RGA_DEBUG_TIME = 0;
 | |
| 			RGA_DEBUG_INT_FLAG = 0;
 | |
| 
 | |
| 			RGA_DEBUG_DEBUG_MODE = 0;
 | |
| 			pr_info("close debug mode!\n");
 | |
| 		} else {
 | |
| 			RGA_DEBUG_REG = 1;
 | |
| 			RGA_DEBUG_MSG = 1;
 | |
| 			RGA_DEBUG_TIME = 1;
 | |
| 			RGA_DEBUG_INT_FLAG = 1;
 | |
| 
 | |
| 			RGA_DEBUG_DEBUG_MODE = 1;
 | |
| 			pr_info("open debug mode!\n");
 | |
| 		}
 | |
| 	} else if (strncmp(buf, "slt", 3) == 0) {
 | |
| 		pr_err("Null");
 | |
| 	}
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| static int rga_version_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	seq_printf(m, "%s: v%s\n", DRIVER_DESC, DRIVER_VERSION);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int rga_load_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	struct rga_scheduler_t *scheduler = NULL;
 | |
| 	struct rga_session_manager *session_manager = NULL;
 | |
| 	struct rga_session *session = NULL;
 | |
| 	unsigned long flags;
 | |
| 	int id = 0;
 | |
| 	int i;
 | |
| 	int load;
 | |
| 	u32 busy_time_total;
 | |
| 	ktime_t now;
 | |
| 
 | |
| 	session_manager = rga_drvdata->session_manager;
 | |
| 
 | |
| 	seq_printf(m, "num of scheduler = %d\n", rga_drvdata->num_of_scheduler);
 | |
| 	seq_puts(m, "================= load ==================\n");
 | |
| 
 | |
| 	for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
 | |
| 		scheduler = rga_drvdata->scheduler[i];
 | |
| 
 | |
| 		seq_printf(m, "scheduler[%d]: %s\n",
 | |
| 			i, dev_driver_string(scheduler->dev));
 | |
| 
 | |
| 		spin_lock_irqsave(&scheduler->irq_lock, flags);
 | |
| 
 | |
| 		busy_time_total = scheduler->timer.busy_time_record;
 | |
| 
 | |
| 		spin_unlock_irqrestore(&scheduler->irq_lock, flags);
 | |
| 
 | |
| 		load = (busy_time_total * 100 / RGA_LOAD_INTERVAL_US);
 | |
| 		if (load > 100)
 | |
| 			load = 100;
 | |
| 
 | |
| 		seq_printf(m, "\t load = %d%%\n", load);
 | |
| 		seq_puts(m, "-----------------------------------\n");
 | |
| 	}
 | |
| 
 | |
| 	seq_puts(m, "=========================================\n");
 | |
| 	seq_puts(m, "<session>  <status>  <tgid>  <process>\n");
 | |
| 
 | |
| 	mutex_lock(&session_manager->lock);
 | |
| 
 | |
| 	now = ktime_get();
 | |
| 	idr_for_each_entry(&session_manager->ctx_id_idr, session, id)
 | |
| 		seq_printf(m, "%-9d  %-8s  %-6d  %-s\n",
 | |
| 			session->id,
 | |
| 			ktime_us_delta(now, session->last_active) < RGA_LOAD_ACTIVE_MAX_US ?
 | |
| 				"active" : "idle",
 | |
| 			session->tgid, session->pname);
 | |
| 
 | |
| 	mutex_unlock(&session_manager->lock);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int rga_scheduler_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	struct rga_scheduler_t *scheduler = NULL;
 | |
| 	int i;
 | |
| 
 | |
| 	seq_printf(m, "num of scheduler = %d\n", rga_drvdata->num_of_scheduler);
 | |
| 	seq_printf(m, "===================================\n");
 | |
| 
 | |
| 	for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
 | |
| 		scheduler = rga_drvdata->scheduler[i];
 | |
| 
 | |
| 		seq_printf(m, "scheduler[%d]: %s\n",
 | |
| 			i, dev_driver_string(scheduler->dev));
 | |
| 		seq_printf(m, "-----------------------------------\n");
 | |
| 		seq_printf(m, "pd_ref = %d\n", scheduler->pd_refcount);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int rga_mm_session_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	int id;
 | |
| 	struct rga_mm *mm_session = NULL;
 | |
| 	struct rga_internal_buffer *dump_buffer;
 | |
| 
 | |
| 	mm_session = rga_drvdata->mm;
 | |
| 
 | |
| 	mutex_lock(&mm_session->lock);
 | |
| 
 | |
| 	seq_puts(m, "rga_mm dump:\n");
 | |
| 	seq_printf(m, "buffer count = %d\n", mm_session->buffer_count);
 | |
| 	seq_puts(m, "===============================================================\n");
 | |
| 
 | |
| 	idr_for_each_entry(&mm_session->memory_idr, dump_buffer, id) {
 | |
| 		seq_printf(m, "handle = %d refcount = %d mm_flag = 0x%x	tgid = %d\n",
 | |
| 			   dump_buffer->handle, kref_read(&dump_buffer->refcount),
 | |
| 			   dump_buffer->mm_flag, dump_buffer->session->tgid);
 | |
| 
 | |
| 		switch (dump_buffer->type) {
 | |
| 		case RGA_DMA_BUFFER:
 | |
| 		case RGA_DMA_BUFFER_PTR:
 | |
| 			if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer))
 | |
| 				break;
 | |
| 
 | |
| 			seq_puts(m, "dma_buffer:\n");
 | |
| 			seq_printf(m, "\t dma_buf = %p, iova = 0x%lxsgt = 0x%p, size = %ld, map_core = 0x%x\n",
 | |
| 				   dump_buffer->dma_buffer->dma_buf,
 | |
| 				   (unsigned long)dump_buffer->dma_buffer->iova,
 | |
| 				   dump_buffer->dma_buffer->sgt,
 | |
| 				   dump_buffer->dma_buffer->size,
 | |
| 				   dump_buffer->dma_buffer->scheduler->core);
 | |
| 
 | |
| 			if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
 | |
| 				seq_printf(m, "\t is contiguous, pa = 0x%lx\n",
 | |
| 					   (unsigned long)dump_buffer->phys_addr);
 | |
| 
 | |
| 			break;
 | |
| 		case RGA_VIRTUAL_ADDRESS:
 | |
| 			if (dump_buffer->virt_addr == NULL)
 | |
| 				break;
 | |
| 			seq_puts(m, "virtual address:\n");
 | |
| 			seq_printf(m, "\t va = 0x%lx, pages = 0x%p, size = %ld\n",
 | |
| 				   (unsigned long)dump_buffer->virt_addr->addr,
 | |
| 				   dump_buffer->virt_addr->pages,
 | |
| 				   dump_buffer->virt_addr->size);
 | |
| 
 | |
| 			if (rga_mm_is_invalid_dma_buffer(dump_buffer->dma_buffer))
 | |
| 				break;
 | |
| 
 | |
| 			seq_printf(m, "\t iova = 0x%lx, offset = 0x%lx, sgt = 0x%p, size = %ld, map_core = 0x%x\n",
 | |
| 				   (unsigned long)dump_buffer->dma_buffer->iova,
 | |
| 				   (unsigned long)dump_buffer->dma_buffer->offset,
 | |
| 				   dump_buffer->dma_buffer->sgt,
 | |
| 				   dump_buffer->dma_buffer->size,
 | |
| 				   dump_buffer->dma_buffer->scheduler->core);
 | |
| 
 | |
| 			if (dump_buffer->mm_flag & RGA_MEM_PHYSICAL_CONTIGUOUS)
 | |
| 				seq_printf(m, "\t is contiguous, pa = 0x%lx\n",
 | |
| 					   (unsigned long)dump_buffer->phys_addr);
 | |
| 
 | |
| 			break;
 | |
| 		case RGA_PHYSICAL_ADDRESS:
 | |
| 			seq_puts(m, "physical address:\n");
 | |
| 			seq_printf(m, "\t pa = 0x%lx\n", (unsigned long)dump_buffer->phys_addr);
 | |
| 			break;
 | |
| 		default:
 | |
| 			seq_puts(m, "Illegal external buffer!\n");
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		seq_puts(m, "---------------------------------------------------------------\n");
 | |
| 	}
 | |
| 	mutex_unlock(&mm_session->lock);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int rga_request_manager_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	int id, i;
 | |
| 	struct rga_pending_request_manager *request_manager;
 | |
| 	struct rga_request *request;
 | |
| 	struct rga_req *task_list;
 | |
| 	unsigned long flags;
 | |
| 	int task_count = 0;
 | |
| 	int finished_task_count = 0, failed_task_count = 0;
 | |
| 
 | |
| 	request_manager = rga_drvdata->pend_request_manager;
 | |
| 
 | |
| 	seq_puts(m, "rga internal request dump:\n");
 | |
| 	seq_printf(m, "request count = %d\n", request_manager->request_count);
 | |
| 	seq_puts(m, "===============================================================\n");
 | |
| 
 | |
| 	mutex_lock(&request_manager->lock);
 | |
| 
 | |
| 	idr_for_each_entry(&request_manager->request_idr, request, id) {
 | |
| 		seq_printf(m, "------------------ request: %d ------------------\n", request->id);
 | |
| 
 | |
| 		spin_lock_irqsave(&request->lock, flags);
 | |
| 
 | |
| 		task_count = request->task_count;
 | |
| 		finished_task_count = request->finished_task_count;
 | |
| 		failed_task_count = request->failed_task_count;
 | |
| 		task_list = request->task_list;
 | |
| 
 | |
| 		spin_unlock_irqrestore(&request->lock, flags);
 | |
| 
 | |
| 		if (task_list == NULL) {
 | |
| 			seq_puts(m, "\t can not find task list from id\n");
 | |
| 			continue;
 | |
| 		}
 | |
| 
 | |
| 		seq_printf(m, "\t set cmd num: %d, finish job: %d, failed job: %d, flags = 0x%x, ref = %d\n",
 | |
| 			   task_count, finished_task_count, failed_task_count,
 | |
| 			   request->flags, kref_read(&request->refcount));
 | |
| 
 | |
| 		seq_puts(m, "\t cmd dump:\n\n");
 | |
| 
 | |
| 		for (i = 0; i < request->task_count; i++)
 | |
| 			rga_request_task_debug_info(m, &(task_list[i]));
 | |
| 	}
 | |
| 
 | |
| 	mutex_unlock(&request_manager->lock);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_NO_GKI
 | |
| static int rga_dump_path_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	seq_printf(m, "dump path: %s\n", g_dump_path);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static ssize_t rga_dump_path_write(struct file *file, const char __user *ubuf,
 | |
| 				    size_t len, loff_t *offp)
 | |
| {
 | |
| 	char buf[100];
 | |
| 
 | |
| 	if (len > sizeof(buf) - 1)
 | |
| 		return -EINVAL;
 | |
| 	if (copy_from_user(buf, ubuf, len))
 | |
| 		return -EFAULT;
 | |
| 	buf[len - 1] = '\0';
 | |
| 
 | |
| 	snprintf(g_dump_path, sizeof(buf), "%s", buf);
 | |
| 	pr_info("dump path change to: %s\n", g_dump_path);
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| static int rga_dump_image_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	seq_printf(m, "dump image count: %d\n", RGA_DEBUG_DUMP_IMAGE);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static ssize_t rga_dump_image_write(struct file *file, const char __user *ubuf,
 | |
| 				    size_t len, loff_t *offp)
 | |
| {
 | |
| 	int ret;
 | |
| 	int dump_count = 0;
 | |
| 	char buf[14];
 | |
| 
 | |
| 	if (len > sizeof(buf) - 1)
 | |
| 		return -EINVAL;
 | |
| 	if (copy_from_user(buf, ubuf, len))
 | |
| 		return -EFAULT;
 | |
| 	buf[len - 1] = '\0';
 | |
| 
 | |
| 	ret = kstrtoint(buf, 10, &dump_count);
 | |
| 	if (ret) {
 | |
| 		pr_err("Failed to parse str[%s]\n", buf);
 | |
| 		return -EFAULT;
 | |
| 	}
 | |
| 
 | |
| 	if (dump_count <= 0) {
 | |
| 		pr_err("dump_image count is invalid [%d]!\n", dump_count);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	RGA_DEBUG_DUMP_IMAGE = dump_count;
 | |
| 	pr_info("dump image %d\n", RGA_DEBUG_DUMP_IMAGE);
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| #endif /* #ifdef CONFIG_NO_GKI */
 | |
| 
 | |
| static int rga_hardware_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	struct rga_scheduler_t *scheduler = NULL;
 | |
| 	const struct rga_hw_data *hw_data = NULL;
 | |
| 	int i;
 | |
| 
 | |
| 	seq_puts(m, "===================================\n");
 | |
| 
 | |
| 	for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
 | |
| 		scheduler = rga_drvdata->scheduler[i];
 | |
| 		hw_data = scheduler->data;
 | |
| 
 | |
| 		seq_printf(m, "%s, core %d: version: %s\n",
 | |
| 			   dev_driver_string(scheduler->dev),
 | |
| 			   scheduler->core, scheduler->version.str);
 | |
| 		seq_printf(m, "input range: %dx%d ~ %dx%d\n",
 | |
| 			   hw_data->input_range.min.width, hw_data->input_range.min.height,
 | |
| 			   hw_data->input_range.max.width, hw_data->input_range.max.height);
 | |
| 		seq_printf(m, "output range: %dx%d ~ %dx%d\n",
 | |
| 			   hw_data->output_range.min.width, hw_data->output_range.min.height,
 | |
| 			   hw_data->output_range.max.width, hw_data->output_range.max.height);
 | |
| 		seq_printf(m, "scale limit: 1/%d ~ %d\n",
 | |
| 			   (1 << hw_data->max_downscale_factor),
 | |
| 			   (1 << hw_data->max_upscale_factor));
 | |
| 		seq_printf(m, "byte_stride_align: %d\n", hw_data->byte_stride_align);
 | |
| 		seq_printf(m, "max_byte_stride: %d\n", hw_data->max_byte_stride);
 | |
| 		seq_printf(m, "csc: RGB2YUV 0x%x YUV2RGB 0x%x\n",
 | |
| 			   hw_data->csc_r2y_mode, hw_data->csc_y2r_mode);
 | |
| 		seq_printf(m, "feature: 0x%x\n", hw_data->feature);
 | |
| 		seq_printf(m, "mmu: %s\n", rga_get_mmu_type_str(hw_data->mmu));
 | |
| 		seq_puts(m, "-----------------------------------\n");
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int rga_reset_show(struct seq_file *m, void *data)
 | |
| {
 | |
| 	struct rga_scheduler_t *scheduler = NULL;
 | |
| 	int i;
 | |
| 
 | |
| 	seq_puts(m, "help:\n");
 | |
| 	seq_puts(m, " 'echo <core> > reset' to reset hardware.\n");
 | |
| 
 | |
| 	seq_puts(m, "core:\n");
 | |
| 	for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
 | |
| 		scheduler = rga_drvdata->scheduler[i];
 | |
| 
 | |
| 		seq_printf(m, "  %s core <%d>\n",
 | |
| 			   dev_driver_string(scheduler->dev), scheduler->core);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static ssize_t rga_reset_write(struct file *file, const char __user *ubuf,
 | |
| 			       size_t len, loff_t *offp)
 | |
| {
 | |
| 	char buf[14];
 | |
| 	int i, ret;
 | |
| 	int reset_core = 0;
 | |
| 	int reset_done = false;
 | |
| 	struct rga_scheduler_t *scheduler = NULL;
 | |
| 
 | |
| 	if (len > sizeof(buf) - 1)
 | |
| 		return -EINVAL;
 | |
| 	if (copy_from_user(buf, ubuf, len))
 | |
| 		return -EFAULT;
 | |
| 	buf[len - 1] = '\0';
 | |
| 
 | |
| 	ret = kstrtoint(buf, 10, &reset_core);
 | |
| 	if (ret < 0 || reset_core <= 0) {
 | |
| 		pr_err("invalid core! failed to reset hardware, data = %s len = %zu.\n", buf, len);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	for (i = 0; i < rga_drvdata->num_of_scheduler; i++) {
 | |
| 		scheduler = rga_drvdata->scheduler[i];
 | |
| 
 | |
| 		if (scheduler->core == reset_core) {
 | |
| 			reset_done = true;
 | |
| 			pr_info("reset hardware core[%d]!\n", reset_core);
 | |
| 
 | |
| 			rga_request_scheduler_abort(scheduler);
 | |
| 
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (!reset_done)
 | |
| 		pr_err("cannot find core[%d]\n", reset_core);
 | |
| 
 | |
| 	return len;
 | |
| }
 | |
| 
 | |
| static struct rga_debugger_list rga_debugger_root_list[] = {
 | |
| 	{"debug", rga_debug_show, rga_debug_write, NULL},
 | |
| 	{"driver_version", rga_version_show, NULL, NULL},
 | |
| 	{"load", rga_load_show, NULL, NULL},
 | |
| 	{"scheduler_status", rga_scheduler_show, NULL, NULL},
 | |
| 	{"mm_session", rga_mm_session_show, NULL, NULL},
 | |
| 	{"request_manager", rga_request_manager_show, NULL, NULL},
 | |
| #ifdef CONFIG_NO_GKI
 | |
| 	{"dump_path", rga_dump_path_show, rga_dump_path_write, NULL},
 | |
| 	{"dump_image", rga_dump_image_show, rga_dump_image_write, NULL},
 | |
| #endif
 | |
| 	{"hardware", rga_hardware_show, NULL, NULL},
 | |
| 	{"reset", rga_reset_show, rga_reset_write, NULL},
 | |
| };
 | |
| 
 | |
| static ssize_t rga_debugger_write(struct file *file, const char __user *ubuf,
 | |
| 				 size_t len, loff_t *offp)
 | |
| {
 | |
| 	struct seq_file *priv = file->private_data;
 | |
| 	struct rga_debugger_node *node = priv->private;
 | |
| 
 | |
| 	if (node->info_ent->write)
 | |
| 		return node->info_ent->write(file, ubuf, len, offp);
 | |
| 	else
 | |
| 		return len;
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS
 | |
| static int rga_debugfs_open(struct inode *inode, struct file *file)
 | |
| {
 | |
| 	struct rga_debugger_node *node = inode->i_private;
 | |
| 
 | |
| 	return single_open(file, node->info_ent->show, node);
 | |
| }
 | |
| 
 | |
| static const struct file_operations rga_debugfs_fops = {
 | |
| 	.owner = THIS_MODULE,
 | |
| 	.open = rga_debugfs_open,
 | |
| 	.read = seq_read,
 | |
| 	.llseek = seq_lseek,
 | |
| 	.release = single_release,
 | |
| 	.write = rga_debugger_write,
 | |
| };
 | |
| 
 | |
| static int rga_debugfs_remove_files(struct rga_debugger *debugger)
 | |
| {
 | |
| 	struct rga_debugger_node *pos, *q;
 | |
| 	struct list_head *entry_list;
 | |
| 
 | |
| 	mutex_lock(&debugger->debugfs_lock);
 | |
| 
 | |
| 	/* Delete debugfs entry list */
 | |
| 	entry_list = &debugger->debugfs_entry_list;
 | |
| 	list_for_each_entry_safe(pos, q, entry_list, list) {
 | |
| 		if (pos->dent == NULL)
 | |
| 			continue;
 | |
| 		list_del(&pos->list);
 | |
| 		kfree(pos);
 | |
| 		pos = NULL;
 | |
| 	}
 | |
| 
 | |
| 	/* Delete all debugfs node in this directory */
 | |
| 	debugfs_remove_recursive(debugger->debugfs_dir);
 | |
| 	debugger->debugfs_dir = NULL;
 | |
| 
 | |
| 	mutex_unlock(&debugger->debugfs_lock);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int rga_debugfs_create_files(const struct rga_debugger_list *files,
 | |
| 					int count, struct dentry *root,
 | |
| 					struct rga_debugger *debugger)
 | |
| {
 | |
| 	int i;
 | |
| 	struct dentry *ent;
 | |
| 	struct rga_debugger_node *tmp;
 | |
| 
 | |
| 	for (i = 0; i < count; i++) {
 | |
| 		tmp = kmalloc(sizeof(struct rga_debugger_node), GFP_KERNEL);
 | |
| 		if (tmp == NULL) {
 | |
| 			pr_err("Cannot alloc node path /sys/kernel/debug/%pd/%s\n",
 | |
| 				 root, files[i].name);
 | |
| 			goto MALLOC_FAIL;
 | |
| 		}
 | |
| 
 | |
| 		tmp->info_ent = &files[i];
 | |
| 		tmp->debugger = debugger;
 | |
| 
 | |
| 		ent = debugfs_create_file(files[i].name, S_IFREG | S_IRUGO,
 | |
| 					 root, tmp, &rga_debugfs_fops);
 | |
| 		if (!ent) {
 | |
| 			pr_err("Cannot create /sys/kernel/debug/%pd/%s\n", root,
 | |
| 				 files[i].name);
 | |
| 			goto CREATE_FAIL;
 | |
| 		}
 | |
| 
 | |
| 		tmp->dent = ent;
 | |
| 
 | |
| 		mutex_lock(&debugger->debugfs_lock);
 | |
| 		list_add_tail(&tmp->list, &debugger->debugfs_entry_list);
 | |
| 		mutex_unlock(&debugger->debugfs_lock);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| CREATE_FAIL:
 | |
| 	kfree(tmp);
 | |
| MALLOC_FAIL:
 | |
| 	rga_debugfs_remove_files(debugger);
 | |
| 
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| int rga_debugfs_remove(void)
 | |
| {
 | |
| 	struct rga_debugger *debugger;
 | |
| 
 | |
| 	debugger = rga_drvdata->debugger;
 | |
| 
 | |
| 	rga_debugfs_remove_files(debugger);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int rga_debugfs_init(void)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct rga_debugger *debugger;
 | |
| 
 | |
| 	debugger = rga_drvdata->debugger;
 | |
| 
 | |
| 	debugger->debugfs_dir =
 | |
| 		debugfs_create_dir(RGA_DEBUGGER_ROOT_NAME, NULL);
 | |
| 	if (IS_ERR_OR_NULL(debugger->debugfs_dir)) {
 | |
| 		pr_err("failed on mkdir /sys/kernel/debug/%s\n",
 | |
| 			 RGA_DEBUGGER_ROOT_NAME);
 | |
| 		debugger->debugfs_dir = NULL;
 | |
| 		return -EIO;
 | |
| 	}
 | |
| 
 | |
| 	ret = rga_debugfs_create_files(rga_debugger_root_list, ARRAY_SIZE(rga_debugger_root_list),
 | |
| 					 debugger->debugfs_dir, debugger);
 | |
| 	if (ret) {
 | |
| 		pr_err("Could not install rga_debugger_root_list debugfs\n");
 | |
| 		goto CREATE_FAIL;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| CREATE_FAIL:
 | |
| 	rga_debugfs_remove();
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| #endif /* #ifdef CONFIG_ROCKCHIP_RGA_DEBUG_FS */
 | |
| 
 | |
| #ifdef CONFIG_ROCKCHIP_RGA_PROC_FS
 | |
| static int rga_procfs_open(struct inode *inode, struct file *file)
 | |
| {
 | |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
 | |
| 	struct rga_debugger_node *node = pde_data(inode);
 | |
| #else
 | |
| 	struct rga_debugger_node *node = PDE_DATA(inode);
 | |
| #endif
 | |
| 
 | |
| 	return single_open(file, node->info_ent->show, node);
 | |
| }
 | |
| 
 | |
| static const struct proc_ops rga_procfs_fops = {
 | |
| 	.proc_open = rga_procfs_open,
 | |
| 	.proc_read = seq_read,
 | |
| 	.proc_lseek = seq_lseek,
 | |
| 	.proc_release = single_release,
 | |
| 	.proc_write = rga_debugger_write,
 | |
| };
 | |
| 
 | |
| static int rga_procfs_remove_files(struct rga_debugger *debugger)
 | |
| {
 | |
| 	struct rga_debugger_node *pos, *q;
 | |
| 	struct list_head *entry_list;
 | |
| 
 | |
| 	mutex_lock(&debugger->procfs_lock);
 | |
| 
 | |
| 	/* Delete procfs entry list */
 | |
| 	entry_list = &debugger->procfs_entry_list;
 | |
| 	list_for_each_entry_safe(pos, q, entry_list, list) {
 | |
| 		if (pos->pent == NULL)
 | |
| 			continue;
 | |
| 		list_del(&pos->list);
 | |
| 		kfree(pos);
 | |
| 		pos = NULL;
 | |
| 	}
 | |
| 
 | |
| 	/* Delete all procfs node in this directory */
 | |
| 	proc_remove(debugger->procfs_dir);
 | |
| 	debugger->procfs_dir = NULL;
 | |
| 
 | |
| 	mutex_unlock(&debugger->procfs_lock);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int rga_procfs_create_files(const struct rga_debugger_list *files,
 | |
| 				 int count, struct proc_dir_entry *root,
 | |
| 				 struct rga_debugger *debugger)
 | |
| {
 | |
| 	int i;
 | |
| 	struct proc_dir_entry *ent;
 | |
| 	struct rga_debugger_node *tmp;
 | |
| 
 | |
| 	for (i = 0; i < count; i++) {
 | |
| 		tmp = kmalloc(sizeof(struct rga_debugger_node), GFP_KERNEL);
 | |
| 		if (tmp == NULL) {
 | |
| 			pr_err("Cannot alloc node path for /proc/%s/%s\n",
 | |
| 				 RGA_DEBUGGER_ROOT_NAME, files[i].name);
 | |
| 			goto MALLOC_FAIL;
 | |
| 		}
 | |
| 
 | |
| 		tmp->info_ent = &files[i];
 | |
| 		tmp->debugger = debugger;
 | |
| 
 | |
| 		ent = proc_create_data(files[i].name, S_IFREG | S_IRUGO,
 | |
| 					 root, &rga_procfs_fops, tmp);
 | |
| 		if (!ent) {
 | |
| 			pr_err("Cannot create /proc/%s/%s\n",
 | |
| 				 RGA_DEBUGGER_ROOT_NAME, files[i].name);
 | |
| 			goto CREATE_FAIL;
 | |
| 		}
 | |
| 
 | |
| 		tmp->pent = ent;
 | |
| 
 | |
| 		mutex_lock(&debugger->procfs_lock);
 | |
| 		list_add_tail(&tmp->list, &debugger->procfs_entry_list);
 | |
| 		mutex_unlock(&debugger->procfs_lock);
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| CREATE_FAIL:
 | |
| 	kfree(tmp);
 | |
| MALLOC_FAIL:
 | |
| 	rga_procfs_remove_files(debugger);
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| int rga_procfs_remove(void)
 | |
| {
 | |
| 	struct rga_debugger *debugger;
 | |
| 
 | |
| 	debugger = rga_drvdata->debugger;
 | |
| 
 | |
| 	rga_procfs_remove_files(debugger);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int rga_procfs_init(void)
 | |
| {
 | |
| 	int ret;
 | |
| 	struct rga_debugger *debugger;
 | |
| 
 | |
| 	debugger = rga_drvdata->debugger;
 | |
| 
 | |
| 	debugger->procfs_dir = proc_mkdir(RGA_DEBUGGER_ROOT_NAME, NULL);
 | |
| 	if (IS_ERR_OR_NULL(debugger->procfs_dir)) {
 | |
| 		pr_err("failed on mkdir /proc/%s\n", RGA_DEBUGGER_ROOT_NAME);
 | |
| 		debugger->procfs_dir = NULL;
 | |
| 		return -EIO;
 | |
| 	}
 | |
| 
 | |
| 	ret = rga_procfs_create_files(rga_debugger_root_list, ARRAY_SIZE(rga_debugger_root_list),
 | |
| 					 debugger->procfs_dir, debugger);
 | |
| 	if (ret) {
 | |
| 		pr_err("Could not install rga_debugger_root_list procfs\n");
 | |
| 		goto CREATE_FAIL;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| 
 | |
| CREATE_FAIL:
 | |
| 	rga_procfs_remove();
 | |
| 
 | |
| 	return ret;
 | |
| }
 | |
| #endif /* #ifdef CONFIG_ROCKCHIP_RGA_PROC_FS */
 | |
| 
 | |
| void rga_request_task_debug_info(struct seq_file *m, struct rga_req *req)
 | |
| {
 | |
| 	seq_printf(m, "\t\t rotate_mode = %d\n", req->rotate_mode);
 | |
| 	seq_printf(m, "\t\t src: y = %lx uv = %lx v = %lx aw = %d ah = %d vw = %d vh = %d\n",
 | |
| 		 (unsigned long)req->src.yrgb_addr, (unsigned long)req->src.uv_addr,
 | |
| 		 (unsigned long)req->src.v_addr, req->src.act_w, req->src.act_h,
 | |
| 		 req->src.vir_w, req->src.vir_h);
 | |
| 	seq_printf(m, "\t\t src: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n",
 | |
| 		req->src.x_offset, req->src.y_offset, req->src.format, req->src.rd_mode);
 | |
| 
 | |
| 	if (req->pat.yrgb_addr != 0 || req->pat.uv_addr != 0
 | |
| 		|| req->pat.v_addr != 0) {
 | |
| 		seq_printf(m, "\t\t pat: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
 | |
| 			 (unsigned long)req->pat.yrgb_addr, (unsigned long)req->pat.uv_addr,
 | |
| 			 (unsigned long)req->pat.v_addr, req->pat.act_w, req->pat.act_h,
 | |
| 			 req->pat.vir_w, req->pat.vir_h);
 | |
| 		seq_printf(m, "\t\t xoff = %d yoff = %d, format = 0x%x, rd_mode = %d\n",
 | |
| 			req->pat.x_offset, req->pat.y_offset, req->pat.format, req->pat.rd_mode);
 | |
| 	}
 | |
| 
 | |
| 	seq_printf(m, "\t\t dst: y=%lx uv=%lx v=%lx aw=%d ah=%d vw=%d vh=%d\n",
 | |
| 		 (unsigned long)req->dst.yrgb_addr, (unsigned long)req->dst.uv_addr,
 | |
| 		 (unsigned long)req->dst.v_addr, req->dst.act_w, req->dst.act_h,
 | |
| 		 req->dst.vir_w, req->dst.vir_h);
 | |
| 	seq_printf(m, "\t\t dst: xoff = %d, yoff = %d, format = 0x%x, rd_mode = %d\n",
 | |
| 		req->dst.x_offset, req->dst.y_offset, req->dst.format, req->dst.rd_mode);
 | |
| 
 | |
| 	seq_printf(m, "\t\t mmu: mmu_flag=%x en=%x\n",
 | |
| 		req->mmu_info.mmu_flag, req->mmu_info.mmu_en);
 | |
| 	seq_printf(m, "\t\t alpha: rop_mode = %x\n", req->alpha_rop_mode);
 | |
| 	seq_printf(m, "\t\t yuv2rgb mode is %x\n", req->yuv2rgb_mode);
 | |
| 	seq_printf(m, "\t\t set core = %d, priority = %d, in_fence_fd = %d\n",
 | |
| 		req->core, req->priority, req->in_fence_fd);
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_NO_GKI
 | |
| static int rga_dump_image_to_file(struct rga_internal_buffer *dump_buffer,
 | |
| 				  const char *channel_name,
 | |
| 				  int plane_id,
 | |
| 				  int core)
 | |
| {
 | |
| 	char file_name[100];
 | |
| 	struct file *file;
 | |
| 	size_t size = 0;
 | |
| 	loff_t pos = 0;
 | |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
 | |
| 	int ret;
 | |
| 	struct iosys_map map;
 | |
| #endif
 | |
| 	void *kvaddr = NULL;
 | |
| 	void *kvaddr_origin = NULL;
 | |
| 
 | |
| 	switch (dump_buffer->type) {
 | |
| 	case RGA_DMA_BUFFER:
 | |
| 	case RGA_DMA_BUFFER_PTR:
 | |
| 		if (IS_ERR_OR_NULL(dump_buffer->dma_buffer->dma_buf)) {
 | |
| 			pr_err("Failed to dump dma_buf 0x%px\n",
 | |
| 			       dump_buffer->dma_buffer->dma_buf);
 | |
| 			return -EINVAL;
 | |
| 		}
 | |
| 
 | |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
 | |
| 		ret = dma_buf_vmap(dump_buffer->dma_buffer->dma_buf, &map);
 | |
| 		kvaddr = ret ? NULL : map.vaddr;
 | |
| #else
 | |
| 		kvaddr = dma_buf_vmap(dump_buffer->dma_buffer->dma_buf);
 | |
| #endif
 | |
| 		if (!kvaddr) {
 | |
| 			pr_err("can't vmap the dma buffer!\n");
 | |
| 			return -EINVAL;
 | |
| 		}
 | |
| 
 | |
| 		kvaddr_origin = kvaddr;
 | |
| 		kvaddr += dump_buffer->dma_buffer->offset;
 | |
| 		break;
 | |
| 	case RGA_VIRTUAL_ADDRESS:
 | |
| 		kvaddr = vmap(dump_buffer->virt_addr->pages, dump_buffer->virt_addr->page_count,
 | |
| 			      VM_MAP, pgprot_writecombine(PAGE_KERNEL));
 | |
| 		if (!kvaddr) {
 | |
| 			pr_err("dump_vaddr vmap error!, 0x%lx\n",
 | |
| 			       (unsigned long)dump_buffer->virt_addr->addr);
 | |
| 			return -EFAULT;
 | |
| 		}
 | |
| 
 | |
| 		kvaddr_origin = kvaddr;
 | |
| 		kvaddr += dump_buffer->virt_addr->offset;
 | |
| 		break;
 | |
| 	case RGA_PHYSICAL_ADDRESS:
 | |
| 		kvaddr = phys_to_virt(dump_buffer->phys_addr);
 | |
| 		break;
 | |
| 	default:
 | |
| 		pr_err("unsupported memory type[%x]\n", dump_buffer->type);
 | |
| 		return -EINVAL;
 | |
| 	}
 | |
| 
 | |
| 	size = dump_buffer->size;
 | |
| 
 | |
| 	if (kvaddr == NULL) {
 | |
| 		pr_err("dump addr is NULL!\n");
 | |
| 		return -EFAULT;
 | |
| 	}
 | |
| 
 | |
| 	if (size <= 0) {
 | |
| 		pr_err("dump buffer size[%lx] is invalid!\n", (unsigned long)size);
 | |
| 		return -EFAULT;
 | |
| 	}
 | |
| 
 | |
| 	if (dump_buffer->memory_parm.width == 0 &&
 | |
| 	    dump_buffer->memory_parm.height == 0)
 | |
| 		snprintf(file_name, 100, "%s/%d_core%d_%s_plane%d_%s_size%zu_%s.bin",
 | |
| 			 g_dump_path,
 | |
| 			 RGA_DEBUG_DUMP_IMAGE, core, channel_name, plane_id,
 | |
| 			 rga_get_memory_type_str(dump_buffer->type),
 | |
| 			 size,
 | |
| 			 rga_get_format_name(dump_buffer->memory_parm.format));
 | |
| 	else
 | |
| 		snprintf(file_name, 100, "%s/%d_core%d_%s_plane%d_%s_w%d_h%d_%s.bin",
 | |
| 			 g_dump_path,
 | |
| 			 RGA_DEBUG_DUMP_IMAGE, core, channel_name, plane_id,
 | |
| 			 rga_get_memory_type_str(dump_buffer->type),
 | |
| 			 dump_buffer->memory_parm.width,
 | |
| 			 dump_buffer->memory_parm.height,
 | |
| 			 rga_get_format_name(dump_buffer->memory_parm.format));
 | |
| 
 | |
| 	file = filp_open(file_name, O_RDWR | O_CREAT | O_TRUNC, 0600);
 | |
| 	if (!IS_ERR(file)) {
 | |
| 		kernel_write(file, kvaddr, size, &pos);
 | |
| 		pr_info("dump image to: %s\n", file_name);
 | |
| 		fput(file);
 | |
| 	} else {
 | |
| 		pr_info("open %s failed\n", file_name);
 | |
| 	}
 | |
| 
 | |
| 	switch (dump_buffer->type) {
 | |
| 	case RGA_DMA_BUFFER:
 | |
| 	case RGA_DMA_BUFFER_PTR:
 | |
| #if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 1, 0)
 | |
| 		dma_buf_vunmap(dump_buffer->dma_buffer->dma_buf, &map);
 | |
| #else
 | |
| 		dma_buf_vunmap(dump_buffer->dma_buffer->dma_buf, kvaddr_origin);
 | |
| #endif
 | |
| 		break;
 | |
| 	case RGA_VIRTUAL_ADDRESS:
 | |
| 		vunmap(kvaddr_origin);
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static inline void rga_dump_channel_image(struct rga_job_buffer *job_buffer,
 | |
| 					  const char *channel_name,
 | |
| 					  int core)
 | |
| {
 | |
| 	if (job_buffer->y_addr)
 | |
| 		rga_dump_image_to_file(job_buffer->y_addr, channel_name, 0, core);
 | |
| 	if (job_buffer->uv_addr)
 | |
| 		rga_dump_image_to_file(job_buffer->uv_addr, channel_name, 1, core);
 | |
| 	if (job_buffer->v_addr)
 | |
| 		rga_dump_image_to_file(job_buffer->v_addr, channel_name, 2, core);
 | |
| }
 | |
| 
 | |
| void rga_dump_job_image(struct rga_job *dump_job)
 | |
| {
 | |
| 	rga_dump_channel_image(&dump_job->src_buffer, "src", dump_job->core);
 | |
| 	rga_dump_channel_image(&dump_job->src1_buffer, "src1", dump_job->core);
 | |
| 	rga_dump_channel_image(&dump_job->dst_buffer, "dst", dump_job->core);
 | |
| 	rga_dump_channel_image(&dump_job->els_buffer, "els", dump_job->core);
 | |
| 
 | |
| 	if (RGA_DEBUG_DUMP_IMAGE > 0)
 | |
| 		RGA_DEBUG_DUMP_IMAGE--;
 | |
| }
 | |
| #endif /* #ifdef CONFIG_NO_GKI */
 |