1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c
4  *
5  * Copyright (C) 2011 Samsung Electronics Co., Ltd.
6  *		http://www.samsung.com/
7  */
8 
9 #include "regs-mfc.h"
10 #include "s5p_mfc_cmd.h"
11 #include "s5p_mfc_common.h"
12 #include "s5p_mfc_debug.h"
13 #include "s5p_mfc_cmd_v5.h"
14 
15 /* This function is used to send a command to the MFC */
s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev * dev,int cmd,struct s5p_mfc_cmd_args * args)16 static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd,
17 				struct s5p_mfc_cmd_args *args)
18 {
19 	int cur_cmd;
20 	unsigned long timeout;
21 
22 	timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
23 	/* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */
24 	do {
25 		if (time_after(jiffies, timeout)) {
26 			mfc_err("Timeout while waiting for hardware\n");
27 			return -EIO;
28 		}
29 		cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD);
30 	} while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY);
31 	mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1);
32 	mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2);
33 	mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3);
34 	mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4);
35 	/* Issue the command */
36 	mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD);
37 	return 0;
38 }
39 
40 /* Initialize the MFC */
s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev * dev)41 static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev)
42 {
43 	struct s5p_mfc_cmd_args h2r_args;
44 
45 	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
46 	h2r_args.arg[0] = dev->fw_buf.size;
47 	return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT,
48 			&h2r_args);
49 }
50 
51 /* Suspend the MFC hardware */
s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev * dev)52 static int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev)
53 {
54 	struct s5p_mfc_cmd_args h2r_args;
55 
56 	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
57 	return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args);
58 }
59 
60 /* Wake up the MFC hardware */
s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev * dev)61 static int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev)
62 {
63 	struct s5p_mfc_cmd_args h2r_args;
64 
65 	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
66 	return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP,
67 			&h2r_args);
68 }
69 
70 
s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx * ctx)71 static int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
72 {
73 	struct s5p_mfc_dev *dev = ctx->dev;
74 	struct s5p_mfc_cmd_args h2r_args;
75 	int ret;
76 
77 	/* Preparing decoding - getting instance number */
78 	mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode);
79 	dev->curr_ctx = ctx->num;
80 	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
81 	switch (ctx->codec_mode) {
82 	case S5P_MFC_CODEC_H264_DEC:
83 		h2r_args.arg[0] = S5P_FIMV_CODEC_H264_DEC;
84 		break;
85 	case S5P_MFC_CODEC_VC1_DEC:
86 		h2r_args.arg[0] = S5P_FIMV_CODEC_VC1_DEC;
87 		break;
88 	case S5P_MFC_CODEC_MPEG4_DEC:
89 		h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_DEC;
90 		break;
91 	case S5P_MFC_CODEC_MPEG2_DEC:
92 		h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG2_DEC;
93 		break;
94 	case S5P_MFC_CODEC_H263_DEC:
95 		h2r_args.arg[0] = S5P_FIMV_CODEC_H263_DEC;
96 		break;
97 	case S5P_MFC_CODEC_VC1RCV_DEC:
98 		h2r_args.arg[0] = S5P_FIMV_CODEC_VC1RCV_DEC;
99 		break;
100 	case S5P_MFC_CODEC_H264_ENC:
101 		h2r_args.arg[0] = S5P_FIMV_CODEC_H264_ENC;
102 		break;
103 	case S5P_MFC_CODEC_MPEG4_ENC:
104 		h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_ENC;
105 		break;
106 	case S5P_MFC_CODEC_H263_ENC:
107 		h2r_args.arg[0] = S5P_FIMV_CODEC_H263_ENC;
108 		break;
109 	default:
110 		h2r_args.arg[0] = S5P_FIMV_CODEC_NONE;
111 	}
112 	h2r_args.arg[1] = 0; /* no crc & no pixelcache */
113 	h2r_args.arg[2] = ctx->ctx.ofs;
114 	h2r_args.arg[3] = ctx->ctx.size;
115 	ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE,
116 								&h2r_args);
117 	if (ret) {
118 		mfc_err("Failed to create a new instance\n");
119 		ctx->state = MFCINST_ERROR;
120 	}
121 	return ret;
122 }
123 
s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx * ctx)124 static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx)
125 {
126 	struct s5p_mfc_dev *dev = ctx->dev;
127 	struct s5p_mfc_cmd_args h2r_args;
128 	int ret;
129 
130 	if (ctx->state == MFCINST_FREE) {
131 		mfc_err("Instance already returned\n");
132 		ctx->state = MFCINST_ERROR;
133 		return -EINVAL;
134 	}
135 	/* Closing decoding instance  */
136 	mfc_debug(2, "Returning instance number %d\n", ctx->inst_no);
137 	dev->curr_ctx = ctx->num;
138 	memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args));
139 	h2r_args.arg[0] = ctx->inst_no;
140 	ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE,
141 								&h2r_args);
142 	if (ret) {
143 		mfc_err("Failed to return an instance\n");
144 		ctx->state = MFCINST_ERROR;
145 		return -EINVAL;
146 	}
147 	return 0;
148 }
149 
150 /* Initialize cmd function pointers for MFC v5 */
151 static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = {
152 	.cmd_host2risc = s5p_mfc_cmd_host2risc_v5,
153 	.sys_init_cmd = s5p_mfc_sys_init_cmd_v5,
154 	.sleep_cmd = s5p_mfc_sleep_cmd_v5,
155 	.wakeup_cmd = s5p_mfc_wakeup_cmd_v5,
156 	.open_inst_cmd = s5p_mfc_open_inst_cmd_v5,
157 	.close_inst_cmd = s5p_mfc_close_inst_cmd_v5,
158 };
159 
s5p_mfc_init_hw_cmds_v5(void)160 struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void)
161 {
162 	return &s5p_mfc_cmds_v5;
163 }
164