blob: 3d9c9d11d494325ab5d31bdba43a9d7f70715f70 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
37#define DRIVER_NAME "msm_rotator"
38
39#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
40#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
41#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
42#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
43#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
44#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
45#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
46#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
47#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
48#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070049#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070050#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
51#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
52#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
53#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
54#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
55#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
56#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
57#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070058#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070059#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
60#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
61#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
62#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
63
64#define MSM_ROTATOR_MAX_ROT 0x07
65#define MSM_ROTATOR_MAX_H 0x1fff
66#define MSM_ROTATOR_MAX_W 0x1fff
67
68/* 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
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070089#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070090
91struct tile_parm {
92 unsigned int width; /* tile's width */
93 unsigned int height; /* tile's height */
94 unsigned int row_tile_w; /* tiles per row's width */
95 unsigned int row_tile_h; /* tiles per row's height */
96};
97
Adrian Salido-Moreno88411862011-09-20 18:54:03 -070098struct msm_rotator_mem_planes {
99 unsigned int num_planes;
100 unsigned int plane_size[4];
101 unsigned int total_size;
102};
103
104#define checkoffset(offset, size, max_size) \
105 ((size) > (max_size) || (offset) > ((max_size) - (size)))
106
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107struct msm_rotator_dev {
108 void __iomem *io_base;
109 int irq;
110 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
111 struct clk *core_clk;
112 int pid_list[MAX_SESSIONS];
113 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700114 int rot_clk_state;
115 struct regulator *regulator;
116 struct delayed_work rot_clk_work;
117 struct clk *imem_clk;
118 int imem_clk_state;
119 struct delayed_work imem_clk_work;
120 struct platform_device *pdev;
121 struct cdev cdev;
122 struct device *device;
123 struct class *class;
124 dev_t dev_num;
125 int processing;
126 int last_session_idx;
127 struct mutex rotator_lock;
128 struct mutex imem_lock;
129 int imem_owner;
130 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700131 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800132 #ifdef CONFIG_MSM_BUS_SCALING
133 uint32_t bus_client_handle;
134 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700135};
136
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137#define COMPONENT_5BITS 1
138#define COMPONENT_6BITS 2
139#define COMPONENT_8BITS 3
140
141static struct msm_rotator_dev *msm_rotator_dev;
142
143enum {
144 CLK_EN,
145 CLK_DIS,
146 CLK_SUSPEND,
147};
148
149int msm_rotator_imem_allocate(int requestor)
150{
151 int rc = 0;
152
153#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
154 switch (requestor) {
155 case ROTATOR_REQUEST:
156 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
157 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
158 rc = 1;
159 } else
160 rc = 0;
161 break;
162 case JPEG_REQUEST:
163 mutex_lock(&msm_rotator_dev->imem_lock);
164 msm_rotator_dev->imem_owner = JPEG_REQUEST;
165 rc = 1;
166 break;
167 default:
168 rc = 0;
169 }
170#else
171 if (requestor == JPEG_REQUEST)
172 rc = 1;
173#endif
174 if (rc == 1) {
175 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
176 if (msm_rotator_dev->imem_clk_state != CLK_EN
177 && msm_rotator_dev->imem_clk) {
178 clk_enable(msm_rotator_dev->imem_clk);
179 msm_rotator_dev->imem_clk_state = CLK_EN;
180 }
181 }
182
183 return rc;
184}
185EXPORT_SYMBOL(msm_rotator_imem_allocate);
186
187void msm_rotator_imem_free(int requestor)
188{
189#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
190 if (msm_rotator_dev->imem_owner == requestor) {
191 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
192 mutex_unlock(&msm_rotator_dev->imem_lock);
193 }
194#else
195 if (requestor == JPEG_REQUEST)
196 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
197#endif
198}
199EXPORT_SYMBOL(msm_rotator_imem_free);
200
201static void msm_rotator_imem_clk_work_f(struct work_struct *work)
202{
203#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
204 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
205 if (msm_rotator_dev->imem_clk_state == CLK_EN
206 && msm_rotator_dev->imem_clk) {
207 clk_disable(msm_rotator_dev->imem_clk);
208 msm_rotator_dev->imem_clk_state = CLK_DIS;
209 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
210 msm_rotator_dev->imem_clk_state = CLK_DIS;
211 mutex_unlock(&msm_rotator_dev->imem_lock);
212 }
213#endif
214}
215
216/* enable clocks needed by rotator block */
217static void enable_rot_clks(void)
218{
219 if (msm_rotator_dev->regulator)
220 regulator_enable(msm_rotator_dev->regulator);
221 if (msm_rotator_dev->core_clk != NULL)
222 clk_enable(msm_rotator_dev->core_clk);
223 if (msm_rotator_dev->pclk != NULL)
224 clk_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225}
226
227/* disable clocks needed by rotator block */
228static void disable_rot_clks(void)
229{
230 if (msm_rotator_dev->core_clk != NULL)
231 clk_disable(msm_rotator_dev->core_clk);
232 if (msm_rotator_dev->pclk != NULL)
233 clk_disable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234 if (msm_rotator_dev->regulator)
235 regulator_disable(msm_rotator_dev->regulator);
236}
237
238static void msm_rotator_rot_clk_work_f(struct work_struct *work)
239{
240 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
241 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
242 disable_rot_clks();
243 msm_rotator_dev->rot_clk_state = CLK_DIS;
244 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
245 msm_rotator_dev->rot_clk_state = CLK_DIS;
246 mutex_unlock(&msm_rotator_dev->rotator_lock);
247 }
248}
249
250static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
251{
252 if (msm_rotator_dev->processing) {
253 msm_rotator_dev->processing = 0;
254 wake_up(&msm_rotator_dev->wq);
255 } else
256 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
257
258 return IRQ_HANDLED;
259}
260
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700261static unsigned int tile_size(unsigned int src_width,
262 unsigned int src_height,
263 const struct tile_parm *tp)
264{
265 unsigned int tile_w, tile_h;
266 unsigned int row_num_w, row_num_h;
267 tile_w = tp->width * tp->row_tile_w;
268 tile_h = tp->height * tp->row_tile_h;
269 row_num_w = (src_width + tile_w - 1) / tile_w;
270 row_num_h = (src_height + tile_h - 1) / tile_h;
271 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
272}
273
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274static int get_bpp(int format)
275{
276 switch (format) {
277 case MDP_RGB_565:
278 case MDP_BGR_565:
279 return 2;
280
281 case MDP_XRGB_8888:
282 case MDP_ARGB_8888:
283 case MDP_RGBA_8888:
284 case MDP_BGRA_8888:
285 case MDP_RGBX_8888:
286 return 4;
287
288 case MDP_Y_CBCR_H2V2:
289 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700290 case MDP_Y_CB_CR_H2V2:
291 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530292 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 case MDP_Y_CRCB_H2V2_TILE:
294 case MDP_Y_CBCR_H2V2_TILE:
295 return 1;
296
297 case MDP_RGB_888:
298 return 3;
299
300 case MDP_YCRYCB_H2V1:
301 return 2;/* YCrYCb interleave */
302
303 case MDP_Y_CRCB_H2V1:
304 case MDP_Y_CBCR_H2V1:
305 return 1;
306
307 default:
308 return -1;
309 }
310
311}
312
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700313static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
314 struct msm_rotator_mem_planes *p)
315{
316 /*
317 * each row of samsung tile consists of two tiles in height
318 * and two tiles in width which means width should align to
319 * 64 x 2 bytes and height should align to 32 x 2 bytes.
320 * video decoder generate two tiles in width and one tile
321 * in height which ends up height align to 32 X 1 bytes.
322 */
323 const struct tile_parm tile = {64, 32, 2, 1};
324 int i;
325
326 if (p == NULL)
327 return -EINVAL;
328
329 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
330 return -ERANGE;
331
332 memset(p, 0, sizeof(*p));
333
334 switch (format) {
335 case MDP_XRGB_8888:
336 case MDP_ARGB_8888:
337 case MDP_RGBA_8888:
338 case MDP_BGRA_8888:
339 case MDP_RGBX_8888:
340 case MDP_RGB_888:
341 case MDP_RGB_565:
342 case MDP_BGR_565:
343 case MDP_YCRYCB_H2V1:
344 p->num_planes = 1;
345 p->plane_size[0] = w * h * get_bpp(format);
346 break;
347 case MDP_Y_CRCB_H2V1:
348 case MDP_Y_CBCR_H2V1:
349 p->num_planes = 2;
350 p->plane_size[0] = w * h;
351 p->plane_size[1] = w * h;
352 break;
353 case MDP_Y_CBCR_H2V2:
354 case MDP_Y_CRCB_H2V2:
355 p->num_planes = 2;
356 p->plane_size[0] = w * h;
357 p->plane_size[1] = w * h / 2;
358 break;
359 case MDP_Y_CRCB_H2V2_TILE:
360 case MDP_Y_CBCR_H2V2_TILE:
361 p->num_planes = 2;
362 p->plane_size[0] = tile_size(w, h, &tile);
363 p->plane_size[1] = tile_size(w, h/2, &tile);
364 break;
365 case MDP_Y_CB_CR_H2V2:
366 case MDP_Y_CR_CB_H2V2:
367 p->num_planes = 3;
368 p->plane_size[0] = w * h;
369 p->plane_size[1] = (w / 2) * (h / 2);
370 p->plane_size[2] = (w / 2) * (h / 2);
371 break;
372 case MDP_Y_CR_CB_GH2V2:
373 p->num_planes = 3;
374 p->plane_size[0] = ALIGN(w, 16) * h;
375 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
376 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
377 break;
378 default:
379 return -EINVAL;
380 }
381
382 for (i = 0; i < p->num_planes; i++)
383 p->total_size += p->plane_size[i];
384
385 return 0;
386}
387
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700388static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
389 unsigned int in_paddr,
390 unsigned int out_paddr,
391 unsigned int use_imem,
392 int new_session,
393 unsigned int in_chroma_paddr,
394 unsigned int out_chroma_paddr)
395{
396 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700397
398 if (info->src.format != info->dst.format)
399 return -EINVAL;
400
401 bpp = get_bpp(info->src.format);
402 if (bpp < 0)
403 return -ENOTTY;
404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700405 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700406 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700407 iowrite32(out_paddr +
408 ((info->dst_y * info->dst.width) + info->dst_x),
409 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700410 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700411 ((info->dst_y * info->dst.width) + info->dst_x),
412 MSM_ROTATOR_OUTP1_ADDR);
413
414 if (new_session) {
415 iowrite32(info->src.width |
416 info->src.width << 16,
417 MSM_ROTATOR_SRC_YSTRIDE1);
418 if (info->rotations & MDP_ROT_90)
419 iowrite32(info->dst.width |
420 info->dst.width*2 << 16,
421 MSM_ROTATOR_OUT_YSTRIDE1);
422 else
423 iowrite32(info->dst.width |
424 info->dst.width << 16,
425 MSM_ROTATOR_OUT_YSTRIDE1);
426 if (info->src.format == MDP_Y_CBCR_H2V1) {
427 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
428 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
429 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
430 MSM_ROTATOR_OUT_PACK_PATTERN1);
431 } else {
432 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
433 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
434 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
435 MSM_ROTATOR_OUT_PACK_PATTERN1);
436 }
437 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
438 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700439 1 << 8 | /* ROT_EN */
440 info->downscale_ratio << 2 | /* downscale v ratio */
441 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700442 MSM_ROTATOR_SUB_BLOCK_CFG);
443 iowrite32(0 << 29 | /* frame format 0 = linear */
444 (use_imem ? 0 : 1) << 22 | /* tile size */
445 2 << 19 | /* fetch planes 2 = pseudo */
446 0 << 18 | /* unpack align */
447 1 << 17 | /* unpack tight */
448 1 << 13 | /* unpack count 0=1 component */
449 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
450 0 << 8 | /* has alpha */
451 0 << 6 | /* alpha bits 3=8bits */
452 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
453 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
454 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
455 MSM_ROTATOR_SRC_FORMAT);
456 }
457
458 return 0;
459}
460
461static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
462 unsigned int in_paddr,
463 unsigned int out_paddr,
464 unsigned int use_imem,
465 int new_session,
466 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700467 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700468 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700470 uint32_t dst_format;
471 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700472
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700473 switch (info->src.format) {
474 case MDP_Y_CRCB_H2V2_TILE:
475 is_tile = 1;
476 case MDP_Y_CR_CB_H2V2:
477 case MDP_Y_CR_CB_GH2V2:
478 case MDP_Y_CRCB_H2V2:
479 dst_format = MDP_Y_CRCB_H2V2;
480 break;
481 case MDP_Y_CBCR_H2V2_TILE:
482 is_tile = 1;
483 case MDP_Y_CB_CR_H2V2:
484 case MDP_Y_CBCR_H2V2:
485 dst_format = MDP_Y_CBCR_H2V2;
486 break;
487 default:
488 return -EINVAL;
489 }
490 if (info->dst.format != dst_format)
491 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800493 /* rotator expects YCbCr for planar input format */
494 if (info->src.format == MDP_Y_CR_CB_H2V2 ||
495 info->src.format == MDP_Y_CR_CB_GH2V2)
496 swap(in_chroma_paddr, in_chroma2_paddr);
497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700499 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
500 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
501
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700502 iowrite32(out_paddr +
503 ((info->dst_y * info->dst.width) + info->dst_x),
504 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700505 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700506 ((info->dst_y * info->dst.width)/2 + info->dst_x),
507 MSM_ROTATOR_OUTP1_ADDR);
508
509 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700510 if (in_chroma2_paddr) {
511 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530512 iowrite32(ALIGN(info->src.width, 16) |
513 ALIGN((info->src.width / 2), 16) << 16,
514 MSM_ROTATOR_SRC_YSTRIDE1);
515 iowrite32(ALIGN((info->src.width / 2), 16),
516 MSM_ROTATOR_SRC_YSTRIDE2);
517 } else {
518 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700519 (info->src.width / 2) << 16,
520 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530521 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700522 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530523 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700524 } else {
525 iowrite32(info->src.width |
526 info->src.width << 16,
527 MSM_ROTATOR_SRC_YSTRIDE1);
528 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700530 info->dst.width << 16,
531 MSM_ROTATOR_OUT_YSTRIDE1);
532
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700533 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
535 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
536 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
537 MSM_ROTATOR_OUT_PACK_PATTERN1);
538 } else {
539 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
540 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
541 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
542 MSM_ROTATOR_OUT_PACK_PATTERN1);
543 }
544 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
545 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700546 1 << 8 | /* ROT_EN */
547 info->downscale_ratio << 2 | /* downscale v ratio */
548 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700550
551 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700552 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700553 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554 0 << 18 | /* unpack align */
555 1 << 17 | /* unpack tight */
556 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700557 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558 0 << 8 | /* has alpha */
559 0 << 6 | /* alpha bits 3=8bits */
560 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
561 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
562 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
563 MSM_ROTATOR_SRC_FORMAT);
564 }
565 return 0;
566}
567
568static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
569 unsigned int in_paddr,
570 unsigned int out_paddr,
571 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530572 int new_session,
573 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700574{
575 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530576 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577
Mayank Chopra732dcd62012-01-09 20:53:39 +0530578 if (info->src.format == MDP_YCRYCB_H2V1)
579 dst_format = MDP_Y_CRCB_H2V1;
580 else
581 return -EINVAL;
582
583 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584 return -EINVAL;
585
586 bpp = get_bpp(info->src.format);
587 if (bpp < 0)
588 return -ENOTTY;
589
590 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
591 iowrite32(out_paddr +
592 ((info->dst_y * info->dst.width) + info->dst_x),
593 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530594 iowrite32(out_chroma_paddr +
595 ((info->dst_y * info->dst.width)/2 + info->dst_x),
596 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597
598 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530599 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530601 if (info->rotations & MDP_ROT_90)
602 iowrite32(info->dst.width |
603 (info->dst.width*2) << 16,
604 MSM_ROTATOR_OUT_YSTRIDE1);
605 else
606 iowrite32(info->dst.width |
607 (info->dst.width) << 16,
608 MSM_ROTATOR_OUT_YSTRIDE1);
609
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
611 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530612 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613 MSM_ROTATOR_OUT_PACK_PATTERN1);
614 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
615 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700616 1 << 8 | /* ROT_EN */
617 info->downscale_ratio << 2 | /* downscale v ratio */
618 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700619 MSM_ROTATOR_SUB_BLOCK_CFG);
620 iowrite32(0 << 29 | /* frame format 0 = linear */
621 (use_imem ? 0 : 1) << 22 | /* tile size */
622 0 << 19 | /* fetch planes 0=interleaved */
623 0 << 18 | /* unpack align */
624 1 << 17 | /* unpack tight */
625 3 << 13 | /* unpack count 0=1 component */
626 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
627 0 << 8 | /* has alpha */
628 0 << 6 | /* alpha bits 3=8bits */
629 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
630 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
631 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
632 MSM_ROTATOR_SRC_FORMAT);
633 }
634
635 return 0;
636}
637
638static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
639 unsigned int in_paddr,
640 unsigned int out_paddr,
641 unsigned int use_imem,
642 int new_session)
643{
644 int bpp, abits, rbits, gbits, bbits;
645
646 if (info->src.format != info->dst.format)
647 return -EINVAL;
648
649 bpp = get_bpp(info->src.format);
650 if (bpp < 0)
651 return -ENOTTY;
652
653 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
654 iowrite32(out_paddr +
655 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
656 MSM_ROTATOR_OUTP0_ADDR);
657
658 if (new_session) {
659 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
660 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
661 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
662 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700663 1 << 8 | /* ROT_EN */
664 info->downscale_ratio << 2 | /* downscale v ratio */
665 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 MSM_ROTATOR_SUB_BLOCK_CFG);
667 switch (info->src.format) {
668 case MDP_RGB_565:
669 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
670 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
671 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
672 MSM_ROTATOR_OUT_PACK_PATTERN1);
673 abits = 0;
674 rbits = COMPONENT_5BITS;
675 gbits = COMPONENT_6BITS;
676 bbits = COMPONENT_5BITS;
677 break;
678
679 case MDP_BGR_565:
680 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
681 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
682 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
683 MSM_ROTATOR_OUT_PACK_PATTERN1);
684 abits = 0;
685 rbits = COMPONENT_5BITS;
686 gbits = COMPONENT_6BITS;
687 bbits = COMPONENT_5BITS;
688 break;
689
690 case MDP_RGB_888:
691 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
692 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
693 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
694 MSM_ROTATOR_OUT_PACK_PATTERN1);
695 abits = 0;
696 rbits = COMPONENT_8BITS;
697 gbits = COMPONENT_8BITS;
698 bbits = COMPONENT_8BITS;
699 break;
700
701 case MDP_ARGB_8888:
702 case MDP_RGBA_8888:
703 case MDP_XRGB_8888:
704 case MDP_RGBX_8888:
705 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
706 CLR_B, 8),
707 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
708 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
709 CLR_B, 8),
710 MSM_ROTATOR_OUT_PACK_PATTERN1);
711 abits = COMPONENT_8BITS;
712 rbits = COMPONENT_8BITS;
713 gbits = COMPONENT_8BITS;
714 bbits = COMPONENT_8BITS;
715 break;
716
717 case MDP_BGRA_8888:
718 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
719 CLR_R, 8),
720 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
721 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
722 CLR_R, 8),
723 MSM_ROTATOR_OUT_PACK_PATTERN1);
724 abits = COMPONENT_8BITS;
725 rbits = COMPONENT_8BITS;
726 gbits = COMPONENT_8BITS;
727 bbits = COMPONENT_8BITS;
728 break;
729
730 default:
731 return -EINVAL;
732 }
733 iowrite32(0 << 29 | /* frame format 0 = linear */
734 (use_imem ? 0 : 1) << 22 | /* tile size */
735 0 << 19 | /* fetch planes 0=interleaved */
736 0 << 18 | /* unpack align */
737 1 << 17 | /* unpack tight */
738 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
739 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
740 (abits ? 1 : 0) << 8 | /* has alpha */
741 abits << 6 | /* alpha bits 3=8bits */
742 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
743 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
744 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
745 MSM_ROTATOR_SRC_FORMAT);
746 }
747
748 return 0;
749}
750
Naseer Ahmed18018602011-10-25 13:32:58 -0700751static int get_img(struct msmfb_data *fbd, unsigned long *start,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800752 unsigned long *len, struct file **p_file, int *p_need,
753 struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700754{
755 int ret = 0;
756#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700757 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700758 int put_needed, fb_num;
759#endif
760#ifdef CONFIG_ANDROID_PMEM
761 unsigned long vstart;
762#endif
763
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800764 *p_need = 0;
765
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700766#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700767 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
768 file = fget_light(fbd->memory_id, &put_needed);
769 if (file == NULL)
770 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700771
Naseer Ahmed18018602011-10-25 13:32:58 -0700772 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
773 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
774 if (get_fb_phys_info(start, len, fb_num))
775 ret = -1;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800776 else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700777 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800778 *p_need = put_needed;
779 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700780 } else
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700781 ret = -1;
Naseer Ahmed18018602011-10-25 13:32:58 -0700782 if (ret)
783 fput_light(file, put_needed);
784 return ret;
785 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700786#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700787
788#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
789 *p_ihdl = ion_import_fd(msm_rotator_dev->client,
790 fbd->memory_id);
791 if (IS_ERR_OR_NULL(*p_ihdl))
792 return PTR_ERR(*p_ihdl);
793 if (!ion_phys(msm_rotator_dev->client, *p_ihdl, start,
794 (size_t *) len))
795 return 0;
796 else
797 return -ENOMEM;
798#endif
799#ifdef CONFIG_ANDROID_PMEM
800 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
801 return 0;
802 else
803 return -ENOMEM;
804#endif
805
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700806}
807
Naseer Ahmed18018602011-10-25 13:32:58 -0700808static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
809{
810#ifdef CONFIG_ANDROID_PMEM
811 if (p_file != NULL)
812 put_pmem_file(p_file);
813#endif
814#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
815 if (!IS_ERR_OR_NULL(p_ihdl))
816 ion_free(msm_rotator_dev->client, p_ihdl);
817#endif
818}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819static int msm_rotator_do_rotate(unsigned long arg)
820{
Naseer Ahmed18018602011-10-25 13:32:58 -0700821 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 struct msm_rotator_data_info info;
823 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700824 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700825 int use_imem = 0, rc = 0, s;
826 struct file *srcp0_file = NULL, *dstp0_file = NULL;
827 struct file *srcp1_file = NULL, *dstp1_file = NULL;
828 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
829 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800830 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700832 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700833 struct msm_rotator_img_info *img_info;
834 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835
836 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
837 return -EFAULT;
838
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700839 mutex_lock(&msm_rotator_dev->rotator_lock);
840 for (s = 0; s < MAX_SESSIONS; s++)
841 if ((msm_rotator_dev->img_info[s] != NULL) &&
842 (info.session_id ==
843 (unsigned int)msm_rotator_dev->img_info[s]
844 ))
845 break;
846
847 if (s == MAX_SESSIONS) {
848 dev_dbg(msm_rotator_dev->device,
849 "%s() : Attempt to use invalid session_id %d\n",
850 __func__, s);
851 rc = -EINVAL;
852 goto do_rotate_unlock_mutex;
853 }
854
855 if (msm_rotator_dev->img_info[s]->enable == 0) {
856 dev_dbg(msm_rotator_dev->device,
857 "%s() : Session_id %d not enabled \n",
858 __func__, s);
859 rc = -EINVAL;
860 goto do_rotate_unlock_mutex;
861 }
862
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700863 img_info = msm_rotator_dev->img_info[s];
864 if (msm_rotator_get_plane_sizes(img_info->src.format,
865 img_info->src.width,
866 img_info->src.height,
867 &src_planes)) {
868 pr_err("%s: invalid src format\n", __func__);
869 rc = -EINVAL;
870 goto do_rotate_unlock_mutex;
871 }
872 if (msm_rotator_get_plane_sizes(img_info->dst.format,
873 img_info->dst.width,
874 img_info->dst.height,
875 &dst_planes)) {
876 pr_err("%s: invalid dst format\n", __func__);
877 rc = -EINVAL;
878 goto do_rotate_unlock_mutex;
879 }
880
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800881
Naseer Ahmed18018602011-10-25 13:32:58 -0700882 rc = get_img(&info.src, (unsigned long *)&in_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800883 (unsigned long *)&src_len, &srcp0_file, &ps0_need, &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700884 if (rc) {
885 pr_err("%s: in get_img() failed id=0x%08x\n",
886 DRIVER_NAME, info.src.memory_id);
887 goto do_rotate_unlock_mutex;
888 }
889
Naseer Ahmed18018602011-10-25 13:32:58 -0700890 rc = get_img(&info.dst, (unsigned long *)&out_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800891 (unsigned long *)&dst_len, &dstp0_file, &p_need, &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700892 if (rc) {
893 pr_err("%s: out get_img() failed id=0x%08x\n",
894 DRIVER_NAME, info.dst.memory_id);
895 goto do_rotate_unlock_mutex;
896 }
897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 format = msm_rotator_dev->img_info[s]->src.format;
899 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700900 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
901 (src_planes.num_planes == 2)) {
902 if (checkoffset(info.src.offset,
903 src_planes.plane_size[0],
904 src_len)) {
905 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
906 __func__, src_len, info.src.offset);
907 rc = -ERANGE;
908 goto do_rotate_unlock_mutex;
909 }
910 if (checkoffset(info.dst.offset,
911 dst_planes.plane_size[0],
912 dst_len)) {
913 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
914 __func__, dst_len, info.dst.offset);
915 rc = -ERANGE;
916 goto do_rotate_unlock_mutex;
917 }
918
Naseer Ahmed18018602011-10-25 13:32:58 -0700919 rc = get_img(&info.src_chroma,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800921 (unsigned long *)&src_len, &srcp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700922 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700923 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700924 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925 DRIVER_NAME, info.src_chroma.memory_id);
926 goto do_rotate_unlock_mutex;
927 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928
Naseer Ahmed18018602011-10-25 13:32:58 -0700929 rc = get_img(&info.dst_chroma,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800931 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700932 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700934 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700935 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700936 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700937 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700938
939 if (checkoffset(info.src_chroma.offset,
940 src_planes.plane_size[1],
941 src_len)) {
942 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
943 __func__, src_len, info.src_chroma.offset);
944 rc = -ERANGE;
945 goto do_rotate_unlock_mutex;
946 }
947
948 if (checkoffset(info.dst_chroma.offset,
949 src_planes.plane_size[1],
950 dst_len)) {
951 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
952 __func__, dst_len, info.dst_chroma.offset);
953 rc = -ERANGE;
954 goto do_rotate_unlock_mutex;
955 }
956
957 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700959 } else {
960 if (checkoffset(info.src.offset,
961 src_planes.total_size,
962 src_len)) {
963 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
964 __func__, src_len, info.src.offset);
965 rc = -ERANGE;
966 goto do_rotate_unlock_mutex;
967 }
968 if (checkoffset(info.dst.offset,
969 dst_planes.total_size,
970 dst_len)) {
971 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
972 __func__, dst_len, info.dst.offset);
973 rc = -ERANGE;
974 goto do_rotate_unlock_mutex;
975 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976 }
977
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700978 in_paddr += info.src.offset;
979 out_paddr += info.dst.offset;
980
981 if (!in_chroma_paddr && src_planes.num_planes >= 2)
982 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
983 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
984 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
985 if (src_planes.num_planes >= 3)
986 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
987
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
989 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
990 enable_rot_clks();
991 msm_rotator_dev->rot_clk_state = CLK_EN;
992 }
993 enable_irq(msm_rotator_dev->irq);
994
995#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
996 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
997#else
998 use_imem = 0;
999#endif
1000 /*
1001 * workaround for a hardware bug. rotator hardware hangs when we
1002 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1003 * temporary fix use 0x42 for BURST_SIZE when imem used.
1004 */
1005 if (use_imem)
1006 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1007
1008 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1009 << 16) |
1010 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1011 MSM_ROTATOR_SRC_SIZE);
1012 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1013 << 16) |
1014 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1015 MSM_ROTATOR_SRC_XY);
1016 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1017 << 16) |
1018 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1019 MSM_ROTATOR_SRC_IMAGE_SIZE);
1020
1021 switch (format) {
1022 case MDP_RGB_565:
1023 case MDP_BGR_565:
1024 case MDP_RGB_888:
1025 case MDP_ARGB_8888:
1026 case MDP_RGBA_8888:
1027 case MDP_XRGB_8888:
1028 case MDP_BGRA_8888:
1029 case MDP_RGBX_8888:
1030 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1031 in_paddr, out_paddr,
1032 use_imem,
1033 msm_rotator_dev->last_session_idx
1034 != s);
1035 break;
1036 case MDP_Y_CBCR_H2V2:
1037 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001038 case MDP_Y_CB_CR_H2V2:
1039 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301040 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 case MDP_Y_CRCB_H2V2_TILE:
1042 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001043 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1044 in_paddr, out_paddr, use_imem,
1045 msm_rotator_dev->last_session_idx
1046 != s,
1047 in_chroma_paddr,
1048 out_chroma_paddr,
1049 in_chroma2_paddr);
1050 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 case MDP_Y_CBCR_H2V1:
1052 case MDP_Y_CRCB_H2V1:
1053 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1054 in_paddr, out_paddr, use_imem,
1055 msm_rotator_dev->last_session_idx
1056 != s,
1057 in_chroma_paddr,
1058 out_chroma_paddr);
1059 break;
1060 case MDP_YCRYCB_H2V1:
1061 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1062 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301063 msm_rotator_dev->last_session_idx != s,
1064 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 break;
1066 default:
1067 rc = -EINVAL;
1068 goto do_rotate_exit;
1069 }
1070
1071 if (rc != 0) {
1072 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1073 goto do_rotate_exit;
1074 }
1075
1076 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1077
1078 msm_rotator_dev->processing = 1;
1079 iowrite32(0x1, MSM_ROTATOR_START);
1080
1081 wait_event(msm_rotator_dev->wq,
1082 (msm_rotator_dev->processing == 0));
1083 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
1084 if ((status & 0x03) != 0x01)
1085 rc = -EFAULT;
1086 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1087 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1088
1089do_rotate_exit:
1090 disable_irq(msm_rotator_dev->irq);
1091#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1092 msm_rotator_imem_free(ROTATOR_REQUEST);
1093#endif
1094 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001095do_rotate_unlock_mutex:
Naseer Ahmed18018602011-10-25 13:32:58 -07001096 put_img(dstp1_file, dstp1_ihdl);
1097 put_img(srcp1_file, srcp1_ihdl);
1098 put_img(dstp0_file, dstp0_ihdl);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001099
1100 /* only source may use frame buffer */
1101 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1102 fput_light(srcp0_file, ps0_need);
1103 else
1104 put_img(srcp0_file, srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001105 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1107 __func__, rc);
1108 return rc;
1109}
1110
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001111static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1112{
1113 u32 perf_level;
1114
1115 if (is_rgb)
1116 perf_level = 1;
1117 else if (wh <= (640 * 480))
1118 perf_level = 2;
1119 else if (wh <= (736 * 1280))
1120 perf_level = 3;
1121 else
1122 perf_level = 4;
1123
1124#ifdef CONFIG_MSM_BUS_SCALING
1125 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1126 perf_level);
1127#endif
1128
1129}
1130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001131static int msm_rotator_start(unsigned long arg, int pid)
1132{
1133 struct msm_rotator_img_info info;
1134 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001135 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001137 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138
1139 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1140 return -EFAULT;
1141
1142 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1143 (info.src.height > MSM_ROTATOR_MAX_H) ||
1144 (info.src.width > MSM_ROTATOR_MAX_W) ||
1145 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1146 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001147 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1148 pr_err("%s: Invalid parameters\n", __func__);
1149 return -EINVAL;
1150 }
1151
1152 if (info.rotations & MDP_ROT_90) {
1153 dst_w = info.src_rect.h >> info.downscale_ratio;
1154 dst_h = info.src_rect.w >> info.downscale_ratio;
1155 } else {
1156 dst_w = info.src_rect.w >> info.downscale_ratio;
1157 dst_h = info.src_rect.h >> info.downscale_ratio;
1158 }
1159
1160 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001161 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1162 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001163 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1164 pr_err("%s: Invalid src or dst rect\n", __func__);
1165 return -ERANGE;
1166 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167
1168 switch (info.src.format) {
1169 case MDP_RGB_565:
1170 case MDP_BGR_565:
1171 case MDP_RGB_888:
1172 case MDP_ARGB_8888:
1173 case MDP_RGBA_8888:
1174 case MDP_XRGB_8888:
1175 case MDP_RGBX_8888:
1176 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001177 is_rgb = 1;
1178 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001179 case MDP_Y_CBCR_H2V2:
1180 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001181 case MDP_Y_CB_CR_H2V2:
1182 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301183 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 case MDP_Y_CBCR_H2V1:
1185 case MDP_Y_CRCB_H2V1:
1186 case MDP_YCRYCB_H2V1:
1187 case MDP_Y_CRCB_H2V2_TILE:
1188 case MDP_Y_CBCR_H2V2_TILE:
1189 break;
1190 default:
1191 return -EINVAL;
1192 }
1193
1194 switch (info.dst.format) {
1195 case MDP_RGB_565:
1196 case MDP_BGR_565:
1197 case MDP_RGB_888:
1198 case MDP_ARGB_8888:
1199 case MDP_RGBA_8888:
1200 case MDP_XRGB_8888:
1201 case MDP_RGBX_8888:
1202 case MDP_BGRA_8888:
1203 case MDP_Y_CBCR_H2V2:
1204 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001205 case MDP_Y_CB_CR_H2V2:
1206 case MDP_Y_CR_CB_H2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001207 case MDP_Y_CBCR_H2V1:
1208 case MDP_Y_CRCB_H2V1:
1209 case MDP_YCRYCB_H2V1:
1210 break;
1211 default:
1212 return -EINVAL;
1213 }
1214
1215 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001216
1217 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001219 for (s = 0; s < MAX_SESSIONS; s++) {
1220 if ((msm_rotator_dev->img_info[s] != NULL) &&
1221 (info.session_id ==
1222 (unsigned int)msm_rotator_dev->img_info[s]
1223 )) {
1224 *(msm_rotator_dev->img_info[s]) = info;
1225 msm_rotator_dev->pid_list[s] = pid;
1226
1227 if (msm_rotator_dev->last_session_idx == s)
1228 msm_rotator_dev->last_session_idx =
1229 INVALID_SESSION;
1230 break;
1231 }
1232
1233 if ((msm_rotator_dev->img_info[s] == NULL) &&
1234 (first_free_index ==
1235 INVALID_SESSION))
1236 first_free_index = s;
1237 }
1238
1239 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1240 /* allocate a session id */
1241 msm_rotator_dev->img_info[first_free_index] =
1242 kzalloc(sizeof(struct msm_rotator_img_info),
1243 GFP_KERNEL);
1244 if (!msm_rotator_dev->img_info[first_free_index]) {
1245 printk(KERN_ERR "%s : unable to alloc mem\n",
1246 __func__);
1247 rc = -ENOMEM;
1248 goto rotator_start_exit;
1249 }
1250 info.session_id = (unsigned int)
1251 msm_rotator_dev->img_info[first_free_index];
1252 *(msm_rotator_dev->img_info[first_free_index]) = info;
1253 msm_rotator_dev->pid_list[first_free_index] = pid;
1254
1255 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1256 rc = -EFAULT;
1257 } else if (s == MAX_SESSIONS) {
1258 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1259 __func__);
1260 rc = -EBUSY;
1261 }
1262
1263rotator_start_exit:
1264 mutex_unlock(&msm_rotator_dev->rotator_lock);
1265
1266 return rc;
1267}
1268
1269static int msm_rotator_finish(unsigned long arg)
1270{
1271 int rc = 0;
1272 int s;
1273 unsigned int session_id;
1274
1275 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1276 return -EFAULT;
1277
1278 mutex_lock(&msm_rotator_dev->rotator_lock);
1279 for (s = 0; s < MAX_SESSIONS; s++) {
1280 if ((msm_rotator_dev->img_info[s] != NULL) &&
1281 (session_id ==
1282 (unsigned int)msm_rotator_dev->img_info[s])) {
1283 if (msm_rotator_dev->last_session_idx == s)
1284 msm_rotator_dev->last_session_idx =
1285 INVALID_SESSION;
1286 kfree(msm_rotator_dev->img_info[s]);
1287 msm_rotator_dev->img_info[s] = NULL;
1288 msm_rotator_dev->pid_list[s] = 0;
1289 break;
1290 }
1291 }
1292
1293 if (s == MAX_SESSIONS)
1294 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001295#ifdef CONFIG_MSM_BUS_SCALING
1296 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1297 0);
1298#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299 mutex_unlock(&msm_rotator_dev->rotator_lock);
1300 return rc;
1301}
1302
1303static int
1304msm_rotator_open(struct inode *inode, struct file *filp)
1305{
1306 int *id;
1307 int i;
1308
1309 if (filp->private_data)
1310 return -EBUSY;
1311
1312 mutex_lock(&msm_rotator_dev->rotator_lock);
1313 id = &msm_rotator_dev->pid_list[0];
1314 for (i = 0; i < MAX_SESSIONS; i++, id++) {
1315 if (*id == 0)
1316 break;
1317 }
1318 mutex_unlock(&msm_rotator_dev->rotator_lock);
1319
1320 if (i == MAX_SESSIONS)
1321 return -EBUSY;
1322
kuogee hsieh7a46d592011-09-09 10:27:23 -07001323 filp->private_data = (void *)current->pid;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324
1325 return 0;
1326}
1327
1328static int
1329msm_rotator_close(struct inode *inode, struct file *filp)
1330{
1331 int s;
1332 int pid;
1333
1334 pid = (int)filp->private_data;
1335 mutex_lock(&msm_rotator_dev->rotator_lock);
1336 for (s = 0; s < MAX_SESSIONS; s++) {
1337 if (msm_rotator_dev->img_info[s] != NULL &&
1338 msm_rotator_dev->pid_list[s] == pid) {
1339 kfree(msm_rotator_dev->img_info[s]);
1340 msm_rotator_dev->img_info[s] = NULL;
1341 if (msm_rotator_dev->last_session_idx == s)
1342 msm_rotator_dev->last_session_idx =
1343 INVALID_SESSION;
1344 }
1345 }
1346 mutex_unlock(&msm_rotator_dev->rotator_lock);
1347
1348 return 0;
1349}
1350
1351static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1352 unsigned long arg)
1353{
1354 int pid;
1355
1356 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1357 return -ENOTTY;
1358
1359 pid = (int)file->private_data;
1360
1361 switch (cmd) {
1362 case MSM_ROTATOR_IOCTL_START:
1363 return msm_rotator_start(arg, pid);
1364 case MSM_ROTATOR_IOCTL_ROTATE:
1365 return msm_rotator_do_rotate(arg);
1366 case MSM_ROTATOR_IOCTL_FINISH:
1367 return msm_rotator_finish(arg);
1368
1369 default:
1370 dev_dbg(msm_rotator_dev->device,
1371 "unexpected IOCTL %d\n", cmd);
1372 return -ENOTTY;
1373 }
1374}
1375
1376static const struct file_operations msm_rotator_fops = {
1377 .owner = THIS_MODULE,
1378 .open = msm_rotator_open,
1379 .release = msm_rotator_close,
1380 .unlocked_ioctl = msm_rotator_ioctl,
1381};
1382
1383static int __devinit msm_rotator_probe(struct platform_device *pdev)
1384{
1385 int rc = 0;
1386 struct resource *res;
1387 struct msm_rotator_platform_data *pdata = NULL;
1388 int i, number_of_clks;
1389 uint32_t ver;
1390
1391 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1392 if (!msm_rotator_dev) {
1393 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1394 __func__);
1395 return -ENOMEM;
1396 }
1397 for (i = 0; i < MAX_SESSIONS; i++)
1398 msm_rotator_dev->img_info[i] = NULL;
1399 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1400
1401 pdata = pdev->dev.platform_data;
1402 number_of_clks = pdata->number_of_clocks;
1403
1404 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1405 mutex_init(&msm_rotator_dev->imem_lock);
1406 msm_rotator_dev->imem_clk_state = CLK_DIS;
1407 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1408 msm_rotator_imem_clk_work_f);
1409 msm_rotator_dev->imem_clk = NULL;
1410 msm_rotator_dev->pdev = pdev;
1411
1412 msm_rotator_dev->core_clk = NULL;
1413 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001415#ifdef CONFIG_MSM_BUS_SCALING
1416 if (!msm_rotator_dev->bus_client_handle && pdata &&
1417 pdata->bus_scale_table) {
1418 msm_rotator_dev->bus_client_handle =
1419 msm_bus_scale_register_client(
1420 pdata->bus_scale_table);
1421 if (!msm_rotator_dev->bus_client_handle) {
1422 pr_err("%s not able to get bus scale handle\n",
1423 __func__);
1424 }
1425 }
1426#endif
1427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 for (i = 0; i < number_of_clks; i++) {
1429 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1430 msm_rotator_dev->imem_clk =
1431 clk_get(&msm_rotator_dev->pdev->dev,
1432 pdata->rotator_clks[i].clk_name);
1433 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1434 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1435 msm_rotator_dev->imem_clk = NULL;
1436 printk(KERN_ERR "%s: cannot get imem_clk "
1437 "rc=%d\n", DRIVER_NAME, rc);
1438 goto error_imem_clk;
1439 }
1440 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001441 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 pdata->rotator_clks[i].clk_rate);
1443 }
1444 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1445 msm_rotator_dev->pclk =
1446 clk_get(&msm_rotator_dev->pdev->dev,
1447 pdata->rotator_clks[i].clk_name);
1448 if (IS_ERR(msm_rotator_dev->pclk)) {
1449 rc = PTR_ERR(msm_rotator_dev->pclk);
1450 msm_rotator_dev->pclk = NULL;
1451 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1452 DRIVER_NAME, rc);
1453 goto error_pclk;
1454 }
1455
1456 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001457 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 pdata->rotator_clks[i].clk_rate);
1459 }
1460
1461 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1462 msm_rotator_dev->core_clk =
1463 clk_get(&msm_rotator_dev->pdev->dev,
1464 pdata->rotator_clks[i].clk_name);
1465 if (IS_ERR(msm_rotator_dev->core_clk)) {
1466 rc = PTR_ERR(msm_rotator_dev->core_clk);
1467 msm_rotator_dev->core_clk = NULL;
1468 printk(KERN_ERR "%s: cannot get core clk "
1469 "rc=%d\n", DRIVER_NAME, rc);
1470 goto error_core_clk;
1471 }
1472
1473 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001474 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 pdata->rotator_clks[i].clk_rate);
1476 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001477 }
1478
1479 msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
1480 if (IS_ERR(msm_rotator_dev->regulator))
1481 msm_rotator_dev->regulator = NULL;
1482
1483 msm_rotator_dev->rot_clk_state = CLK_DIS;
1484 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1485 msm_rotator_rot_clk_work_f);
1486
1487 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001488#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1489 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1490#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491 platform_set_drvdata(pdev, msm_rotator_dev);
1492
1493
1494 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1495 if (!res) {
1496 printk(KERN_ALERT
1497 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1498 rc = -ENODEV;
1499 goto error_get_resource;
1500 }
1501 msm_rotator_dev->io_base = ioremap(res->start,
1502 resource_size(res));
1503
1504#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1505 if (msm_rotator_dev->imem_clk)
1506 clk_enable(msm_rotator_dev->imem_clk);
1507#endif
1508 enable_rot_clks();
1509 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1510 disable_rot_clks();
1511
1512#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1513 if (msm_rotator_dev->imem_clk)
1514 clk_disable(msm_rotator_dev->imem_clk);
1515#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001516 if (ver != pdata->hardware_version_number)
Nagamalleswararao Ganjibcdea002011-09-13 15:43:47 -07001517 pr_info("%s: invalid HW version\n", DRIVER_NAME);
Naseer Ahmed18018602011-10-25 13:32:58 -07001518
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1520 if (msm_rotator_dev->irq < 0) {
1521 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1522 DRIVER_NAME);
1523 rc = -ENODEV;
1524 goto error_get_irq;
1525 }
1526 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1527 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1528 if (rc) {
1529 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1530 goto error_get_irq;
1531 }
1532 /* we enable the IRQ when we need it in the ioctl */
1533 disable_irq(msm_rotator_dev->irq);
1534
1535 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1536 if (rc < 0) {
1537 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1538 __func__, rc);
1539 goto error_get_irq;
1540 }
1541
1542 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1543 if (IS_ERR(msm_rotator_dev->class)) {
1544 rc = PTR_ERR(msm_rotator_dev->class);
1545 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1546 DRIVER_NAME, rc);
1547 goto error_class_create;
1548 }
1549
1550 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1551 msm_rotator_dev->dev_num, NULL,
1552 DRIVER_NAME);
1553 if (IS_ERR(msm_rotator_dev->device)) {
1554 rc = PTR_ERR(msm_rotator_dev->device);
1555 printk(KERN_ERR "%s: device_create failed %d\n",
1556 DRIVER_NAME, rc);
1557 goto error_class_device_create;
1558 }
1559
1560 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1561 rc = cdev_add(&msm_rotator_dev->cdev,
1562 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1563 1);
1564 if (rc < 0) {
1565 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1566 goto error_cdev_add;
1567 }
1568
1569 init_waitqueue_head(&msm_rotator_dev->wq);
1570
1571 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1572 return rc;
1573
1574error_cdev_add:
1575 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1576error_class_device_create:
1577 class_destroy(msm_rotator_dev->class);
1578error_class_create:
1579 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1580error_get_irq:
1581 iounmap(msm_rotator_dev->io_base);
1582error_get_resource:
1583 mutex_destroy(&msm_rotator_dev->rotator_lock);
1584 if (msm_rotator_dev->regulator)
1585 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001586 clk_put(msm_rotator_dev->core_clk);
1587error_core_clk:
1588 clk_put(msm_rotator_dev->pclk);
1589error_pclk:
1590 if (msm_rotator_dev->imem_clk)
1591 clk_put(msm_rotator_dev->imem_clk);
1592error_imem_clk:
1593 mutex_destroy(&msm_rotator_dev->imem_lock);
1594 kfree(msm_rotator_dev);
1595 return rc;
1596}
1597
1598static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1599{
1600 int i;
1601
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001602#ifdef CONFIG_MSM_BUS_SCALING
1603 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1604#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001605 free_irq(msm_rotator_dev->irq, NULL);
1606 mutex_destroy(&msm_rotator_dev->rotator_lock);
1607 cdev_del(&msm_rotator_dev->cdev);
1608 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1609 class_destroy(msm_rotator_dev->class);
1610 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1611 iounmap(msm_rotator_dev->io_base);
1612 if (msm_rotator_dev->imem_clk) {
1613 if (msm_rotator_dev->imem_clk_state == CLK_EN)
1614 clk_disable(msm_rotator_dev->imem_clk);
1615 clk_put(msm_rotator_dev->imem_clk);
1616 msm_rotator_dev->imem_clk = NULL;
1617 }
1618 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1619 disable_rot_clks();
1620 clk_put(msm_rotator_dev->core_clk);
1621 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 if (msm_rotator_dev->regulator)
1623 regulator_put(msm_rotator_dev->regulator);
1624 msm_rotator_dev->core_clk = NULL;
1625 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001626 mutex_destroy(&msm_rotator_dev->imem_lock);
1627 for (i = 0; i < MAX_SESSIONS; i++)
1628 if (msm_rotator_dev->img_info[i] != NULL)
1629 kfree(msm_rotator_dev->img_info[i]);
1630 kfree(msm_rotator_dev);
1631 return 0;
1632}
1633
1634#ifdef CONFIG_PM
1635static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1636{
1637 mutex_lock(&msm_rotator_dev->imem_lock);
1638 if (msm_rotator_dev->imem_clk_state == CLK_EN
1639 && msm_rotator_dev->imem_clk) {
1640 clk_disable(msm_rotator_dev->imem_clk);
1641 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1642 }
1643 mutex_unlock(&msm_rotator_dev->imem_lock);
1644 mutex_lock(&msm_rotator_dev->rotator_lock);
1645 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1646 disable_rot_clks();
1647 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1648 }
1649 mutex_unlock(&msm_rotator_dev->rotator_lock);
1650 return 0;
1651}
1652
1653static int msm_rotator_resume(struct platform_device *dev)
1654{
1655 mutex_lock(&msm_rotator_dev->imem_lock);
1656 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1657 && msm_rotator_dev->imem_clk) {
1658 clk_enable(msm_rotator_dev->imem_clk);
1659 msm_rotator_dev->imem_clk_state = CLK_EN;
1660 }
1661 mutex_unlock(&msm_rotator_dev->imem_lock);
1662 mutex_lock(&msm_rotator_dev->rotator_lock);
1663 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1664 enable_rot_clks();
1665 msm_rotator_dev->rot_clk_state = CLK_EN;
1666 }
1667 mutex_unlock(&msm_rotator_dev->rotator_lock);
1668 return 0;
1669}
1670#endif
1671
1672static struct platform_driver msm_rotator_platform_driver = {
1673 .probe = msm_rotator_probe,
1674 .remove = __devexit_p(msm_rotator_remove),
1675#ifdef CONFIG_PM
1676 .suspend = msm_rotator_suspend,
1677 .resume = msm_rotator_resume,
1678#endif
1679 .driver = {
1680 .owner = THIS_MODULE,
1681 .name = DRIVER_NAME
1682 }
1683};
1684
1685static int __init msm_rotator_init(void)
1686{
1687 return platform_driver_register(&msm_rotator_platform_driver);
1688}
1689
1690static void __exit msm_rotator_exit(void)
1691{
1692 return platform_driver_unregister(&msm_rotator_platform_driver);
1693}
1694
1695module_init(msm_rotator_init);
1696module_exit(msm_rotator_exit);
1697
1698MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1699MODULE_VERSION("1.0");
1700MODULE_LICENSE("GPL v2");