brintos

brintos / linux-shallow public Read only

0
0
Text · 11.1 KiB · b74a407 Raw
422 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright 2020-2021 NXP4 */5 6#include <linux/init.h>7#include <linux/interconnect.h>8#include <linux/ioctl.h>9#include <linux/list.h>10#include <linux/kernel.h>11#include <linux/module.h>12#include "vpu.h"13#include "vpu_core.h"14#include "vpu_rpc.h"15#include "vpu_mbox.h"16#include "vpu_defs.h"17#include "vpu_cmds.h"18#include "vpu_msgs.h"19#include "vpu_v4l2.h"20 21#define VPU_PKT_HEADER_LENGTH		322 23struct vpu_msg_handler {24	u32 id;25	void (*done)(struct vpu_inst *inst, struct vpu_rpc_event *pkt);26	u32 is_str;27};28 29static void vpu_session_handle_start_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt)30{31	vpu_trace(inst->dev, "[%d]\n", inst->id);32}33 34static void vpu_session_handle_mem_request(struct vpu_inst *inst, struct vpu_rpc_event *pkt)35{36	struct vpu_pkt_mem_req_data req_data = { 0 };37 38	vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&req_data);39	vpu_trace(inst->dev, "[%d] %d:%d %d:%d %d:%d\n",40		  inst->id,41		  req_data.enc_frame_size,42		  req_data.enc_frame_num,43		  req_data.ref_frame_size,44		  req_data.ref_frame_num,45		  req_data.act_buf_size,46		  req_data.act_buf_num);47	vpu_inst_lock(inst);48	call_void_vop(inst, mem_request,49		      req_data.enc_frame_size,50		      req_data.enc_frame_num,51		      req_data.ref_frame_size,52		      req_data.ref_frame_num,53		      req_data.act_buf_size,54		      req_data.act_buf_num);55	vpu_inst_unlock(inst);56}57 58static void vpu_session_handle_stop_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt)59{60	vpu_trace(inst->dev, "[%d]\n", inst->id);61 62	call_void_vop(inst, stop_done);63}64 65static void vpu_session_handle_seq_hdr(struct vpu_inst *inst, struct vpu_rpc_event *pkt)66{67	struct vpu_dec_codec_info info;68	const struct vpu_core_resources *res;69 70	memset(&info, 0, sizeof(info));71	res = vpu_get_resource(inst);72	info.stride = res ? res->stride : 1;73	vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&info);74	call_void_vop(inst, event_notify, VPU_MSG_ID_SEQ_HDR_FOUND, &info);75}76 77static void vpu_session_handle_resolution_change(struct vpu_inst *inst, struct vpu_rpc_event *pkt)78{79	call_void_vop(inst, event_notify, VPU_MSG_ID_RES_CHANGE, NULL);80}81 82static void vpu_session_handle_enc_frame_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt)83{84	struct vpu_enc_pic_info info = { 0 };85 86	vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&info);87	dev_dbg(inst->dev, "[%d] frame id = %d, wptr = 0x%x, size = %d\n",88		inst->id, info.frame_id, info.wptr, info.frame_size);89	call_void_vop(inst, get_one_frame, &info);90}91 92static void vpu_session_handle_frame_request(struct vpu_inst *inst, struct vpu_rpc_event *pkt)93{94	struct vpu_fs_info fs = { 0 };95 96	vpu_iface_unpack_msg_data(inst->core, pkt, &fs);97	call_void_vop(inst, event_notify, VPU_MSG_ID_FRAME_REQ, &fs);98}99 100static void vpu_session_handle_frame_release(struct vpu_inst *inst, struct vpu_rpc_event *pkt)101{102	if (inst->core->type == VPU_CORE_TYPE_ENC) {103		struct vpu_frame_info info;104 105		memset(&info, 0, sizeof(info));106		vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&info.sequence);107		dev_dbg(inst->dev, "[%d] %d\n", inst->id, info.sequence);108		info.type = inst->out_format.type;109		call_void_vop(inst, buf_done, &info);110	} else if (inst->core->type == VPU_CORE_TYPE_DEC) {111		struct vpu_fs_info fs = { 0 };112 113		vpu_iface_unpack_msg_data(inst->core, pkt, &fs);114		call_void_vop(inst, event_notify, VPU_MSG_ID_FRAME_RELEASE, &fs);115	}116}117 118static void vpu_session_handle_input_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt)119{120	dev_dbg(inst->dev, "[%d]\n", inst->id);121	call_void_vop(inst, input_done);122}123 124static void vpu_session_handle_pic_decoded(struct vpu_inst *inst, struct vpu_rpc_event *pkt)125{126	struct vpu_dec_pic_info info = { 0 };127 128	vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&info);129	call_void_vop(inst, get_one_frame, &info);130}131 132static void vpu_session_handle_pic_done(struct vpu_inst *inst, struct vpu_rpc_event *pkt)133{134	struct vpu_dec_pic_info info = { 0 };135	struct vpu_frame_info frame;136 137	memset(&frame, 0, sizeof(frame));138	vpu_iface_unpack_msg_data(inst->core, pkt, (void *)&info);139	if (inst->core->type == VPU_CORE_TYPE_DEC)140		frame.type = inst->cap_format.type;141	frame.id = info.id;142	frame.luma = info.luma;143	frame.skipped = info.skipped;144	frame.timestamp = info.timestamp;145 146	call_void_vop(inst, buf_done, &frame);147}148 149static void vpu_session_handle_eos(struct vpu_inst *inst, struct vpu_rpc_event *pkt)150{151	call_void_vop(inst, event_notify, VPU_MSG_ID_PIC_EOS, NULL);152}153 154static void vpu_session_handle_error(struct vpu_inst *inst, struct vpu_rpc_event *pkt)155{156	char *str = (char *)pkt->data;157 158	if (*str)159		dev_err(inst->dev, "instance %d firmware error : %s\n", inst->id, str);160	else161		dev_err(inst->dev, "instance %d is unsupported stream\n", inst->id);162	call_void_vop(inst, event_notify, VPU_MSG_ID_UNSUPPORTED, NULL);163	vpu_v4l2_set_error(inst);164}165 166static void vpu_session_handle_firmware_xcpt(struct vpu_inst *inst, struct vpu_rpc_event *pkt)167{168	char *str = (char *)pkt->data;169 170	dev_err(inst->dev, "%s firmware xcpt: %s\n",171		vpu_core_type_desc(inst->core->type), str);172	call_void_vop(inst, event_notify, VPU_MSG_ID_FIRMWARE_XCPT, NULL);173	set_bit(inst->id, &inst->core->hang_mask);174	vpu_v4l2_set_error(inst);175}176 177static void vpu_session_handle_pic_skipped(struct vpu_inst *inst, struct vpu_rpc_event *pkt)178{179	vpu_inst_lock(inst);180	vpu_skip_frame(inst, 1);181	vpu_inst_unlock(inst);182}183 184static void vpu_session_handle_dbg_msg(struct vpu_inst *inst, struct vpu_rpc_event *pkt)185{186	char *str = (char *)pkt->data;187 188	if (*str)189		dev_info(inst->dev, "instance %d firmware dbg msg : %s\n", inst->id, str);190}191 192static void vpu_terminate_string_msg(struct vpu_rpc_event *pkt)193{194	if (pkt->hdr.num == ARRAY_SIZE(pkt->data))195		pkt->hdr.num--;196	pkt->data[pkt->hdr.num] = 0;197}198 199static struct vpu_msg_handler handlers[] = {200	{VPU_MSG_ID_START_DONE, vpu_session_handle_start_done},201	{VPU_MSG_ID_STOP_DONE, vpu_session_handle_stop_done},202	{VPU_MSG_ID_MEM_REQUEST, vpu_session_handle_mem_request},203	{VPU_MSG_ID_SEQ_HDR_FOUND, vpu_session_handle_seq_hdr},204	{VPU_MSG_ID_RES_CHANGE, vpu_session_handle_resolution_change},205	{VPU_MSG_ID_FRAME_INPUT_DONE, vpu_session_handle_input_done},206	{VPU_MSG_ID_FRAME_REQ, vpu_session_handle_frame_request},207	{VPU_MSG_ID_FRAME_RELEASE, vpu_session_handle_frame_release},208	{VPU_MSG_ID_ENC_DONE, vpu_session_handle_enc_frame_done},209	{VPU_MSG_ID_PIC_DECODED, vpu_session_handle_pic_decoded},210	{VPU_MSG_ID_DEC_DONE, vpu_session_handle_pic_done},211	{VPU_MSG_ID_PIC_EOS, vpu_session_handle_eos},212	{VPU_MSG_ID_UNSUPPORTED, vpu_session_handle_error, true},213	{VPU_MSG_ID_FIRMWARE_XCPT, vpu_session_handle_firmware_xcpt, true},214	{VPU_MSG_ID_PIC_SKIPPED, vpu_session_handle_pic_skipped},215	{VPU_MSG_ID_DBG_MSG, vpu_session_handle_dbg_msg, true},216};217 218static int vpu_session_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *msg)219{220	int ret;221	u32 msg_id;222	struct vpu_msg_handler *handler = NULL;223	unsigned int i;224 225	ret = vpu_iface_convert_msg_id(inst->core, msg->hdr.id);226	if (ret < 0)227		return -EINVAL;228 229	msg_id = ret;230	dev_dbg(inst->dev, "[%d] receive event(%s)\n", inst->id, vpu_id_name(msg_id));231 232	for (i = 0; i < ARRAY_SIZE(handlers); i++) {233		if (handlers[i].id == msg_id) {234			handler = &handlers[i];235			break;236		}237	}238 239	if (handler) {240		if (handler->is_str)241			vpu_terminate_string_msg(msg);242		if (handler->done)243			handler->done(inst, msg);244	}245 246	vpu_response_cmd(inst, msg_id, 1);247 248	return 0;249}250 251static bool vpu_inst_receive_msg(struct vpu_inst *inst, struct vpu_rpc_event *pkt)252{253	unsigned long bytes = sizeof(struct vpu_rpc_event_header);254	u32 ret;255 256	memset(pkt, 0, sizeof(*pkt));257	if (kfifo_len(&inst->msg_fifo) < bytes)258		return false;259 260	ret = kfifo_out(&inst->msg_fifo, pkt, bytes);261	if (ret != bytes)262		return false;263 264	if (pkt->hdr.num > 0) {265		bytes = pkt->hdr.num * sizeof(u32);266		ret = kfifo_out(&inst->msg_fifo, pkt->data, bytes);267		if (ret != bytes)268			return false;269	}270 271	return true;272}273 274void vpu_inst_run_work(struct work_struct *work)275{276	struct vpu_inst *inst = container_of(work, struct vpu_inst, msg_work);277	struct vpu_rpc_event pkt;278 279	while (vpu_inst_receive_msg(inst, &pkt))280		vpu_session_handle_msg(inst, &pkt);281}282 283static void vpu_inst_handle_msg(struct vpu_inst *inst, struct vpu_rpc_event *pkt)284{285	unsigned long bytes;286	u32 id = pkt->hdr.id;287	int ret;288 289	if (!inst->workqueue)290		return;291 292	bytes = sizeof(pkt->hdr) + pkt->hdr.num * sizeof(u32);293	ret = kfifo_in(&inst->msg_fifo, pkt, bytes);294	if (ret != bytes)295		dev_err(inst->dev, "[%d:%d]overflow: %d\n", inst->core->id, inst->id, id);296	queue_work(inst->workqueue, &inst->msg_work);297}298 299static int vpu_handle_msg(struct vpu_core *core)300{301	struct vpu_rpc_event pkt;302	struct vpu_inst *inst;303	int ret;304 305	memset(&pkt, 0, sizeof(pkt));306	while (!vpu_iface_receive_msg(core, &pkt)) {307		dev_dbg(core->dev, "event index = %d, id = %d, num = %d\n",308			pkt.hdr.index, pkt.hdr.id, pkt.hdr.num);309 310		ret = vpu_iface_convert_msg_id(core, pkt.hdr.id);311		if (ret < 0)312			continue;313 314		inst = vpu_core_find_instance(core, pkt.hdr.index);315		if (inst) {316			vpu_response_cmd(inst, ret, 0);317			mutex_lock(&core->cmd_lock);318			vpu_inst_record_flow(inst, ret);319			mutex_unlock(&core->cmd_lock);320 321			vpu_inst_handle_msg(inst, &pkt);322			vpu_inst_put(inst);323		}324		memset(&pkt, 0, sizeof(pkt));325	}326 327	return 0;328}329 330static int vpu_isr_thread(struct vpu_core *core, u32 irq_code)331{332	dev_dbg(core->dev, "irq code = 0x%x\n", irq_code);333	switch (irq_code) {334	case VPU_IRQ_CODE_SYNC:335		vpu_mbox_send_msg(core, PRC_BUF_OFFSET, core->rpc.phys - core->fw.phys);336		vpu_mbox_send_msg(core, BOOT_ADDRESS, core->fw.phys);337		vpu_mbox_send_msg(core, INIT_DONE, 2);338		break;339	case VPU_IRQ_CODE_BOOT_DONE:340		break;341	case VPU_IRQ_CODE_SNAPSHOT_DONE:342		break;343	default:344		vpu_handle_msg(core);345		break;346	}347 348	return 0;349}350 351static void vpu_core_run_msg_work(struct vpu_core *core)352{353	const unsigned int SIZE = sizeof(u32);354 355	while (kfifo_len(&core->msg_fifo) >= SIZE) {356		u32 data = 0;357 358		if (kfifo_out(&core->msg_fifo, &data, SIZE) == SIZE)359			vpu_isr_thread(core, data);360	}361}362 363void vpu_msg_run_work(struct work_struct *work)364{365	struct vpu_core *core = container_of(work, struct vpu_core, msg_work);366	unsigned long delay = msecs_to_jiffies(10);367 368	vpu_core_run_msg_work(core);369	queue_delayed_work(core->workqueue, &core->msg_delayed_work, delay);370}371 372void vpu_msg_delayed_work(struct work_struct *work)373{374	struct vpu_core *core;375	struct delayed_work *dwork;376	unsigned long bytes = sizeof(u32);377	u32 i;378 379	if (!work)380		return;381 382	dwork = to_delayed_work(work);383	core = container_of(dwork, struct vpu_core, msg_delayed_work);384	if (kfifo_len(&core->msg_fifo) >= bytes)385		vpu_core_run_msg_work(core);386 387	bytes = sizeof(struct vpu_rpc_event_header);388	for (i = 0; i < core->supported_instance_count; i++) {389		struct vpu_inst *inst = vpu_core_find_instance(core, i);390 391		if (!inst)392			continue;393 394		if (inst->workqueue && kfifo_len(&inst->msg_fifo) >= bytes)395			queue_work(inst->workqueue, &inst->msg_work);396 397		vpu_inst_put(inst);398	}399}400 401int vpu_isr(struct vpu_core *core, u32 irq)402{403	switch (irq) {404	case VPU_IRQ_CODE_SYNC:405		break;406	case VPU_IRQ_CODE_BOOT_DONE:407		complete(&core->cmp);408		break;409	case VPU_IRQ_CODE_SNAPSHOT_DONE:410		complete(&core->cmp);411		break;412	default:413		break;414	}415 416	if (kfifo_in(&core->msg_fifo, &irq, sizeof(irq)) != sizeof(irq))417		dev_err(core->dev, "[%d]overflow: %d\n", core->id, irq);418	queue_work(core->workqueue, &core->msg_work);419 420	return 0;421}422