blob: 59013e37bbcf01bc3a41a95fa28673ad3a41fe17 [file] [log] [blame]
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/platform_device.h>
14#include <linux/cdev.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/uaccess.h>
21#include <linux/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/android_pmem.h>
23#include <linux/msm_rotator.h>
24#include <linux/io.h>
25#include <mach/msm_rotator_imem.h>
26#include <linux/ktime.h>
27#include <linux/workqueue.h>
28#include <linux/file.h>
29#include <linux/major.h>
30#include <linux/regulator/consumer.h>
Naseer Ahmed18018602011-10-25 13:32:58 -070031#include <linux/ion.h>
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080032#ifdef CONFIG_MSM_BUS_SCALING
33#include <mach/msm_bus.h>
34#include <mach/msm_bus_board.h>
35#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070036#include <mach/msm_subsystem_map.h>
37#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#define DRIVER_NAME "msm_rotator"
40
41#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
42#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
43#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
44#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
45#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
46#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
47#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
48#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
49#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
50#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070051#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
53#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
54#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
55#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
56#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
57#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
58#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
59#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070060#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
62#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
63#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
64#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
65
66#define MSM_ROTATOR_MAX_ROT 0x07
67#define MSM_ROTATOR_MAX_H 0x1fff
68#define MSM_ROTATOR_MAX_W 0x1fff
69
70/* from lsb to msb */
71#define GET_PACK_PATTERN(a, x, y, z, bit) \
72 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
73#define CLR_G 0x0
74#define CLR_B 0x1
75#define CLR_R 0x2
76#define CLR_ALPHA 0x3
77
78#define CLR_Y CLR_G
79#define CLR_CB CLR_B
80#define CLR_CR CLR_R
81
82#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
83 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
84 (((r) & MDP_FLIP_UD) ? 4 : 0))
85
86#define IMEM_NO_OWNER -1;
87
88#define MAX_SESSIONS 16
89#define INVALID_SESSION -1
90#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070091#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092
93struct tile_parm {
94 unsigned int width; /* tile's width */
95 unsigned int height; /* tile's height */
96 unsigned int row_tile_w; /* tiles per row's width */
97 unsigned int row_tile_h; /* tiles per row's height */
98};
99
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700100struct msm_rotator_mem_planes {
101 unsigned int num_planes;
102 unsigned int plane_size[4];
103 unsigned int total_size;
104};
105
106#define checkoffset(offset, size, max_size) \
107 ((size) > (max_size) || (offset) > ((max_size) - (size)))
108
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109struct msm_rotator_dev {
110 void __iomem *io_base;
111 int irq;
112 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
113 struct clk *core_clk;
114 int pid_list[MAX_SESSIONS];
115 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700116 int rot_clk_state;
117 struct regulator *regulator;
118 struct delayed_work rot_clk_work;
119 struct clk *imem_clk;
120 int imem_clk_state;
121 struct delayed_work imem_clk_work;
122 struct platform_device *pdev;
123 struct cdev cdev;
124 struct device *device;
125 struct class *class;
126 dev_t dev_num;
127 int processing;
128 int last_session_idx;
129 struct mutex rotator_lock;
130 struct mutex imem_lock;
131 int imem_owner;
132 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700133 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800134 #ifdef CONFIG_MSM_BUS_SCALING
135 uint32_t bus_client_handle;
136 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137};
138
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139#define COMPONENT_5BITS 1
140#define COMPONENT_6BITS 2
141#define COMPONENT_8BITS 3
142
143static struct msm_rotator_dev *msm_rotator_dev;
144
145enum {
146 CLK_EN,
147 CLK_DIS,
148 CLK_SUSPEND,
149};
150
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700151int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
152 unsigned long *start, unsigned long *len,
153 struct ion_handle **pihdl)
154{
155 if (!msm_rotator_dev->client)
156 return -EINVAL;
157
158 *pihdl = ion_import_fd(msm_rotator_dev->client, mem_id);
159 if (IS_ERR_OR_NULL(*pihdl)) {
160 pr_err("ion_import_fd() failed\n");
161 return PTR_ERR(*pihdl);
162 }
163 pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
164 ion_share(msm_rotator_dev->client, *pihdl));
165
166 if (ion_map_iommu(msm_rotator_dev->client,
167 *pihdl, ROTATOR_DOMAIN, GEN_POOL,
168 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
169 pr_err("ion_map_iommu() failed\n");
170 return -EINVAL;
171 }
172
173 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
174 __func__, mem_id, *start, *len);
175 return 0;
176}
177
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700178int msm_rotator_imem_allocate(int requestor)
179{
180 int rc = 0;
181
182#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
183 switch (requestor) {
184 case ROTATOR_REQUEST:
185 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
186 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
187 rc = 1;
188 } else
189 rc = 0;
190 break;
191 case JPEG_REQUEST:
192 mutex_lock(&msm_rotator_dev->imem_lock);
193 msm_rotator_dev->imem_owner = JPEG_REQUEST;
194 rc = 1;
195 break;
196 default:
197 rc = 0;
198 }
199#else
200 if (requestor == JPEG_REQUEST)
201 rc = 1;
202#endif
203 if (rc == 1) {
204 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
205 if (msm_rotator_dev->imem_clk_state != CLK_EN
206 && msm_rotator_dev->imem_clk) {
207 clk_enable(msm_rotator_dev->imem_clk);
208 msm_rotator_dev->imem_clk_state = CLK_EN;
209 }
210 }
211
212 return rc;
213}
214EXPORT_SYMBOL(msm_rotator_imem_allocate);
215
216void msm_rotator_imem_free(int requestor)
217{
218#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
219 if (msm_rotator_dev->imem_owner == requestor) {
220 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
221 mutex_unlock(&msm_rotator_dev->imem_lock);
222 }
223#else
224 if (requestor == JPEG_REQUEST)
225 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
226#endif
227}
228EXPORT_SYMBOL(msm_rotator_imem_free);
229
230static void msm_rotator_imem_clk_work_f(struct work_struct *work)
231{
232#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
233 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
234 if (msm_rotator_dev->imem_clk_state == CLK_EN
235 && msm_rotator_dev->imem_clk) {
236 clk_disable(msm_rotator_dev->imem_clk);
237 msm_rotator_dev->imem_clk_state = CLK_DIS;
238 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
239 msm_rotator_dev->imem_clk_state = CLK_DIS;
240 mutex_unlock(&msm_rotator_dev->imem_lock);
241 }
242#endif
243}
244
245/* enable clocks needed by rotator block */
246static void enable_rot_clks(void)
247{
248 if (msm_rotator_dev->regulator)
249 regulator_enable(msm_rotator_dev->regulator);
250 if (msm_rotator_dev->core_clk != NULL)
251 clk_enable(msm_rotator_dev->core_clk);
252 if (msm_rotator_dev->pclk != NULL)
253 clk_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700254}
255
256/* disable clocks needed by rotator block */
257static void disable_rot_clks(void)
258{
259 if (msm_rotator_dev->core_clk != NULL)
260 clk_disable(msm_rotator_dev->core_clk);
261 if (msm_rotator_dev->pclk != NULL)
262 clk_disable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700263 if (msm_rotator_dev->regulator)
264 regulator_disable(msm_rotator_dev->regulator);
265}
266
267static void msm_rotator_rot_clk_work_f(struct work_struct *work)
268{
269 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
270 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
271 disable_rot_clks();
272 msm_rotator_dev->rot_clk_state = CLK_DIS;
273 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
274 msm_rotator_dev->rot_clk_state = CLK_DIS;
275 mutex_unlock(&msm_rotator_dev->rotator_lock);
276 }
277}
278
279static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
280{
281 if (msm_rotator_dev->processing) {
282 msm_rotator_dev->processing = 0;
283 wake_up(&msm_rotator_dev->wq);
284 } else
285 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
286
287 return IRQ_HANDLED;
288}
289
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700290static unsigned int tile_size(unsigned int src_width,
291 unsigned int src_height,
292 const struct tile_parm *tp)
293{
294 unsigned int tile_w, tile_h;
295 unsigned int row_num_w, row_num_h;
296 tile_w = tp->width * tp->row_tile_w;
297 tile_h = tp->height * tp->row_tile_h;
298 row_num_w = (src_width + tile_w - 1) / tile_w;
299 row_num_h = (src_height + tile_h - 1) / tile_h;
300 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
301}
302
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303static int get_bpp(int format)
304{
305 switch (format) {
306 case MDP_RGB_565:
307 case MDP_BGR_565:
308 return 2;
309
310 case MDP_XRGB_8888:
311 case MDP_ARGB_8888:
312 case MDP_RGBA_8888:
313 case MDP_BGRA_8888:
314 case MDP_RGBX_8888:
315 return 4;
316
317 case MDP_Y_CBCR_H2V2:
318 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700319 case MDP_Y_CB_CR_H2V2:
320 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530321 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700322 case MDP_Y_CRCB_H2V2_TILE:
323 case MDP_Y_CBCR_H2V2_TILE:
324 return 1;
325
326 case MDP_RGB_888:
327 return 3;
328
329 case MDP_YCRYCB_H2V1:
330 return 2;/* YCrYCb interleave */
331
332 case MDP_Y_CRCB_H2V1:
333 case MDP_Y_CBCR_H2V1:
334 return 1;
335
336 default:
337 return -1;
338 }
339
340}
341
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700342static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
343 struct msm_rotator_mem_planes *p)
344{
345 /*
346 * each row of samsung tile consists of two tiles in height
347 * and two tiles in width which means width should align to
348 * 64 x 2 bytes and height should align to 32 x 2 bytes.
349 * video decoder generate two tiles in width and one tile
350 * in height which ends up height align to 32 X 1 bytes.
351 */
352 const struct tile_parm tile = {64, 32, 2, 1};
353 int i;
354
355 if (p == NULL)
356 return -EINVAL;
357
358 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
359 return -ERANGE;
360
361 memset(p, 0, sizeof(*p));
362
363 switch (format) {
364 case MDP_XRGB_8888:
365 case MDP_ARGB_8888:
366 case MDP_RGBA_8888:
367 case MDP_BGRA_8888:
368 case MDP_RGBX_8888:
369 case MDP_RGB_888:
370 case MDP_RGB_565:
371 case MDP_BGR_565:
372 case MDP_YCRYCB_H2V1:
373 p->num_planes = 1;
374 p->plane_size[0] = w * h * get_bpp(format);
375 break;
376 case MDP_Y_CRCB_H2V1:
377 case MDP_Y_CBCR_H2V1:
378 p->num_planes = 2;
379 p->plane_size[0] = w * h;
380 p->plane_size[1] = w * h;
381 break;
382 case MDP_Y_CBCR_H2V2:
383 case MDP_Y_CRCB_H2V2:
384 p->num_planes = 2;
385 p->plane_size[0] = w * h;
386 p->plane_size[1] = w * h / 2;
387 break;
388 case MDP_Y_CRCB_H2V2_TILE:
389 case MDP_Y_CBCR_H2V2_TILE:
390 p->num_planes = 2;
391 p->plane_size[0] = tile_size(w, h, &tile);
392 p->plane_size[1] = tile_size(w, h/2, &tile);
393 break;
394 case MDP_Y_CB_CR_H2V2:
395 case MDP_Y_CR_CB_H2V2:
396 p->num_planes = 3;
397 p->plane_size[0] = w * h;
398 p->plane_size[1] = (w / 2) * (h / 2);
399 p->plane_size[2] = (w / 2) * (h / 2);
400 break;
401 case MDP_Y_CR_CB_GH2V2:
402 p->num_planes = 3;
403 p->plane_size[0] = ALIGN(w, 16) * h;
404 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
405 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
406 break;
407 default:
408 return -EINVAL;
409 }
410
411 for (i = 0; i < p->num_planes; i++)
412 p->total_size += p->plane_size[i];
413
414 return 0;
415}
416
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700417static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
418 unsigned int in_paddr,
419 unsigned int out_paddr,
420 unsigned int use_imem,
421 int new_session,
422 unsigned int in_chroma_paddr,
423 unsigned int out_chroma_paddr)
424{
425 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700426
427 if (info->src.format != info->dst.format)
428 return -EINVAL;
429
430 bpp = get_bpp(info->src.format);
431 if (bpp < 0)
432 return -ENOTTY;
433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700435 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700436 iowrite32(out_paddr +
437 ((info->dst_y * info->dst.width) + info->dst_x),
438 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700439 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440 ((info->dst_y * info->dst.width) + info->dst_x),
441 MSM_ROTATOR_OUTP1_ADDR);
442
443 if (new_session) {
444 iowrite32(info->src.width |
445 info->src.width << 16,
446 MSM_ROTATOR_SRC_YSTRIDE1);
447 if (info->rotations & MDP_ROT_90)
448 iowrite32(info->dst.width |
449 info->dst.width*2 << 16,
450 MSM_ROTATOR_OUT_YSTRIDE1);
451 else
452 iowrite32(info->dst.width |
453 info->dst.width << 16,
454 MSM_ROTATOR_OUT_YSTRIDE1);
455 if (info->src.format == MDP_Y_CBCR_H2V1) {
456 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
457 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
458 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
459 MSM_ROTATOR_OUT_PACK_PATTERN1);
460 } else {
461 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
462 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
463 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
464 MSM_ROTATOR_OUT_PACK_PATTERN1);
465 }
466 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
467 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700468 1 << 8 | /* ROT_EN */
469 info->downscale_ratio << 2 | /* downscale v ratio */
470 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471 MSM_ROTATOR_SUB_BLOCK_CFG);
472 iowrite32(0 << 29 | /* frame format 0 = linear */
473 (use_imem ? 0 : 1) << 22 | /* tile size */
474 2 << 19 | /* fetch planes 2 = pseudo */
475 0 << 18 | /* unpack align */
476 1 << 17 | /* unpack tight */
477 1 << 13 | /* unpack count 0=1 component */
478 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
479 0 << 8 | /* has alpha */
480 0 << 6 | /* alpha bits 3=8bits */
481 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
482 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
483 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
484 MSM_ROTATOR_SRC_FORMAT);
485 }
486
487 return 0;
488}
489
490static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
491 unsigned int in_paddr,
492 unsigned int out_paddr,
493 unsigned int use_imem,
494 int new_session,
495 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700496 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700497 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700499 uint32_t dst_format;
500 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700501
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700502 switch (info->src.format) {
503 case MDP_Y_CRCB_H2V2_TILE:
504 is_tile = 1;
505 case MDP_Y_CR_CB_H2V2:
506 case MDP_Y_CR_CB_GH2V2:
507 case MDP_Y_CRCB_H2V2:
508 dst_format = MDP_Y_CRCB_H2V2;
509 break;
510 case MDP_Y_CBCR_H2V2_TILE:
511 is_tile = 1;
512 case MDP_Y_CB_CR_H2V2:
513 case MDP_Y_CBCR_H2V2:
514 dst_format = MDP_Y_CBCR_H2V2;
515 break;
516 default:
517 return -EINVAL;
518 }
519 if (info->dst.format != dst_format)
520 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800522 /* rotator expects YCbCr for planar input format */
523 if (info->src.format == MDP_Y_CR_CB_H2V2 ||
524 info->src.format == MDP_Y_CR_CB_GH2V2)
525 swap(in_chroma_paddr, in_chroma2_paddr);
526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700528 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
529 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
530
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531 iowrite32(out_paddr +
532 ((info->dst_y * info->dst.width) + info->dst_x),
533 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700534 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700535 ((info->dst_y * info->dst.width)/2 + info->dst_x),
536 MSM_ROTATOR_OUTP1_ADDR);
537
538 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700539 if (in_chroma2_paddr) {
540 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530541 iowrite32(ALIGN(info->src.width, 16) |
542 ALIGN((info->src.width / 2), 16) << 16,
543 MSM_ROTATOR_SRC_YSTRIDE1);
544 iowrite32(ALIGN((info->src.width / 2), 16),
545 MSM_ROTATOR_SRC_YSTRIDE2);
546 } else {
547 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700548 (info->src.width / 2) << 16,
549 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530550 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700551 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530552 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700553 } else {
554 iowrite32(info->src.width |
555 info->src.width << 16,
556 MSM_ROTATOR_SRC_YSTRIDE1);
557 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700559 info->dst.width << 16,
560 MSM_ROTATOR_OUT_YSTRIDE1);
561
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700562 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700563 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
564 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
565 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
566 MSM_ROTATOR_OUT_PACK_PATTERN1);
567 } else {
568 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
569 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
570 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
571 MSM_ROTATOR_OUT_PACK_PATTERN1);
572 }
573 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
574 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700575 1 << 8 | /* ROT_EN */
576 info->downscale_ratio << 2 | /* downscale v ratio */
577 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700578 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700579
580 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700582 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700583 0 << 18 | /* unpack align */
584 1 << 17 | /* unpack tight */
585 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700586 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 0 << 8 | /* has alpha */
588 0 << 6 | /* alpha bits 3=8bits */
589 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
590 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
591 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
592 MSM_ROTATOR_SRC_FORMAT);
593 }
594 return 0;
595}
596
597static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
598 unsigned int in_paddr,
599 unsigned int out_paddr,
600 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530601 int new_session,
602 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700603{
604 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530605 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700606
Mayank Chopra732dcd62012-01-09 20:53:39 +0530607 if (info->src.format == MDP_YCRYCB_H2V1)
608 dst_format = MDP_Y_CRCB_H2V1;
609 else
610 return -EINVAL;
611
612 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613 return -EINVAL;
614
615 bpp = get_bpp(info->src.format);
616 if (bpp < 0)
617 return -ENOTTY;
618
619 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
620 iowrite32(out_paddr +
621 ((info->dst_y * info->dst.width) + info->dst_x),
622 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530623 iowrite32(out_chroma_paddr +
624 ((info->dst_y * info->dst.width)/2 + info->dst_x),
625 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700626
627 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530628 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530630 if (info->rotations & MDP_ROT_90)
631 iowrite32(info->dst.width |
632 (info->dst.width*2) << 16,
633 MSM_ROTATOR_OUT_YSTRIDE1);
634 else
635 iowrite32(info->dst.width |
636 (info->dst.width) << 16,
637 MSM_ROTATOR_OUT_YSTRIDE1);
638
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700639 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
640 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530641 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 MSM_ROTATOR_OUT_PACK_PATTERN1);
643 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
644 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700645 1 << 8 | /* ROT_EN */
646 info->downscale_ratio << 2 | /* downscale v ratio */
647 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648 MSM_ROTATOR_SUB_BLOCK_CFG);
649 iowrite32(0 << 29 | /* frame format 0 = linear */
650 (use_imem ? 0 : 1) << 22 | /* tile size */
651 0 << 19 | /* fetch planes 0=interleaved */
652 0 << 18 | /* unpack align */
653 1 << 17 | /* unpack tight */
654 3 << 13 | /* unpack count 0=1 component */
655 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
656 0 << 8 | /* has alpha */
657 0 << 6 | /* alpha bits 3=8bits */
658 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
659 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
660 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
661 MSM_ROTATOR_SRC_FORMAT);
662 }
663
664 return 0;
665}
666
667static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
668 unsigned int in_paddr,
669 unsigned int out_paddr,
670 unsigned int use_imem,
671 int new_session)
672{
673 int bpp, abits, rbits, gbits, bbits;
674
675 if (info->src.format != info->dst.format)
676 return -EINVAL;
677
678 bpp = get_bpp(info->src.format);
679 if (bpp < 0)
680 return -ENOTTY;
681
682 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
683 iowrite32(out_paddr +
684 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
685 MSM_ROTATOR_OUTP0_ADDR);
686
687 if (new_session) {
688 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
689 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
690 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
691 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700692 1 << 8 | /* ROT_EN */
693 info->downscale_ratio << 2 | /* downscale v ratio */
694 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700695 MSM_ROTATOR_SUB_BLOCK_CFG);
696 switch (info->src.format) {
697 case MDP_RGB_565:
698 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
699 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
700 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
701 MSM_ROTATOR_OUT_PACK_PATTERN1);
702 abits = 0;
703 rbits = COMPONENT_5BITS;
704 gbits = COMPONENT_6BITS;
705 bbits = COMPONENT_5BITS;
706 break;
707
708 case MDP_BGR_565:
709 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
710 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
711 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
712 MSM_ROTATOR_OUT_PACK_PATTERN1);
713 abits = 0;
714 rbits = COMPONENT_5BITS;
715 gbits = COMPONENT_6BITS;
716 bbits = COMPONENT_5BITS;
717 break;
718
719 case MDP_RGB_888:
720 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
721 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
722 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
723 MSM_ROTATOR_OUT_PACK_PATTERN1);
724 abits = 0;
725 rbits = COMPONENT_8BITS;
726 gbits = COMPONENT_8BITS;
727 bbits = COMPONENT_8BITS;
728 break;
729
730 case MDP_ARGB_8888:
731 case MDP_RGBA_8888:
732 case MDP_XRGB_8888:
733 case MDP_RGBX_8888:
734 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
735 CLR_B, 8),
736 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
737 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
738 CLR_B, 8),
739 MSM_ROTATOR_OUT_PACK_PATTERN1);
740 abits = COMPONENT_8BITS;
741 rbits = COMPONENT_8BITS;
742 gbits = COMPONENT_8BITS;
743 bbits = COMPONENT_8BITS;
744 break;
745
746 case MDP_BGRA_8888:
747 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
748 CLR_R, 8),
749 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
750 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
751 CLR_R, 8),
752 MSM_ROTATOR_OUT_PACK_PATTERN1);
753 abits = COMPONENT_8BITS;
754 rbits = COMPONENT_8BITS;
755 gbits = COMPONENT_8BITS;
756 bbits = COMPONENT_8BITS;
757 break;
758
759 default:
760 return -EINVAL;
761 }
762 iowrite32(0 << 29 | /* frame format 0 = linear */
763 (use_imem ? 0 : 1) << 22 | /* tile size */
764 0 << 19 | /* fetch planes 0=interleaved */
765 0 << 18 | /* unpack align */
766 1 << 17 | /* unpack tight */
767 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
768 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
769 (abits ? 1 : 0) << 8 | /* has alpha */
770 abits << 6 | /* alpha bits 3=8bits */
771 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
772 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
773 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
774 MSM_ROTATOR_SRC_FORMAT);
775 }
776
777 return 0;
778}
779
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700780static int get_img(struct msmfb_data *fbd, unsigned char src,
781 unsigned long *start, unsigned long *len, struct file **p_file,
782 int *p_need, struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700783{
784 int ret = 0;
785#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700786 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700787 int put_needed, fb_num;
788#endif
789#ifdef CONFIG_ANDROID_PMEM
790 unsigned long vstart;
791#endif
792
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800793 *p_need = 0;
794
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700795#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700796 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
797 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700798 if (file == NULL) {
799 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700800 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700801 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802
Naseer Ahmed18018602011-10-25 13:32:58 -0700803 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
804 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700805 if (get_fb_phys_info(start, len, fb_num,
806 ROTATOR_SUBSYSTEM_ID)) {
807 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700808 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700809 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700810 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800811 *p_need = put_needed;
812 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700813 } else {
814 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700815 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700816 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700817 if (ret)
818 fput_light(file, put_needed);
819 return ret;
820 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700822
823#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700824 return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
825 len, p_ihdl);
Naseer Ahmed18018602011-10-25 13:32:58 -0700826#endif
827#ifdef CONFIG_ANDROID_PMEM
828 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
829 return 0;
830 else
831 return -ENOMEM;
832#endif
833
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700834}
835
Naseer Ahmed18018602011-10-25 13:32:58 -0700836static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
837{
838#ifdef CONFIG_ANDROID_PMEM
839 if (p_file != NULL)
840 put_pmem_file(p_file);
841#endif
842#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700843 if (!IS_ERR_OR_NULL(p_ihdl)) {
844 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
845 ion_unmap_iommu(msm_rotator_dev->client,
846 p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
847
Naseer Ahmed18018602011-10-25 13:32:58 -0700848 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700849 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700850#endif
851}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852static int msm_rotator_do_rotate(unsigned long arg)
853{
Naseer Ahmed18018602011-10-25 13:32:58 -0700854 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700855 struct msm_rotator_data_info info;
856 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700857 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700858 int use_imem = 0, rc = 0, s;
859 struct file *srcp0_file = NULL, *dstp0_file = NULL;
860 struct file *srcp1_file = NULL, *dstp1_file = NULL;
861 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
862 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800863 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700864 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700865 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700866 struct msm_rotator_img_info *img_info;
867 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868
869 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
870 return -EFAULT;
871
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872 mutex_lock(&msm_rotator_dev->rotator_lock);
873 for (s = 0; s < MAX_SESSIONS; s++)
874 if ((msm_rotator_dev->img_info[s] != NULL) &&
875 (info.session_id ==
876 (unsigned int)msm_rotator_dev->img_info[s]
877 ))
878 break;
879
880 if (s == MAX_SESSIONS) {
881 dev_dbg(msm_rotator_dev->device,
882 "%s() : Attempt to use invalid session_id %d\n",
883 __func__, s);
884 rc = -EINVAL;
885 goto do_rotate_unlock_mutex;
886 }
887
888 if (msm_rotator_dev->img_info[s]->enable == 0) {
889 dev_dbg(msm_rotator_dev->device,
890 "%s() : Session_id %d not enabled \n",
891 __func__, s);
892 rc = -EINVAL;
893 goto do_rotate_unlock_mutex;
894 }
895
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700896 img_info = msm_rotator_dev->img_info[s];
897 if (msm_rotator_get_plane_sizes(img_info->src.format,
898 img_info->src.width,
899 img_info->src.height,
900 &src_planes)) {
901 pr_err("%s: invalid src format\n", __func__);
902 rc = -EINVAL;
903 goto do_rotate_unlock_mutex;
904 }
905 if (msm_rotator_get_plane_sizes(img_info->dst.format,
906 img_info->dst.width,
907 img_info->dst.height,
908 &dst_planes)) {
909 pr_err("%s: invalid dst format\n", __func__);
910 rc = -EINVAL;
911 goto do_rotate_unlock_mutex;
912 }
913
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700914 rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
915 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
916 &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700917 if (rc) {
918 pr_err("%s: in get_img() failed id=0x%08x\n",
919 DRIVER_NAME, info.src.memory_id);
920 goto do_rotate_unlock_mutex;
921 }
922
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700923 rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
924 (unsigned long *)&dst_len, &dstp0_file, &p_need,
925 &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700926 if (rc) {
927 pr_err("%s: out get_img() failed id=0x%08x\n",
928 DRIVER_NAME, info.dst.memory_id);
929 goto do_rotate_unlock_mutex;
930 }
931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 format = msm_rotator_dev->img_info[s]->src.format;
933 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700934 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
935 (src_planes.num_planes == 2)) {
936 if (checkoffset(info.src.offset,
937 src_planes.plane_size[0],
938 src_len)) {
939 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
940 __func__, src_len, info.src.offset);
941 rc = -ERANGE;
942 goto do_rotate_unlock_mutex;
943 }
944 if (checkoffset(info.dst.offset,
945 dst_planes.plane_size[0],
946 dst_len)) {
947 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
948 __func__, dst_len, info.dst.offset);
949 rc = -ERANGE;
950 goto do_rotate_unlock_mutex;
951 }
952
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700953 rc = get_img(&info.src_chroma, 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800955 (unsigned long *)&src_len, &srcp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700956 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700957 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700958 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700959 DRIVER_NAME, info.src_chroma.memory_id);
960 goto do_rotate_unlock_mutex;
961 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700962
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700963 rc = get_img(&info.dst_chroma, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800965 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700966 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700967 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700968 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700970 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700972
973 if (checkoffset(info.src_chroma.offset,
974 src_planes.plane_size[1],
975 src_len)) {
976 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
977 __func__, src_len, info.src_chroma.offset);
978 rc = -ERANGE;
979 goto do_rotate_unlock_mutex;
980 }
981
982 if (checkoffset(info.dst_chroma.offset,
983 src_planes.plane_size[1],
984 dst_len)) {
985 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
986 __func__, dst_len, info.dst_chroma.offset);
987 rc = -ERANGE;
988 goto do_rotate_unlock_mutex;
989 }
990
991 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700993 } else {
994 if (checkoffset(info.src.offset,
995 src_planes.total_size,
996 src_len)) {
997 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
998 __func__, src_len, info.src.offset);
999 rc = -ERANGE;
1000 goto do_rotate_unlock_mutex;
1001 }
1002 if (checkoffset(info.dst.offset,
1003 dst_planes.total_size,
1004 dst_len)) {
1005 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1006 __func__, dst_len, info.dst.offset);
1007 rc = -ERANGE;
1008 goto do_rotate_unlock_mutex;
1009 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001010 }
1011
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001012 in_paddr += info.src.offset;
1013 out_paddr += info.dst.offset;
1014
1015 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1016 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1017 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1018 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1019 if (src_planes.num_planes >= 3)
1020 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1021
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1023 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1024 enable_rot_clks();
1025 msm_rotator_dev->rot_clk_state = CLK_EN;
1026 }
1027 enable_irq(msm_rotator_dev->irq);
1028
1029#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1030 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1031#else
1032 use_imem = 0;
1033#endif
1034 /*
1035 * workaround for a hardware bug. rotator hardware hangs when we
1036 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1037 * temporary fix use 0x42 for BURST_SIZE when imem used.
1038 */
1039 if (use_imem)
1040 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1041
1042 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1043 << 16) |
1044 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1045 MSM_ROTATOR_SRC_SIZE);
1046 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1047 << 16) |
1048 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1049 MSM_ROTATOR_SRC_XY);
1050 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1051 << 16) |
1052 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1053 MSM_ROTATOR_SRC_IMAGE_SIZE);
1054
1055 switch (format) {
1056 case MDP_RGB_565:
1057 case MDP_BGR_565:
1058 case MDP_RGB_888:
1059 case MDP_ARGB_8888:
1060 case MDP_RGBA_8888:
1061 case MDP_XRGB_8888:
1062 case MDP_BGRA_8888:
1063 case MDP_RGBX_8888:
1064 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1065 in_paddr, out_paddr,
1066 use_imem,
1067 msm_rotator_dev->last_session_idx
1068 != s);
1069 break;
1070 case MDP_Y_CBCR_H2V2:
1071 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001072 case MDP_Y_CB_CR_H2V2:
1073 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301074 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001075 case MDP_Y_CRCB_H2V2_TILE:
1076 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001077 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1078 in_paddr, out_paddr, use_imem,
1079 msm_rotator_dev->last_session_idx
1080 != s,
1081 in_chroma_paddr,
1082 out_chroma_paddr,
1083 in_chroma2_paddr);
1084 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 case MDP_Y_CBCR_H2V1:
1086 case MDP_Y_CRCB_H2V1:
1087 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1088 in_paddr, out_paddr, use_imem,
1089 msm_rotator_dev->last_session_idx
1090 != s,
1091 in_chroma_paddr,
1092 out_chroma_paddr);
1093 break;
1094 case MDP_YCRYCB_H2V1:
1095 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1096 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301097 msm_rotator_dev->last_session_idx != s,
1098 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 break;
1100 default:
1101 rc = -EINVAL;
1102 goto do_rotate_exit;
1103 }
1104
1105 if (rc != 0) {
1106 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1107 goto do_rotate_exit;
1108 }
1109
1110 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1111
1112 msm_rotator_dev->processing = 1;
1113 iowrite32(0x1, MSM_ROTATOR_START);
1114
1115 wait_event(msm_rotator_dev->wq,
1116 (msm_rotator_dev->processing == 0));
1117 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
1118 if ((status & 0x03) != 0x01)
1119 rc = -EFAULT;
1120 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1121 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1122
1123do_rotate_exit:
1124 disable_irq(msm_rotator_dev->irq);
1125#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1126 msm_rotator_imem_free(ROTATOR_REQUEST);
1127#endif
1128 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001129do_rotate_unlock_mutex:
Naseer Ahmed18018602011-10-25 13:32:58 -07001130 put_img(dstp1_file, dstp1_ihdl);
1131 put_img(srcp1_file, srcp1_ihdl);
1132 put_img(dstp0_file, dstp0_ihdl);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001133
1134 /* only source may use frame buffer */
1135 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1136 fput_light(srcp0_file, ps0_need);
1137 else
1138 put_img(srcp0_file, srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001139 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001140 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1141 __func__, rc);
1142 return rc;
1143}
1144
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001145static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1146{
1147 u32 perf_level;
1148
1149 if (is_rgb)
1150 perf_level = 1;
1151 else if (wh <= (640 * 480))
1152 perf_level = 2;
1153 else if (wh <= (736 * 1280))
1154 perf_level = 3;
1155 else
1156 perf_level = 4;
1157
1158#ifdef CONFIG_MSM_BUS_SCALING
1159 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1160 perf_level);
1161#endif
1162
1163}
1164
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001165static int msm_rotator_start(unsigned long arg, int pid)
1166{
1167 struct msm_rotator_img_info info;
1168 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001169 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001171 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172
1173 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1174 return -EFAULT;
1175
1176 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1177 (info.src.height > MSM_ROTATOR_MAX_H) ||
1178 (info.src.width > MSM_ROTATOR_MAX_W) ||
1179 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1180 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001181 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1182 pr_err("%s: Invalid parameters\n", __func__);
1183 return -EINVAL;
1184 }
1185
1186 if (info.rotations & MDP_ROT_90) {
1187 dst_w = info.src_rect.h >> info.downscale_ratio;
1188 dst_h = info.src_rect.w >> info.downscale_ratio;
1189 } else {
1190 dst_w = info.src_rect.w >> info.downscale_ratio;
1191 dst_h = info.src_rect.h >> info.downscale_ratio;
1192 }
1193
1194 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001195 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1196 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001197 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1198 pr_err("%s: Invalid src or dst rect\n", __func__);
1199 return -ERANGE;
1200 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201
1202 switch (info.src.format) {
1203 case MDP_RGB_565:
1204 case MDP_BGR_565:
1205 case MDP_RGB_888:
1206 case MDP_ARGB_8888:
1207 case MDP_RGBA_8888:
1208 case MDP_XRGB_8888:
1209 case MDP_RGBX_8888:
1210 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001211 is_rgb = 1;
1212 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001213 case MDP_Y_CBCR_H2V2:
1214 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001215 case MDP_Y_CB_CR_H2V2:
1216 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301217 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001218 case MDP_Y_CBCR_H2V1:
1219 case MDP_Y_CRCB_H2V1:
1220 case MDP_YCRYCB_H2V1:
1221 case MDP_Y_CRCB_H2V2_TILE:
1222 case MDP_Y_CBCR_H2V2_TILE:
1223 break;
1224 default:
1225 return -EINVAL;
1226 }
1227
1228 switch (info.dst.format) {
1229 case MDP_RGB_565:
1230 case MDP_BGR_565:
1231 case MDP_RGB_888:
1232 case MDP_ARGB_8888:
1233 case MDP_RGBA_8888:
1234 case MDP_XRGB_8888:
1235 case MDP_RGBX_8888:
1236 case MDP_BGRA_8888:
1237 case MDP_Y_CBCR_H2V2:
1238 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001239 case MDP_Y_CB_CR_H2V2:
1240 case MDP_Y_CR_CB_H2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 case MDP_Y_CBCR_H2V1:
1242 case MDP_Y_CRCB_H2V1:
1243 case MDP_YCRYCB_H2V1:
1244 break;
1245 default:
1246 return -EINVAL;
1247 }
1248
1249 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001250
1251 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1252
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253 for (s = 0; s < MAX_SESSIONS; s++) {
1254 if ((msm_rotator_dev->img_info[s] != NULL) &&
1255 (info.session_id ==
1256 (unsigned int)msm_rotator_dev->img_info[s]
1257 )) {
1258 *(msm_rotator_dev->img_info[s]) = info;
1259 msm_rotator_dev->pid_list[s] = pid;
1260
1261 if (msm_rotator_dev->last_session_idx == s)
1262 msm_rotator_dev->last_session_idx =
1263 INVALID_SESSION;
1264 break;
1265 }
1266
1267 if ((msm_rotator_dev->img_info[s] == NULL) &&
1268 (first_free_index ==
1269 INVALID_SESSION))
1270 first_free_index = s;
1271 }
1272
1273 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1274 /* allocate a session id */
1275 msm_rotator_dev->img_info[first_free_index] =
1276 kzalloc(sizeof(struct msm_rotator_img_info),
1277 GFP_KERNEL);
1278 if (!msm_rotator_dev->img_info[first_free_index]) {
1279 printk(KERN_ERR "%s : unable to alloc mem\n",
1280 __func__);
1281 rc = -ENOMEM;
1282 goto rotator_start_exit;
1283 }
1284 info.session_id = (unsigned int)
1285 msm_rotator_dev->img_info[first_free_index];
1286 *(msm_rotator_dev->img_info[first_free_index]) = info;
1287 msm_rotator_dev->pid_list[first_free_index] = pid;
1288
1289 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1290 rc = -EFAULT;
1291 } else if (s == MAX_SESSIONS) {
1292 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1293 __func__);
1294 rc = -EBUSY;
1295 }
1296
1297rotator_start_exit:
1298 mutex_unlock(&msm_rotator_dev->rotator_lock);
1299
1300 return rc;
1301}
1302
1303static int msm_rotator_finish(unsigned long arg)
1304{
1305 int rc = 0;
1306 int s;
1307 unsigned int session_id;
1308
1309 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1310 return -EFAULT;
1311
1312 mutex_lock(&msm_rotator_dev->rotator_lock);
1313 for (s = 0; s < MAX_SESSIONS; s++) {
1314 if ((msm_rotator_dev->img_info[s] != NULL) &&
1315 (session_id ==
1316 (unsigned int)msm_rotator_dev->img_info[s])) {
1317 if (msm_rotator_dev->last_session_idx == s)
1318 msm_rotator_dev->last_session_idx =
1319 INVALID_SESSION;
1320 kfree(msm_rotator_dev->img_info[s]);
1321 msm_rotator_dev->img_info[s] = NULL;
1322 msm_rotator_dev->pid_list[s] = 0;
1323 break;
1324 }
1325 }
1326
1327 if (s == MAX_SESSIONS)
1328 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001329#ifdef CONFIG_MSM_BUS_SCALING
1330 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1331 0);
1332#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001333 mutex_unlock(&msm_rotator_dev->rotator_lock);
1334 return rc;
1335}
1336
1337static int
1338msm_rotator_open(struct inode *inode, struct file *filp)
1339{
1340 int *id;
1341 int i;
1342
1343 if (filp->private_data)
1344 return -EBUSY;
1345
1346 mutex_lock(&msm_rotator_dev->rotator_lock);
1347 id = &msm_rotator_dev->pid_list[0];
1348 for (i = 0; i < MAX_SESSIONS; i++, id++) {
1349 if (*id == 0)
1350 break;
1351 }
1352 mutex_unlock(&msm_rotator_dev->rotator_lock);
1353
1354 if (i == MAX_SESSIONS)
1355 return -EBUSY;
1356
kuogee hsieh7a46d592011-09-09 10:27:23 -07001357 filp->private_data = (void *)current->pid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358
1359 return 0;
1360}
1361
1362static int
1363msm_rotator_close(struct inode *inode, struct file *filp)
1364{
1365 int s;
1366 int pid;
1367
1368 pid = (int)filp->private_data;
1369 mutex_lock(&msm_rotator_dev->rotator_lock);
1370 for (s = 0; s < MAX_SESSIONS; s++) {
1371 if (msm_rotator_dev->img_info[s] != NULL &&
1372 msm_rotator_dev->pid_list[s] == pid) {
1373 kfree(msm_rotator_dev->img_info[s]);
1374 msm_rotator_dev->img_info[s] = NULL;
1375 if (msm_rotator_dev->last_session_idx == s)
1376 msm_rotator_dev->last_session_idx =
1377 INVALID_SESSION;
1378 }
1379 }
1380 mutex_unlock(&msm_rotator_dev->rotator_lock);
1381
1382 return 0;
1383}
1384
1385static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1386 unsigned long arg)
1387{
1388 int pid;
1389
1390 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1391 return -ENOTTY;
1392
1393 pid = (int)file->private_data;
1394
1395 switch (cmd) {
1396 case MSM_ROTATOR_IOCTL_START:
1397 return msm_rotator_start(arg, pid);
1398 case MSM_ROTATOR_IOCTL_ROTATE:
1399 return msm_rotator_do_rotate(arg);
1400 case MSM_ROTATOR_IOCTL_FINISH:
1401 return msm_rotator_finish(arg);
1402
1403 default:
1404 dev_dbg(msm_rotator_dev->device,
1405 "unexpected IOCTL %d\n", cmd);
1406 return -ENOTTY;
1407 }
1408}
1409
1410static const struct file_operations msm_rotator_fops = {
1411 .owner = THIS_MODULE,
1412 .open = msm_rotator_open,
1413 .release = msm_rotator_close,
1414 .unlocked_ioctl = msm_rotator_ioctl,
1415};
1416
1417static int __devinit msm_rotator_probe(struct platform_device *pdev)
1418{
1419 int rc = 0;
1420 struct resource *res;
1421 struct msm_rotator_platform_data *pdata = NULL;
1422 int i, number_of_clks;
1423 uint32_t ver;
1424
1425 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1426 if (!msm_rotator_dev) {
1427 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1428 __func__);
1429 return -ENOMEM;
1430 }
1431 for (i = 0; i < MAX_SESSIONS; i++)
1432 msm_rotator_dev->img_info[i] = NULL;
1433 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1434
1435 pdata = pdev->dev.platform_data;
1436 number_of_clks = pdata->number_of_clocks;
1437
1438 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1439 mutex_init(&msm_rotator_dev->imem_lock);
1440 msm_rotator_dev->imem_clk_state = CLK_DIS;
1441 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1442 msm_rotator_imem_clk_work_f);
1443 msm_rotator_dev->imem_clk = NULL;
1444 msm_rotator_dev->pdev = pdev;
1445
1446 msm_rotator_dev->core_clk = NULL;
1447 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001449#ifdef CONFIG_MSM_BUS_SCALING
1450 if (!msm_rotator_dev->bus_client_handle && pdata &&
1451 pdata->bus_scale_table) {
1452 msm_rotator_dev->bus_client_handle =
1453 msm_bus_scale_register_client(
1454 pdata->bus_scale_table);
1455 if (!msm_rotator_dev->bus_client_handle) {
1456 pr_err("%s not able to get bus scale handle\n",
1457 __func__);
1458 }
1459 }
1460#endif
1461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 for (i = 0; i < number_of_clks; i++) {
1463 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1464 msm_rotator_dev->imem_clk =
1465 clk_get(&msm_rotator_dev->pdev->dev,
1466 pdata->rotator_clks[i].clk_name);
1467 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1468 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1469 msm_rotator_dev->imem_clk = NULL;
1470 printk(KERN_ERR "%s: cannot get imem_clk "
1471 "rc=%d\n", DRIVER_NAME, rc);
1472 goto error_imem_clk;
1473 }
1474 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001475 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476 pdata->rotator_clks[i].clk_rate);
1477 }
1478 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1479 msm_rotator_dev->pclk =
1480 clk_get(&msm_rotator_dev->pdev->dev,
1481 pdata->rotator_clks[i].clk_name);
1482 if (IS_ERR(msm_rotator_dev->pclk)) {
1483 rc = PTR_ERR(msm_rotator_dev->pclk);
1484 msm_rotator_dev->pclk = NULL;
1485 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1486 DRIVER_NAME, rc);
1487 goto error_pclk;
1488 }
1489
1490 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001491 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 pdata->rotator_clks[i].clk_rate);
1493 }
1494
1495 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1496 msm_rotator_dev->core_clk =
1497 clk_get(&msm_rotator_dev->pdev->dev,
1498 pdata->rotator_clks[i].clk_name);
1499 if (IS_ERR(msm_rotator_dev->core_clk)) {
1500 rc = PTR_ERR(msm_rotator_dev->core_clk);
1501 msm_rotator_dev->core_clk = NULL;
1502 printk(KERN_ERR "%s: cannot get core clk "
1503 "rc=%d\n", DRIVER_NAME, rc);
1504 goto error_core_clk;
1505 }
1506
1507 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001508 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 pdata->rotator_clks[i].clk_rate);
1510 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001511 }
1512
1513 msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
1514 if (IS_ERR(msm_rotator_dev->regulator))
1515 msm_rotator_dev->regulator = NULL;
1516
1517 msm_rotator_dev->rot_clk_state = CLK_DIS;
1518 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1519 msm_rotator_rot_clk_work_f);
1520
1521 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001522#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1523 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1524#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525 platform_set_drvdata(pdev, msm_rotator_dev);
1526
1527
1528 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1529 if (!res) {
1530 printk(KERN_ALERT
1531 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1532 rc = -ENODEV;
1533 goto error_get_resource;
1534 }
1535 msm_rotator_dev->io_base = ioremap(res->start,
1536 resource_size(res));
1537
1538#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1539 if (msm_rotator_dev->imem_clk)
1540 clk_enable(msm_rotator_dev->imem_clk);
1541#endif
1542 enable_rot_clks();
1543 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1544 disable_rot_clks();
1545
1546#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1547 if (msm_rotator_dev->imem_clk)
1548 clk_disable(msm_rotator_dev->imem_clk);
1549#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001550 if (ver != pdata->hardware_version_number)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001551 pr_info("%s: invalid HW version ver 0x%x\n",
1552 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001554 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1555 if (msm_rotator_dev->irq < 0) {
1556 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1557 DRIVER_NAME);
1558 rc = -ENODEV;
1559 goto error_get_irq;
1560 }
1561 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1562 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1563 if (rc) {
1564 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1565 goto error_get_irq;
1566 }
1567 /* we enable the IRQ when we need it in the ioctl */
1568 disable_irq(msm_rotator_dev->irq);
1569
1570 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1571 if (rc < 0) {
1572 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1573 __func__, rc);
1574 goto error_get_irq;
1575 }
1576
1577 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1578 if (IS_ERR(msm_rotator_dev->class)) {
1579 rc = PTR_ERR(msm_rotator_dev->class);
1580 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1581 DRIVER_NAME, rc);
1582 goto error_class_create;
1583 }
1584
1585 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1586 msm_rotator_dev->dev_num, NULL,
1587 DRIVER_NAME);
1588 if (IS_ERR(msm_rotator_dev->device)) {
1589 rc = PTR_ERR(msm_rotator_dev->device);
1590 printk(KERN_ERR "%s: device_create failed %d\n",
1591 DRIVER_NAME, rc);
1592 goto error_class_device_create;
1593 }
1594
1595 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1596 rc = cdev_add(&msm_rotator_dev->cdev,
1597 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1598 1);
1599 if (rc < 0) {
1600 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1601 goto error_cdev_add;
1602 }
1603
1604 init_waitqueue_head(&msm_rotator_dev->wq);
1605
1606 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1607 return rc;
1608
1609error_cdev_add:
1610 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1611error_class_device_create:
1612 class_destroy(msm_rotator_dev->class);
1613error_class_create:
1614 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1615error_get_irq:
1616 iounmap(msm_rotator_dev->io_base);
1617error_get_resource:
1618 mutex_destroy(&msm_rotator_dev->rotator_lock);
1619 if (msm_rotator_dev->regulator)
1620 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621 clk_put(msm_rotator_dev->core_clk);
1622error_core_clk:
1623 clk_put(msm_rotator_dev->pclk);
1624error_pclk:
1625 if (msm_rotator_dev->imem_clk)
1626 clk_put(msm_rotator_dev->imem_clk);
1627error_imem_clk:
1628 mutex_destroy(&msm_rotator_dev->imem_lock);
1629 kfree(msm_rotator_dev);
1630 return rc;
1631}
1632
1633static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1634{
1635 int i;
1636
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001637#ifdef CONFIG_MSM_BUS_SCALING
1638 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1639#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640 free_irq(msm_rotator_dev->irq, NULL);
1641 mutex_destroy(&msm_rotator_dev->rotator_lock);
1642 cdev_del(&msm_rotator_dev->cdev);
1643 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1644 class_destroy(msm_rotator_dev->class);
1645 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1646 iounmap(msm_rotator_dev->io_base);
1647 if (msm_rotator_dev->imem_clk) {
1648 if (msm_rotator_dev->imem_clk_state == CLK_EN)
1649 clk_disable(msm_rotator_dev->imem_clk);
1650 clk_put(msm_rotator_dev->imem_clk);
1651 msm_rotator_dev->imem_clk = NULL;
1652 }
1653 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1654 disable_rot_clks();
1655 clk_put(msm_rotator_dev->core_clk);
1656 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 if (msm_rotator_dev->regulator)
1658 regulator_put(msm_rotator_dev->regulator);
1659 msm_rotator_dev->core_clk = NULL;
1660 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001661 mutex_destroy(&msm_rotator_dev->imem_lock);
1662 for (i = 0; i < MAX_SESSIONS; i++)
1663 if (msm_rotator_dev->img_info[i] != NULL)
1664 kfree(msm_rotator_dev->img_info[i]);
1665 kfree(msm_rotator_dev);
1666 return 0;
1667}
1668
1669#ifdef CONFIG_PM
1670static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1671{
1672 mutex_lock(&msm_rotator_dev->imem_lock);
1673 if (msm_rotator_dev->imem_clk_state == CLK_EN
1674 && msm_rotator_dev->imem_clk) {
1675 clk_disable(msm_rotator_dev->imem_clk);
1676 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1677 }
1678 mutex_unlock(&msm_rotator_dev->imem_lock);
1679 mutex_lock(&msm_rotator_dev->rotator_lock);
1680 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1681 disable_rot_clks();
1682 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1683 }
1684 mutex_unlock(&msm_rotator_dev->rotator_lock);
1685 return 0;
1686}
1687
1688static int msm_rotator_resume(struct platform_device *dev)
1689{
1690 mutex_lock(&msm_rotator_dev->imem_lock);
1691 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1692 && msm_rotator_dev->imem_clk) {
1693 clk_enable(msm_rotator_dev->imem_clk);
1694 msm_rotator_dev->imem_clk_state = CLK_EN;
1695 }
1696 mutex_unlock(&msm_rotator_dev->imem_lock);
1697 mutex_lock(&msm_rotator_dev->rotator_lock);
1698 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1699 enable_rot_clks();
1700 msm_rotator_dev->rot_clk_state = CLK_EN;
1701 }
1702 mutex_unlock(&msm_rotator_dev->rotator_lock);
1703 return 0;
1704}
1705#endif
1706
1707static struct platform_driver msm_rotator_platform_driver = {
1708 .probe = msm_rotator_probe,
1709 .remove = __devexit_p(msm_rotator_remove),
1710#ifdef CONFIG_PM
1711 .suspend = msm_rotator_suspend,
1712 .resume = msm_rotator_resume,
1713#endif
1714 .driver = {
1715 .owner = THIS_MODULE,
1716 .name = DRIVER_NAME
1717 }
1718};
1719
1720static int __init msm_rotator_init(void)
1721{
1722 return platform_driver_register(&msm_rotator_platform_driver);
1723}
1724
1725static void __exit msm_rotator_exit(void)
1726{
1727 return platform_driver_unregister(&msm_rotator_platform_driver);
1728}
1729
1730module_init(msm_rotator_init);
1731module_exit(msm_rotator_exit);
1732
1733MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1734MODULE_VERSION("1.0");
1735MODULE_LICENSE("GPL v2");