Full support for Ginger Console
[linux-ginger.git] / drivers / media / video / isp / ispresizer.c
blob3542b165683eef1078548419772213dd05dbf248
1 /*
2 * ispresizer.c
4 * Driver Library for Resizer module in TI's OMAP3 Camera ISP
6 * Copyright (C)2009 Texas Instruments, Inc.
8 * Contributors:
9 * Sameer Venkatraman <sameerv@ti.com>
10 * Mohit Jalori
11 * Sergio Aguirre <saaguirre@ti.com>
13 * This package is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License version 2 as
15 * published by the Free Software Foundation.
17 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
19 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
22 #include <linux/module.h>
23 #include <linux/device.h>
25 #include "isp.h"
26 #include "ispreg.h"
27 #include "ispresizer.h"
29 /* Default configuration of resizer,filter coefficients,yenh for camera isp */
30 static struct isprsz_coef ispreszdefcoef = {
32 0x0000, 0x0100, 0x0000, 0x0000,
33 0x03FA, 0x00F6, 0x0010, 0x0000,
34 0x03F9, 0x00DB, 0x002C, 0x0000,
35 0x03FB, 0x00B3, 0x0053, 0x03FF,
36 0x03FD, 0x0082, 0x0084, 0x03FD,
37 0x03FF, 0x0053, 0x00B3, 0x03FB,
38 0x0000, 0x002C, 0x00DB, 0x03F9,
39 0x0000, 0x0010, 0x00F6, 0x03FA
42 0x0000, 0x0100, 0x0000, 0x0000,
43 0x03FA, 0x00F6, 0x0010, 0x0000,
44 0x03F9, 0x00DB, 0x002C, 0x0000,
45 0x03FB, 0x00B3, 0x0053, 0x03FF,
46 0x03FD, 0x0082, 0x0084, 0x03FD,
47 0x03FF, 0x0053, 0x00B3, 0x03FB,
48 0x0000, 0x002C, 0x00DB, 0x03F9,
49 0x0000, 0x0010, 0x00F6, 0x03FA
52 0x0004, 0x0023, 0x005A, 0x0058,
53 0x0023, 0x0004, 0x0000, 0x0002,
54 0x0018, 0x004d, 0x0060, 0x0031,
55 0x0008, 0x0000, 0x0001, 0x000f,
56 0x003f, 0x0062, 0x003f, 0x000f,
57 0x0001, 0x0000, 0x0008, 0x0031,
58 0x0060, 0x004d, 0x0018, 0x0002
61 0x0004, 0x0023, 0x005A, 0x0058,
62 0x0023, 0x0004, 0x0000, 0x0002,
63 0x0018, 0x004d, 0x0060, 0x0031,
64 0x0008, 0x0000, 0x0001, 0x000f,
65 0x003f, 0x0062, 0x003f, 0x000f,
66 0x0001, 0x0000, 0x0008, 0x0031,
67 0x0060, 0x004d, 0x0018, 0x0002
71 /* Structure for saving/restoring resizer module registers */
72 static struct isp_reg isprsz_reg_list[] = {
73 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, 0x0000},
74 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE, 0x0000},
75 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START, 0x0000},
76 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE, 0x0000},
77 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD, 0x0000},
78 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF, 0x0000},
79 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD, 0x0000},
80 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF, 0x0000},
81 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT10, 0x0000},
82 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT32, 0x0000},
83 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT54, 0x0000},
84 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT76, 0x0000},
85 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT98, 0x0000},
86 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT1110, 0x0000},
87 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT1312, 0x0000},
88 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT1514, 0x0000},
89 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT1716, 0x0000},
90 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT1918, 0x0000},
91 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT2120, 0x0000},
92 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT2322, 0x0000},
93 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT2524, 0x0000},
94 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT2726, 0x0000},
95 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT2928, 0x0000},
96 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_HFILT3130, 0x0000},
97 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT10, 0x0000},
98 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT32, 0x0000},
99 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT54, 0x0000},
100 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT76, 0x0000},
101 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT98, 0x0000},
102 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT1110, 0x0000},
103 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT1312, 0x0000},
104 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT1514, 0x0000},
105 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT1716, 0x0000},
106 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT1918, 0x0000},
107 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT2120, 0x0000},
108 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT2322, 0x0000},
109 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT2524, 0x0000},
110 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT2726, 0x0000},
111 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT2928, 0x0000},
112 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_VFILT3130, 0x0000},
113 {OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH, 0x0000},
114 {0, ISP_TOK_TERM, 0x0000}
118 * ispresizer_applycrop - Apply crop to input image.
120 void ispresizer_applycrop(struct isp_res_device *isp_res)
122 struct isp_device *isp =
123 container_of(isp_res, struct isp_device, isp_res);
124 if (!isp_res->applycrop)
125 return;
127 ispresizer_s_pipeline(isp_res, &isp->pipeline);
129 isp_res->applycrop = 0;
131 return;
135 * ispresizer_config_shadow_registers - Configure shadow registers.
137 void ispresizer_config_shadow_registers(struct isp_res_device *isp_res)
139 ispresizer_applycrop(isp_res);
141 return;
143 EXPORT_SYMBOL(ispresizer_config_shadow_registers);
145 int ispresizer_config_crop(struct isp_res_device *isp_res,
146 struct v4l2_crop *a)
148 struct isp_device *isp =
149 container_of(isp_res, struct isp_device, isp_res);
150 struct v4l2_crop *crop = a;
151 int rval;
153 if (crop->c.left < 0)
154 crop->c.left = 0;
155 if (crop->c.width < 0)
156 crop->c.width = 0;
157 if (crop->c.top < 0)
158 crop->c.top = 0;
159 if (crop->c.height < 0)
160 crop->c.height = 0;
162 if (crop->c.left >= isp->pipeline.prv_out_w_img)
163 crop->c.left = isp->pipeline.prv_out_w_img - 1;
164 if (crop->c.top >= isp->pipeline.rsz_out_h)
165 crop->c.top = isp->pipeline.rsz_out_h - 1;
167 /* Make sure the crop rectangle is never smaller than width
168 * and height divided by 4, since the resizer cannot upscale it
169 * by more than 4x. */
171 if (crop->c.width < (isp->pipeline.rsz_out_w + 3) / 4)
172 crop->c.width = (isp->pipeline.rsz_out_w + 3) / 4;
173 if (crop->c.height < (isp->pipeline.rsz_out_h + 3) / 4)
174 crop->c.height = (isp->pipeline.rsz_out_h + 3) / 4;
176 if (crop->c.left + crop->c.width > isp->pipeline.prv_out_w_img)
177 crop->c.width = isp->pipeline.prv_out_w_img - crop->c.left;
178 if (crop->c.top + crop->c.height > isp->pipeline.rsz_out_h)
179 crop->c.height =
180 isp->pipeline.prv_out_h - crop->c.top;
182 isp->pipeline.rsz_crop = crop->c;
184 rval = ispresizer_try_pipeline(isp_res, &isp->pipeline);
185 if (rval)
186 return rval;
188 isp_res->applycrop = 1;
190 if (isp->running == ISP_STOPPED)
191 ispresizer_applycrop(isp_res);
193 return 0;
195 EXPORT_SYMBOL(ispresizer_config_crop);
198 * ispresizer_request - Reserves the Resizer module.
200 * Allows only one user at a time.
202 * Returns 0 if successful, or -EBUSY if resizer module was already requested.
204 int ispresizer_request(struct isp_res_device *isp_res)
206 mutex_lock(&isp_res->ispres_mutex);
207 if (!isp_res->res_inuse) {
208 isp_res->res_inuse = 1;
209 mutex_unlock(&isp_res->ispres_mutex);
210 isp_reg_writel(isp_res->dev,
211 isp_reg_readl(isp_res->dev,
212 OMAP3_ISP_IOMEM_MAIN, ISP_CTRL) |
213 ISPCTRL_SBL_WR0_RAM_EN |
214 ISPCTRL_RSZ_CLK_EN,
215 OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
216 return 0;
217 } else {
218 mutex_unlock(&isp_res->ispres_mutex);
219 dev_err(isp_res->dev, "resizer: Module Busy\n");
220 return -EBUSY;
223 EXPORT_SYMBOL(ispresizer_request);
226 * ispresizer_free - Makes Resizer module free.
228 * Returns 0 if successful, or -EINVAL if resizer module was already freed.
230 int ispresizer_free(struct isp_res_device *isp_res)
232 mutex_lock(&isp_res->ispres_mutex);
233 if (isp_res->res_inuse) {
234 isp_res->res_inuse = 0;
235 mutex_unlock(&isp_res->ispres_mutex);
236 isp_reg_and(isp_res->dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
237 ~(ISPCTRL_RSZ_CLK_EN | ISPCTRL_SBL_WR0_RAM_EN));
238 return 0;
239 } else {
240 mutex_unlock(&isp_res->ispres_mutex);
241 DPRINTK_ISPRESZ("ISP_ERR : Resizer Module already freed\n");
242 return -EINVAL;
245 EXPORT_SYMBOL(ispresizer_free);
248 * ispresizer_config_datapath - Specifies which input to use in resizer module
249 * @input: Indicates the module that gives the image to resizer.
251 * Sets up the default resizer configuration according to the arguments.
253 * Returns 0 if successful, or -EINVAL if an unsupported input was requested.
255 int ispresizer_config_datapath(struct isp_res_device *isp_res,
256 struct isp_pipeline *pipe)
258 u32 cnt = 0;
260 DPRINTK_ISPRESZ("ispresizer_config_datapath()+\n");
262 switch (pipe->rsz_in) {
263 case RSZ_OTFLY_YUV:
264 cnt &= ~ISPRSZ_CNT_INPTYP;
265 cnt &= ~ISPRSZ_CNT_INPSRC;
266 ispresizer_set_inaddr(isp_res, 0);
267 ispresizer_config_inlineoffset(isp_res, 0);
268 break;
269 case RSZ_MEM_YUV:
270 cnt |= ISPRSZ_CNT_INPSRC;
271 cnt &= ~ISPRSZ_CNT_INPTYP;
272 break;
273 case RSZ_MEM_COL8:
274 cnt |= ISPRSZ_CNT_INPSRC;
275 cnt |= ISPRSZ_CNT_INPTYP;
276 break;
277 default:
278 dev_err(isp_res->dev, "resizer: Wrong Input\n");
279 return -EINVAL;
281 isp_reg_or(isp_res->dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, cnt);
282 ispresizer_config_ycpos(isp_res, 0);
283 ispresizer_config_filter_coef(isp_res, &ispreszdefcoef);
284 ispresizer_enable_cbilin(isp_res, 0);
285 ispresizer_config_luma_enhance(isp_res, &isp_res->defaultyenh);
286 DPRINTK_ISPRESZ("ispresizer_config_datapath()-\n");
287 return 0;
289 EXPORT_SYMBOL(ispresizer_config_datapath);
292 * ispresizer_try_size - Validates input and output images size.
293 * @input_w: input width for the resizer in number of pixels per line
294 * @input_h: input height for the resizer in number of lines
295 * @output_w: output width from the resizer in number of pixels per line
296 * resizer when writing to memory needs this to be multiple of 16.
297 * @pipe->rsz_out_h: output height for the resizer in number of lines, must be
298 * even.
300 * Calculates the horizontal and vertical resize ratio, number of pixels to
301 * be cropped in the resizer module and checks the validity of various
302 * parameters. Formula used for calculation is:-
304 * 8-phase 4-tap mode :-
305 * inputwidth = (32 * sph + (ow - 1) * hrsz + 16) >> 8 + 7
306 * inputheight = (32 * spv + (oh - 1) * vrsz + 16) >> 8 + 4
307 * endpahse for width = ((32 * sph + (ow - 1) * hrsz + 16) >> 5) % 8
308 * endphase for height = ((32 * sph + (oh - 1) * hrsz + 16) >> 5) % 8
310 * 4-phase 7-tap mode :-
311 * inputwidth = (64 * sph + (ow - 1) * hrsz + 32) >> 8 + 7
312 * inputheight = (64 * spv + (oh - 1) * vrsz + 32) >> 8 + 7
313 * endpahse for width = ((64 * sph + (ow - 1) * hrsz + 32) >> 6) % 4
314 * endphase for height = ((64 * sph + (oh - 1) * hrsz + 32) >> 6) % 4
316 * Where:
317 * sph = Start phase horizontal
318 * spv = Start phase vertical
319 * ow = Output width
320 * oh = Output height
321 * hrsz = Horizontal resize value
322 * vrsz = Vertical resize value
324 * Fills up the output/input widht/height, horizontal/vertical resize ratio,
325 * horizontal/vertical crop variables in the isp_res structure.
327 int ispresizer_try_pipeline(struct isp_res_device *isp_res,
328 struct isp_pipeline *pipe)
330 u32 rsz, rsz_7, rsz_4;
331 u32 sph;
332 int max_in_otf, max_out_7tap;
334 if (pipe->rsz_crop.width < 32 || pipe->rsz_crop.height < 32) {
335 DPRINTK_ISPCCDC("ISP_ERR: RESIZER cannot handle input width"
336 " less than 32 pixels or height less than"
337 " 32\n");
338 return -EINVAL;
341 if (pipe->rsz_crop.height > MAX_IN_HEIGHT)
342 return -EINVAL;
344 if (pipe->rsz_out_w < 16)
345 pipe->rsz_out_w = 16;
347 if (pipe->rsz_out_h < 2)
348 pipe->rsz_out_h = 2;
350 if (omap_rev() == OMAP3430_REV_ES1_0) {
351 max_in_otf = MAX_IN_WIDTH_ONTHEFLY_MODE;
352 max_out_7tap = MAX_7TAP_VRSZ_OUTWIDTH;
353 } else {
354 max_in_otf = MAX_IN_WIDTH_ONTHEFLY_MODE_ES2;
355 max_out_7tap = MAX_7TAP_VRSZ_OUTWIDTH_ES2;
358 if (pipe->rsz_in == RSZ_OTFLY_YUV) {
359 if (pipe->rsz_crop.width > max_in_otf)
360 return -EINVAL;
361 } else {
362 if (pipe->rsz_crop.width > MAX_IN_WIDTH_MEMORY_MODE)
363 return -EINVAL;
366 pipe->rsz_out_h &= 0xfffffffe;
367 sph = DEFAULTSTPHASE;
369 rsz_7 = ((pipe->rsz_crop.height - 7) * 256) / (pipe->rsz_out_h - 1);
370 rsz_4 = ((pipe->rsz_crop.height - 4) * 256) / (pipe->rsz_out_h - 1);
372 rsz = (pipe->rsz_crop.height * 256) / pipe->rsz_out_h;
374 if (rsz <= MID_RESIZE_VALUE) {
375 rsz = rsz_4;
376 if (rsz < MINIMUM_RESIZE_VALUE) {
377 rsz = MINIMUM_RESIZE_VALUE;
378 pipe->rsz_out_h =
379 (((pipe->rsz_crop.height - 4) * 256) / rsz) + 1;
380 dev_dbg(isp_res->dev,
381 "resizer: %s: using height %d instead\n",
382 __func__, pipe->rsz_out_h);
384 } else {
385 rsz = rsz_7;
386 if (pipe->rsz_out_w > max_out_7tap)
387 pipe->rsz_out_w = max_out_7tap;
388 if (rsz > MAXIMUM_RESIZE_VALUE) {
389 rsz = MAXIMUM_RESIZE_VALUE;
390 pipe->rsz_out_h =
391 (((pipe->rsz_crop.height - 7) * 256) / rsz) + 1;
392 dev_dbg(isp_res->dev,
393 "resizer: %s: using height %d instead\n",
394 __func__, pipe->rsz_out_h);
398 if (rsz > MID_RESIZE_VALUE) {
399 pipe->rsz_crop.height =
400 (((64 * sph) + ((pipe->rsz_out_h - 1) * rsz) + 32)
401 / 256) + 7;
402 } else {
403 pipe->rsz_crop.height =
404 (((32 * sph) + ((pipe->rsz_out_h - 1) * rsz) + 16)
405 / 256) + 4;
408 isp_res->v_resz = rsz;
409 /* FIXME: pipe->rsz_crop.height here is the real input height! */
410 isp_res->v_startphase = sph;
412 pipe->rsz_out_w &= 0xfffffff0;
413 sph = DEFAULTSTPHASE;
415 rsz_7 = ((pipe->rsz_crop.width - 7) * 256) / (pipe->rsz_out_w - 1);
416 rsz_4 = ((pipe->rsz_crop.width - 4) * 256) / (pipe->rsz_out_w - 1);
418 rsz = (pipe->rsz_crop.width * 256) / pipe->rsz_out_w;
419 if (rsz > MID_RESIZE_VALUE) {
420 rsz = rsz_7;
421 if (rsz > MAXIMUM_RESIZE_VALUE) {
422 rsz = MAXIMUM_RESIZE_VALUE;
423 pipe->rsz_out_w =
424 (((pipe->rsz_crop.width - 7) * 256) / rsz) + 1;
425 pipe->rsz_out_w = (pipe->rsz_out_w + 0xf) & 0xfffffff0;
426 dev_dbg(isp_res->dev,
427 "resizer: %s: using width %d instead\n",
428 __func__, pipe->rsz_out_w);
430 } else {
431 rsz = rsz_4;
432 if (rsz < MINIMUM_RESIZE_VALUE) {
433 rsz = MINIMUM_RESIZE_VALUE;
434 pipe->rsz_out_w =
435 (((pipe->rsz_crop.width - 4) * 256) / rsz) + 1;
436 pipe->rsz_out_w = (pipe->rsz_out_w + 0xf) & 0xfffffff0;
437 dev_dbg(isp_res->dev,
438 "resizer: %s: using width %d instead\n",
439 __func__, pipe->rsz_out_w);
443 /* Recalculate input based on TRM equations */
444 if (rsz > MID_RESIZE_VALUE) {
445 pipe->rsz_crop.width =
446 (((64 * sph) + ((pipe->rsz_out_w - 1) * rsz) + 32)
447 / 256) + 7;
448 } else {
449 pipe->rsz_crop.width =
450 (((32 * sph) + ((pipe->rsz_out_w - 1) * rsz) + 16)
451 / 256) + 7;
454 isp_res->h_resz = rsz;
455 /* FIXME: pipe->rsz_crop.width here is the real input width! */
456 isp_res->h_startphase = sph;
458 pipe->rsz_out_w_img = pipe->rsz_out_w;
460 return 0;
462 EXPORT_SYMBOL(ispresizer_try_pipeline);
465 * ispresizer_config_size - Configures input and output image size.
466 * @pipe->rsz_crop.width: input width for the resizer in number of pixels per
467 * line.
468 * @pipe->rsz_crop.height: input height for the resizer in number of lines.
469 * @pipe->rsz_out_w: output width from the resizer in number of pixels per line.
470 * @pipe->rsz_out_h: output height for the resizer in number of lines.
472 * Configures the appropriate values stored in the isp_res structure in the
473 * resizer registers.
475 * Returns 0 if successful, or -EINVAL if passed values haven't been verified
476 * with ispresizer_try_size() previously.
478 int ispresizer_s_pipeline(struct isp_res_device *isp_res,
479 struct isp_pipeline *pipe)
481 int i, j;
482 u32 res;
483 int rval;
485 rval = ispresizer_config_datapath(isp_res, pipe);
486 if (rval)
487 return rval;
489 /* Set Resizer input address and offset adderss */
490 ispresizer_config_inlineoffset(isp_res,
491 pipe->prv_out_w * ISP_BYTES_PER_PIXEL);
493 res = isp_reg_readl(isp_res->dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
494 ~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
495 isp_reg_writel(isp_res->dev, res |
496 (isp_res->h_startphase << ISPRSZ_CNT_HSTPH_SHIFT) |
497 (isp_res->v_startphase << ISPRSZ_CNT_VSTPH_SHIFT),
498 OMAP3_ISP_IOMEM_RESZ,
499 ISPRSZ_CNT);
500 /* Set start address for cropping */
501 ispresizer_set_inaddr(isp_res, isp_res->tmp_buf);
503 isp_reg_writel(isp_res->dev,
504 (pipe->rsz_crop.width << ISPRSZ_IN_SIZE_HORZ_SHIFT) |
505 (pipe->rsz_crop.height <<
506 ISPRSZ_IN_SIZE_VERT_SHIFT),
507 OMAP3_ISP_IOMEM_RESZ,
508 ISPRSZ_IN_SIZE);
509 if (!isp_res->algo) {
510 isp_reg_writel(isp_res->dev,
511 (pipe->rsz_out_w << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
512 (pipe->rsz_out_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
513 OMAP3_ISP_IOMEM_RESZ,
514 ISPRSZ_OUT_SIZE);
515 } else {
516 isp_reg_writel(isp_res->dev,
517 ((pipe->rsz_out_w - 4)
518 << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
519 (pipe->rsz_out_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
520 OMAP3_ISP_IOMEM_RESZ,
521 ISPRSZ_OUT_SIZE);
524 res = isp_reg_readl(isp_res->dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
525 ~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
526 isp_reg_writel(isp_res->dev, res |
527 ((isp_res->h_resz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) |
528 ((isp_res->v_resz - 1) << ISPRSZ_CNT_VRSZ_SHIFT),
529 OMAP3_ISP_IOMEM_RESZ,
530 ISPRSZ_CNT);
531 if (isp_res->h_resz <= MID_RESIZE_VALUE) {
532 j = 0;
533 for (i = 0; i < 16; i++) {
534 isp_reg_writel(isp_res->dev,
535 (isp_res->coeflist.h_filter_coef_4tap[j]
536 << ISPRSZ_HFILT10_COEF0_SHIFT) |
537 (isp_res->coeflist.h_filter_coef_4tap[j + 1]
538 << ISPRSZ_HFILT10_COEF1_SHIFT),
539 OMAP3_ISP_IOMEM_RESZ,
540 ISPRSZ_HFILT10 + (i * 0x04));
541 j += 2;
543 } else {
544 j = 0;
545 for (i = 0; i < 16; i++) {
546 if ((i + 1) % 4 == 0) {
547 isp_reg_writel(isp_res->dev,
548 (isp_res->coeflist.
549 h_filter_coef_7tap[j] <<
550 ISPRSZ_HFILT10_COEF0_SHIFT),
551 OMAP3_ISP_IOMEM_RESZ,
552 ISPRSZ_HFILT10 + (i * 0x04));
553 j += 1;
554 } else {
555 isp_reg_writel(isp_res->dev,
556 (isp_res->coeflist.
557 h_filter_coef_7tap[j] <<
558 ISPRSZ_HFILT10_COEF0_SHIFT) |
559 (isp_res->coeflist.
560 h_filter_coef_7tap[j+1] <<
561 ISPRSZ_HFILT10_COEF1_SHIFT),
562 OMAP3_ISP_IOMEM_RESZ,
563 ISPRSZ_HFILT10 + (i * 0x04));
564 j += 2;
568 if (isp_res->v_resz <= MID_RESIZE_VALUE) {
569 j = 0;
570 for (i = 0; i < 16; i++) {
571 isp_reg_writel(isp_res->dev, (isp_res->coeflist.
572 v_filter_coef_4tap[j] <<
573 ISPRSZ_VFILT10_COEF0_SHIFT) |
574 (isp_res->coeflist.
575 v_filter_coef_4tap[j + 1] <<
576 ISPRSZ_VFILT10_COEF1_SHIFT),
577 OMAP3_ISP_IOMEM_RESZ,
578 ISPRSZ_VFILT10 + (i * 0x04));
579 j += 2;
581 } else {
582 j = 0;
583 for (i = 0; i < 16; i++) {
584 if ((i + 1) % 4 == 0) {
585 isp_reg_writel(isp_res->dev,
586 (isp_res->coeflist.
587 v_filter_coef_7tap[j] <<
588 ISPRSZ_VFILT10_COEF0_SHIFT),
589 OMAP3_ISP_IOMEM_RESZ,
590 ISPRSZ_VFILT10 + (i * 0x04));
591 j += 1;
592 } else {
593 isp_reg_writel(isp_res->dev,
594 (isp_res->coeflist.
595 v_filter_coef_7tap[j] <<
596 ISPRSZ_VFILT10_COEF0_SHIFT) |
597 (isp_res->coeflist.
598 v_filter_coef_7tap[j+1] <<
599 ISPRSZ_VFILT10_COEF1_SHIFT),
600 OMAP3_ISP_IOMEM_RESZ,
601 ISPRSZ_VFILT10 + (i * 0x04));
602 j += 2;
607 ispresizer_config_outlineoffset(isp_res, pipe->rsz_out_w*2);
609 if (pipe->pix.pixelformat == V4L2_PIX_FMT_UYVY)
610 ispresizer_config_ycpos(isp_res, 0);
611 else
612 ispresizer_config_ycpos(isp_res, 1);
614 DPRINTK_ISPRESZ("ispresizer_config_size()-\n");
615 return 0;
617 EXPORT_SYMBOL(ispresizer_s_pipeline);
620 * ispresizer_enable - Enables the resizer module.
621 * @enable: 1 - Enable, 0 - Disable
623 * Client should configure all the sub modules in resizer before this.
625 void ispresizer_enable(struct isp_res_device *isp_res, int enable)
627 int val;
628 DPRINTK_ISPRESZ("+ispresizer_enable()+\n");
629 if (enable) {
630 val = (isp_reg_readl(isp_res->dev,
631 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) & 0x2) |
632 ISPRSZ_PCR_ENABLE;
633 } else {
634 val = isp_reg_readl(isp_res->dev,
635 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
636 ~ISPRSZ_PCR_ENABLE;
638 isp_reg_writel(isp_res->dev, val, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR);
639 DPRINTK_ISPRESZ("+ispresizer_enable()-\n");
641 EXPORT_SYMBOL(ispresizer_enable);
644 * ispresizer_busy - Checks if ISP resizer is busy.
646 * Returns busy field from ISPRSZ_PCR register.
648 int ispresizer_busy(struct isp_res_device *isp_res)
650 return isp_reg_readl(isp_res->dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
651 ISPPRV_PCR_BUSY;
653 EXPORT_SYMBOL(ispresizer_busy);
656 * ispresizer_config_startphase - Sets the horizontal and vertical start phase.
657 * @hstartphase: horizontal start phase (0 - 7).
658 * @vstartphase: vertical startphase (0 - 7).
660 * This API just updates the isp_res struct. Actual register write happens in
661 * ispresizer_config_size.
663 void ispresizer_config_startphase(struct isp_res_device *isp_res,
664 u8 hstartphase, u8 vstartphase)
666 DPRINTK_ISPRESZ("ispresizer_config_startphase()+\n");
667 isp_res->h_startphase = hstartphase;
668 isp_res->v_startphase = vstartphase;
669 DPRINTK_ISPRESZ("ispresizer_config_startphase()-\n");
671 EXPORT_SYMBOL(ispresizer_config_startphase);
674 * ispresizer_config_ycpos - Specifies if output should be in YC or CY format.
675 * @yc: 0 - YC format, 1 - CY format
677 void ispresizer_config_ycpos(struct isp_res_device *isp_res, u8 yc)
679 DPRINTK_ISPRESZ("ispresizer_config_ycpos()+\n");
680 isp_reg_and_or(isp_res->dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
681 ~ISPRSZ_CNT_YCPOS, (yc ? ISPRSZ_CNT_YCPOS : 0));
682 DPRINTK_ISPRESZ("ispresizer_config_ycpos()-\n");
684 EXPORT_SYMBOL(ispresizer_config_ycpos);
687 * Sets the chrominance algorithm
688 * @cbilin: 0 - chrominance uses same processing as luminance,
689 * 1 - bilinear interpolation processing
691 void ispresizer_enable_cbilin(struct isp_res_device *isp_res, u8 enable)
693 DPRINTK_ISPRESZ("ispresizer_enable_cbilin()+\n");
694 isp_reg_and_or(isp_res->dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
695 ~ISPRSZ_CNT_CBILIN, (enable ? ISPRSZ_CNT_CBILIN : 0));
696 DPRINTK_ISPRESZ("ispresizer_enable_cbilin()-\n");
698 EXPORT_SYMBOL(ispresizer_enable_cbilin);
701 * ispresizer_config_luma_enhance - Configures luminance enhancer parameters.
702 * @yenh: Pointer to structure containing desired values for core, slope, gain
703 * and algo parameters.
705 void ispresizer_config_luma_enhance(struct isp_res_device *isp_res,
706 struct isprsz_yenh *yenh)
708 DPRINTK_ISPRESZ("ispresizer_config_luma_enhance()+\n");
709 isp_res->algo = yenh->algo;
710 isp_reg_writel(isp_res->dev, (yenh->algo << ISPRSZ_YENH_ALGO_SHIFT) |
711 (yenh->gain << ISPRSZ_YENH_GAIN_SHIFT) |
712 (yenh->slope << ISPRSZ_YENH_SLOP_SHIFT) |
713 (yenh->coreoffset << ISPRSZ_YENH_CORE_SHIFT),
714 OMAP3_ISP_IOMEM_RESZ,
715 ISPRSZ_YENH);
716 DPRINTK_ISPRESZ("ispresizer_config_luma_enhance()-\n");
718 EXPORT_SYMBOL(ispresizer_config_luma_enhance);
721 * ispresizer_config_filter_coef - Sets filter coefficients for 4 & 7-tap mode.
722 * This API just updates the isp_res struct.Actual register write happens in
723 * ispresizer_config_size.
724 * @coef: Structure containing horizontal and vertical filter coefficients for
725 * both 4-tap and 7-tap mode.
727 void ispresizer_config_filter_coef(struct isp_res_device *isp_res,
728 struct isprsz_coef *coef)
730 int i;
731 DPRINTK_ISPRESZ("ispresizer_config_filter_coef()+\n");
732 for (i = 0; i < 32; i++) {
733 isp_res->coeflist.h_filter_coef_4tap[i] =
734 coef->h_filter_coef_4tap[i];
735 isp_res->coeflist.v_filter_coef_4tap[i] =
736 coef->v_filter_coef_4tap[i];
738 for (i = 0; i < 28; i++) {
739 isp_res->coeflist.h_filter_coef_7tap[i] =
740 coef->h_filter_coef_7tap[i];
741 isp_res->coeflist.v_filter_coef_7tap[i] =
742 coef->v_filter_coef_7tap[i];
744 DPRINTK_ISPRESZ("ispresizer_config_filter_coef()-\n");
746 EXPORT_SYMBOL(ispresizer_config_filter_coef);
749 * ispresizer_config_inlineoffset - Configures the read address line offset.
750 * @offset: Line Offset for the input image.
752 * Returns 0 if successful, or -EINVAL if offset is not 32 bits aligned.
754 int ispresizer_config_inlineoffset(struct isp_res_device *isp_res, u32 offset)
756 DPRINTK_ISPRESZ("ispresizer_config_inlineoffset()+\n");
757 if (offset % 32)
758 return -EINVAL;
759 isp_reg_writel(isp_res->dev, offset << ISPRSZ_SDR_INOFF_OFFSET_SHIFT,
760 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
761 DPRINTK_ISPRESZ("ispresizer_config_inlineoffset()-\n");
762 return 0;
764 EXPORT_SYMBOL(ispresizer_config_inlineoffset);
767 * ispresizer_set_inaddr - Sets the memory address of the input frame.
768 * @addr: 32bit memory address aligned on 32byte boundary.
770 * Returns 0 if successful, or -EINVAL if address is not 32 bits aligned.
772 int ispresizer_set_inaddr(struct isp_res_device *isp_res, u32 addr)
774 struct isp_device *isp =
775 container_of(isp_res, struct isp_device, isp_res);
777 DPRINTK_ISPRESZ("ispresizer_set_inaddr()+\n");
779 if (addr % 32)
780 return -EINVAL;
781 isp_res->tmp_buf = addr;
782 /* FIXME: is this the right place to put crop-related junk? */
783 isp_reg_writel(isp_res->dev,
784 isp_res->tmp_buf + ISP_BYTES_PER_PIXEL
785 * ((isp->pipeline.rsz_crop.left & ~0xf) +
786 isp->pipeline.prv_out_w
787 * isp->pipeline.rsz_crop.top),
788 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
789 /* Set the fractional part of the starting address. Needed for crop */
790 isp_reg_writel(isp_res->dev, ((isp->pipeline.rsz_crop.left & 0xf) <<
791 ISPRSZ_IN_START_HORZ_ST_SHIFT) |
792 (0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT),
793 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
795 DPRINTK_ISPRESZ("ispresizer_set_inaddr()-\n");
796 return 0;
798 EXPORT_SYMBOL(ispresizer_set_inaddr);
801 * ispresizer_config_outlineoffset - Configures the write address line offset.
802 * @offset: Line offset for the preview output.
804 * Returns 0 if successful, or -EINVAL if address is not 32 bits aligned.
806 int ispresizer_config_outlineoffset(struct isp_res_device *isp_res, u32 offset)
808 DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()+\n");
809 if (offset % 32)
810 return -EINVAL;
811 isp_reg_writel(isp_res->dev, offset << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT,
812 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
813 DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()-\n");
814 return 0;
816 EXPORT_SYMBOL(ispresizer_config_outlineoffset);
819 * Configures the memory address to which the output frame is written.
820 * @addr: 32bit memory address aligned on 32byte boundary.
822 int ispresizer_set_outaddr(struct isp_res_device *isp_res, u32 addr)
824 DPRINTK_ISPRESZ("ispresizer_set_outaddr()+\n");
825 if (addr % 32)
826 return -EINVAL;
827 isp_reg_writel(isp_res->dev, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
828 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
829 DPRINTK_ISPRESZ("ispresizer_set_outaddr()-\n");
830 return 0;
832 EXPORT_SYMBOL(ispresizer_set_outaddr);
835 * ispresizer_save_context - Saves the values of the resizer module registers.
837 void ispresizer_save_context(struct device *dev)
839 DPRINTK_ISPRESZ("Saving context\n");
840 isp_save_context(dev, isprsz_reg_list);
842 EXPORT_SYMBOL(ispresizer_save_context);
845 * ispresizer_restore_context - Restores resizer module register values.
847 void ispresizer_restore_context(struct device *dev)
849 DPRINTK_ISPRESZ("Restoring context\n");
850 isp_restore_context(dev, isprsz_reg_list);
852 EXPORT_SYMBOL(ispresizer_restore_context);
855 * ispresizer_print_status - Prints the values of the resizer module registers.
857 void ispresizer_print_status(struct isp_res_device *isp_res)
859 if (!is_ispresz_debug_enabled())
860 return;
861 DPRINTK_ISPRESZ("###ISP_CTRL inresizer =0x%x\n",
862 isp_reg_readl(isp_res->dev,
863 OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
864 DPRINTK_ISPRESZ("###ISP_IRQ0ENABLE in resizer =0x%x\n",
865 isp_reg_readl(isp_res->dev,
866 OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
867 DPRINTK_ISPRESZ("###ISP_IRQ0STATUS in resizer =0x%x\n",
868 isp_reg_readl(isp_res->dev,
869 OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
870 DPRINTK_ISPRESZ("###RSZ PCR =0x%x\n",
871 isp_reg_readl(isp_res->dev,
872 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR));
873 DPRINTK_ISPRESZ("###RSZ CNT =0x%x\n",
874 isp_reg_readl(isp_res->dev,
875 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT));
876 DPRINTK_ISPRESZ("###RSZ OUT SIZE =0x%x\n",
877 isp_reg_readl(isp_res->dev,
878 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE));
879 DPRINTK_ISPRESZ("###RSZ IN START =0x%x\n",
880 isp_reg_readl(isp_res->dev,
881 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START));
882 DPRINTK_ISPRESZ("###RSZ IN SIZE =0x%x\n",
883 isp_reg_readl(isp_res->dev,
884 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE));
885 DPRINTK_ISPRESZ("###RSZ SDR INADD =0x%x\n",
886 isp_reg_readl(isp_res->dev,
887 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD));
888 DPRINTK_ISPRESZ("###RSZ SDR INOFF =0x%x\n",
889 isp_reg_readl(isp_res->dev,
890 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF));
891 DPRINTK_ISPRESZ("###RSZ SDR OUTADD =0x%x\n",
892 isp_reg_readl(isp_res->dev,
893 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD));
894 DPRINTK_ISPRESZ("###RSZ SDR OTOFF =0x%x\n",
895 isp_reg_readl(isp_res->dev,
896 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF));
897 DPRINTK_ISPRESZ("###RSZ YENH =0x%x\n",
898 isp_reg_readl(isp_res->dev,
899 OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH));
901 EXPORT_SYMBOL(ispresizer_print_status);
904 * isp_resizer_init - Module Initialisation.
906 * Always returns 0.
908 int __init isp_resizer_init(struct device *dev)
910 struct isp_device *isp = dev_get_drvdata(dev);
911 struct isp_res_device *isp_res = &isp->isp_res;
913 mutex_init(&isp_res->ispres_mutex);
914 isp_res->dev = dev;
916 return 0;
920 * isp_resizer_cleanup - Module Cleanup.
922 void isp_resizer_cleanup(struct device *dev)