diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch | 730 |
1 files changed, 730 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch new file mode 100644 index 0000000000..631b05f417 --- /dev/null +++ b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/standalone/0002-Resizer-bug-fixes-on-top-of-1.0.2-release.patch | |||
@@ -0,0 +1,730 @@ | |||
1 | From 20d79137ecaa6c7dad007d9ea1d7be5550db4839 Mon Sep 17 00:00:00 2001 | ||
2 | From: Vaibhav Hiremath <hvaibhav@ti.com> | ||
3 | Date: Fri, 13 Feb 2009 15:40:25 +0530 | ||
4 | Subject: [PATCH 2/2] Resizer bug fixes on top of 1.0.2 release | ||
5 | |||
6 | This commit contains resizer bug fixes on top of | ||
7 | PSP1.0.2 release - | ||
8 | - 4096 aligned address constraint | ||
9 | - workaround for extra page allocation for page aligned | ||
10 | size buffers | ||
11 | |||
12 | Signed-off-by: Vaibhav Hiremath <hvaibhav@ti.com> | ||
13 | --- | ||
14 | drivers/media/video/isp/omap_resizer.c | 417 ++++++++++++++++++++++++-------- | ||
15 | include/linux/omap_resizer.h | 3 +- | ||
16 | 2 files changed, 321 insertions(+), 99 deletions(-) | ||
17 | |||
18 | diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c | ||
19 | index 54bc425..8059c70 100644 | ||
20 | --- a/drivers/media/video/isp/omap_resizer.c | ||
21 | +++ b/drivers/media/video/isp/omap_resizer.c | ||
22 | @@ -28,6 +28,7 @@ | ||
23 | #include <linux/platform_device.h> | ||
24 | #include <linux/io.h> | ||
25 | #include <linux/uaccess.h> | ||
26 | +#include <linux/pci.h> | ||
27 | #include <media/v4l2-dev.h> | ||
28 | #include <asm/cacheflush.h> | ||
29 | |||
30 | @@ -76,6 +77,10 @@ | ||
31 | #define MAX_COEF_COUNTER 16 | ||
32 | #define COEFF_ADDRESS_OFFSET 0x04 | ||
33 | |||
34 | +#define RSZ_DEF_REQ_EXP 0xE /* Default read operation expand | ||
35 | + * for the Resizer driver; value | ||
36 | + * taken from Davinci. | ||
37 | + */ | ||
38 | /* Global structure which contains information about number of channels | ||
39 | and protection variables */ | ||
40 | struct device_params { | ||
41 | @@ -85,6 +90,7 @@ struct device_params { | ||
42 | struct mutex reszwrap_mutex; /* Semaphore for array */ | ||
43 | |||
44 | struct videobuf_queue_ops vbq_ops; /* videobuf queue operations */ | ||
45 | + unsigned long extra_page_addr; | ||
46 | }; | ||
47 | |||
48 | /* Register mapped structure which contains the every register | ||
49 | @@ -126,6 +132,9 @@ struct resizer_config { | ||
50 | u32 rsz_yehn; /* yehn(luma)register mapping | ||
51 | * variable. | ||
52 | */ | ||
53 | + u32 sdr_req_exp; /* Configuration for Non | ||
54 | + * real time read expand | ||
55 | + */ | ||
56 | }; | ||
57 | |||
58 | struct rsz_mult { | ||
59 | @@ -179,6 +188,7 @@ struct channel_config { | ||
60 | * channel is busy or not | ||
61 | */ | ||
62 | struct mutex chanprotection_mutex; | ||
63 | + int buf_address[VIDEO_MAX_FRAME]; | ||
64 | enum config_done config_state; | ||
65 | u8 input_buf_index; | ||
66 | u8 output_buf_index; | ||
67 | @@ -200,8 +210,6 @@ struct rsz_fh { | ||
68 | struct videobuf_queue vbq; | ||
69 | struct device_params *device; | ||
70 | |||
71 | - dma_addr_t isp_addr_read; /* Input/Output address */ | ||
72 | - dma_addr_t isp_addr_write; /* Input/Output address */ | ||
73 | u32 rsz_bufsize; /* channel specific buffersize | ||
74 | */ | ||
75 | }; | ||
76 | @@ -227,6 +235,10 @@ static int rsz_set_ratio(struct rsz_mult *multipass, | ||
77 | static void rsz_config_ratio(struct rsz_mult *multipass, | ||
78 | struct channel_config *rsz_conf_chan); | ||
79 | |||
80 | +static void inline rsz_set_exp(unsigned int exp) | ||
81 | +{ | ||
82 | + omap_writel(((exp & 0x3FF) << 10), OMAP3ISP_SBL_REG(0xF8)); | ||
83 | +} | ||
84 | /** | ||
85 | * rsz_hardware_setup - Sets hardware configuration registers | ||
86 | * @rsz_conf_chan: Structure containing channel configuration | ||
87 | @@ -271,12 +283,15 @@ static void rsz_hardware_setup(struct channel_config *rsz_conf_chan) | ||
88 | + coeffoffset)); | ||
89 | coeffoffset = coeffoffset + COEFF_ADDRESS_OFFSET; | ||
90 | } | ||
91 | + /* Configure the read expand register */ | ||
92 | + rsz_set_exp(rsz_conf_chan->register_config.sdr_req_exp); | ||
93 | } | ||
94 | |||
95 | /** | ||
96 | * rsz_start - Enables Resizer Wrapper | ||
97 | * @arg: Currently not used. | ||
98 | - * @device: Structure containing ISP resizer wrapper global information | ||
99 | + * @fh: File structure containing ISP resizer information specific to | ||
100 | + * channel opened. | ||
101 | * | ||
102 | * Submits a resizing task specified by the rsz_resize structure. The call can | ||
103 | * either be blocked until the task is completed or returned immediately based | ||
104 | @@ -292,12 +307,18 @@ int rsz_start(int *arg, struct rsz_fh *fh) | ||
105 | struct channel_config *rsz_conf_chan = fh->config; | ||
106 | struct rsz_mult *multipass = fh->multipass; | ||
107 | struct videobuf_queue *q = &fh->vbq; | ||
108 | + struct videobuf_buffer *buf; | ||
109 | int ret; | ||
110 | |||
111 | if (rsz_conf_chan->config_state) { | ||
112 | dev_err(rsz_device, "State not configured \n"); | ||
113 | goto err_einval; | ||
114 | } | ||
115 | + if (!rsz_conf_chan->register_config.rsz_sdr_inadd || | ||
116 | + !rsz_conf_chan->register_config.rsz_sdr_outadd) { | ||
117 | + dev_err(rsz_device, "address is null\n"); | ||
118 | + goto err_einval; | ||
119 | + } | ||
120 | |||
121 | rsz_conf_chan->status = CHANNEL_BUSY; | ||
122 | |||
123 | @@ -325,33 +346,22 @@ mult: | ||
124 | goto mult; | ||
125 | } | ||
126 | |||
127 | - if (fh->isp_addr_read) { | ||
128 | - ispmmu_vunmap(fh->isp_addr_read); | ||
129 | - fh->isp_addr_read = 0; | ||
130 | - } | ||
131 | - if (fh->isp_addr_write) { | ||
132 | - ispmmu_vunmap(fh->isp_addr_write); | ||
133 | - fh->isp_addr_write = 0; | ||
134 | - } | ||
135 | - | ||
136 | rsz_conf_chan->status = CHANNEL_FREE; | ||
137 | - q->bufs[rsz_conf_chan->input_buf_index]->state = VIDEOBUF_NEEDS_INIT; | ||
138 | - q->bufs[rsz_conf_chan->output_buf_index]->state = VIDEOBUF_NEEDS_INIT; | ||
139 | rsz_conf_chan->register_config.rsz_sdr_outadd = 0; | ||
140 | rsz_conf_chan->register_config.rsz_sdr_inadd = 0; | ||
141 | |||
142 | - /* Unmap and free the DMA memory allocated for buffers */ | ||
143 | - videobuf_dma_unmap(q, videobuf_to_dma( | ||
144 | - q->bufs[rsz_conf_chan->input_buf_index])); | ||
145 | - videobuf_dma_unmap(q, videobuf_to_dma( | ||
146 | - q->bufs[rsz_conf_chan->output_buf_index])); | ||
147 | - videobuf_dma_free(videobuf_to_dma( | ||
148 | - q->bufs[rsz_conf_chan->input_buf_index])); | ||
149 | - videobuf_dma_free(videobuf_to_dma( | ||
150 | - q->bufs[rsz_conf_chan->output_buf_index])); | ||
151 | - | ||
152 | isp_unset_callback(CBK_RESZ_DONE); | ||
153 | |||
154 | + /* Empty the Videobuf queue which was filled during the qbuf */ | ||
155 | + buf = q->bufs[rsz_conf_chan->input_buf_index]; | ||
156 | + buf->state = VIDEOBUF_IDLE; | ||
157 | + list_del(&buf->stream); | ||
158 | + if (rsz_conf_chan->input_buf_index != rsz_conf_chan->output_buf_index) { | ||
159 | + buf = q->bufs[rsz_conf_chan->output_buf_index]; | ||
160 | + buf->state = VIDEOBUF_IDLE; | ||
161 | + list_del(&buf->stream); | ||
162 | + } | ||
163 | + | ||
164 | return 0; | ||
165 | err_einval: | ||
166 | return -EINVAL; | ||
167 | @@ -359,6 +369,8 @@ err_einval: | ||
168 | |||
169 | /** | ||
170 | * rsz_set_multipass - Set resizer multipass | ||
171 | + * @multipass: Structure containing channel configuration | ||
172 | + for multipass support | ||
173 | * @rsz_conf_chan: Structure containing channel configuration | ||
174 | * | ||
175 | * Returns always 0 | ||
176 | @@ -384,6 +396,8 @@ static int rsz_set_multipass(struct rsz_mult *multipass, | ||
177 | |||
178 | /** | ||
179 | * rsz_copy_data - Copy data | ||
180 | + * @multipass: Structure containing channel configuration | ||
181 | + for multipass support | ||
182 | * @params: Structure containing the Resizer Wrapper parameters | ||
183 | * | ||
184 | * Copy data | ||
185 | @@ -413,6 +427,8 @@ static void rsz_copy_data(struct rsz_mult *multipass, struct rsz_params *params) | ||
186 | |||
187 | /** | ||
188 | * rsz_set_params - Set parameters for resizer wrapper | ||
189 | + * @multipass: Structure containing channel configuration | ||
190 | + for multipass support | ||
191 | * @params: Structure containing the Resizer Wrapper parameters | ||
192 | * @rsz_conf_chan: Structure containing channel configuration | ||
193 | * | ||
194 | @@ -524,6 +540,8 @@ static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *params, | ||
195 | } | ||
196 | |||
197 | rsz_config_ratio(multipass, rsz_conf_chan); | ||
198 | + /* Default value for read expand:Taken from Davinci */ | ||
199 | + rsz_conf_chan->register_config.sdr_req_exp = RSZ_DEF_REQ_EXP; | ||
200 | |||
201 | rsz_conf_chan->config_state = STATE_CONFIGURED; | ||
202 | |||
203 | @@ -534,6 +552,8 @@ err_einval: | ||
204 | |||
205 | /** | ||
206 | * rsz_set_ratio - Set ratio | ||
207 | + * @multipass: Structure containing channel configuration | ||
208 | + for multipass support | ||
209 | * @rsz_conf_chan: Structure containing channel configuration | ||
210 | * | ||
211 | * Returns 0 if successful, -EINVAL if invalid output size, upscaling ratio is | ||
212 | @@ -548,7 +568,8 @@ static int rsz_set_ratio(struct rsz_mult *multipass, | ||
213 | |||
214 | if ((multipass->out_hsize > MAX_IMAGE_WIDTH) || | ||
215 | (multipass->out_vsize > MAX_IMAGE_WIDTH)) { | ||
216 | - dev_err(rsz_device, "Invalid output size!"); | ||
217 | + dev_err(rsz_device, "Invalid output size! - %d", \ | ||
218 | + multipass->out_hsize); | ||
219 | goto err_einval; | ||
220 | } | ||
221 | if (multipass->cbilin) { | ||
222 | @@ -758,6 +779,8 @@ err_einval: | ||
223 | |||
224 | /** | ||
225 | * rsz_config_ratio - Configure ratio | ||
226 | + * @multipass: Structure containing channel configuration | ||
227 | + for multipass support | ||
228 | * @rsz_conf_chan: Structure containing channel configuration | ||
229 | * | ||
230 | * Configure ratio | ||
231 | @@ -789,6 +812,20 @@ static void rsz_config_ratio(struct rsz_mult *multipass, | ||
232 | ((vsize << ISPRSZ_IN_SIZE_VERT_SHIFT) | ||
233 | & ISPRSZ_IN_SIZE_VERT_MASK); | ||
234 | |||
235 | + /* This is another workaround for the ISP-MMU translation fault. | ||
236 | + For the parameters whose image size comes exactly to PAGE_SIZE | ||
237 | + generates ISP-MMU translation fault. The root-cause is the equation | ||
238 | + input width = (32*sph + (ow - 1)*hrsz + 16) >> 8 + 7 | ||
239 | + = (64*sph + (ow - 1)*hrsz + 32) >> 8 + 7 | ||
240 | + input height = (32*spv + (oh - 1)*vrsz + 16) >> 8 + 4 | ||
241 | + = (64*spv + (oh - 1)*vrsz + 32) >> 8 + 7 | ||
242 | + | ||
243 | + we are adjusting the input width to suit for Resizer module, | ||
244 | + application should use this configuration henceforth. | ||
245 | + */ | ||
246 | + multipass->in_hsize = hsize; | ||
247 | + multipass->in_vsize = vsize; | ||
248 | + | ||
249 | for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER; | ||
250 | coeffcounter++) { | ||
251 | if (multipass->num_htap) { | ||
252 | @@ -990,24 +1027,15 @@ static void rsz_calculate_crop(struct channel_config *rsz_conf_chan, | ||
253 | static void rsz_vbq_release(struct videobuf_queue *q, | ||
254 | struct videobuf_buffer *vb) | ||
255 | { | ||
256 | - int i; | ||
257 | struct rsz_fh *fh = q->priv_data; | ||
258 | + struct videobuf_dmabuf *dma = NULL; | ||
259 | |||
260 | - for (i = 0; i < VIDEO_MAX_FRAME; i++) { | ||
261 | - struct videobuf_dmabuf *dma = NULL; | ||
262 | - if (!q->bufs[i]) | ||
263 | - continue; | ||
264 | - if (q->bufs[i]->memory != V4L2_MEMORY_MMAP) | ||
265 | - continue; | ||
266 | - dma = videobuf_to_dma(q->bufs[i]); | ||
267 | - videobuf_dma_unmap(q, dma); | ||
268 | - videobuf_dma_free(dma); | ||
269 | - } | ||
270 | + dma = videobuf_to_dma(q->bufs[vb->i]); | ||
271 | + videobuf_dma_unmap(q, dma); | ||
272 | + videobuf_dma_free(dma); | ||
273 | + ispmmu_vunmap(fh->config->buf_address[vb->i]); | ||
274 | + fh->config->buf_address[vb->i] = 0; | ||
275 | |||
276 | - ispmmu_vunmap(fh->isp_addr_read); | ||
277 | - ispmmu_vunmap(fh->isp_addr_write); | ||
278 | - fh->isp_addr_read = 0; | ||
279 | - fh->isp_addr_write = 0; | ||
280 | spin_lock(&fh->vbq_lock); | ||
281 | vb->state = VIDEOBUF_NEEDS_INIT; | ||
282 | spin_unlock(&fh->vbq_lock); | ||
283 | @@ -1062,7 +1090,105 @@ err_einval: | ||
284 | spin_unlock(&fh->vbq_lock); | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | +/* | ||
288 | + * This function is work around for the videobuf_iolock API, | ||
289 | + * for User memory allocated with ioremap (VM_IO flag) the API | ||
290 | + * get_user_pages fails. | ||
291 | + * | ||
292 | + * To fulfill this requirement, we have completely ignored VM layer of | ||
293 | + * Linux, and configuring the ISP MMU with physical address. | ||
294 | + */ | ||
295 | +static int omap_videobuf_dma_init_user(struct videobuf_buffer *vb, | ||
296 | + unsigned long physp, unsigned long asize) | ||
297 | +{ | ||
298 | + struct videobuf_dmabuf *dma; | ||
299 | + struct scatterlist *sglist; | ||
300 | + unsigned long data, first, last; | ||
301 | + int len, i = 0; | ||
302 | + | ||
303 | + dma = videobuf_to_dma(vb); | ||
304 | + data = vb->baddr; | ||
305 | + | ||
306 | + first = (data & PAGE_MASK) >> PAGE_SHIFT; | ||
307 | + last = ((data+asize-1) & PAGE_MASK) >> PAGE_SHIFT; | ||
308 | + dma->offset = data & ~PAGE_MASK; | ||
309 | + dma->nr_pages = last-first+1; | ||
310 | + | ||
311 | + dma->direction = PCI_DMA_FROMDEVICE; | ||
312 | + /* | ||
313 | + * Allocate array of sglen + 1, to add entry of extra page | ||
314 | + * for input buffer. Driver always uses 0th buffer as input buffer. | ||
315 | + */ | ||
316 | + len = dma->nr_pages + (vb->i ? 0 : 1); | ||
317 | + sglist = kcalloc(len, sizeof(*sglist), GFP_KERNEL); | ||
318 | + if (NULL == sglist) | ||
319 | + return -ENOMEM; | ||
320 | + | ||
321 | + sglist[0].offset = 0; | ||
322 | + sglist[0].length = PAGE_SIZE - dma->offset; | ||
323 | + sglist[0].dma_address = (dma_addr_t)physp; | ||
324 | + physp += sglist[0].length; | ||
325 | + /* | ||
326 | + * Iterate in a loop for the number of pages | ||
327 | + */ | ||
328 | + for (i = 1; i < (len - (vb->i ? 0 : 1)); i++) { | ||
329 | + sglist[i].offset = 0; | ||
330 | + sglist[i].length = PAGE_SIZE; | ||
331 | + sglist[i].dma_address = (dma_addr_t)physp; | ||
332 | + physp += PAGE_SIZE; | ||
333 | + } | ||
334 | + if (0 == vb->i) { | ||
335 | + sglist[i].offset = 0; | ||
336 | + sglist[i].length = PAGE_SIZE; | ||
337 | + sglist[i].dma_address = | ||
338 | + (dma_addr_t)device_config->extra_page_addr; | ||
339 | + } | ||
340 | + dma->sglist = sglist; | ||
341 | + dma->sglen = len; | ||
342 | + return 0; | ||
343 | + | ||
344 | + } | ||
345 | +/* | ||
346 | + * This function is workaround for the issue, where ISP-MMU generated | ||
347 | + * translation fault for specific params whose size is aligned to PAGE_SIZE. | ||
348 | + | ||
349 | + * As a workaround we are padding one extra page for input buffer. This page | ||
350 | + * we are allocating during init time and will not be released through-out | ||
351 | + * life time of resizer driver. Please note that Resizer module only reads | ||
352 | + * from this extra page. | ||
353 | + */ | ||
354 | +int omap_create_sg(struct videobuf_queue *q, struct videobuf_dmabuf *dma) | ||
355 | +{ | ||
356 | + struct scatterlist *sglist; | ||
357 | + int sglen; | ||
358 | |||
359 | + sglen = dma->sglen; | ||
360 | + sglist = kcalloc(sglen + 1, sizeof(*sglist), GFP_KERNEL); | ||
361 | + if (NULL == sglist) | ||
362 | + return -ENOMEM; | ||
363 | + /* | ||
364 | + * Copy the sglist locally | ||
365 | + */ | ||
366 | + memcpy(sglist, dma->sglist, sglen * sizeof(*sglist)); | ||
367 | + /* | ||
368 | + * Release the old sglist, since we already copied it locally | ||
369 | + */ | ||
370 | + videobuf_dma_unmap(q, dma); | ||
371 | + /* | ||
372 | + * Add extra entry to sglist to work with specific params, whose | ||
373 | + * buffer address alined to PAGE_SIZE. | ||
374 | + */ | ||
375 | + sglist[sglen].offset = 0; | ||
376 | + sglist[sglen].length = PAGE_SIZE; | ||
377 | + sglist[sglen].dma_address = (dma_addr_t)device_config->extra_page_addr; | ||
378 | + sglen++; | ||
379 | + /* | ||
380 | + * Save the sglist for mapping to ISP-MMU space | ||
381 | + */ | ||
382 | + dma->sglist = sglist; | ||
383 | + dma->sglen = sglen; | ||
384 | + return 0; | ||
385 | +} | ||
386 | /** | ||
387 | * rsz_vbq_prepare - Videobuffer is prepared and mmapped. | ||
388 | * @q: Structure containing the videobuffer queue file handle, and device | ||
389 | @@ -1079,19 +1205,24 @@ static int rsz_vbq_prepare(struct videobuf_queue *q, | ||
390 | { | ||
391 | struct rsz_fh *fh = q->priv_data; | ||
392 | struct channel_config *rsz_conf_chan = fh->config; | ||
393 | - struct rsz_mult *multipass = fh->multipass; | ||
394 | int err = 0; | ||
395 | unsigned int isp_addr, insize, outsize; | ||
396 | - struct videobuf_dmabuf *dma = videobuf_to_dma(vb); | ||
397 | - | ||
398 | + struct rsz_mult *multipass = fh->multipass; | ||
399 | spin_lock(&fh->vbq_lock); | ||
400 | if (vb->baddr) { | ||
401 | + /* Check for 32 byte alignement */ | ||
402 | + if (vb->baddr != (vb->baddr & ~0x1F)) { | ||
403 | + spin_unlock(&fh->vbq_lock); | ||
404 | + dev_err(rsz_device, "Buffer address should be aligned \ | ||
405 | + to 32 byte\n"); | ||
406 | + return -EINVAL; | ||
407 | + } | ||
408 | vb->size = fh->rsz_bufsize; | ||
409 | vb->bsize = fh->rsz_bufsize; | ||
410 | } else { | ||
411 | spin_unlock(&fh->vbq_lock); | ||
412 | dev_err(rsz_device, "No user buffer allocated\n"); | ||
413 | - goto out; | ||
414 | + return -EINVAL; | ||
415 | } | ||
416 | if (vb->i) { | ||
417 | vb->width = fh->params->out_hsize; | ||
418 | @@ -1103,55 +1234,128 @@ static int rsz_vbq_prepare(struct videobuf_queue *q, | ||
419 | |||
420 | vb->field = field; | ||
421 | spin_unlock(&fh->vbq_lock); | ||
422 | + /* | ||
423 | + * Calculate input and output sizes, will be used while mapping | ||
424 | + * user pages | ||
425 | + */ | ||
426 | + outsize = multipass->out_pitch * multipass->out_vsize; | ||
427 | + insize = multipass->in_pitch * multipass->in_vsize; | ||
428 | |||
429 | if (vb->state == VIDEOBUF_NEEDS_INIT) { | ||
430 | - err = videobuf_iolock(q, vb, NULL); | ||
431 | - if (!err) { | ||
432 | - isp_addr = ispmmu_vmap(dma->sglist, dma->sglen); | ||
433 | - if (!isp_addr) | ||
434 | - err = -EIO; | ||
435 | - else { | ||
436 | - if (vb->i) { | ||
437 | - rsz_conf_chan->register_config. | ||
438 | - rsz_sdr_outadd | ||
439 | - = isp_addr; | ||
440 | - fh->isp_addr_write = isp_addr; | ||
441 | - rsz_conf_chan->output_buf_index = vb->i; | ||
442 | - } else { | ||
443 | + struct videobuf_dmabuf *dma; | ||
444 | + struct vm_area_struct *vma; | ||
445 | + spin_lock(&fh->vbq_lock); | ||
446 | + dma = videobuf_to_dma(vb); | ||
447 | + vma = find_vma(current->mm, vb->baddr); | ||
448 | + if ((vma) && (vma->vm_flags & VM_IO) && (vma->vm_pgoff)) { | ||
449 | + /* This will catch ioremaped buffers to the kernel. | ||
450 | + * It gives two possible scenarios - | ||
451 | + * - Driver allocates buffer using either | ||
452 | + * dma_alloc_coherent or get_free_pages, | ||
453 | + * and maps to user space using | ||
454 | + * io_remap_pfn_range/remap_pfn_range | ||
455 | + * - Drivers maps memory outside from Linux using | ||
456 | + * io_remap | ||
457 | + */ | ||
458 | + unsigned long physp = 0, asize; | ||
459 | + asize = vb->i ? outsize : insize; | ||
460 | + if ((vb->baddr + asize) > vma->vm_end) { | ||
461 | + spin_unlock(&fh->vbq_lock); | ||
462 | + dev_err(rsz_device, "User Buffer Allocation:" \ | ||
463 | + "err=%lu[%lu]\n",\ | ||
464 | + (vma->vm_end - vb->baddr), asize); | ||
465 | + return -ENOMEM; | ||
466 | + } | ||
467 | + physp = (vma->vm_pgoff << PAGE_SHIFT) + | ||
468 | + (vb->baddr - vma->vm_start); | ||
469 | + err = omap_videobuf_dma_init_user(vb, physp, asize); | ||
470 | + spin_unlock(&fh->vbq_lock); | ||
471 | + if (0 != err) | ||
472 | + return err; | ||
473 | + } else { | ||
474 | + err = videobuf_iolock(q, vb, NULL); | ||
475 | + /* | ||
476 | + * In case of user pointer mode, the get_user_pages | ||
477 | + * will fail if user has allocated less memory than | ||
478 | + * vb->size. But it is not error from resizer driver | ||
479 | + * point of view. so handled seperately | ||
480 | + */ | ||
481 | + if ((err < 0) && (dma->nr_pages > 0)) | ||
482 | + err = videobuf_dma_map(q, dma); | ||
483 | + if (err) | ||
484 | + goto buf_release; | ||
485 | + /* | ||
486 | + * Add one extra page for input buffer | ||
487 | + */ | ||
488 | + if (0 == vb->i) | ||
489 | + err = omap_create_sg(q, dma); | ||
490 | + if (err) | ||
491 | + goto buf_release; | ||
492 | + spin_unlock(&fh->vbq_lock); | ||
493 | + } | ||
494 | + isp_addr = ispmmu_vmap(dma->sglist, dma->sglen); | ||
495 | + if (!isp_addr) | ||
496 | + err = -EIO; | ||
497 | + else { | ||
498 | + if (vb->i) { | ||
499 | + rsz_conf_chan->buf_address[vb->i] = isp_addr; | ||
500 | + rsz_conf_chan->register_config. | ||
501 | + rsz_sdr_outadd | ||
502 | + = isp_addr; | ||
503 | + rsz_conf_chan->output_buf_index = vb->i; | ||
504 | + } else { | ||
505 | + rsz_conf_chan->buf_address[vb->i] = isp_addr; | ||
506 | + rsz_conf_chan->register_config. | ||
507 | + rsz_sdr_inadd | ||
508 | + = isp_addr; | ||
509 | + rsz_conf_chan->input_buf_index = vb->i; | ||
510 | + if (outsize < insize && rsz_conf_chan-> | ||
511 | + register_config. | ||
512 | + rsz_sdr_outadd == 0) { | ||
513 | rsz_conf_chan->register_config. | ||
514 | - rsz_sdr_inadd | ||
515 | - = isp_addr; | ||
516 | - rsz_conf_chan->input_buf_index = vb->i; | ||
517 | - outsize = multipass->out_pitch * | ||
518 | - multipass->out_vsize; | ||
519 | - insize = multipass->in_pitch * | ||
520 | - multipass->in_vsize; | ||
521 | - if (outsize < insize) { | ||
522 | - rsz_conf_chan->register_config. | ||
523 | - rsz_sdr_outadd | ||
524 | - = isp_addr; | ||
525 | - rsz_conf_chan-> | ||
526 | - output_buf_index = | ||
527 | - vb->i; | ||
528 | - } | ||
529 | - | ||
530 | - fh->isp_addr_read = isp_addr; | ||
531 | + rsz_sdr_outadd | ||
532 | + = isp_addr; | ||
533 | + rsz_conf_chan-> | ||
534 | + output_buf_index = | ||
535 | + vb->i; | ||
536 | } | ||
537 | } | ||
538 | } | ||
539 | |||
540 | - } | ||
541 | + } else { | ||
542 | + if(vb->i) { | ||
543 | + rsz_conf_chan->register_config. | ||
544 | + rsz_sdr_outadd = | ||
545 | + rsz_conf_chan->buf_address[vb->i]; | ||
546 | + rsz_conf_chan->output_buf_index = vb->i; | ||
547 | + } else { | ||
548 | + rsz_conf_chan->register_config. | ||
549 | + rsz_sdr_inadd = | ||
550 | + rsz_conf_chan->buf_address[vb->i]; | ||
551 | + rsz_conf_chan->input_buf_index = vb->i; | ||
552 | + if(outsize < insize && rsz_conf_chan-> | ||
553 | + register_config. | ||
554 | + rsz_sdr_outadd == 0) { | ||
555 | + rsz_conf_chan->register_config. | ||
556 | + rsz_sdr_outadd | ||
557 | + = rsz_conf_chan->buf_address[vb->i]; | ||
558 | + rsz_conf_chan->output_buf_index = vb->i; | ||
559 | + } | ||
560 | + | ||
561 | + } | ||
562 | |||
563 | + } | ||
564 | if (!err) { | ||
565 | spin_lock(&fh->vbq_lock); | ||
566 | vb->state = VIDEOBUF_PREPARED; | ||
567 | spin_unlock(&fh->vbq_lock); | ||
568 | - flush_cache_user_range(NULL, vb->baddr, (vb->baddr | ||
569 | - + vb->bsize)); | ||
570 | } else | ||
571 | rsz_vbq_release(q, vb); | ||
572 | |||
573 | -out: | ||
574 | + return err; | ||
575 | +buf_release: | ||
576 | + spin_unlock(&fh->vbq_lock); | ||
577 | + rsz_vbq_release(q, vb); | ||
578 | return err; | ||
579 | } | ||
580 | |||
581 | @@ -1255,7 +1459,8 @@ err_enomem0: | ||
582 | **/ | ||
583 | static int rsz_release(struct inode *inode, struct file *filp) | ||
584 | { | ||
585 | - u32 timeout = 0; | ||
586 | + int i; | ||
587 | + unsigned int timeout = 0; | ||
588 | struct rsz_fh *fh = filp->private_data; | ||
589 | struct channel_config *rsz_conf_chan = fh->config; | ||
590 | struct rsz_params *params = fh->params; | ||
591 | @@ -1266,17 +1471,17 @@ static int rsz_release(struct inode *inode, struct file *filp) | ||
592 | timeout++; | ||
593 | schedule(); | ||
594 | } | ||
595 | - if (mutex_lock_interruptible(&device_config->reszwrap_mutex)) | ||
596 | - return -EINTR; | ||
597 | - device_config->opened--; | ||
598 | - mutex_unlock(&device_config->reszwrap_mutex); | ||
599 | - /* This will Free memory allocated to the buffers, | ||
600 | - * and flushes the queue | ||
601 | - */ | ||
602 | - videobuf_queue_cancel(q); | ||
603 | - fh->params = NULL; | ||
604 | - fh->config = NULL; | ||
605 | + /* Free memory allocated to the buffers */ | ||
606 | + for (i = 0 ; i < VIDEO_MAX_FRAME ; i++) { | ||
607 | + struct videobuf_dmabuf *dma = NULL; | ||
608 | + if (!q->bufs[i]) | ||
609 | + continue; | ||
610 | + dma = videobuf_to_dma(q->bufs[i]); | ||
611 | + videobuf_dma_unmap(q, dma); | ||
612 | + videobuf_dma_free(dma); | ||
613 | + } | ||
614 | |||
615 | + videobuf_mmap_free(q); | ||
616 | fh->rsz_bufsize = 0; | ||
617 | filp->private_data = NULL; | ||
618 | |||
619 | @@ -1286,7 +1491,8 @@ static int rsz_release(struct inode *inode, struct file *filp) | ||
620 | kfree(fh); | ||
621 | |||
622 | isp_put(); | ||
623 | - | ||
624 | + fh->params = NULL; | ||
625 | + fh->config = NULL; | ||
626 | return 0; | ||
627 | } | ||
628 | |||
629 | @@ -1353,6 +1559,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd, | ||
630 | chanprotection_mutex)) | ||
631 | return -EINTR; | ||
632 | ret = videobuf_reqbufs(&fh->vbq, (void *)&req_buf); | ||
633 | + if (ret >= 0) { | ||
634 | + if (copy_to_user((struct v4l2_requestbuffers *)arg, | ||
635 | + &req_buf, sizeof(struct | ||
636 | + v4l2_requestbuffers))) | ||
637 | + return -EFAULT; | ||
638 | + } | ||
639 | mutex_unlock(&rsz_conf_chan->chanprotection_mutex); | ||
640 | break; | ||
641 | } | ||
642 | @@ -1394,11 +1606,7 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd, | ||
643 | sizeof(struct rsz_params))) { | ||
644 | return -EFAULT; | ||
645 | } | ||
646 | - if (mutex_lock_interruptible(&rsz_conf_chan-> | ||
647 | - chanprotection_mutex)) | ||
648 | - return -EINTR; | ||
649 | - ret = rsz_set_params(fh->multipass, params, rsz_conf_chan); | ||
650 | - mutex_unlock(&rsz_conf_chan->chanprotection_mutex); | ||
651 | + ret = rsz_set_params(fh->multipass, fh->params, rsz_conf_chan); | ||
652 | break; | ||
653 | } | ||
654 | case RSZ_G_PARAM: | ||
655 | @@ -1433,6 +1641,12 @@ static long rsz_unlocked_ioctl(struct file *file, unsigned int cmd, | ||
656 | rsz_calculate_crop(rsz_conf_chan, (struct rsz_cropsize *)arg); | ||
657 | break; | ||
658 | |||
659 | + case RSZ_S_EXP: | ||
660 | + if (mutex_lock_interruptible(&rsz_conf_chan->chanprotection_mutex)) | ||
661 | + return -EINTR; | ||
662 | + rsz_conf_chan->register_config.sdr_req_exp = *((unsigned int *)arg); | ||
663 | + mutex_unlock(&rsz_conf_chan->chanprotection_mutex); | ||
664 | + break; | ||
665 | default: | ||
666 | dev_err(rsz_device, "resizer_ioctl: Invalid Command Value"); | ||
667 | return -EINVAL; | ||
668 | @@ -1535,14 +1749,18 @@ static int __init omap_rsz_init(void) | ||
669 | "memory\n"); | ||
670 | return -ENOMEM; | ||
671 | } | ||
672 | - | ||
673 | + device->extra_page_addr = __get_free_pages(GFP_KERNEL | GFP_DMA, 0); | ||
674 | + if (!device->extra_page_addr) { | ||
675 | + dev_err(rsz_device, OMAP_REZR_NAME ":Allocation failed. "); | ||
676 | + kfree(device); | ||
677 | + return -ENOMEM; | ||
678 | + } | ||
679 | ret = alloc_chrdev_region(&dev, 0, 1, OMAP_REZR_NAME); | ||
680 | if (ret < 0) { | ||
681 | dev_err(rsz_device, OMAP_REZR_NAME ": intialization failed. " | ||
682 | "Could not allocate region " | ||
683 | "for character device\n"); | ||
684 | - kfree(device); | ||
685 | - return -ENODEV; | ||
686 | + goto fail1; | ||
687 | } | ||
688 | |||
689 | /* Register the driver in the kernel */ | ||
690 | @@ -1608,6 +1826,8 @@ fail3: | ||
691 | cdev_del(&c_dev); | ||
692 | fail2: | ||
693 | unregister_chrdev_region(dev, 1); | ||
694 | +fail1: | ||
695 | + free_pages((unsigned long)device->extra_page_addr, 0); | ||
696 | kfree(device); | ||
697 | return ret; | ||
698 | } | ||
699 | @@ -1623,6 +1843,7 @@ void __exit omap_rsz_exit(void) | ||
700 | platform_driver_unregister(&omap_resizer_driver); | ||
701 | cdev_del(&c_dev); | ||
702 | unregister_chrdev_region(dev, 1); | ||
703 | + free_pages((unsigned long)device_config->extra_page_addr, 0); | ||
704 | kfree(device_config); | ||
705 | } | ||
706 | |||
707 | diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h | ||
708 | index 5ac0c88..47b8dd8 100644 | ||
709 | --- a/include/linux/omap_resizer.h | ||
710 | +++ b/include/linux/omap_resizer.h | ||
711 | @@ -21,7 +21,7 @@ | ||
712 | |||
713 | /* ioctls definition */ | ||
714 | #define RSZ_IOC_BASE 'R' | ||
715 | -#define RSZ_IOC_MAXNR 8 | ||
716 | +#define RSZ_IOC_MAXNR 9 | ||
717 | |||
718 | /*Ioctl options which are to be passed while calling the ioctl*/ | ||
719 | #define RSZ_REQBUF _IOWR(RSZ_IOC_BASE, 1,\ | ||
720 | @@ -33,6 +33,7 @@ | ||
721 | #define RSZ_G_STATUS _IOWR(RSZ_IOC_BASE, 6, struct rsz_status) | ||
722 | #define RSZ_QUEUEBUF _IOWR(RSZ_IOC_BASE, 7, struct v4l2_buffer) | ||
723 | #define RSZ_GET_CROPSIZE _IOWR(RSZ_IOC_BASE, 8, struct rsz_cropsize) | ||
724 | +#define RSZ_S_EXP _IOWR(RSZ_IOC_BASE, 9, __s32) | ||
725 | |||
726 | #define RSZ_INTYPE_YCBCR422_16BIT 0 | ||
727 | #define RSZ_INTYPE_PLANAR_8BIT 1 | ||
728 | -- | ||
729 | 1.6.0.3 | ||
730 | |||