blob: 4d03dca2e57a4806f91f5e028e9ba7588eb234e8 [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>
20#include <linux/android_pmem.h>
21
22#include <mach/qdsp5/qdsp5vdeccmdi.h>
23#include "adsp.h"
24#include <mach/debug_mm.h>
25
Mahesh Lankac6af7eb2011-08-02 18:00:35 +053026#define MAX_FLUSH_SIZE 160
27
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070028static inline void *high_low_short_to_ptr(unsigned short high,
29 unsigned short low)
30{
31 return (void *)((((unsigned long)high) << 16) | ((unsigned long)low));
32}
33
34static inline void ptr_to_high_low_short(void *ptr, unsigned short *high,
35 unsigned short *low)
36{
37 *high = (unsigned short)((((unsigned long)ptr) >> 16) & 0xffff);
38 *low = (unsigned short)((unsigned long)ptr & 0xffff);
39}
40
41static int pmem_fixup_high_low(unsigned short *high,
42 unsigned short *low,
43 unsigned short size_high,
44 unsigned short size_low,
45 struct msm_adsp_module *module,
46 unsigned long *addr, unsigned long *size,
47 struct file **filp, unsigned long *offset)
48{
49 void *phys_addr;
50 unsigned long phys_size;
51 unsigned long kvaddr;
52
53 phys_addr = high_low_short_to_ptr(*high, *low);
54 phys_size = (unsigned long)high_low_short_to_ptr(size_high, size_low);
55 MM_DBG("virt %x %x\n", (unsigned int)phys_addr,
56 (unsigned int)phys_size);
57 if (phys_addr) {
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +053058 if (adsp_ion_fixup_kvaddr(module, &phys_addr,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059 &kvaddr, phys_size, filp, offset)) {
60 MM_ERR("ah%x al%x sh%x sl%x addr %x size %x\n",
61 *high, *low, size_high,
62 size_low, (unsigned int)phys_addr,
63 (unsigned int)phys_size);
64 return -EINVAL;
65 }
66 }
67 ptr_to_high_low_short(phys_addr, high, low);
68 MM_DBG("phys %x %x\n", (unsigned int)phys_addr,
69 (unsigned int)phys_size);
70 if (addr)
71 *addr = kvaddr;
72 if (size)
73 *size = phys_size;
74 return 0;
75}
76
77static int verify_vdec_pkt_cmd(struct msm_adsp_module *module,
78 void *cmd_data, size_t cmd_size)
79{
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +053080 void *phys_addr;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070081 unsigned short cmd_id = ((unsigned short *)cmd_data)[0];
82 viddec_cmd_subframe_pkt *pkt;
83 unsigned long subframe_pkt_addr;
84 unsigned long subframe_pkt_size;
85 unsigned short *frame_header_pkt;
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +053086 int i, num_addr, col_addr = 0, skip;
87 int start_pos = 0, xdim_pos = 1, ydim_pos = 2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070088 unsigned short *frame_buffer_high, *frame_buffer_low;
89 unsigned long frame_buffer_size;
90 unsigned short frame_buffer_size_high, frame_buffer_size_low;
91 struct file *filp = NULL;
92 unsigned long offset = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093 unsigned long Codec_Id = 0;
94
95 MM_DBG("cmd_size %d cmd_id %d cmd_data %x\n", cmd_size, cmd_id,
96 (unsigned int)cmd_data);
97 if (cmd_id != VIDDEC_CMD_SUBFRAME_PKT) {
98 MM_INFO("adsp_video: unknown video packet %u\n", cmd_id);
99 return 0;
100 }
101 if (cmd_size < sizeof(viddec_cmd_subframe_pkt))
102 return -1;
103
104 pkt = (viddec_cmd_subframe_pkt *)cmd_data;
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +0530105 phys_addr = high_low_short_to_ptr(pkt->subframe_packet_high,
106 pkt->subframe_packet_low);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107
108 if (pmem_fixup_high_low(&(pkt->subframe_packet_high),
109 &(pkt->subframe_packet_low),
110 pkt->subframe_packet_size_high,
111 pkt->subframe_packet_size_low,
112 module,
113 &subframe_pkt_addr,
114 &subframe_pkt_size,
115 &filp, &offset))
116 return -1;
117 Codec_Id = pkt->codec_selection_word;
Mahesh Lankac6af7eb2011-08-02 18:00:35 +0530118 /*Invalidate cache before accessing the cached pmem buffer*/
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +0530119 if (adsp_ion_do_cache_op(module, phys_addr, (void *)subframe_pkt_addr,
120 subframe_pkt_size*2, offset, ION_IOC_INV_CACHES)){
121 MM_ERR("Cache operation failed for" \
122 " phys addr high %x addr low %x\n",
123 pkt->subframe_packet_high, pkt->subframe_packet_low);
124 return -EINVAL;
Mahesh Lankac6af7eb2011-08-02 18:00:35 +0530125 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700126 /* deref those ptrs and check if they are a frame header packet */
127 frame_header_pkt = (unsigned short *)subframe_pkt_addr;
128 switch (frame_header_pkt[0]) {
129 case 0xB201: /* h.264 vld in dsp */
130 if (Codec_Id == 0x8) {
131 num_addr = 16;
132 skip = 0;
133 start_pos = 5;
134 } else {
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +0530135 num_addr = 16;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 skip = 0;
137 start_pos = 6;
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +0530138 col_addr = 17;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 }
140 break;
141 case 0x8201: /* h.264 vld in arm */
142 num_addr = 16;
143 skip = 0;
144 start_pos = 6;
145 break;
146 case 0x4D01: /* mpeg-4 and h.263 vld in arm */
147 num_addr = 3;
148 skip = 0;
149 start_pos = 5;
150 break;
151 case 0x9201: /*For Real Decoder*/
152 num_addr = 2;
153 skip = 0;
154 start_pos = 5;
155 break;
156 case 0xBD01: /* mpeg-4 and h.263 vld in dsp */
157 num_addr = 3;
158 skip = 0;
159 start_pos = 6;
160 if (((frame_header_pkt[5] & 0x000c) >> 2) == 0x2) /* B-frame */
161 start_pos = 8;
162 break;
163 case 0x0001: /* wmv */
164 num_addr = 2;
165 skip = 0;
166 start_pos = 5;
167 break;
168 case 0xC201: /*WMV main profile*/
169 num_addr = 3;
170 skip = 0;
171 start_pos = 6;
172 break;
173 case 0xDD01: /* VP6 */
174 num_addr = 3;
175 skip = 0;
176 start_pos = 10;
177 break;
178 case 0xFD01: /* VP8 */
179 num_addr = 3;
180 skip = 0;
181 start_pos = 24;
182 break;
183 default:
184 return 0;
185 }
186
187 frame_buffer_high = &frame_header_pkt[start_pos];
188 frame_buffer_low = &frame_header_pkt[start_pos + 1];
189 frame_buffer_size = (frame_header_pkt[xdim_pos] *
190 frame_header_pkt[ydim_pos] * 3) / 2;
191 ptr_to_high_low_short((void *)frame_buffer_size,
192 &frame_buffer_size_high,
193 &frame_buffer_size_low);
194 for (i = 0; i < num_addr; i++) {
195 if (frame_buffer_high && frame_buffer_low) {
196 if (pmem_fixup_high_low(frame_buffer_high,
197 frame_buffer_low,
198 frame_buffer_size_high,
199 frame_buffer_size_low,
200 module,
201 NULL, NULL, NULL, NULL))
202 return -EINVAL;
203 }
204 frame_buffer_high += 2;
205 frame_buffer_low += 2;
206 }
207 /* Patch the output buffer. */
208 frame_buffer_high += 2*skip;
209 frame_buffer_low += 2*skip;
210 if (frame_buffer_high && frame_buffer_low) {
211 if (pmem_fixup_high_low(frame_buffer_high,
212 frame_buffer_low,
213 frame_buffer_size_high,
214 frame_buffer_size_low,
215 module,
216 NULL, NULL, NULL, NULL))
217 return -EINVAL;
218 }
Saikumar Kondaparthi7821dbc2011-11-23 19:17:30 +0530219 if (col_addr) {
220 frame_buffer_high += 2;
221 frame_buffer_low += 2;
222 /* Patch the Co-located buffers.*/
223 frame_buffer_size = (72 * frame_header_pkt[xdim_pos] *
224 frame_header_pkt[ydim_pos]) >> 16;
225 ptr_to_high_low_short((void *)frame_buffer_size,
226 &frame_buffer_size_high,
227 &frame_buffer_size_low);
228 for (i = 0; i < col_addr; i++) {
229 if (frame_buffer_high && frame_buffer_low) {
230 if (pmem_fixup_high_low(frame_buffer_high,
231 frame_buffer_low,
232 frame_buffer_size_high,
233 frame_buffer_size_low,
234 module,
235 NULL, NULL, NULL, NULL))
236 return -EINVAL;
237 }
238 frame_buffer_high += 2;
239 frame_buffer_low += 2;
240 }
241 }
Saikumar Kondaparthi316620f2012-06-26 15:43:22 +0530242 /*Flush the cached mem subframe packet before sending to DSP*/
243 if (adsp_ion_do_cache_op(module, phys_addr, (void *)subframe_pkt_addr,
244 MAX_FLUSH_SIZE, offset, ION_IOC_CLEAN_CACHES)){
245 MM_ERR("Cache operation failed for" \
246 " phys addr high %x addr low %x\n",
247 pkt->subframe_packet_high, pkt->subframe_packet_low);
248 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 return 0;
251}
252
253int adsp_video_verify_cmd(struct msm_adsp_module *module,
254 unsigned int queue_id, void *cmd_data,
255 size_t cmd_size)
256{
257 switch (queue_id) {
258 case QDSP_mpuVDecPktQueue:
259 return verify_vdec_pkt_cmd(module, cmd_data, cmd_size);
260 default:
261 MM_INFO("unknown video queue %u\n", queue_id);
262 return 0;
263 }
264}
265