blob: 6cd18060073966d9bac86620145f2a328a693402 [file] [log] [blame]
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/platform_device.h>
14#include <linux/cdev.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/uaccess.h>
21#include <linux/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/android_pmem.h>
23#include <linux/msm_rotator.h>
24#include <linux/io.h>
25#include <mach/msm_rotator_imem.h>
26#include <linux/ktime.h>
27#include <linux/workqueue.h>
28#include <linux/file.h>
29#include <linux/major.h>
30#include <linux/regulator/consumer.h>
Naseer Ahmed18018602011-10-25 13:32:58 -070031#include <linux/ion.h>
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080032#ifdef CONFIG_MSM_BUS_SCALING
33#include <mach/msm_bus.h>
34#include <mach/msm_bus_board.h>
35#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070036#include <mach/msm_subsystem_map.h>
37#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#define DRIVER_NAME "msm_rotator"
40
41#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
42#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
43#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
44#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
45#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
46#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
47#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -070048#define MSM_ROTATOR_SW_RESET (MSM_ROTATOR_BASE+0x0074)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
50#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
51#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070052#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
54#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
55#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
56#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
57#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
58#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
59#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
60#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070061#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
63#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
64#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
65#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
66
67#define MSM_ROTATOR_MAX_ROT 0x07
68#define MSM_ROTATOR_MAX_H 0x1fff
69#define MSM_ROTATOR_MAX_W 0x1fff
70
71/* from lsb to msb */
72#define GET_PACK_PATTERN(a, x, y, z, bit) \
73 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
74#define CLR_G 0x0
75#define CLR_B 0x1
76#define CLR_R 0x2
77#define CLR_ALPHA 0x3
78
79#define CLR_Y CLR_G
80#define CLR_CB CLR_B
81#define CLR_CR CLR_R
82
83#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
84 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
85 (((r) & MDP_FLIP_UD) ? 4 : 0))
86
87#define IMEM_NO_OWNER -1;
88
89#define MAX_SESSIONS 16
90#define INVALID_SESSION -1
91#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070092#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093
Mayank Chopra012a8e72012-04-11 10:41:13 +053094#define ROTATOR_REVISION_V0 0
95#define ROTATOR_REVISION_V1 1
96#define ROTATOR_REVISION_V2 2
97#define ROTATOR_REVISION_NONE 0xffffffff
98
99uint32_t rotator_hw_revision;
100
101/*
102 * rotator_hw_revision:
103 * 0 == 7x30
104 * 1 == 8x60
105 * 2 == 8960
106 *
107 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108struct tile_parm {
109 unsigned int width; /* tile's width */
110 unsigned int height; /* tile's height */
111 unsigned int row_tile_w; /* tiles per row's width */
112 unsigned int row_tile_h; /* tiles per row's height */
113};
114
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700115struct msm_rotator_mem_planes {
116 unsigned int num_planes;
117 unsigned int plane_size[4];
118 unsigned int total_size;
119};
120
121#define checkoffset(offset, size, max_size) \
122 ((size) > (max_size) || (offset) > ((max_size) - (size)))
123
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700124struct msm_rotator_fd_info {
125 int pid;
126 int ref_cnt;
127 struct list_head list;
128};
129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130struct msm_rotator_dev {
131 void __iomem *io_base;
132 int irq;
133 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
134 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700135 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
136 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 int rot_clk_state;
139 struct regulator *regulator;
140 struct delayed_work rot_clk_work;
141 struct clk *imem_clk;
142 int imem_clk_state;
143 struct delayed_work imem_clk_work;
144 struct platform_device *pdev;
145 struct cdev cdev;
146 struct device *device;
147 struct class *class;
148 dev_t dev_num;
149 int processing;
150 int last_session_idx;
151 struct mutex rotator_lock;
152 struct mutex imem_lock;
153 int imem_owner;
154 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700155 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800156 #ifdef CONFIG_MSM_BUS_SCALING
157 uint32_t bus_client_handle;
158 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159};
160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161#define COMPONENT_5BITS 1
162#define COMPONENT_6BITS 2
163#define COMPONENT_8BITS 3
164
165static struct msm_rotator_dev *msm_rotator_dev;
166
167enum {
168 CLK_EN,
169 CLK_DIS,
170 CLK_SUSPEND,
171};
172
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700173int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
174 unsigned long *start, unsigned long *len,
175 struct ion_handle **pihdl)
176{
177 if (!msm_rotator_dev->client)
178 return -EINVAL;
179
180 *pihdl = ion_import_fd(msm_rotator_dev->client, mem_id);
181 if (IS_ERR_OR_NULL(*pihdl)) {
182 pr_err("ion_import_fd() failed\n");
183 return PTR_ERR(*pihdl);
184 }
185 pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
186 ion_share(msm_rotator_dev->client, *pihdl));
187
188 if (ion_map_iommu(msm_rotator_dev->client,
189 *pihdl, ROTATOR_DOMAIN, GEN_POOL,
190 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
191 pr_err("ion_map_iommu() failed\n");
192 return -EINVAL;
193 }
194
195 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
196 __func__, mem_id, *start, *len);
197 return 0;
198}
199
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700200int msm_rotator_imem_allocate(int requestor)
201{
202 int rc = 0;
203
204#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
205 switch (requestor) {
206 case ROTATOR_REQUEST:
207 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
208 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
209 rc = 1;
210 } else
211 rc = 0;
212 break;
213 case JPEG_REQUEST:
214 mutex_lock(&msm_rotator_dev->imem_lock);
215 msm_rotator_dev->imem_owner = JPEG_REQUEST;
216 rc = 1;
217 break;
218 default:
219 rc = 0;
220 }
221#else
222 if (requestor == JPEG_REQUEST)
223 rc = 1;
224#endif
225 if (rc == 1) {
226 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
227 if (msm_rotator_dev->imem_clk_state != CLK_EN
228 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700229 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700230 msm_rotator_dev->imem_clk_state = CLK_EN;
231 }
232 }
233
234 return rc;
235}
236EXPORT_SYMBOL(msm_rotator_imem_allocate);
237
238void msm_rotator_imem_free(int requestor)
239{
240#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
241 if (msm_rotator_dev->imem_owner == requestor) {
242 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
243 mutex_unlock(&msm_rotator_dev->imem_lock);
244 }
245#else
246 if (requestor == JPEG_REQUEST)
247 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
248#endif
249}
250EXPORT_SYMBOL(msm_rotator_imem_free);
251
252static void msm_rotator_imem_clk_work_f(struct work_struct *work)
253{
254#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
255 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
256 if (msm_rotator_dev->imem_clk_state == CLK_EN
257 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700258 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 msm_rotator_dev->imem_clk_state = CLK_DIS;
260 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
261 msm_rotator_dev->imem_clk_state = CLK_DIS;
262 mutex_unlock(&msm_rotator_dev->imem_lock);
263 }
264#endif
265}
266
267/* enable clocks needed by rotator block */
268static void enable_rot_clks(void)
269{
270 if (msm_rotator_dev->regulator)
271 regulator_enable(msm_rotator_dev->regulator);
272 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700273 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700274 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700275 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276}
277
278/* disable clocks needed by rotator block */
279static void disable_rot_clks(void)
280{
281 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700282 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700284 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 if (msm_rotator_dev->regulator)
286 regulator_disable(msm_rotator_dev->regulator);
287}
288
289static void msm_rotator_rot_clk_work_f(struct work_struct *work)
290{
291 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
292 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
293 disable_rot_clks();
294 msm_rotator_dev->rot_clk_state = CLK_DIS;
295 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
296 msm_rotator_dev->rot_clk_state = CLK_DIS;
297 mutex_unlock(&msm_rotator_dev->rotator_lock);
298 }
299}
300
301static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
302{
303 if (msm_rotator_dev->processing) {
304 msm_rotator_dev->processing = 0;
305 wake_up(&msm_rotator_dev->wq);
306 } else
307 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
308
309 return IRQ_HANDLED;
310}
311
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700312static unsigned int tile_size(unsigned int src_width,
313 unsigned int src_height,
314 const struct tile_parm *tp)
315{
316 unsigned int tile_w, tile_h;
317 unsigned int row_num_w, row_num_h;
318 tile_w = tp->width * tp->row_tile_w;
319 tile_h = tp->height * tp->row_tile_h;
320 row_num_w = (src_width + tile_w - 1) / tile_w;
321 row_num_h = (src_height + tile_h - 1) / tile_h;
322 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
323}
324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700325static int get_bpp(int format)
326{
327 switch (format) {
328 case MDP_RGB_565:
329 case MDP_BGR_565:
330 return 2;
331
332 case MDP_XRGB_8888:
333 case MDP_ARGB_8888:
334 case MDP_RGBA_8888:
335 case MDP_BGRA_8888:
336 case MDP_RGBX_8888:
337 return 4;
338
339 case MDP_Y_CBCR_H2V2:
340 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700341 case MDP_Y_CB_CR_H2V2:
342 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530343 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344 case MDP_Y_CRCB_H2V2_TILE:
345 case MDP_Y_CBCR_H2V2_TILE:
346 return 1;
347
348 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700349 case MDP_YCBCR_H1V1:
350 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 return 3;
352
353 case MDP_YCRYCB_H2V1:
354 return 2;/* YCrYCb interleave */
355
356 case MDP_Y_CRCB_H2V1:
357 case MDP_Y_CBCR_H2V1:
358 return 1;
359
360 default:
361 return -1;
362 }
363
364}
365
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700366static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
367 struct msm_rotator_mem_planes *p)
368{
369 /*
370 * each row of samsung tile consists of two tiles in height
371 * and two tiles in width which means width should align to
372 * 64 x 2 bytes and height should align to 32 x 2 bytes.
373 * video decoder generate two tiles in width and one tile
374 * in height which ends up height align to 32 X 1 bytes.
375 */
376 const struct tile_parm tile = {64, 32, 2, 1};
377 int i;
378
379 if (p == NULL)
380 return -EINVAL;
381
382 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
383 return -ERANGE;
384
385 memset(p, 0, sizeof(*p));
386
387 switch (format) {
388 case MDP_XRGB_8888:
389 case MDP_ARGB_8888:
390 case MDP_RGBA_8888:
391 case MDP_BGRA_8888:
392 case MDP_RGBX_8888:
393 case MDP_RGB_888:
394 case MDP_RGB_565:
395 case MDP_BGR_565:
396 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700397 case MDP_YCBCR_H1V1:
398 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700399 p->num_planes = 1;
400 p->plane_size[0] = w * h * get_bpp(format);
401 break;
402 case MDP_Y_CRCB_H2V1:
403 case MDP_Y_CBCR_H2V1:
404 p->num_planes = 2;
405 p->plane_size[0] = w * h;
406 p->plane_size[1] = w * h;
407 break;
408 case MDP_Y_CBCR_H2V2:
409 case MDP_Y_CRCB_H2V2:
410 p->num_planes = 2;
411 p->plane_size[0] = w * h;
412 p->plane_size[1] = w * h / 2;
413 break;
414 case MDP_Y_CRCB_H2V2_TILE:
415 case MDP_Y_CBCR_H2V2_TILE:
416 p->num_planes = 2;
417 p->plane_size[0] = tile_size(w, h, &tile);
418 p->plane_size[1] = tile_size(w, h/2, &tile);
419 break;
420 case MDP_Y_CB_CR_H2V2:
421 case MDP_Y_CR_CB_H2V2:
422 p->num_planes = 3;
423 p->plane_size[0] = w * h;
424 p->plane_size[1] = (w / 2) * (h / 2);
425 p->plane_size[2] = (w / 2) * (h / 2);
426 break;
427 case MDP_Y_CR_CB_GH2V2:
428 p->num_planes = 3;
429 p->plane_size[0] = ALIGN(w, 16) * h;
430 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
431 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
432 break;
433 default:
434 return -EINVAL;
435 }
436
437 for (i = 0; i < p->num_planes; i++)
438 p->total_size += p->plane_size[i];
439
440 return 0;
441}
442
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
444 unsigned int in_paddr,
445 unsigned int out_paddr,
446 unsigned int use_imem,
447 int new_session,
448 unsigned int in_chroma_paddr,
449 unsigned int out_chroma_paddr)
450{
451 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700452
453 if (info->src.format != info->dst.format)
454 return -EINVAL;
455
456 bpp = get_bpp(info->src.format);
457 if (bpp < 0)
458 return -ENOTTY;
459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700460 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700461 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 iowrite32(out_paddr +
463 ((info->dst_y * info->dst.width) + info->dst_x),
464 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700465 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700466 ((info->dst_y * info->dst.width) + info->dst_x),
467 MSM_ROTATOR_OUTP1_ADDR);
468
469 if (new_session) {
470 iowrite32(info->src.width |
471 info->src.width << 16,
472 MSM_ROTATOR_SRC_YSTRIDE1);
473 if (info->rotations & MDP_ROT_90)
474 iowrite32(info->dst.width |
475 info->dst.width*2 << 16,
476 MSM_ROTATOR_OUT_YSTRIDE1);
477 else
478 iowrite32(info->dst.width |
479 info->dst.width << 16,
480 MSM_ROTATOR_OUT_YSTRIDE1);
481 if (info->src.format == MDP_Y_CBCR_H2V1) {
482 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
483 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
484 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
485 MSM_ROTATOR_OUT_PACK_PATTERN1);
486 } else {
487 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
488 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
489 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
490 MSM_ROTATOR_OUT_PACK_PATTERN1);
491 }
492 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
493 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700494 1 << 8 | /* ROT_EN */
495 info->downscale_ratio << 2 | /* downscale v ratio */
496 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 MSM_ROTATOR_SUB_BLOCK_CFG);
498 iowrite32(0 << 29 | /* frame format 0 = linear */
499 (use_imem ? 0 : 1) << 22 | /* tile size */
500 2 << 19 | /* fetch planes 2 = pseudo */
501 0 << 18 | /* unpack align */
502 1 << 17 | /* unpack tight */
503 1 << 13 | /* unpack count 0=1 component */
504 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
505 0 << 8 | /* has alpha */
506 0 << 6 | /* alpha bits 3=8bits */
507 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
508 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
509 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
510 MSM_ROTATOR_SRC_FORMAT);
511 }
512
513 return 0;
514}
515
516static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
517 unsigned int in_paddr,
518 unsigned int out_paddr,
519 unsigned int use_imem,
520 int new_session,
521 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700522 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700523 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700524{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700525 uint32_t dst_format;
526 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700527
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700528 switch (info->src.format) {
529 case MDP_Y_CRCB_H2V2_TILE:
530 is_tile = 1;
531 case MDP_Y_CR_CB_H2V2:
532 case MDP_Y_CR_CB_GH2V2:
533 case MDP_Y_CRCB_H2V2:
534 dst_format = MDP_Y_CRCB_H2V2;
535 break;
536 case MDP_Y_CBCR_H2V2_TILE:
537 is_tile = 1;
538 case MDP_Y_CB_CR_H2V2:
539 case MDP_Y_CBCR_H2V2:
540 dst_format = MDP_Y_CBCR_H2V2;
541 break;
542 default:
543 return -EINVAL;
544 }
545 if (info->dst.format != dst_format)
546 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700547
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800548 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530549 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
550 info->src.format == MDP_Y_CR_CB_GH2V2) &&
551 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800552 swap(in_chroma_paddr, in_chroma2_paddr);
553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700555 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
556 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
557
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700558 iowrite32(out_paddr +
559 ((info->dst_y * info->dst.width) + info->dst_x),
560 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700561 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562 ((info->dst_y * info->dst.width)/2 + info->dst_x),
563 MSM_ROTATOR_OUTP1_ADDR);
564
565 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700566 if (in_chroma2_paddr) {
567 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530568 iowrite32(ALIGN(info->src.width, 16) |
569 ALIGN((info->src.width / 2), 16) << 16,
570 MSM_ROTATOR_SRC_YSTRIDE1);
571 iowrite32(ALIGN((info->src.width / 2), 16),
572 MSM_ROTATOR_SRC_YSTRIDE2);
573 } else {
574 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700575 (info->src.width / 2) << 16,
576 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530577 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700578 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530579 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700580 } else {
581 iowrite32(info->src.width |
582 info->src.width << 16,
583 MSM_ROTATOR_SRC_YSTRIDE1);
584 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700586 info->dst.width << 16,
587 MSM_ROTATOR_OUT_YSTRIDE1);
588
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700589 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
591 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
592 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
593 MSM_ROTATOR_OUT_PACK_PATTERN1);
594 } else {
595 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
596 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
597 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
598 MSM_ROTATOR_OUT_PACK_PATTERN1);
599 }
600 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
601 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700602 1 << 8 | /* ROT_EN */
603 info->downscale_ratio << 2 | /* downscale v ratio */
604 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700606
607 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700608 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700609 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 0 << 18 | /* unpack align */
611 1 << 17 | /* unpack tight */
612 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700613 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700614 0 << 8 | /* has alpha */
615 0 << 6 | /* alpha bits 3=8bits */
616 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
617 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
618 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
619 MSM_ROTATOR_SRC_FORMAT);
620 }
621 return 0;
622}
623
624static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
625 unsigned int in_paddr,
626 unsigned int out_paddr,
627 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530628 int new_session,
629 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630{
631 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530632 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633
Mayank Chopra732dcd62012-01-09 20:53:39 +0530634 if (info->src.format == MDP_YCRYCB_H2V1)
635 dst_format = MDP_Y_CRCB_H2V1;
636 else
637 return -EINVAL;
638
639 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 return -EINVAL;
641
642 bpp = get_bpp(info->src.format);
643 if (bpp < 0)
644 return -ENOTTY;
645
646 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
647 iowrite32(out_paddr +
648 ((info->dst_y * info->dst.width) + info->dst_x),
649 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530650 iowrite32(out_chroma_paddr +
651 ((info->dst_y * info->dst.width)/2 + info->dst_x),
652 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653
654 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530655 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700656 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530657 if (info->rotations & MDP_ROT_90)
658 iowrite32(info->dst.width |
659 (info->dst.width*2) << 16,
660 MSM_ROTATOR_OUT_YSTRIDE1);
661 else
662 iowrite32(info->dst.width |
663 (info->dst.width) << 16,
664 MSM_ROTATOR_OUT_YSTRIDE1);
665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
667 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530668 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700669 MSM_ROTATOR_OUT_PACK_PATTERN1);
670 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
671 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700672 1 << 8 | /* ROT_EN */
673 info->downscale_ratio << 2 | /* downscale v ratio */
674 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 MSM_ROTATOR_SUB_BLOCK_CFG);
676 iowrite32(0 << 29 | /* frame format 0 = linear */
677 (use_imem ? 0 : 1) << 22 | /* tile size */
678 0 << 19 | /* fetch planes 0=interleaved */
679 0 << 18 | /* unpack align */
680 1 << 17 | /* unpack tight */
681 3 << 13 | /* unpack count 0=1 component */
682 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
683 0 << 8 | /* has alpha */
684 0 << 6 | /* alpha bits 3=8bits */
685 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
686 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
687 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
688 MSM_ROTATOR_SRC_FORMAT);
689 }
690
691 return 0;
692}
693
694static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
695 unsigned int in_paddr,
696 unsigned int out_paddr,
697 unsigned int use_imem,
698 int new_session)
699{
700 int bpp, abits, rbits, gbits, bbits;
701
702 if (info->src.format != info->dst.format)
703 return -EINVAL;
704
705 bpp = get_bpp(info->src.format);
706 if (bpp < 0)
707 return -ENOTTY;
708
709 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
710 iowrite32(out_paddr +
711 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
712 MSM_ROTATOR_OUTP0_ADDR);
713
714 if (new_session) {
715 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
716 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
717 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
718 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700719 1 << 8 | /* ROT_EN */
720 info->downscale_ratio << 2 | /* downscale v ratio */
721 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700722 MSM_ROTATOR_SUB_BLOCK_CFG);
723 switch (info->src.format) {
724 case MDP_RGB_565:
725 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
726 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
727 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
728 MSM_ROTATOR_OUT_PACK_PATTERN1);
729 abits = 0;
730 rbits = COMPONENT_5BITS;
731 gbits = COMPONENT_6BITS;
732 bbits = COMPONENT_5BITS;
733 break;
734
735 case MDP_BGR_565:
736 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
737 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
738 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
739 MSM_ROTATOR_OUT_PACK_PATTERN1);
740 abits = 0;
741 rbits = COMPONENT_5BITS;
742 gbits = COMPONENT_6BITS;
743 bbits = COMPONENT_5BITS;
744 break;
745
746 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700747 case MDP_YCBCR_H1V1:
748 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700749 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
750 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
751 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
752 MSM_ROTATOR_OUT_PACK_PATTERN1);
753 abits = 0;
754 rbits = COMPONENT_8BITS;
755 gbits = COMPONENT_8BITS;
756 bbits = COMPONENT_8BITS;
757 break;
758
759 case MDP_ARGB_8888:
760 case MDP_RGBA_8888:
761 case MDP_XRGB_8888:
762 case MDP_RGBX_8888:
763 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
764 CLR_B, 8),
765 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
766 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
767 CLR_B, 8),
768 MSM_ROTATOR_OUT_PACK_PATTERN1);
769 abits = COMPONENT_8BITS;
770 rbits = COMPONENT_8BITS;
771 gbits = COMPONENT_8BITS;
772 bbits = COMPONENT_8BITS;
773 break;
774
775 case MDP_BGRA_8888:
776 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
777 CLR_R, 8),
778 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
779 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
780 CLR_R, 8),
781 MSM_ROTATOR_OUT_PACK_PATTERN1);
782 abits = COMPONENT_8BITS;
783 rbits = COMPONENT_8BITS;
784 gbits = COMPONENT_8BITS;
785 bbits = COMPONENT_8BITS;
786 break;
787
788 default:
789 return -EINVAL;
790 }
791 iowrite32(0 << 29 | /* frame format 0 = linear */
792 (use_imem ? 0 : 1) << 22 | /* tile size */
793 0 << 19 | /* fetch planes 0=interleaved */
794 0 << 18 | /* unpack align */
795 1 << 17 | /* unpack tight */
796 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
797 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
798 (abits ? 1 : 0) << 8 | /* has alpha */
799 abits << 6 | /* alpha bits 3=8bits */
800 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
801 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
802 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
803 MSM_ROTATOR_SRC_FORMAT);
804 }
805
806 return 0;
807}
808
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700809static int get_img(struct msmfb_data *fbd, unsigned char src,
810 unsigned long *start, unsigned long *len, struct file **p_file,
811 int *p_need, struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700812{
813 int ret = 0;
814#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700815 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700816 int put_needed, fb_num;
817#endif
818#ifdef CONFIG_ANDROID_PMEM
819 unsigned long vstart;
820#endif
821
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800822 *p_need = 0;
823
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700824#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700825 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
826 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700827 if (file == NULL) {
828 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700829 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700830 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831
Naseer Ahmed18018602011-10-25 13:32:58 -0700832 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
833 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700834 if (get_fb_phys_info(start, len, fb_num,
835 ROTATOR_SUBSYSTEM_ID)) {
836 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700837 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700838 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700839 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800840 *p_need = put_needed;
841 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700842 } else {
843 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700844 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700845 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700846 if (ret)
847 fput_light(file, put_needed);
848 return ret;
849 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700851
852#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700853 return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
854 len, p_ihdl);
Naseer Ahmed18018602011-10-25 13:32:58 -0700855#endif
856#ifdef CONFIG_ANDROID_PMEM
857 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
858 return 0;
859 else
860 return -ENOMEM;
861#endif
862
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863}
864
Naseer Ahmed18018602011-10-25 13:32:58 -0700865static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
866{
867#ifdef CONFIG_ANDROID_PMEM
868 if (p_file != NULL)
869 put_pmem_file(p_file);
870#endif
871#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700872 if (!IS_ERR_OR_NULL(p_ihdl)) {
873 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
874 ion_unmap_iommu(msm_rotator_dev->client,
875 p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
876
Naseer Ahmed18018602011-10-25 13:32:58 -0700877 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700878 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700879#endif
880}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881static int msm_rotator_do_rotate(unsigned long arg)
882{
Naseer Ahmed18018602011-10-25 13:32:58 -0700883 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700884 struct msm_rotator_data_info info;
885 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700886 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700887 int use_imem = 0, rc = 0, s;
888 struct file *srcp0_file = NULL, *dstp0_file = NULL;
889 struct file *srcp1_file = NULL, *dstp1_file = NULL;
890 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
891 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800892 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700893 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700894 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700895 struct msm_rotator_img_info *img_info;
896 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700897
898 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
899 return -EFAULT;
900
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 mutex_lock(&msm_rotator_dev->rotator_lock);
902 for (s = 0; s < MAX_SESSIONS; s++)
903 if ((msm_rotator_dev->img_info[s] != NULL) &&
904 (info.session_id ==
905 (unsigned int)msm_rotator_dev->img_info[s]
906 ))
907 break;
908
909 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700910 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 __func__, s);
912 rc = -EINVAL;
913 goto do_rotate_unlock_mutex;
914 }
915
916 if (msm_rotator_dev->img_info[s]->enable == 0) {
917 dev_dbg(msm_rotator_dev->device,
918 "%s() : Session_id %d not enabled \n",
919 __func__, s);
920 rc = -EINVAL;
921 goto do_rotate_unlock_mutex;
922 }
923
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700924 img_info = msm_rotator_dev->img_info[s];
925 if (msm_rotator_get_plane_sizes(img_info->src.format,
926 img_info->src.width,
927 img_info->src.height,
928 &src_planes)) {
929 pr_err("%s: invalid src format\n", __func__);
930 rc = -EINVAL;
931 goto do_rotate_unlock_mutex;
932 }
933 if (msm_rotator_get_plane_sizes(img_info->dst.format,
934 img_info->dst.width,
935 img_info->dst.height,
936 &dst_planes)) {
937 pr_err("%s: invalid dst format\n", __func__);
938 rc = -EINVAL;
939 goto do_rotate_unlock_mutex;
940 }
941
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700942 rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
943 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
944 &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700945 if (rc) {
946 pr_err("%s: in get_img() failed id=0x%08x\n",
947 DRIVER_NAME, info.src.memory_id);
948 goto do_rotate_unlock_mutex;
949 }
950
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700951 rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
952 (unsigned long *)&dst_len, &dstp0_file, &p_need,
953 &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700954 if (rc) {
955 pr_err("%s: out get_img() failed id=0x%08x\n",
956 DRIVER_NAME, info.dst.memory_id);
957 goto do_rotate_unlock_mutex;
958 }
959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960 format = msm_rotator_dev->img_info[s]->src.format;
961 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700962 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
963 (src_planes.num_planes == 2)) {
964 if (checkoffset(info.src.offset,
965 src_planes.plane_size[0],
966 src_len)) {
967 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
968 __func__, src_len, info.src.offset);
969 rc = -ERANGE;
970 goto do_rotate_unlock_mutex;
971 }
972 if (checkoffset(info.dst.offset,
973 dst_planes.plane_size[0],
974 dst_len)) {
975 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
976 __func__, dst_len, info.dst.offset);
977 rc = -ERANGE;
978 goto do_rotate_unlock_mutex;
979 }
980
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700981 rc = get_img(&info.src_chroma, 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700982 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800983 (unsigned long *)&src_len, &srcp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700984 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700986 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 DRIVER_NAME, info.src_chroma.memory_id);
988 goto do_rotate_unlock_mutex;
989 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700991 rc = get_img(&info.dst_chroma, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800993 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700994 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700996 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700998 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001000
1001 if (checkoffset(info.src_chroma.offset,
1002 src_planes.plane_size[1],
1003 src_len)) {
1004 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1005 __func__, src_len, info.src_chroma.offset);
1006 rc = -ERANGE;
1007 goto do_rotate_unlock_mutex;
1008 }
1009
1010 if (checkoffset(info.dst_chroma.offset,
1011 src_planes.plane_size[1],
1012 dst_len)) {
1013 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1014 __func__, dst_len, info.dst_chroma.offset);
1015 rc = -ERANGE;
1016 goto do_rotate_unlock_mutex;
1017 }
1018
1019 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001021 } else {
1022 if (checkoffset(info.src.offset,
1023 src_planes.total_size,
1024 src_len)) {
1025 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1026 __func__, src_len, info.src.offset);
1027 rc = -ERANGE;
1028 goto do_rotate_unlock_mutex;
1029 }
1030 if (checkoffset(info.dst.offset,
1031 dst_planes.total_size,
1032 dst_len)) {
1033 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1034 __func__, dst_len, info.dst.offset);
1035 rc = -ERANGE;
1036 goto do_rotate_unlock_mutex;
1037 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 }
1039
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001040 in_paddr += info.src.offset;
1041 out_paddr += info.dst.offset;
1042
1043 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1044 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1045 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1046 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1047 if (src_planes.num_planes >= 3)
1048 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1049
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1051 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1052 enable_rot_clks();
1053 msm_rotator_dev->rot_clk_state = CLK_EN;
1054 }
1055 enable_irq(msm_rotator_dev->irq);
1056
1057#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1058 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1059#else
1060 use_imem = 0;
1061#endif
1062 /*
1063 * workaround for a hardware bug. rotator hardware hangs when we
1064 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1065 * temporary fix use 0x42 for BURST_SIZE when imem used.
1066 */
1067 if (use_imem)
1068 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1069
1070 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1071 << 16) |
1072 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1073 MSM_ROTATOR_SRC_SIZE);
1074 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1075 << 16) |
1076 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1077 MSM_ROTATOR_SRC_XY);
1078 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1079 << 16) |
1080 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1081 MSM_ROTATOR_SRC_IMAGE_SIZE);
1082
1083 switch (format) {
1084 case MDP_RGB_565:
1085 case MDP_BGR_565:
1086 case MDP_RGB_888:
1087 case MDP_ARGB_8888:
1088 case MDP_RGBA_8888:
1089 case MDP_XRGB_8888:
1090 case MDP_BGRA_8888:
1091 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001092 case MDP_YCBCR_H1V1:
1093 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001094 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1095 in_paddr, out_paddr,
1096 use_imem,
1097 msm_rotator_dev->last_session_idx
1098 != s);
1099 break;
1100 case MDP_Y_CBCR_H2V2:
1101 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001102 case MDP_Y_CB_CR_H2V2:
1103 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301104 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001105 case MDP_Y_CRCB_H2V2_TILE:
1106 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001107 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1108 in_paddr, out_paddr, use_imem,
1109 msm_rotator_dev->last_session_idx
1110 != s,
1111 in_chroma_paddr,
1112 out_chroma_paddr,
1113 in_chroma2_paddr);
1114 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001115 case MDP_Y_CBCR_H2V1:
1116 case MDP_Y_CRCB_H2V1:
1117 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1118 in_paddr, out_paddr, use_imem,
1119 msm_rotator_dev->last_session_idx
1120 != s,
1121 in_chroma_paddr,
1122 out_chroma_paddr);
1123 break;
1124 case MDP_YCRYCB_H2V1:
1125 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1126 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301127 msm_rotator_dev->last_session_idx != s,
1128 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 break;
1130 default:
1131 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001132 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001133 goto do_rotate_exit;
1134 }
1135
1136 if (rc != 0) {
1137 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001138 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 goto do_rotate_exit;
1140 }
1141
1142 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1143
1144 msm_rotator_dev->processing = 1;
1145 iowrite32(0x1, MSM_ROTATOR_START);
1146
1147 wait_event(msm_rotator_dev->wq,
1148 (msm_rotator_dev->processing == 0));
1149 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001150 if ((status & 0x03) != 0x01) {
1151 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1152 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001154 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001155 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1156 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1157
1158do_rotate_exit:
1159 disable_irq(msm_rotator_dev->irq);
1160#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1161 msm_rotator_imem_free(ROTATOR_REQUEST);
1162#endif
1163 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001164do_rotate_unlock_mutex:
Naseer Ahmed18018602011-10-25 13:32:58 -07001165 put_img(dstp1_file, dstp1_ihdl);
1166 put_img(srcp1_file, srcp1_ihdl);
1167 put_img(dstp0_file, dstp0_ihdl);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001168
1169 /* only source may use frame buffer */
1170 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1171 fput_light(srcp0_file, ps0_need);
1172 else
1173 put_img(srcp0_file, srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001174 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001175 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1176 __func__, rc);
1177 return rc;
1178}
1179
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001180static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1181{
1182 u32 perf_level;
1183
1184 if (is_rgb)
1185 perf_level = 1;
1186 else if (wh <= (640 * 480))
1187 perf_level = 2;
1188 else if (wh <= (736 * 1280))
1189 perf_level = 3;
1190 else
1191 perf_level = 4;
1192
1193#ifdef CONFIG_MSM_BUS_SCALING
1194 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1195 perf_level);
1196#endif
1197
1198}
1199
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001200static int msm_rotator_start(unsigned long arg,
1201 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202{
1203 struct msm_rotator_img_info info;
1204 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001205 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001206 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001207 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208
1209 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1210 return -EFAULT;
1211
1212 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1213 (info.src.height > MSM_ROTATOR_MAX_H) ||
1214 (info.src.width > MSM_ROTATOR_MAX_W) ||
1215 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1216 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001217 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1218 pr_err("%s: Invalid parameters\n", __func__);
1219 return -EINVAL;
1220 }
1221
1222 if (info.rotations & MDP_ROT_90) {
1223 dst_w = info.src_rect.h >> info.downscale_ratio;
1224 dst_h = info.src_rect.w >> info.downscale_ratio;
1225 } else {
1226 dst_w = info.src_rect.w >> info.downscale_ratio;
1227 dst_h = info.src_rect.h >> info.downscale_ratio;
1228 }
1229
1230 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001231 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1232 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001233 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1234 pr_err("%s: Invalid src or dst rect\n", __func__);
1235 return -ERANGE;
1236 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237
1238 switch (info.src.format) {
1239 case MDP_RGB_565:
1240 case MDP_BGR_565:
1241 case MDP_RGB_888:
1242 case MDP_ARGB_8888:
1243 case MDP_RGBA_8888:
1244 case MDP_XRGB_8888:
1245 case MDP_RGBX_8888:
1246 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001247 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301248 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001249 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001250 case MDP_Y_CBCR_H2V2:
1251 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301252 case MDP_Y_CBCR_H2V1:
1253 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001254 case MDP_YCBCR_H1V1:
1255 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301256 info.dst.format = info.src.format;
1257 break;
1258 case MDP_YCRYCB_H2V1:
1259 info.dst.format = MDP_Y_CRCB_H2V1;
1260 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001261 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301262 case MDP_Y_CBCR_H2V2_TILE:
1263 info.dst.format = MDP_Y_CBCR_H2V2;
1264 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001265 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301266 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001267 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301268 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269 break;
1270 default:
1271 return -EINVAL;
1272 }
1273
1274 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001275
1276 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1277
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 for (s = 0; s < MAX_SESSIONS; s++) {
1279 if ((msm_rotator_dev->img_info[s] != NULL) &&
1280 (info.session_id ==
1281 (unsigned int)msm_rotator_dev->img_info[s]
1282 )) {
1283 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001284 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001285
1286 if (msm_rotator_dev->last_session_idx == s)
1287 msm_rotator_dev->last_session_idx =
1288 INVALID_SESSION;
1289 break;
1290 }
1291
1292 if ((msm_rotator_dev->img_info[s] == NULL) &&
1293 (first_free_index ==
1294 INVALID_SESSION))
1295 first_free_index = s;
1296 }
1297
1298 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1299 /* allocate a session id */
1300 msm_rotator_dev->img_info[first_free_index] =
1301 kzalloc(sizeof(struct msm_rotator_img_info),
1302 GFP_KERNEL);
1303 if (!msm_rotator_dev->img_info[first_free_index]) {
1304 printk(KERN_ERR "%s : unable to alloc mem\n",
1305 __func__);
1306 rc = -ENOMEM;
1307 goto rotator_start_exit;
1308 }
1309 info.session_id = (unsigned int)
1310 msm_rotator_dev->img_info[first_free_index];
1311 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001312 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 } else if (s == MAX_SESSIONS) {
1314 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1315 __func__);
1316 rc = -EBUSY;
1317 }
1318
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001319 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1320 rc = -EFAULT;
1321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322rotator_start_exit:
1323 mutex_unlock(&msm_rotator_dev->rotator_lock);
1324
1325 return rc;
1326}
1327
1328static int msm_rotator_finish(unsigned long arg)
1329{
1330 int rc = 0;
1331 int s;
1332 unsigned int session_id;
1333
1334 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1335 return -EFAULT;
1336
1337 mutex_lock(&msm_rotator_dev->rotator_lock);
1338 for (s = 0; s < MAX_SESSIONS; s++) {
1339 if ((msm_rotator_dev->img_info[s] != NULL) &&
1340 (session_id ==
1341 (unsigned int)msm_rotator_dev->img_info[s])) {
1342 if (msm_rotator_dev->last_session_idx == s)
1343 msm_rotator_dev->last_session_idx =
1344 INVALID_SESSION;
1345 kfree(msm_rotator_dev->img_info[s]);
1346 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001347 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001348 break;
1349 }
1350 }
1351
1352 if (s == MAX_SESSIONS)
1353 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001354#ifdef CONFIG_MSM_BUS_SCALING
1355 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1356 0);
1357#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001358 mutex_unlock(&msm_rotator_dev->rotator_lock);
1359 return rc;
1360}
1361
1362static int
1363msm_rotator_open(struct inode *inode, struct file *filp)
1364{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001365 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366 int i;
1367
1368 if (filp->private_data)
1369 return -EBUSY;
1370
1371 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001372 for (i = 0; i < MAX_SESSIONS; i++) {
1373 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 break;
1375 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001376
1377 if (i == MAX_SESSIONS) {
1378 mutex_unlock(&msm_rotator_dev->rotator_lock);
1379 return -EBUSY;
1380 }
1381
1382 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1383 if (tmp->pid == current->pid) {
1384 fd_info = tmp;
1385 break;
1386 }
1387 }
1388
1389 if (!fd_info) {
1390 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1391 if (!fd_info) {
1392 mutex_unlock(&msm_rotator_dev->rotator_lock);
1393 pr_err("%s: insufficient memory to alloc resources\n",
1394 __func__);
1395 return -ENOMEM;
1396 }
1397 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1398 fd_info->pid = current->pid;
1399 }
1400 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001401 mutex_unlock(&msm_rotator_dev->rotator_lock);
1402
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001403 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001404
1405 return 0;
1406}
1407
1408static int
1409msm_rotator_close(struct inode *inode, struct file *filp)
1410{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001411 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001414 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1415
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001416 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001417 if (--fd_info->ref_cnt > 0) {
1418 mutex_unlock(&msm_rotator_dev->rotator_lock);
1419 return 0;
1420 }
1421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422 for (s = 0; s < MAX_SESSIONS; s++) {
1423 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001424 msm_rotator_dev->fd_info[s] == fd_info) {
1425 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1426 __func__, msm_rotator_dev->img_info[s],
1427 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 kfree(msm_rotator_dev->img_info[s]);
1429 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001430 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 if (msm_rotator_dev->last_session_idx == s)
1432 msm_rotator_dev->last_session_idx =
1433 INVALID_SESSION;
1434 }
1435 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001436 list_del(&fd_info->list);
1437 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001438 mutex_unlock(&msm_rotator_dev->rotator_lock);
1439
1440 return 0;
1441}
1442
1443static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1444 unsigned long arg)
1445{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001446 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001447
1448 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1449 return -ENOTTY;
1450
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001451 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452
1453 switch (cmd) {
1454 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001455 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 case MSM_ROTATOR_IOCTL_ROTATE:
1457 return msm_rotator_do_rotate(arg);
1458 case MSM_ROTATOR_IOCTL_FINISH:
1459 return msm_rotator_finish(arg);
1460
1461 default:
1462 dev_dbg(msm_rotator_dev->device,
1463 "unexpected IOCTL %d\n", cmd);
1464 return -ENOTTY;
1465 }
1466}
1467
1468static const struct file_operations msm_rotator_fops = {
1469 .owner = THIS_MODULE,
1470 .open = msm_rotator_open,
1471 .release = msm_rotator_close,
1472 .unlocked_ioctl = msm_rotator_ioctl,
1473};
1474
1475static int __devinit msm_rotator_probe(struct platform_device *pdev)
1476{
1477 int rc = 0;
1478 struct resource *res;
1479 struct msm_rotator_platform_data *pdata = NULL;
1480 int i, number_of_clks;
1481 uint32_t ver;
1482
1483 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1484 if (!msm_rotator_dev) {
1485 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1486 __func__);
1487 return -ENOMEM;
1488 }
1489 for (i = 0; i < MAX_SESSIONS; i++)
1490 msm_rotator_dev->img_info[i] = NULL;
1491 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1492
1493 pdata = pdev->dev.platform_data;
1494 number_of_clks = pdata->number_of_clocks;
1495
1496 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1497 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001498 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499 msm_rotator_dev->imem_clk_state = CLK_DIS;
1500 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1501 msm_rotator_imem_clk_work_f);
1502 msm_rotator_dev->imem_clk = NULL;
1503 msm_rotator_dev->pdev = pdev;
1504
1505 msm_rotator_dev->core_clk = NULL;
1506 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001507
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001508#ifdef CONFIG_MSM_BUS_SCALING
1509 if (!msm_rotator_dev->bus_client_handle && pdata &&
1510 pdata->bus_scale_table) {
1511 msm_rotator_dev->bus_client_handle =
1512 msm_bus_scale_register_client(
1513 pdata->bus_scale_table);
1514 if (!msm_rotator_dev->bus_client_handle) {
1515 pr_err("%s not able to get bus scale handle\n",
1516 __func__);
1517 }
1518 }
1519#endif
1520
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001521 for (i = 0; i < number_of_clks; i++) {
1522 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1523 msm_rotator_dev->imem_clk =
1524 clk_get(&msm_rotator_dev->pdev->dev,
1525 pdata->rotator_clks[i].clk_name);
1526 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1527 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1528 msm_rotator_dev->imem_clk = NULL;
1529 printk(KERN_ERR "%s: cannot get imem_clk "
1530 "rc=%d\n", DRIVER_NAME, rc);
1531 goto error_imem_clk;
1532 }
1533 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001534 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 pdata->rotator_clks[i].clk_rate);
1536 }
1537 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1538 msm_rotator_dev->pclk =
1539 clk_get(&msm_rotator_dev->pdev->dev,
1540 pdata->rotator_clks[i].clk_name);
1541 if (IS_ERR(msm_rotator_dev->pclk)) {
1542 rc = PTR_ERR(msm_rotator_dev->pclk);
1543 msm_rotator_dev->pclk = NULL;
1544 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1545 DRIVER_NAME, rc);
1546 goto error_pclk;
1547 }
1548
1549 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001550 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 pdata->rotator_clks[i].clk_rate);
1552 }
1553
1554 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1555 msm_rotator_dev->core_clk =
1556 clk_get(&msm_rotator_dev->pdev->dev,
1557 pdata->rotator_clks[i].clk_name);
1558 if (IS_ERR(msm_rotator_dev->core_clk)) {
1559 rc = PTR_ERR(msm_rotator_dev->core_clk);
1560 msm_rotator_dev->core_clk = NULL;
1561 printk(KERN_ERR "%s: cannot get core clk "
1562 "rc=%d\n", DRIVER_NAME, rc);
1563 goto error_core_clk;
1564 }
1565
1566 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001567 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001568 pdata->rotator_clks[i].clk_rate);
1569 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 }
1571
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001572 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1573 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 if (IS_ERR(msm_rotator_dev->regulator))
1575 msm_rotator_dev->regulator = NULL;
1576
1577 msm_rotator_dev->rot_clk_state = CLK_DIS;
1578 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1579 msm_rotator_rot_clk_work_f);
1580
1581 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001582#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1583 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1584#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 platform_set_drvdata(pdev, msm_rotator_dev);
1586
1587
1588 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1589 if (!res) {
1590 printk(KERN_ALERT
1591 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1592 rc = -ENODEV;
1593 goto error_get_resource;
1594 }
1595 msm_rotator_dev->io_base = ioremap(res->start,
1596 resource_size(res));
1597
1598#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1599 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001600 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601#endif
1602 enable_rot_clks();
1603 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1604 disable_rot_clks();
1605
1606#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1607 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001608 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001609#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001610 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301611 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001612 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001613
Mayank Chopra012a8e72012-04-11 10:41:13 +05301614 rotator_hw_revision = ver;
1615 rotator_hw_revision >>= 16; /* bit 31:16 */
1616 rotator_hw_revision &= 0xff;
1617
1618 pr_info("%s: rotator_hw_revision=%x\n",
1619 __func__, rotator_hw_revision);
1620
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001621 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1622 if (msm_rotator_dev->irq < 0) {
1623 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1624 DRIVER_NAME);
1625 rc = -ENODEV;
1626 goto error_get_irq;
1627 }
1628 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1629 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1630 if (rc) {
1631 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1632 goto error_get_irq;
1633 }
1634 /* we enable the IRQ when we need it in the ioctl */
1635 disable_irq(msm_rotator_dev->irq);
1636
1637 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1638 if (rc < 0) {
1639 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1640 __func__, rc);
1641 goto error_get_irq;
1642 }
1643
1644 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1645 if (IS_ERR(msm_rotator_dev->class)) {
1646 rc = PTR_ERR(msm_rotator_dev->class);
1647 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1648 DRIVER_NAME, rc);
1649 goto error_class_create;
1650 }
1651
1652 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1653 msm_rotator_dev->dev_num, NULL,
1654 DRIVER_NAME);
1655 if (IS_ERR(msm_rotator_dev->device)) {
1656 rc = PTR_ERR(msm_rotator_dev->device);
1657 printk(KERN_ERR "%s: device_create failed %d\n",
1658 DRIVER_NAME, rc);
1659 goto error_class_device_create;
1660 }
1661
1662 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1663 rc = cdev_add(&msm_rotator_dev->cdev,
1664 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1665 1);
1666 if (rc < 0) {
1667 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1668 goto error_cdev_add;
1669 }
1670
1671 init_waitqueue_head(&msm_rotator_dev->wq);
1672
1673 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1674 return rc;
1675
1676error_cdev_add:
1677 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1678error_class_device_create:
1679 class_destroy(msm_rotator_dev->class);
1680error_class_create:
1681 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1682error_get_irq:
1683 iounmap(msm_rotator_dev->io_base);
1684error_get_resource:
1685 mutex_destroy(&msm_rotator_dev->rotator_lock);
1686 if (msm_rotator_dev->regulator)
1687 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 clk_put(msm_rotator_dev->core_clk);
1689error_core_clk:
1690 clk_put(msm_rotator_dev->pclk);
1691error_pclk:
1692 if (msm_rotator_dev->imem_clk)
1693 clk_put(msm_rotator_dev->imem_clk);
1694error_imem_clk:
1695 mutex_destroy(&msm_rotator_dev->imem_lock);
1696 kfree(msm_rotator_dev);
1697 return rc;
1698}
1699
1700static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1701{
1702 int i;
1703
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001704#ifdef CONFIG_MSM_BUS_SCALING
1705 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1706#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 free_irq(msm_rotator_dev->irq, NULL);
1708 mutex_destroy(&msm_rotator_dev->rotator_lock);
1709 cdev_del(&msm_rotator_dev->cdev);
1710 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1711 class_destroy(msm_rotator_dev->class);
1712 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1713 iounmap(msm_rotator_dev->io_base);
1714 if (msm_rotator_dev->imem_clk) {
1715 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001716 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001717 clk_put(msm_rotator_dev->imem_clk);
1718 msm_rotator_dev->imem_clk = NULL;
1719 }
1720 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1721 disable_rot_clks();
1722 clk_put(msm_rotator_dev->core_clk);
1723 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001724 if (msm_rotator_dev->regulator)
1725 regulator_put(msm_rotator_dev->regulator);
1726 msm_rotator_dev->core_clk = NULL;
1727 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001728 mutex_destroy(&msm_rotator_dev->imem_lock);
1729 for (i = 0; i < MAX_SESSIONS; i++)
1730 if (msm_rotator_dev->img_info[i] != NULL)
1731 kfree(msm_rotator_dev->img_info[i]);
1732 kfree(msm_rotator_dev);
1733 return 0;
1734}
1735
1736#ifdef CONFIG_PM
1737static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1738{
1739 mutex_lock(&msm_rotator_dev->imem_lock);
1740 if (msm_rotator_dev->imem_clk_state == CLK_EN
1741 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001742 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1744 }
1745 mutex_unlock(&msm_rotator_dev->imem_lock);
1746 mutex_lock(&msm_rotator_dev->rotator_lock);
1747 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1748 disable_rot_clks();
1749 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1750 }
1751 mutex_unlock(&msm_rotator_dev->rotator_lock);
1752 return 0;
1753}
1754
1755static int msm_rotator_resume(struct platform_device *dev)
1756{
1757 mutex_lock(&msm_rotator_dev->imem_lock);
1758 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1759 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001760 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001761 msm_rotator_dev->imem_clk_state = CLK_EN;
1762 }
1763 mutex_unlock(&msm_rotator_dev->imem_lock);
1764 mutex_lock(&msm_rotator_dev->rotator_lock);
1765 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1766 enable_rot_clks();
1767 msm_rotator_dev->rot_clk_state = CLK_EN;
1768 }
1769 mutex_unlock(&msm_rotator_dev->rotator_lock);
1770 return 0;
1771}
1772#endif
1773
1774static struct platform_driver msm_rotator_platform_driver = {
1775 .probe = msm_rotator_probe,
1776 .remove = __devexit_p(msm_rotator_remove),
1777#ifdef CONFIG_PM
1778 .suspend = msm_rotator_suspend,
1779 .resume = msm_rotator_resume,
1780#endif
1781 .driver = {
1782 .owner = THIS_MODULE,
1783 .name = DRIVER_NAME
1784 }
1785};
1786
1787static int __init msm_rotator_init(void)
1788{
1789 return platform_driver_register(&msm_rotator_platform_driver);
1790}
1791
1792static void __exit msm_rotator_exit(void)
1793{
1794 return platform_driver_unregister(&msm_rotator_platform_driver);
1795}
1796
1797module_init(msm_rotator_init);
1798module_exit(msm_rotator_exit);
1799
1800MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1801MODULE_VERSION("1.0");
1802MODULE_LICENSE("GPL v2");