blob: 555e4fa44f447877916417040edc904ac56c7b32 [file] [log] [blame]
Nagamalleswararao Ganjibcdea002011-09-13 15:43:47 -07001/* Copyright (c) 2009-2011, 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>
22#include <mach/clk.h>
23#include <linux/android_pmem.h>
24#include <linux/msm_rotator.h>
25#include <linux/io.h>
26#include <mach/msm_rotator_imem.h>
27#include <linux/ktime.h>
28#include <linux/workqueue.h>
29#include <linux/file.h>
30#include <linux/major.h>
31#include <linux/regulator/consumer.h>
32
33#define DRIVER_NAME "msm_rotator"
34
35#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
36#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
37#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
38#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
39#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
40#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
41#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
42#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
43#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
44#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070045#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070046#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
47#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
48#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
49#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
50#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
51#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
52#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
53#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070054#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070055#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
56#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
57#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
58#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
59
60#define MSM_ROTATOR_MAX_ROT 0x07
61#define MSM_ROTATOR_MAX_H 0x1fff
62#define MSM_ROTATOR_MAX_W 0x1fff
63
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +053064#define IS_NONPLANAR 0x0
65#define IS_PLANAR 0x1
66#define IS_PLANAR_16ALIGNED 0x2
67
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070068/* from lsb to msb */
69#define GET_PACK_PATTERN(a, x, y, z, bit) \
70 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
71#define CLR_G 0x0
72#define CLR_B 0x1
73#define CLR_R 0x2
74#define CLR_ALPHA 0x3
75
76#define CLR_Y CLR_G
77#define CLR_CB CLR_B
78#define CLR_CR CLR_R
79
80#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
81 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
82 (((r) & MDP_FLIP_UD) ? 4 : 0))
83
84#define IMEM_NO_OWNER -1;
85
86#define MAX_SESSIONS 16
87#define INVALID_SESSION -1
88#define VERSION_KEY_MASK 0xFFFFFF00
89
90struct tile_parm {
91 unsigned int width; /* tile's width */
92 unsigned int height; /* tile's height */
93 unsigned int row_tile_w; /* tiles per row's width */
94 unsigned int row_tile_h; /* tiles per row's height */
95};
96
97struct msm_rotator_dev {
98 void __iomem *io_base;
99 int irq;
100 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
101 struct clk *core_clk;
102 int pid_list[MAX_SESSIONS];
103 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700104 int rot_clk_state;
105 struct regulator *regulator;
106 struct delayed_work rot_clk_work;
107 struct clk *imem_clk;
108 int imem_clk_state;
109 struct delayed_work imem_clk_work;
110 struct platform_device *pdev;
111 struct cdev cdev;
112 struct device *device;
113 struct class *class;
114 dev_t dev_num;
115 int processing;
116 int last_session_idx;
117 struct mutex rotator_lock;
118 struct mutex imem_lock;
119 int imem_owner;
120 wait_queue_head_t wq;
121};
122
123#define chroma_addr(start, w, h, bpp) ((start) + ((h) * (w) * (bpp)))
124
125#define COMPONENT_5BITS 1
126#define COMPONENT_6BITS 2
127#define COMPONENT_8BITS 3
128
129static struct msm_rotator_dev *msm_rotator_dev;
130
131enum {
132 CLK_EN,
133 CLK_DIS,
134 CLK_SUSPEND,
135};
136
137int msm_rotator_imem_allocate(int requestor)
138{
139 int rc = 0;
140
141#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
142 switch (requestor) {
143 case ROTATOR_REQUEST:
144 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
145 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
146 rc = 1;
147 } else
148 rc = 0;
149 break;
150 case JPEG_REQUEST:
151 mutex_lock(&msm_rotator_dev->imem_lock);
152 msm_rotator_dev->imem_owner = JPEG_REQUEST;
153 rc = 1;
154 break;
155 default:
156 rc = 0;
157 }
158#else
159 if (requestor == JPEG_REQUEST)
160 rc = 1;
161#endif
162 if (rc == 1) {
163 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
164 if (msm_rotator_dev->imem_clk_state != CLK_EN
165 && msm_rotator_dev->imem_clk) {
166 clk_enable(msm_rotator_dev->imem_clk);
167 msm_rotator_dev->imem_clk_state = CLK_EN;
168 }
169 }
170
171 return rc;
172}
173EXPORT_SYMBOL(msm_rotator_imem_allocate);
174
175void msm_rotator_imem_free(int requestor)
176{
177#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
178 if (msm_rotator_dev->imem_owner == requestor) {
179 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
180 mutex_unlock(&msm_rotator_dev->imem_lock);
181 }
182#else
183 if (requestor == JPEG_REQUEST)
184 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
185#endif
186}
187EXPORT_SYMBOL(msm_rotator_imem_free);
188
189static void msm_rotator_imem_clk_work_f(struct work_struct *work)
190{
191#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
192 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
193 if (msm_rotator_dev->imem_clk_state == CLK_EN
194 && msm_rotator_dev->imem_clk) {
195 clk_disable(msm_rotator_dev->imem_clk);
196 msm_rotator_dev->imem_clk_state = CLK_DIS;
197 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
198 msm_rotator_dev->imem_clk_state = CLK_DIS;
199 mutex_unlock(&msm_rotator_dev->imem_lock);
200 }
201#endif
202}
203
204/* enable clocks needed by rotator block */
205static void enable_rot_clks(void)
206{
207 if (msm_rotator_dev->regulator)
208 regulator_enable(msm_rotator_dev->regulator);
209 if (msm_rotator_dev->core_clk != NULL)
210 clk_enable(msm_rotator_dev->core_clk);
211 if (msm_rotator_dev->pclk != NULL)
212 clk_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213}
214
215/* disable clocks needed by rotator block */
216static void disable_rot_clks(void)
217{
218 if (msm_rotator_dev->core_clk != NULL)
219 clk_disable(msm_rotator_dev->core_clk);
220 if (msm_rotator_dev->pclk != NULL)
221 clk_disable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700222 if (msm_rotator_dev->regulator)
223 regulator_disable(msm_rotator_dev->regulator);
224}
225
226static void msm_rotator_rot_clk_work_f(struct work_struct *work)
227{
228 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
229 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
230 disable_rot_clks();
231 msm_rotator_dev->rot_clk_state = CLK_DIS;
232 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
233 msm_rotator_dev->rot_clk_state = CLK_DIS;
234 mutex_unlock(&msm_rotator_dev->rotator_lock);
235 }
236}
237
238static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
239{
240 if (msm_rotator_dev->processing) {
241 msm_rotator_dev->processing = 0;
242 wake_up(&msm_rotator_dev->wq);
243 } else
244 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
245
246 return IRQ_HANDLED;
247}
248
249static int get_bpp(int format)
250{
251 switch (format) {
252 case MDP_RGB_565:
253 case MDP_BGR_565:
254 return 2;
255
256 case MDP_XRGB_8888:
257 case MDP_ARGB_8888:
258 case MDP_RGBA_8888:
259 case MDP_BGRA_8888:
260 case MDP_RGBX_8888:
261 return 4;
262
263 case MDP_Y_CBCR_H2V2:
264 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700265 case MDP_Y_CB_CR_H2V2:
266 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530267 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 case MDP_Y_CRCB_H2V2_TILE:
269 case MDP_Y_CBCR_H2V2_TILE:
270 return 1;
271
272 case MDP_RGB_888:
273 return 3;
274
275 case MDP_YCRYCB_H2V1:
276 return 2;/* YCrYCb interleave */
277
278 case MDP_Y_CRCB_H2V1:
279 case MDP_Y_CBCR_H2V1:
280 return 1;
281
282 default:
283 return -1;
284 }
285
286}
287
288static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
289 unsigned int in_paddr,
290 unsigned int out_paddr,
291 unsigned int use_imem,
292 int new_session,
293 unsigned int in_chroma_paddr,
294 unsigned int out_chroma_paddr)
295{
296 int bpp;
297 unsigned int in_chr_addr, out_chr_addr;
298
299 if (info->src.format != info->dst.format)
300 return -EINVAL;
301
302 bpp = get_bpp(info->src.format);
303 if (bpp < 0)
304 return -ENOTTY;
305
306 if (!in_chroma_paddr) {
307 in_chr_addr = chroma_addr(in_paddr, info->src.width,
308 info->src.height,
309 bpp);
310 } else
311 in_chr_addr = in_chroma_paddr;
312
313 if (!out_chroma_paddr) {
314 out_chr_addr = chroma_addr(out_paddr, info->dst.width,
315 info->dst.height,
316 bpp);
317 } else
318 out_chr_addr = out_chroma_paddr;
319
320 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
321
322 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
323 iowrite32(in_chr_addr, MSM_ROTATOR_SRCP1_ADDR);
324 iowrite32(out_paddr +
325 ((info->dst_y * info->dst.width) + info->dst_x),
326 MSM_ROTATOR_OUTP0_ADDR);
327 iowrite32(out_chr_addr +
328 ((info->dst_y * info->dst.width) + info->dst_x),
329 MSM_ROTATOR_OUTP1_ADDR);
330
331 if (new_session) {
332 iowrite32(info->src.width |
333 info->src.width << 16,
334 MSM_ROTATOR_SRC_YSTRIDE1);
335 if (info->rotations & MDP_ROT_90)
336 iowrite32(info->dst.width |
337 info->dst.width*2 << 16,
338 MSM_ROTATOR_OUT_YSTRIDE1);
339 else
340 iowrite32(info->dst.width |
341 info->dst.width << 16,
342 MSM_ROTATOR_OUT_YSTRIDE1);
343 if (info->src.format == MDP_Y_CBCR_H2V1) {
344 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
345 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
346 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
347 MSM_ROTATOR_OUT_PACK_PATTERN1);
348 } else {
349 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
350 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
351 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
352 MSM_ROTATOR_OUT_PACK_PATTERN1);
353 }
354 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
355 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
356 1 << 8, /* ROT_EN */
357 MSM_ROTATOR_SUB_BLOCK_CFG);
358 iowrite32(0 << 29 | /* frame format 0 = linear */
359 (use_imem ? 0 : 1) << 22 | /* tile size */
360 2 << 19 | /* fetch planes 2 = pseudo */
361 0 << 18 | /* unpack align */
362 1 << 17 | /* unpack tight */
363 1 << 13 | /* unpack count 0=1 component */
364 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
365 0 << 8 | /* has alpha */
366 0 << 6 | /* alpha bits 3=8bits */
367 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
368 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
369 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
370 MSM_ROTATOR_SRC_FORMAT);
371 }
372
373 return 0;
374}
375
376static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
377 unsigned int in_paddr,
378 unsigned int out_paddr,
379 unsigned int use_imem,
380 int new_session,
381 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700382 unsigned int out_chroma_paddr,
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530383 int planar_mode)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700384{
385 int bpp;
386 unsigned int in_chr_addr, out_chr_addr;
387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388 bpp = get_bpp(info->src.format);
389 if (bpp < 0)
390 return -ENOTTY;
391
392 if (!in_chroma_paddr) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530393 if (planar_mode & IS_PLANAR_16ALIGNED)
394 in_chr_addr = chroma_addr(in_paddr,
395 ALIGN(info->src.width, 16),
396 info->src.height,
397 bpp);
398 else
399 in_chr_addr = chroma_addr(in_paddr, info->src.width,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700400 info->src.height,
401 bpp);
402 } else
403 in_chr_addr = in_chroma_paddr;
404
405 if (!out_chroma_paddr) {
406 out_chr_addr = chroma_addr(out_paddr, info->dst.width,
407 info->dst.height,
408 bpp);
409 } else
410 out_chr_addr = out_chroma_paddr;
411
412 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
413 iowrite32(in_chr_addr,
414 MSM_ROTATOR_SRCP1_ADDR);
415 iowrite32(out_paddr +
416 ((info->dst_y * info->dst.width) + info->dst_x),
417 MSM_ROTATOR_OUTP0_ADDR);
418 iowrite32(out_chr_addr +
419 ((info->dst_y * info->dst.width)/2 + info->dst_x),
420 MSM_ROTATOR_OUTP1_ADDR);
421
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530422 if (planar_mode & IS_PLANAR) {
423 if (planar_mode & IS_PLANAR_16ALIGNED)
424 iowrite32(in_chr_addr +
425 ALIGN((info->src.width / 2), 16) *
426 (info->src.height / 2),
427 MSM_ROTATOR_SRCP2_ADDR);
428 else
429 iowrite32(in_chr_addr +
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700430 (info->src.width / 2) * (info->src.height / 2),
431 MSM_ROTATOR_SRCP2_ADDR);
432 }
433
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700434 if (new_session) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530435 if (planar_mode & IS_PLANAR) {
436 if (planar_mode & IS_PLANAR_16ALIGNED) {
437 iowrite32(ALIGN(info->src.width, 16) |
438 ALIGN((info->src.width / 2), 16) << 16,
439 MSM_ROTATOR_SRC_YSTRIDE1);
440 iowrite32(ALIGN((info->src.width / 2), 16),
441 MSM_ROTATOR_SRC_YSTRIDE2);
442 } else {
443 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700444 (info->src.width / 2) << 16,
445 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530446 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700447 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530448 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700449 } else {
450 iowrite32(info->src.width |
451 info->src.width << 16,
452 MSM_ROTATOR_SRC_YSTRIDE1);
453 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700455 info->dst.width << 16,
456 MSM_ROTATOR_OUT_YSTRIDE1);
457
458 if ((info->src.format == MDP_Y_CBCR_H2V2) ||
459 (info->src.format == MDP_Y_CB_CR_H2V2)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
461 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
462 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
463 MSM_ROTATOR_OUT_PACK_PATTERN1);
464 } else {
465 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
466 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
467 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
468 MSM_ROTATOR_OUT_PACK_PATTERN1);
469 }
470 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
471 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
472 1 << 8, /* ROT_EN */
473 MSM_ROTATOR_SUB_BLOCK_CFG);
474 iowrite32(0 << 29 | /* frame format 0 = linear */
475 (use_imem ? 0 : 1) << 22 | /* tile size */
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530476 ((planar_mode & IS_PLANAR) ?
477 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 0 << 18 | /* unpack align */
479 1 << 17 | /* unpack tight */
480 1 << 13 | /* unpack count 0=1 component */
481 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
482 0 << 8 | /* has alpha */
483 0 << 6 | /* alpha bits 3=8bits */
484 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
485 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
486 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
487 MSM_ROTATOR_SRC_FORMAT);
488 }
489 return 0;
490}
491
492static unsigned int tile_size(unsigned int src_width,
493 unsigned int src_height,
494 const struct tile_parm *tp)
495{
496 unsigned int tile_w, tile_h;
497 unsigned int row_num_w, row_num_h;
498 tile_w = tp->width * tp->row_tile_w;
499 tile_h = tp->height * tp->row_tile_h;
500 row_num_w = (src_width + tile_w - 1) / tile_w;
501 row_num_h = (src_height + tile_h - 1) / tile_h;
502 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
503}
504
505static int msm_rotator_ycxcx_h2v2_tile(struct msm_rotator_img_info *info,
506 unsigned int in_paddr,
507 unsigned int out_paddr,
508 unsigned int use_imem,
509 int new_session,
510 unsigned in_chroma_paddr,
511 unsigned out_chroma_paddr)
512{
513 int bpp;
514 unsigned int offset = 0;
515 unsigned int in_chr_addr, out_chr_addr;
516 /*
517 * each row of samsung tile consists of two tiles in height
518 * and two tiles in width which means width should align to
519 * 64 x 2 bytes and height should align to 32 x 2 bytes.
520 * video decoder generate two tiles in width and one tile
521 * in height which ends up height align to 32 X 1 bytes.
522 */
523 const struct tile_parm tile = {64, 32, 2, 1};
524 if ((info->src.format == MDP_Y_CRCB_H2V2_TILE &&
525 info->dst.format != MDP_Y_CRCB_H2V2) ||
526 (info->src.format == MDP_Y_CBCR_H2V2_TILE &&
527 info->dst.format != MDP_Y_CBCR_H2V2))
528 return -EINVAL;
529
530 bpp = get_bpp(info->src.format);
531 if (bpp < 0)
532 return -ENOTTY;
533
534 offset = tile_size(info->src.width, info->src.height, &tile);
535 if (!in_chroma_paddr)
536 in_chr_addr = in_paddr + offset;
537 else
538 in_chr_addr = in_chroma_paddr;
539
540 if (!out_chroma_paddr) {
541 out_chr_addr = chroma_addr(out_paddr, info->dst.width,
542 info->dst.height,
543 bpp);
544 } else
545 out_chr_addr = out_chroma_paddr;
546
547 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
548 iowrite32(in_paddr + offset, MSM_ROTATOR_SRCP1_ADDR);
549 iowrite32(out_paddr +
550 ((info->dst_y * info->dst.width) + info->dst_x),
551 MSM_ROTATOR_OUTP0_ADDR);
552 iowrite32(out_chr_addr +
553 ((info->dst_y * info->dst.width)/2 + info->dst_x),
554 MSM_ROTATOR_OUTP1_ADDR);
555
556 if (new_session) {
557 iowrite32(info->src.width |
558 info->src.width << 16,
559 MSM_ROTATOR_SRC_YSTRIDE1);
560
561 iowrite32(info->dst.width |
562 info->dst.width << 16,
563 MSM_ROTATOR_OUT_YSTRIDE1);
564 if (info->src.format == MDP_Y_CBCR_H2V2_TILE) {
565 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
566 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
567 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
568 MSM_ROTATOR_OUT_PACK_PATTERN1);
569 } else {
570 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
571 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
572 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
573 MSM_ROTATOR_OUT_PACK_PATTERN1);
574 }
575 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
576 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
577 1 << 8, /* ROT_EN */
578 MSM_ROTATOR_SUB_BLOCK_CFG);
579 iowrite32(2 << 29 | /* frame format 2 = supertile */
580 (use_imem ? 0 : 1) << 22 | /* tile size */
581 2 << 19 | /* fetch planes 2 = pseudo */
582 0 << 18 | /* unpack align */
583 1 << 17 | /* unpack tight */
584 1 << 13 | /* unpack count 0=1 component */
585 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
586 0 << 8 | /* has alpha */
587 0 << 6 | /* alpha bits 3=8bits */
588 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
589 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
590 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
591 MSM_ROTATOR_SRC_FORMAT);
592 }
593 return 0;
594}
595
596static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
597 unsigned int in_paddr,
598 unsigned int out_paddr,
599 unsigned int use_imem,
600 int new_session)
601{
602 int bpp;
603
604 if (info->src.format != info->dst.format)
605 return -EINVAL;
606
607 bpp = get_bpp(info->src.format);
608 if (bpp < 0)
609 return -ENOTTY;
610
611 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
612 iowrite32(out_paddr +
613 ((info->dst_y * info->dst.width) + info->dst_x),
614 MSM_ROTATOR_OUTP0_ADDR);
615
616 if (new_session) {
617 iowrite32(info->src.width,
618 MSM_ROTATOR_SRC_YSTRIDE1);
619 iowrite32(info->dst.width,
620 MSM_ROTATOR_OUT_YSTRIDE1);
621 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
622 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
623 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
624 MSM_ROTATOR_OUT_PACK_PATTERN1);
625 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
626 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
627 1 << 8, /* ROT_EN */
628 MSM_ROTATOR_SUB_BLOCK_CFG);
629 iowrite32(0 << 29 | /* frame format 0 = linear */
630 (use_imem ? 0 : 1) << 22 | /* tile size */
631 0 << 19 | /* fetch planes 0=interleaved */
632 0 << 18 | /* unpack align */
633 1 << 17 | /* unpack tight */
634 3 << 13 | /* unpack count 0=1 component */
635 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
636 0 << 8 | /* has alpha */
637 0 << 6 | /* alpha bits 3=8bits */
638 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
639 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
640 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
641 MSM_ROTATOR_SRC_FORMAT);
642 }
643
644 return 0;
645}
646
647static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
648 unsigned int in_paddr,
649 unsigned int out_paddr,
650 unsigned int use_imem,
651 int new_session)
652{
653 int bpp, abits, rbits, gbits, bbits;
654
655 if (info->src.format != info->dst.format)
656 return -EINVAL;
657
658 bpp = get_bpp(info->src.format);
659 if (bpp < 0)
660 return -ENOTTY;
661
662 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
663 iowrite32(out_paddr +
664 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
665 MSM_ROTATOR_OUTP0_ADDR);
666
667 if (new_session) {
668 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
669 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
670 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
671 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
672 1 << 8, /* ROT_EN */
673 MSM_ROTATOR_SUB_BLOCK_CFG);
674 switch (info->src.format) {
675 case MDP_RGB_565:
676 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
677 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
678 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
679 MSM_ROTATOR_OUT_PACK_PATTERN1);
680 abits = 0;
681 rbits = COMPONENT_5BITS;
682 gbits = COMPONENT_6BITS;
683 bbits = COMPONENT_5BITS;
684 break;
685
686 case MDP_BGR_565:
687 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
688 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
689 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
690 MSM_ROTATOR_OUT_PACK_PATTERN1);
691 abits = 0;
692 rbits = COMPONENT_5BITS;
693 gbits = COMPONENT_6BITS;
694 bbits = COMPONENT_5BITS;
695 break;
696
697 case MDP_RGB_888:
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_8BITS;
704 gbits = COMPONENT_8BITS;
705 bbits = COMPONENT_8BITS;
706 break;
707
708 case MDP_ARGB_8888:
709 case MDP_RGBA_8888:
710 case MDP_XRGB_8888:
711 case MDP_RGBX_8888:
712 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
713 CLR_B, 8),
714 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
715 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
716 CLR_B, 8),
717 MSM_ROTATOR_OUT_PACK_PATTERN1);
718 abits = COMPONENT_8BITS;
719 rbits = COMPONENT_8BITS;
720 gbits = COMPONENT_8BITS;
721 bbits = COMPONENT_8BITS;
722 break;
723
724 case MDP_BGRA_8888:
725 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
726 CLR_R, 8),
727 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
728 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
729 CLR_R, 8),
730 MSM_ROTATOR_OUT_PACK_PATTERN1);
731 abits = COMPONENT_8BITS;
732 rbits = COMPONENT_8BITS;
733 gbits = COMPONENT_8BITS;
734 bbits = COMPONENT_8BITS;
735 break;
736
737 default:
738 return -EINVAL;
739 }
740 iowrite32(0 << 29 | /* frame format 0 = linear */
741 (use_imem ? 0 : 1) << 22 | /* tile size */
742 0 << 19 | /* fetch planes 0=interleaved */
743 0 << 18 | /* unpack align */
744 1 << 17 | /* unpack tight */
745 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
746 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
747 (abits ? 1 : 0) << 8 | /* has alpha */
748 abits << 6 | /* alpha bits 3=8bits */
749 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
750 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
751 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
752 MSM_ROTATOR_SRC_FORMAT);
753 }
754
755 return 0;
756}
757
758static int get_img(int memory_id, unsigned long *start, unsigned long *len,
759 struct file **pp_file)
760{
761 int ret = 0;
762#ifdef CONFIG_FB
763 struct file *file;
764 int put_needed, fb_num;
765#endif
766#ifdef CONFIG_ANDROID_PMEM
767 unsigned long vstart;
768#endif
769
770#ifdef CONFIG_ANDROID_PMEM
771 if (!get_pmem_file(memory_id, start, &vstart, len, pp_file))
772 return 0;
773#endif
774#ifdef CONFIG_FB
775 file = fget_light(memory_id, &put_needed);
776 if (file == NULL)
777 return -1;
778
779 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
780 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
781 if (get_fb_phys_info(start, len, fb_num))
782 ret = -1;
783 else
784 *pp_file = file;
785 } else
786 ret = -1;
787 if (ret)
788 fput_light(file, put_needed);
789#endif
790 return ret;
791}
792
793static int msm_rotator_do_rotate(unsigned long arg)
794{
795 int rc = 0;
796 unsigned int status;
797 struct msm_rotator_data_info info;
798 unsigned int in_paddr, out_paddr;
799 unsigned long len;
800 struct file *src_file = 0;
801 struct file *dst_file = 0;
802 int use_imem = 0;
803 int s;
804 struct file *src_chroma_file = 0;
805 struct file *dst_chroma_file = 0;
806 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
807 uint32_t format;
808
809 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
810 return -EFAULT;
811
812 rc = get_img(info.src.memory_id, (unsigned long *)&in_paddr,
813 (unsigned long *)&len, &src_file);
814 if (rc) {
815 printk(KERN_ERR "%s: in get_img() failed id=0x%08x\n",
816 DRIVER_NAME, info.src.memory_id);
817 return rc;
818 }
819 in_paddr += info.src.offset;
820
821 rc = get_img(info.dst.memory_id, (unsigned long *)&out_paddr,
822 (unsigned long *)&len, &dst_file);
823 if (rc) {
824 printk(KERN_ERR "%s: out get_img() failed id=0x%08x\n",
825 DRIVER_NAME, info.dst.memory_id);
826 goto do_rotate_fail_dst_img;
827 }
828 out_paddr += info.dst.offset;
829
830 mutex_lock(&msm_rotator_dev->rotator_lock);
831 for (s = 0; s < MAX_SESSIONS; s++)
832 if ((msm_rotator_dev->img_info[s] != NULL) &&
833 (info.session_id ==
834 (unsigned int)msm_rotator_dev->img_info[s]
835 ))
836 break;
837
838 if (s == MAX_SESSIONS) {
839 dev_dbg(msm_rotator_dev->device,
840 "%s() : Attempt to use invalid session_id %d\n",
841 __func__, s);
842 rc = -EINVAL;
843 goto do_rotate_unlock_mutex;
844 }
845
846 if (msm_rotator_dev->img_info[s]->enable == 0) {
847 dev_dbg(msm_rotator_dev->device,
848 "%s() : Session_id %d not enabled \n",
849 __func__, s);
850 rc = -EINVAL;
851 goto do_rotate_unlock_mutex;
852 }
853
854 format = msm_rotator_dev->img_info[s]->src.format;
855 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
856 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
857 (format == MDP_Y_CBCR_H2V2 ||
858 format == MDP_Y_CRCB_H2V2 ||
859 format == MDP_Y_CRCB_H2V2_TILE ||
860 format == MDP_Y_CBCR_H2V2_TILE ||
861 format == MDP_Y_CBCR_H2V1 ||
862 format == MDP_Y_CRCB_H2V1)) {
863 rc = get_img(info.src_chroma.memory_id,
864 (unsigned long *)&in_chroma_paddr,
865 (unsigned long *)&len, &src_chroma_file);
866 if (rc) {
867 printk(KERN_ERR "%s: in chroma get_img() failed id=0x%08x\n",
868 DRIVER_NAME, info.src_chroma.memory_id);
869 goto do_rotate_unlock_mutex;
870 }
871 in_chroma_paddr += info.src_chroma.offset;
872
873 rc = get_img(info.dst_chroma.memory_id,
874 (unsigned long *)&out_chroma_paddr,
875 (unsigned long *)&len, &dst_chroma_file);
876 if (rc) {
877 printk(KERN_ERR "%s: out chroma get_img() failed id=0x%08x\n",
878 DRIVER_NAME, info.dst_chroma.memory_id);
879 goto do_rotate_fail_dst_chr_img;
880 }
881 out_chroma_paddr += info.dst_chroma.offset;
882 }
883
884 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
885 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
886 enable_rot_clks();
887 msm_rotator_dev->rot_clk_state = CLK_EN;
888 }
889 enable_irq(msm_rotator_dev->irq);
890
891#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
892 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
893#else
894 use_imem = 0;
895#endif
896 /*
897 * workaround for a hardware bug. rotator hardware hangs when we
898 * use write burst beat size 16 on 128X128 tile fetch mode. As a
899 * temporary fix use 0x42 for BURST_SIZE when imem used.
900 */
901 if (use_imem)
902 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
903
904 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
905 << 16) |
906 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
907 MSM_ROTATOR_SRC_SIZE);
908 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
909 << 16) |
910 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
911 MSM_ROTATOR_SRC_XY);
912 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
913 << 16) |
914 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
915 MSM_ROTATOR_SRC_IMAGE_SIZE);
916
917 switch (format) {
918 case MDP_RGB_565:
919 case MDP_BGR_565:
920 case MDP_RGB_888:
921 case MDP_ARGB_8888:
922 case MDP_RGBA_8888:
923 case MDP_XRGB_8888:
924 case MDP_BGRA_8888:
925 case MDP_RGBX_8888:
926 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
927 in_paddr, out_paddr,
928 use_imem,
929 msm_rotator_dev->last_session_idx
930 != s);
931 break;
932 case MDP_Y_CBCR_H2V2:
933 case MDP_Y_CRCB_H2V2:
934 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
935 in_paddr, out_paddr, use_imem,
936 msm_rotator_dev->last_session_idx
937 != s,
938 in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700939 out_chroma_paddr,
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530940 IS_NONPLANAR);
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700941 break;
942 case MDP_Y_CB_CR_H2V2:
943 case MDP_Y_CR_CB_H2V2:
944 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
945 in_paddr, out_paddr, use_imem,
946 msm_rotator_dev->last_session_idx
947 != s,
948 in_chroma_paddr,
949 out_chroma_paddr,
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530950 IS_PLANAR);
951 break;
952 case MDP_Y_CR_CB_GH2V2:
953 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
954 in_paddr, out_paddr, use_imem,
955 msm_rotator_dev->last_session_idx
956 != s,
957 in_chroma_paddr,
958 out_chroma_paddr,
959 IS_PLANAR | IS_PLANAR_16ALIGNED);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960 break;
961 case MDP_Y_CRCB_H2V2_TILE:
962 case MDP_Y_CBCR_H2V2_TILE:
963 rc = msm_rotator_ycxcx_h2v2_tile(msm_rotator_dev->img_info[s],
964 in_paddr, out_paddr, use_imem,
965 msm_rotator_dev->last_session_idx
966 != s,
967 in_chroma_paddr,
968 out_chroma_paddr);
969 break;
970
971 case MDP_Y_CBCR_H2V1:
972 case MDP_Y_CRCB_H2V1:
973 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
974 in_paddr, out_paddr, use_imem,
975 msm_rotator_dev->last_session_idx
976 != s,
977 in_chroma_paddr,
978 out_chroma_paddr);
979 break;
980 case MDP_YCRYCB_H2V1:
981 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
982 in_paddr, out_paddr, use_imem,
983 msm_rotator_dev->last_session_idx != s);
984 break;
985 default:
986 rc = -EINVAL;
987 goto do_rotate_exit;
988 }
989
990 if (rc != 0) {
991 msm_rotator_dev->last_session_idx = INVALID_SESSION;
992 goto do_rotate_exit;
993 }
994
995 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
996
997 msm_rotator_dev->processing = 1;
998 iowrite32(0x1, MSM_ROTATOR_START);
999
1000 wait_event(msm_rotator_dev->wq,
1001 (msm_rotator_dev->processing == 0));
1002 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
1003 if ((status & 0x03) != 0x01)
1004 rc = -EFAULT;
1005 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1006 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1007
1008do_rotate_exit:
1009 disable_irq(msm_rotator_dev->irq);
1010#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1011 msm_rotator_imem_free(ROTATOR_REQUEST);
1012#endif
1013 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
1014 if (dst_chroma_file)
1015 put_pmem_file(dst_chroma_file);
1016do_rotate_fail_dst_chr_img:
1017 if (src_chroma_file)
1018 put_pmem_file(src_chroma_file);
1019do_rotate_unlock_mutex:
1020 mutex_unlock(&msm_rotator_dev->rotator_lock);
1021 if (dst_file)
1022 put_pmem_file(dst_file);
1023do_rotate_fail_dst_img:
1024 if (src_file)
1025 put_pmem_file(src_file);
1026 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1027 __func__, rc);
1028 return rc;
1029}
1030
1031static int msm_rotator_start(unsigned long arg, int pid)
1032{
1033 struct msm_rotator_img_info info;
1034 int rc = 0;
1035 int s;
1036 int first_free_index = INVALID_SESSION;
1037
1038 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1039 return -EFAULT;
1040
1041 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1042 (info.src.height > MSM_ROTATOR_MAX_H) ||
1043 (info.src.width > MSM_ROTATOR_MAX_W) ||
1044 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1045 (info.dst.width > MSM_ROTATOR_MAX_W) ||
1046 ((info.src_rect.x + info.src_rect.w) > info.src.width) ||
1047 ((info.src_rect.y + info.src_rect.h) > info.src.height) ||
1048 ((info.rotations & MDP_ROT_90) &&
1049 ((info.dst_x + info.src_rect.h) > info.dst.width)) ||
1050 ((info.rotations & MDP_ROT_90) &&
1051 ((info.dst_y + info.src_rect.w) > info.dst.height)) ||
1052 (!(info.rotations & MDP_ROT_90) &&
1053 ((info.dst_x + info.src_rect.w) > info.dst.width)) ||
1054 (!(info.rotations & MDP_ROT_90) &&
1055 ((info.dst_y + info.src_rect.h) > info.dst.height)))
1056 return -EINVAL;
1057
1058 switch (info.src.format) {
1059 case MDP_RGB_565:
1060 case MDP_BGR_565:
1061 case MDP_RGB_888:
1062 case MDP_ARGB_8888:
1063 case MDP_RGBA_8888:
1064 case MDP_XRGB_8888:
1065 case MDP_RGBX_8888:
1066 case MDP_BGRA_8888:
1067 case MDP_Y_CBCR_H2V2:
1068 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001069 case MDP_Y_CB_CR_H2V2:
1070 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301071 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001072 case MDP_Y_CBCR_H2V1:
1073 case MDP_Y_CRCB_H2V1:
1074 case MDP_YCRYCB_H2V1:
1075 case MDP_Y_CRCB_H2V2_TILE:
1076 case MDP_Y_CBCR_H2V2_TILE:
1077 break;
1078 default:
1079 return -EINVAL;
1080 }
1081
1082 switch (info.dst.format) {
1083 case MDP_RGB_565:
1084 case MDP_BGR_565:
1085 case MDP_RGB_888:
1086 case MDP_ARGB_8888:
1087 case MDP_RGBA_8888:
1088 case MDP_XRGB_8888:
1089 case MDP_RGBX_8888:
1090 case MDP_BGRA_8888:
1091 case MDP_Y_CBCR_H2V2:
1092 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001093 case MDP_Y_CB_CR_H2V2:
1094 case MDP_Y_CR_CB_H2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001095 case MDP_Y_CBCR_H2V1:
1096 case MDP_Y_CRCB_H2V1:
1097 case MDP_YCRYCB_H2V1:
1098 break;
1099 default:
1100 return -EINVAL;
1101 }
1102
1103 mutex_lock(&msm_rotator_dev->rotator_lock);
1104 for (s = 0; s < MAX_SESSIONS; s++) {
1105 if ((msm_rotator_dev->img_info[s] != NULL) &&
1106 (info.session_id ==
1107 (unsigned int)msm_rotator_dev->img_info[s]
1108 )) {
1109 *(msm_rotator_dev->img_info[s]) = info;
1110 msm_rotator_dev->pid_list[s] = pid;
1111
1112 if (msm_rotator_dev->last_session_idx == s)
1113 msm_rotator_dev->last_session_idx =
1114 INVALID_SESSION;
1115 break;
1116 }
1117
1118 if ((msm_rotator_dev->img_info[s] == NULL) &&
1119 (first_free_index ==
1120 INVALID_SESSION))
1121 first_free_index = s;
1122 }
1123
1124 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1125 /* allocate a session id */
1126 msm_rotator_dev->img_info[first_free_index] =
1127 kzalloc(sizeof(struct msm_rotator_img_info),
1128 GFP_KERNEL);
1129 if (!msm_rotator_dev->img_info[first_free_index]) {
1130 printk(KERN_ERR "%s : unable to alloc mem\n",
1131 __func__);
1132 rc = -ENOMEM;
1133 goto rotator_start_exit;
1134 }
1135 info.session_id = (unsigned int)
1136 msm_rotator_dev->img_info[first_free_index];
1137 *(msm_rotator_dev->img_info[first_free_index]) = info;
1138 msm_rotator_dev->pid_list[first_free_index] = pid;
1139
1140 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1141 rc = -EFAULT;
1142 } else if (s == MAX_SESSIONS) {
1143 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1144 __func__);
1145 rc = -EBUSY;
1146 }
1147
1148rotator_start_exit:
1149 mutex_unlock(&msm_rotator_dev->rotator_lock);
1150
1151 return rc;
1152}
1153
1154static int msm_rotator_finish(unsigned long arg)
1155{
1156 int rc = 0;
1157 int s;
1158 unsigned int session_id;
1159
1160 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1161 return -EFAULT;
1162
1163 mutex_lock(&msm_rotator_dev->rotator_lock);
1164 for (s = 0; s < MAX_SESSIONS; s++) {
1165 if ((msm_rotator_dev->img_info[s] != NULL) &&
1166 (session_id ==
1167 (unsigned int)msm_rotator_dev->img_info[s])) {
1168 if (msm_rotator_dev->last_session_idx == s)
1169 msm_rotator_dev->last_session_idx =
1170 INVALID_SESSION;
1171 kfree(msm_rotator_dev->img_info[s]);
1172 msm_rotator_dev->img_info[s] = NULL;
1173 msm_rotator_dev->pid_list[s] = 0;
1174 break;
1175 }
1176 }
1177
1178 if (s == MAX_SESSIONS)
1179 rc = -EINVAL;
1180 mutex_unlock(&msm_rotator_dev->rotator_lock);
1181 return rc;
1182}
1183
1184static int
1185msm_rotator_open(struct inode *inode, struct file *filp)
1186{
1187 int *id;
1188 int i;
1189
1190 if (filp->private_data)
1191 return -EBUSY;
1192
1193 mutex_lock(&msm_rotator_dev->rotator_lock);
1194 id = &msm_rotator_dev->pid_list[0];
1195 for (i = 0; i < MAX_SESSIONS; i++, id++) {
1196 if (*id == 0)
1197 break;
1198 }
1199 mutex_unlock(&msm_rotator_dev->rotator_lock);
1200
1201 if (i == MAX_SESSIONS)
1202 return -EBUSY;
1203
kuogee hsieh7a46d592011-09-09 10:27:23 -07001204 filp->private_data = (void *)current->pid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001205
1206 return 0;
1207}
1208
1209static int
1210msm_rotator_close(struct inode *inode, struct file *filp)
1211{
1212 int s;
1213 int pid;
1214
1215 pid = (int)filp->private_data;
1216 mutex_lock(&msm_rotator_dev->rotator_lock);
1217 for (s = 0; s < MAX_SESSIONS; s++) {
1218 if (msm_rotator_dev->img_info[s] != NULL &&
1219 msm_rotator_dev->pid_list[s] == pid) {
1220 kfree(msm_rotator_dev->img_info[s]);
1221 msm_rotator_dev->img_info[s] = NULL;
1222 if (msm_rotator_dev->last_session_idx == s)
1223 msm_rotator_dev->last_session_idx =
1224 INVALID_SESSION;
1225 }
1226 }
1227 mutex_unlock(&msm_rotator_dev->rotator_lock);
1228
1229 return 0;
1230}
1231
1232static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1233 unsigned long arg)
1234{
1235 int pid;
1236
1237 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1238 return -ENOTTY;
1239
1240 pid = (int)file->private_data;
1241
1242 switch (cmd) {
1243 case MSM_ROTATOR_IOCTL_START:
1244 return msm_rotator_start(arg, pid);
1245 case MSM_ROTATOR_IOCTL_ROTATE:
1246 return msm_rotator_do_rotate(arg);
1247 case MSM_ROTATOR_IOCTL_FINISH:
1248 return msm_rotator_finish(arg);
1249
1250 default:
1251 dev_dbg(msm_rotator_dev->device,
1252 "unexpected IOCTL %d\n", cmd);
1253 return -ENOTTY;
1254 }
1255}
1256
1257static const struct file_operations msm_rotator_fops = {
1258 .owner = THIS_MODULE,
1259 .open = msm_rotator_open,
1260 .release = msm_rotator_close,
1261 .unlocked_ioctl = msm_rotator_ioctl,
1262};
1263
1264static int __devinit msm_rotator_probe(struct platform_device *pdev)
1265{
1266 int rc = 0;
1267 struct resource *res;
1268 struct msm_rotator_platform_data *pdata = NULL;
1269 int i, number_of_clks;
1270 uint32_t ver;
1271
1272 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1273 if (!msm_rotator_dev) {
1274 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1275 __func__);
1276 return -ENOMEM;
1277 }
1278 for (i = 0; i < MAX_SESSIONS; i++)
1279 msm_rotator_dev->img_info[i] = NULL;
1280 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1281
1282 pdata = pdev->dev.platform_data;
1283 number_of_clks = pdata->number_of_clocks;
1284
1285 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1286 mutex_init(&msm_rotator_dev->imem_lock);
1287 msm_rotator_dev->imem_clk_state = CLK_DIS;
1288 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1289 msm_rotator_imem_clk_work_f);
1290 msm_rotator_dev->imem_clk = NULL;
1291 msm_rotator_dev->pdev = pdev;
1292
1293 msm_rotator_dev->core_clk = NULL;
1294 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001295
1296 for (i = 0; i < number_of_clks; i++) {
1297 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1298 msm_rotator_dev->imem_clk =
1299 clk_get(&msm_rotator_dev->pdev->dev,
1300 pdata->rotator_clks[i].clk_name);
1301 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1302 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1303 msm_rotator_dev->imem_clk = NULL;
1304 printk(KERN_ERR "%s: cannot get imem_clk "
1305 "rc=%d\n", DRIVER_NAME, rc);
1306 goto error_imem_clk;
1307 }
1308 if (pdata->rotator_clks[i].clk_rate)
1309 clk_set_min_rate(msm_rotator_dev->imem_clk,
1310 pdata->rotator_clks[i].clk_rate);
1311 }
1312 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1313 msm_rotator_dev->pclk =
1314 clk_get(&msm_rotator_dev->pdev->dev,
1315 pdata->rotator_clks[i].clk_name);
1316 if (IS_ERR(msm_rotator_dev->pclk)) {
1317 rc = PTR_ERR(msm_rotator_dev->pclk);
1318 msm_rotator_dev->pclk = NULL;
1319 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1320 DRIVER_NAME, rc);
1321 goto error_pclk;
1322 }
1323
1324 if (pdata->rotator_clks[i].clk_rate)
1325 clk_set_min_rate(msm_rotator_dev->pclk,
1326 pdata->rotator_clks[i].clk_rate);
1327 }
1328
1329 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1330 msm_rotator_dev->core_clk =
1331 clk_get(&msm_rotator_dev->pdev->dev,
1332 pdata->rotator_clks[i].clk_name);
1333 if (IS_ERR(msm_rotator_dev->core_clk)) {
1334 rc = PTR_ERR(msm_rotator_dev->core_clk);
1335 msm_rotator_dev->core_clk = NULL;
1336 printk(KERN_ERR "%s: cannot get core clk "
1337 "rc=%d\n", DRIVER_NAME, rc);
1338 goto error_core_clk;
1339 }
1340
1341 if (pdata->rotator_clks[i].clk_rate)
1342 clk_set_min_rate(msm_rotator_dev->core_clk,
1343 pdata->rotator_clks[i].clk_rate);
1344 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001345 }
1346
1347 msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
1348 if (IS_ERR(msm_rotator_dev->regulator))
1349 msm_rotator_dev->regulator = NULL;
1350
1351 msm_rotator_dev->rot_clk_state = CLK_DIS;
1352 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1353 msm_rotator_rot_clk_work_f);
1354
1355 mutex_init(&msm_rotator_dev->rotator_lock);
1356
1357 platform_set_drvdata(pdev, msm_rotator_dev);
1358
1359
1360 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1361 if (!res) {
1362 printk(KERN_ALERT
1363 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1364 rc = -ENODEV;
1365 goto error_get_resource;
1366 }
1367 msm_rotator_dev->io_base = ioremap(res->start,
1368 resource_size(res));
1369
1370#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1371 if (msm_rotator_dev->imem_clk)
1372 clk_enable(msm_rotator_dev->imem_clk);
1373#endif
1374 enable_rot_clks();
1375 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1376 disable_rot_clks();
1377
1378#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1379 if (msm_rotator_dev->imem_clk)
1380 clk_disable(msm_rotator_dev->imem_clk);
1381#endif
1382 if (ver != pdata->hardware_version_number) {
Nagamalleswararao Ganjibcdea002011-09-13 15:43:47 -07001383 pr_info("%s: invalid HW version\n", DRIVER_NAME);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 }
1385 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1386 if (msm_rotator_dev->irq < 0) {
1387 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1388 DRIVER_NAME);
1389 rc = -ENODEV;
1390 goto error_get_irq;
1391 }
1392 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1393 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1394 if (rc) {
1395 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1396 goto error_get_irq;
1397 }
1398 /* we enable the IRQ when we need it in the ioctl */
1399 disable_irq(msm_rotator_dev->irq);
1400
1401 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1402 if (rc < 0) {
1403 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1404 __func__, rc);
1405 goto error_get_irq;
1406 }
1407
1408 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1409 if (IS_ERR(msm_rotator_dev->class)) {
1410 rc = PTR_ERR(msm_rotator_dev->class);
1411 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1412 DRIVER_NAME, rc);
1413 goto error_class_create;
1414 }
1415
1416 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1417 msm_rotator_dev->dev_num, NULL,
1418 DRIVER_NAME);
1419 if (IS_ERR(msm_rotator_dev->device)) {
1420 rc = PTR_ERR(msm_rotator_dev->device);
1421 printk(KERN_ERR "%s: device_create failed %d\n",
1422 DRIVER_NAME, rc);
1423 goto error_class_device_create;
1424 }
1425
1426 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1427 rc = cdev_add(&msm_rotator_dev->cdev,
1428 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1429 1);
1430 if (rc < 0) {
1431 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1432 goto error_cdev_add;
1433 }
1434
1435 init_waitqueue_head(&msm_rotator_dev->wq);
1436
1437 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1438 return rc;
1439
1440error_cdev_add:
1441 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1442error_class_device_create:
1443 class_destroy(msm_rotator_dev->class);
1444error_class_create:
1445 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1446error_get_irq:
1447 iounmap(msm_rotator_dev->io_base);
1448error_get_resource:
1449 mutex_destroy(&msm_rotator_dev->rotator_lock);
1450 if (msm_rotator_dev->regulator)
1451 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 clk_put(msm_rotator_dev->core_clk);
1453error_core_clk:
1454 clk_put(msm_rotator_dev->pclk);
1455error_pclk:
1456 if (msm_rotator_dev->imem_clk)
1457 clk_put(msm_rotator_dev->imem_clk);
1458error_imem_clk:
1459 mutex_destroy(&msm_rotator_dev->imem_lock);
1460 kfree(msm_rotator_dev);
1461 return rc;
1462}
1463
1464static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1465{
1466 int i;
1467
1468 free_irq(msm_rotator_dev->irq, NULL);
1469 mutex_destroy(&msm_rotator_dev->rotator_lock);
1470 cdev_del(&msm_rotator_dev->cdev);
1471 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1472 class_destroy(msm_rotator_dev->class);
1473 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1474 iounmap(msm_rotator_dev->io_base);
1475 if (msm_rotator_dev->imem_clk) {
1476 if (msm_rotator_dev->imem_clk_state == CLK_EN)
1477 clk_disable(msm_rotator_dev->imem_clk);
1478 clk_put(msm_rotator_dev->imem_clk);
1479 msm_rotator_dev->imem_clk = NULL;
1480 }
1481 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1482 disable_rot_clks();
1483 clk_put(msm_rotator_dev->core_clk);
1484 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 if (msm_rotator_dev->regulator)
1486 regulator_put(msm_rotator_dev->regulator);
1487 msm_rotator_dev->core_clk = NULL;
1488 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001489 mutex_destroy(&msm_rotator_dev->imem_lock);
1490 for (i = 0; i < MAX_SESSIONS; i++)
1491 if (msm_rotator_dev->img_info[i] != NULL)
1492 kfree(msm_rotator_dev->img_info[i]);
1493 kfree(msm_rotator_dev);
1494 return 0;
1495}
1496
1497#ifdef CONFIG_PM
1498static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1499{
1500 mutex_lock(&msm_rotator_dev->imem_lock);
1501 if (msm_rotator_dev->imem_clk_state == CLK_EN
1502 && msm_rotator_dev->imem_clk) {
1503 clk_disable(msm_rotator_dev->imem_clk);
1504 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1505 }
1506 mutex_unlock(&msm_rotator_dev->imem_lock);
1507 mutex_lock(&msm_rotator_dev->rotator_lock);
1508 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1509 disable_rot_clks();
1510 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1511 }
1512 mutex_unlock(&msm_rotator_dev->rotator_lock);
1513 return 0;
1514}
1515
1516static int msm_rotator_resume(struct platform_device *dev)
1517{
1518 mutex_lock(&msm_rotator_dev->imem_lock);
1519 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1520 && msm_rotator_dev->imem_clk) {
1521 clk_enable(msm_rotator_dev->imem_clk);
1522 msm_rotator_dev->imem_clk_state = CLK_EN;
1523 }
1524 mutex_unlock(&msm_rotator_dev->imem_lock);
1525 mutex_lock(&msm_rotator_dev->rotator_lock);
1526 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1527 enable_rot_clks();
1528 msm_rotator_dev->rot_clk_state = CLK_EN;
1529 }
1530 mutex_unlock(&msm_rotator_dev->rotator_lock);
1531 return 0;
1532}
1533#endif
1534
1535static struct platform_driver msm_rotator_platform_driver = {
1536 .probe = msm_rotator_probe,
1537 .remove = __devexit_p(msm_rotator_remove),
1538#ifdef CONFIG_PM
1539 .suspend = msm_rotator_suspend,
1540 .resume = msm_rotator_resume,
1541#endif
1542 .driver = {
1543 .owner = THIS_MODULE,
1544 .name = DRIVER_NAME
1545 }
1546};
1547
1548static int __init msm_rotator_init(void)
1549{
1550 return platform_driver_register(&msm_rotator_platform_driver);
1551}
1552
1553static void __exit msm_rotator_exit(void)
1554{
1555 return platform_driver_unregister(&msm_rotator_platform_driver);
1556}
1557
1558module_init(msm_rotator_init);
1559module_exit(msm_rotator_exit);
1560
1561MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1562MODULE_VERSION("1.0");
1563MODULE_LICENSE("GPL v2");