blob: 62d6d58d1b601c3a675cf6ca03936f1160bf714f [file] [log] [blame]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001/* arch/arm/mach-msm/qdsp5/adsp_video_verify_cmd.c
2 *
3 * Verificion code for aDSP VDEC packets from userspace.
4 *
5 * Copyright (C) 2008 Google, Inc.
Duy Truong790f06d2013-02-13 16:38:12 -08006 * Copyright (c) 2008-2010, 2012 The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07007 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19#include <linux/io.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070020
21#include <mach/qdsp5/qdsp5vdeccmdi.h>
22#include "adsp.h"
23#include <mach/debug_mm.h>
24
Mahesh Lankac6af7eb2011-08-02 18:00:35 +053025#define MAX_FLUSH_SIZE 160
26
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070027static inline void *high_low_short_to_ptr(unsigned short high,
28 unsigned short low)
29{
30 return (void *)((((unsigned long)high) << 16) | ((unsigned long)low));
31}
32
33static inline void ptr_to_high_low_short(void *ptr, unsigned short *high,
34 unsigned short *low)
35{
36 *high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff);
37 *low = (unsigned short)((unsigned long)ptr & 0xffff);
38}
39
40static int pmem_fixup_high_low(unsigned short *high,
41 unsigned short *low,
42 unsigned short size_high,
43 unsigned short size_low,
44 struct msm_adsp_module *module,
45 unsigned long *addr, unsigned long *size,
46 struct file **filp, unsigned long *offset)
47{
48 void *phys_addr;
49 unsigned long phys_size;
50 unsigned long kvaddr;
51
52 phys_addr = high_low_short_to_ptr(*high, *low);
53 phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low);
54 MM_DBG("virt %x %x\n", (unsigned int)phys_addr,
55 (unsigned int)phys_size);
56 if (phys_addr) {
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +053057 if (adsp_ion_fixup_kvaddr(module, &phys_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070058 &kvaddr, phys_size, filp, offset)) {
59 MM_ERR("ah%x al%x sh%x sl%x addr %x size %x\n",
60 *high, *low, size_high,
61 size_low, (unsigned int)phys_addr,
62 (unsigned int)phys_size);
63 return -EINVAL;
64 }
65 }
66 ptr_to_high_low_short(phys_addr, high, low);
67 MM_DBG("phys %x %x\n", (unsigned int)phys_addr,
68 (unsigned int)phys_size);
69 if (addr)
70 *addr = kvaddr;
71 if (size)
72 *size = phys_size;
73 return 0;
74}
75
76static int verify_vdec_pkt_cmd(struct msm_adsp_module *module,
77 void *cmd_data, size_t cmd_size)
78{
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +053079 void *phys_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070080 unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
81 viddec_cmd_subframe_pkt *pkt;
82 unsigned long subframe_pkt_addr;
83 unsigned long subframe_pkt_size;
84 unsigned short *frame_header_pkt;
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +053085 int i, num_addr, col_addr = 0, skip;
86 int start_pos = 0, xdim_pos = 1, ydim_pos = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070087 unsigned short *frame_buffer_high, *frame_buffer_low;
88 unsigned long frame_buffer_size;
89 unsigned short frame_buffer_size_high, frame_buffer_size_low;
90 struct file *filp = NULL;
91 unsigned long offset = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092 unsigned long Codec_Id = 0;
93
94 MM_DBG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id,
95 (unsigned int)cmd_data);
96 if (cmd_id != VIDDEC_CMD_SUBFRAME_PKT) {
97 MM_INFO("adsp_video: unknown video packet %u\n", cmd_id);
98 return 0;
99 }
100 if (cmd_size < sizeof(viddec_cmd_subframe_pkt))
101 return -1;
102
103 pkt = (viddec_cmd_subframe_pkt *)cmd_data;
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +0530104 phys_addr = high_low_short_to_ptr(pkt->subframe_packet_high,
105 pkt->subframe_packet_low);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700106
107 if (pmem_fixup_high_low(&(pkt->subframe_packet_high),
108 &(pkt->subframe_packet_low),
109 pkt->subframe_packet_size_high,
110 pkt->subframe_packet_size_low,
111 module,
112 &subframe_pkt_addr,
113 &subframe_pkt_size,
114 &filp, &offset))
115 return -1;
116 Codec_Id = pkt->codec_selection_word;
Mahesh Lankac6af7eb2011-08-02 18:00:35 +0530117 /*Invalidate cache before accessing the cached pmem buffer*/
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +0530118 if (adsp_ion_do_cache_op(module, phys_addr, (void *)subframe_pkt_addr,
119 subframe_pkt_size*2, offset, ION_IOC_INV_CACHES)){
120 MM_ERR("Cache operation failed for" \
121 " phys addr high %x addr low %x\n",
122 pkt->subframe_packet_high, pkt->subframe_packet_low);
123 return -EINVAL;
Mahesh Lankac6af7eb2011-08-02 18:00:35 +0530124 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700125 /* deref those ptrs and check if they are a frame header packet */
126 frame_header_pkt = (unsigned short *)subframe_pkt_addr;
127 switch (frame_header_pkt[0]) {
128 case 0xB201: /* h.264 vld in dsp */
129 if (Codec_Id == 0x8) {
130 num_addr = 16;
131 skip = 0;
132 start_pos = 5;
133 } else {
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +0530134 num_addr = 16;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135 skip = 0;
136 start_pos = 6;
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +0530137 col_addr = 17;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 }
139 break;
140 case 0x8201: /* h.264 vld in arm */
141 num_addr = 16;
142 skip = 0;
143 start_pos = 6;
144 break;
145 case 0x4D01: /* mpeg-4 and h.263 vld in arm */
146 num_addr = 3;
147 skip = 0;
148 start_pos = 5;
149 break;
150 case 0x9201: /*For Real Decoder*/
151 num_addr = 2;
152 skip = 0;
153 start_pos = 5;
154 break;
155 case 0xBD01: /* mpeg-4 and h.263 vld in dsp */
156 num_addr = 3;
157 skip = 0;
158 start_pos = 6;
159 if (((frame_header_pkt[5] & 0x000c) >> 2) == 0x2) /* B-frame */
160 start_pos = 8;
161 break;
162 case 0x0001: /* wmv */
163 num_addr = 2;
164 skip = 0;
165 start_pos = 5;
166 break;
167 case 0xC201: /*WMV main profile*/
168 num_addr = 3;
169 skip = 0;
170 start_pos = 6;
171 break;
172 case 0xDD01: /* VP6 */
173 num_addr = 3;
174 skip = 0;
175 start_pos = 10;
176 break;
177 case 0xFD01: /* VP8 */
178 num_addr = 3;
179 skip = 0;
180 start_pos = 24;
181 break;
182 default:
183 return 0;
184 }
185
186 frame_buffer_high = &frame_header_pkt[start_pos];
187 frame_buffer_low = &frame_header_pkt[start_pos + 1];
188 frame_buffer_size = (frame_header_pkt[xdim_pos] *
189 frame_header_pkt[ydim_pos] * 3) / 2;
190 ptr_to_high_low_short((void *)frame_buffer_size,
191 &frame_buffer_size_high,
192 &frame_buffer_size_low);
193 for (i = 0; i < num_addr; i++) {
194 if (frame_buffer_high && frame_buffer_low) {
195 if (pmem_fixup_high_low(frame_buffer_high,
196 frame_buffer_low,
197 frame_buffer_size_high,
198 frame_buffer_size_low,
199 module,
200 NULL, NULL, NULL, NULL))
201 return -EINVAL;
202 }
203 frame_buffer_high += 2;
204 frame_buffer_low += 2;
205 }
206 /* Patch the output buffer. */
207 frame_buffer_high += 2*skip;
208 frame_buffer_low += 2*skip;
209 if (frame_buffer_high && frame_buffer_low) {
210 if (pmem_fixup_high_low(frame_buffer_high,
211 frame_buffer_low,
212 frame_buffer_size_high,
213 frame_buffer_size_low,
214 module,
215 NULL, NULL, NULL, NULL))
216 return -EINVAL;
217 }
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +0530218 if (col_addr) {
219 frame_buffer_high += 2;
220 frame_buffer_low += 2;
221 /* Patch the Co-located buffers.*/
222 frame_buffer_size = (72 * frame_header_pkt[xdim_pos] *
223 frame_header_pkt[ydim_pos]) >> 16;
224 ptr_to_high_low_short((void *)frame_buffer_size,
225 &frame_buffer_size_high,
226 &frame_buffer_size_low);
227 for (i = 0; i < col_addr; i++) {
228 if (frame_buffer_high && frame_buffer_low) {
229 if (pmem_fixup_high_low(frame_buffer_high,
230 frame_buffer_low,
231 frame_buffer_size_high,
232 frame_buffer_size_low,
233 module,
234 NULL, NULL, NULL, NULL))
235 return -EINVAL;
236 }
237 frame_buffer_high += 2;
238 frame_buffer_low += 2;
239 }
240 }
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +0530241 /*Flush the cached mem subframe packet before sending to DSP*/
242 if (adsp_ion_do_cache_op(module, phys_addr, (void *)subframe_pkt_addr,
243 MAX_FLUSH_SIZE, offset, ION_IOC_CLEAN_CACHES)){
244 MM_ERR("Cache operation failed for" \
245 " phys addr high %x addr low %x\n",
246 pkt->subframe_packet_high, pkt->subframe_packet_low);
247 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700248 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 return 0;
250}
251
252int adsp_video_verify_cmd(struct msm_adsp_module *module,
253 unsigned int queue_id, void *cmd_data,
254 size_t cmd_size)
255{
256 switch (queue_id) {
257 case QDSP_mpuVDecPktQueue:
258 return verify_vdec_pkt_cmd(module, cmd_data, cmd_size);
259 default:
260 MM_INFO("unknown video queue %u\n", queue_id);
261 return 0;
262 }
263}
264