blob: 47bc750c2f67efebf93e62f90adc2bf2f8b42552 [file] [log] [blame]
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/platform_device.h>
14#include <linux/cdev.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/uaccess.h>
21#include <linux/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/android_pmem.h>
23#include <linux/msm_rotator.h>
24#include <linux/io.h>
25#include <mach/msm_rotator_imem.h>
26#include <linux/ktime.h>
27#include <linux/workqueue.h>
28#include <linux/file.h>
29#include <linux/major.h>
30#include <linux/regulator/consumer.h>
Naseer Ahmed18018602011-10-25 13:32:58 -070031#include <linux/ion.h>
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080032#ifdef CONFIG_MSM_BUS_SCALING
33#include <mach/msm_bus.h>
34#include <mach/msm_bus_board.h>
35#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070036#include <mach/msm_subsystem_map.h>
37#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#define DRIVER_NAME "msm_rotator"
40
41#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
42#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
43#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
44#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
45#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
46#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
47#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
48#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
49#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
50#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070051#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
53#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
54#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
55#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
56#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
57#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
58#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
59#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070060#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
62#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
63#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
64#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
65
66#define MSM_ROTATOR_MAX_ROT 0x07
67#define MSM_ROTATOR_MAX_H 0x1fff
68#define MSM_ROTATOR_MAX_W 0x1fff
69
70/* from lsb to msb */
71#define GET_PACK_PATTERN(a, x, y, z, bit) \
72 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
73#define CLR_G 0x0
74#define CLR_B 0x1
75#define CLR_R 0x2
76#define CLR_ALPHA 0x3
77
78#define CLR_Y CLR_G
79#define CLR_CB CLR_B
80#define CLR_CR CLR_R
81
82#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
83 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
84 (((r) & MDP_FLIP_UD) ? 4 : 0))
85
86#define IMEM_NO_OWNER -1;
87
88#define MAX_SESSIONS 16
89#define INVALID_SESSION -1
90#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070091#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092
Mayank Chopra012a8e72012-04-11 10:41:13 +053093#define ROTATOR_REVISION_V0 0
94#define ROTATOR_REVISION_V1 1
95#define ROTATOR_REVISION_V2 2
96#define ROTATOR_REVISION_NONE 0xffffffff
97
98uint32_t rotator_hw_revision;
99
100/*
101 * rotator_hw_revision:
102 * 0 == 7x30
103 * 1 == 8x60
104 * 2 == 8960
105 *
106 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107struct tile_parm {
108 unsigned int width; /* tile's width */
109 unsigned int height; /* tile's height */
110 unsigned int row_tile_w; /* tiles per row's width */
111 unsigned int row_tile_h; /* tiles per row's height */
112};
113
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700114struct msm_rotator_mem_planes {
115 unsigned int num_planes;
116 unsigned int plane_size[4];
117 unsigned int total_size;
118};
119
120#define checkoffset(offset, size, max_size) \
121 ((size) > (max_size) || (offset) > ((max_size) - (size)))
122
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700123struct msm_rotator_fd_info {
124 int pid;
125 int ref_cnt;
126 struct list_head list;
127};
128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129struct msm_rotator_dev {
130 void __iomem *io_base;
131 int irq;
132 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
133 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700134 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
135 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 int rot_clk_state;
138 struct regulator *regulator;
139 struct delayed_work rot_clk_work;
140 struct clk *imem_clk;
141 int imem_clk_state;
142 struct delayed_work imem_clk_work;
143 struct platform_device *pdev;
144 struct cdev cdev;
145 struct device *device;
146 struct class *class;
147 dev_t dev_num;
148 int processing;
149 int last_session_idx;
150 struct mutex rotator_lock;
151 struct mutex imem_lock;
152 int imem_owner;
153 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700154 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800155 #ifdef CONFIG_MSM_BUS_SCALING
156 uint32_t bus_client_handle;
157 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158};
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160#define COMPONENT_5BITS 1
161#define COMPONENT_6BITS 2
162#define COMPONENT_8BITS 3
163
164static struct msm_rotator_dev *msm_rotator_dev;
165
166enum {
167 CLK_EN,
168 CLK_DIS,
169 CLK_SUSPEND,
170};
171
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700172int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
173 unsigned long *start, unsigned long *len,
174 struct ion_handle **pihdl)
175{
176 if (!msm_rotator_dev->client)
177 return -EINVAL;
178
179 *pihdl = ion_import_fd(msm_rotator_dev->client, mem_id);
180 if (IS_ERR_OR_NULL(*pihdl)) {
181 pr_err("ion_import_fd() failed\n");
182 return PTR_ERR(*pihdl);
183 }
184 pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
185 ion_share(msm_rotator_dev->client, *pihdl));
186
187 if (ion_map_iommu(msm_rotator_dev->client,
188 *pihdl, ROTATOR_DOMAIN, GEN_POOL,
189 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
190 pr_err("ion_map_iommu() failed\n");
191 return -EINVAL;
192 }
193
194 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
195 __func__, mem_id, *start, *len);
196 return 0;
197}
198
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700199int msm_rotator_imem_allocate(int requestor)
200{
201 int rc = 0;
202
203#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
204 switch (requestor) {
205 case ROTATOR_REQUEST:
206 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
207 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
208 rc = 1;
209 } else
210 rc = 0;
211 break;
212 case JPEG_REQUEST:
213 mutex_lock(&msm_rotator_dev->imem_lock);
214 msm_rotator_dev->imem_owner = JPEG_REQUEST;
215 rc = 1;
216 break;
217 default:
218 rc = 0;
219 }
220#else
221 if (requestor == JPEG_REQUEST)
222 rc = 1;
223#endif
224 if (rc == 1) {
225 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
226 if (msm_rotator_dev->imem_clk_state != CLK_EN
227 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700228 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700229 msm_rotator_dev->imem_clk_state = CLK_EN;
230 }
231 }
232
233 return rc;
234}
235EXPORT_SYMBOL(msm_rotator_imem_allocate);
236
237void msm_rotator_imem_free(int requestor)
238{
239#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
240 if (msm_rotator_dev->imem_owner == requestor) {
241 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
242 mutex_unlock(&msm_rotator_dev->imem_lock);
243 }
244#else
245 if (requestor == JPEG_REQUEST)
246 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
247#endif
248}
249EXPORT_SYMBOL(msm_rotator_imem_free);
250
251static void msm_rotator_imem_clk_work_f(struct work_struct *work)
252{
253#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
254 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
255 if (msm_rotator_dev->imem_clk_state == CLK_EN
256 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700257 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700258 msm_rotator_dev->imem_clk_state = CLK_DIS;
259 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
260 msm_rotator_dev->imem_clk_state = CLK_DIS;
261 mutex_unlock(&msm_rotator_dev->imem_lock);
262 }
263#endif
264}
265
266/* enable clocks needed by rotator block */
267static void enable_rot_clks(void)
268{
269 if (msm_rotator_dev->regulator)
270 regulator_enable(msm_rotator_dev->regulator);
271 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700272 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700273 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700274 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700275}
276
277/* disable clocks needed by rotator block */
278static void disable_rot_clks(void)
279{
280 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700281 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700282 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700283 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700284 if (msm_rotator_dev->regulator)
285 regulator_disable(msm_rotator_dev->regulator);
286}
287
288static void msm_rotator_rot_clk_work_f(struct work_struct *work)
289{
290 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
291 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
292 disable_rot_clks();
293 msm_rotator_dev->rot_clk_state = CLK_DIS;
294 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
295 msm_rotator_dev->rot_clk_state = CLK_DIS;
296 mutex_unlock(&msm_rotator_dev->rotator_lock);
297 }
298}
299
300static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
301{
302 if (msm_rotator_dev->processing) {
303 msm_rotator_dev->processing = 0;
304 wake_up(&msm_rotator_dev->wq);
305 } else
306 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
307
308 return IRQ_HANDLED;
309}
310
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700311static unsigned int tile_size(unsigned int src_width,
312 unsigned int src_height,
313 const struct tile_parm *tp)
314{
315 unsigned int tile_w, tile_h;
316 unsigned int row_num_w, row_num_h;
317 tile_w = tp->width * tp->row_tile_w;
318 tile_h = tp->height * tp->row_tile_h;
319 row_num_w = (src_width + tile_w - 1) / tile_w;
320 row_num_h = (src_height + tile_h - 1) / tile_h;
321 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
322}
323
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700324static int get_bpp(int format)
325{
326 switch (format) {
327 case MDP_RGB_565:
328 case MDP_BGR_565:
329 return 2;
330
331 case MDP_XRGB_8888:
332 case MDP_ARGB_8888:
333 case MDP_RGBA_8888:
334 case MDP_BGRA_8888:
335 case MDP_RGBX_8888:
336 return 4;
337
338 case MDP_Y_CBCR_H2V2:
339 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700340 case MDP_Y_CB_CR_H2V2:
341 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530342 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700343 case MDP_Y_CRCB_H2V2_TILE:
344 case MDP_Y_CBCR_H2V2_TILE:
345 return 1;
346
347 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700348 case MDP_YCBCR_H1V1:
349 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700350 return 3;
351
352 case MDP_YCRYCB_H2V1:
353 return 2;/* YCrYCb interleave */
354
355 case MDP_Y_CRCB_H2V1:
356 case MDP_Y_CBCR_H2V1:
357 return 1;
358
359 default:
360 return -1;
361 }
362
363}
364
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700365static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
366 struct msm_rotator_mem_planes *p)
367{
368 /*
369 * each row of samsung tile consists of two tiles in height
370 * and two tiles in width which means width should align to
371 * 64 x 2 bytes and height should align to 32 x 2 bytes.
372 * video decoder generate two tiles in width and one tile
373 * in height which ends up height align to 32 X 1 bytes.
374 */
375 const struct tile_parm tile = {64, 32, 2, 1};
376 int i;
377
378 if (p == NULL)
379 return -EINVAL;
380
381 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
382 return -ERANGE;
383
384 memset(p, 0, sizeof(*p));
385
386 switch (format) {
387 case MDP_XRGB_8888:
388 case MDP_ARGB_8888:
389 case MDP_RGBA_8888:
390 case MDP_BGRA_8888:
391 case MDP_RGBX_8888:
392 case MDP_RGB_888:
393 case MDP_RGB_565:
394 case MDP_BGR_565:
395 case MDP_YCRYCB_H2V1:
396 p->num_planes = 1;
397 p->plane_size[0] = w * h * get_bpp(format);
398 break;
399 case MDP_Y_CRCB_H2V1:
400 case MDP_Y_CBCR_H2V1:
401 p->num_planes = 2;
402 p->plane_size[0] = w * h;
403 p->plane_size[1] = w * h;
404 break;
405 case MDP_Y_CBCR_H2V2:
406 case MDP_Y_CRCB_H2V2:
407 p->num_planes = 2;
408 p->plane_size[0] = w * h;
409 p->plane_size[1] = w * h / 2;
410 break;
411 case MDP_Y_CRCB_H2V2_TILE:
412 case MDP_Y_CBCR_H2V2_TILE:
413 p->num_planes = 2;
414 p->plane_size[0] = tile_size(w, h, &tile);
415 p->plane_size[1] = tile_size(w, h/2, &tile);
416 break;
417 case MDP_Y_CB_CR_H2V2:
418 case MDP_Y_CR_CB_H2V2:
419 p->num_planes = 3;
420 p->plane_size[0] = w * h;
421 p->plane_size[1] = (w / 2) * (h / 2);
422 p->plane_size[2] = (w / 2) * (h / 2);
423 break;
424 case MDP_Y_CR_CB_GH2V2:
425 p->num_planes = 3;
426 p->plane_size[0] = ALIGN(w, 16) * h;
427 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
428 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
429 break;
430 default:
431 return -EINVAL;
432 }
433
434 for (i = 0; i < p->num_planes; i++)
435 p->total_size += p->plane_size[i];
436
437 return 0;
438}
439
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700440static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
441 unsigned int in_paddr,
442 unsigned int out_paddr,
443 unsigned int use_imem,
444 int new_session,
445 unsigned int in_chroma_paddr,
446 unsigned int out_chroma_paddr)
447{
448 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700449
450 if (info->src.format != info->dst.format)
451 return -EINVAL;
452
453 bpp = get_bpp(info->src.format);
454 if (bpp < 0)
455 return -ENOTTY;
456
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700457 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700458 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459 iowrite32(out_paddr +
460 ((info->dst_y * info->dst.width) + info->dst_x),
461 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700462 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700463 ((info->dst_y * info->dst.width) + info->dst_x),
464 MSM_ROTATOR_OUTP1_ADDR);
465
466 if (new_session) {
467 iowrite32(info->src.width |
468 info->src.width << 16,
469 MSM_ROTATOR_SRC_YSTRIDE1);
470 if (info->rotations & MDP_ROT_90)
471 iowrite32(info->dst.width |
472 info->dst.width*2 << 16,
473 MSM_ROTATOR_OUT_YSTRIDE1);
474 else
475 iowrite32(info->dst.width |
476 info->dst.width << 16,
477 MSM_ROTATOR_OUT_YSTRIDE1);
478 if (info->src.format == MDP_Y_CBCR_H2V1) {
479 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
480 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
481 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
482 MSM_ROTATOR_OUT_PACK_PATTERN1);
483 } else {
484 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
485 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
486 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
487 MSM_ROTATOR_OUT_PACK_PATTERN1);
488 }
489 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
490 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700491 1 << 8 | /* ROT_EN */
492 info->downscale_ratio << 2 | /* downscale v ratio */
493 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 MSM_ROTATOR_SUB_BLOCK_CFG);
495 iowrite32(0 << 29 | /* frame format 0 = linear */
496 (use_imem ? 0 : 1) << 22 | /* tile size */
497 2 << 19 | /* fetch planes 2 = pseudo */
498 0 << 18 | /* unpack align */
499 1 << 17 | /* unpack tight */
500 1 << 13 | /* unpack count 0=1 component */
501 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
502 0 << 8 | /* has alpha */
503 0 << 6 | /* alpha bits 3=8bits */
504 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
505 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
506 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
507 MSM_ROTATOR_SRC_FORMAT);
508 }
509
510 return 0;
511}
512
513static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
514 unsigned int in_paddr,
515 unsigned int out_paddr,
516 unsigned int use_imem,
517 int new_session,
518 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700519 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700520 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700521{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700522 uint32_t dst_format;
523 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700524
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700525 switch (info->src.format) {
526 case MDP_Y_CRCB_H2V2_TILE:
527 is_tile = 1;
528 case MDP_Y_CR_CB_H2V2:
529 case MDP_Y_CR_CB_GH2V2:
530 case MDP_Y_CRCB_H2V2:
531 dst_format = MDP_Y_CRCB_H2V2;
532 break;
533 case MDP_Y_CBCR_H2V2_TILE:
534 is_tile = 1;
535 case MDP_Y_CB_CR_H2V2:
536 case MDP_Y_CBCR_H2V2:
537 dst_format = MDP_Y_CBCR_H2V2;
538 break;
539 default:
540 return -EINVAL;
541 }
542 if (info->dst.format != dst_format)
543 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700544
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800545 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530546 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
547 info->src.format == MDP_Y_CR_CB_GH2V2) &&
548 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800549 swap(in_chroma_paddr, in_chroma2_paddr);
550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700551 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700552 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
553 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
554
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700555 iowrite32(out_paddr +
556 ((info->dst_y * info->dst.width) + info->dst_x),
557 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700558 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700559 ((info->dst_y * info->dst.width)/2 + info->dst_x),
560 MSM_ROTATOR_OUTP1_ADDR);
561
562 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700563 if (in_chroma2_paddr) {
564 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530565 iowrite32(ALIGN(info->src.width, 16) |
566 ALIGN((info->src.width / 2), 16) << 16,
567 MSM_ROTATOR_SRC_YSTRIDE1);
568 iowrite32(ALIGN((info->src.width / 2), 16),
569 MSM_ROTATOR_SRC_YSTRIDE2);
570 } else {
571 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700572 (info->src.width / 2) << 16,
573 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530574 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700575 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530576 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700577 } else {
578 iowrite32(info->src.width |
579 info->src.width << 16,
580 MSM_ROTATOR_SRC_YSTRIDE1);
581 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700582 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700583 info->dst.width << 16,
584 MSM_ROTATOR_OUT_YSTRIDE1);
585
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700586 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
588 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
589 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
590 MSM_ROTATOR_OUT_PACK_PATTERN1);
591 } else {
592 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
593 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
594 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
595 MSM_ROTATOR_OUT_PACK_PATTERN1);
596 }
597 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
598 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700599 1 << 8 | /* ROT_EN */
600 info->downscale_ratio << 2 | /* downscale v ratio */
601 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700602 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700603
604 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700605 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700606 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607 0 << 18 | /* unpack align */
608 1 << 17 | /* unpack tight */
609 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700610 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700611 0 << 8 | /* has alpha */
612 0 << 6 | /* alpha bits 3=8bits */
613 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
614 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
615 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
616 MSM_ROTATOR_SRC_FORMAT);
617 }
618 return 0;
619}
620
621static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
622 unsigned int in_paddr,
623 unsigned int out_paddr,
624 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530625 int new_session,
626 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627{
628 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530629 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700630
Mayank Chopra732dcd62012-01-09 20:53:39 +0530631 if (info->src.format == MDP_YCRYCB_H2V1)
632 dst_format = MDP_Y_CRCB_H2V1;
633 else
634 return -EINVAL;
635
636 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 return -EINVAL;
638
639 bpp = get_bpp(info->src.format);
640 if (bpp < 0)
641 return -ENOTTY;
642
643 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
644 iowrite32(out_paddr +
645 ((info->dst_y * info->dst.width) + info->dst_x),
646 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530647 iowrite32(out_chroma_paddr +
648 ((info->dst_y * info->dst.width)/2 + info->dst_x),
649 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700650
651 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530652 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700653 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530654 if (info->rotations & MDP_ROT_90)
655 iowrite32(info->dst.width |
656 (info->dst.width*2) << 16,
657 MSM_ROTATOR_OUT_YSTRIDE1);
658 else
659 iowrite32(info->dst.width |
660 (info->dst.width) << 16,
661 MSM_ROTATOR_OUT_YSTRIDE1);
662
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
664 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530665 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700666 MSM_ROTATOR_OUT_PACK_PATTERN1);
667 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
668 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700669 1 << 8 | /* ROT_EN */
670 info->downscale_ratio << 2 | /* downscale v ratio */
671 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672 MSM_ROTATOR_SUB_BLOCK_CFG);
673 iowrite32(0 << 29 | /* frame format 0 = linear */
674 (use_imem ? 0 : 1) << 22 | /* tile size */
675 0 << 19 | /* fetch planes 0=interleaved */
676 0 << 18 | /* unpack align */
677 1 << 17 | /* unpack tight */
678 3 << 13 | /* unpack count 0=1 component */
679 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
680 0 << 8 | /* has alpha */
681 0 << 6 | /* alpha bits 3=8bits */
682 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
683 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
684 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
685 MSM_ROTATOR_SRC_FORMAT);
686 }
687
688 return 0;
689}
690
691static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
692 unsigned int in_paddr,
693 unsigned int out_paddr,
694 unsigned int use_imem,
695 int new_session)
696{
697 int bpp, abits, rbits, gbits, bbits;
698
699 if (info->src.format != info->dst.format)
700 return -EINVAL;
701
702 bpp = get_bpp(info->src.format);
703 if (bpp < 0)
704 return -ENOTTY;
705
706 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
707 iowrite32(out_paddr +
708 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
709 MSM_ROTATOR_OUTP0_ADDR);
710
711 if (new_session) {
712 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
713 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
714 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
715 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700716 1 << 8 | /* ROT_EN */
717 info->downscale_ratio << 2 | /* downscale v ratio */
718 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700719 MSM_ROTATOR_SUB_BLOCK_CFG);
720 switch (info->src.format) {
721 case MDP_RGB_565:
722 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
723 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
724 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
725 MSM_ROTATOR_OUT_PACK_PATTERN1);
726 abits = 0;
727 rbits = COMPONENT_5BITS;
728 gbits = COMPONENT_6BITS;
729 bbits = COMPONENT_5BITS;
730 break;
731
732 case MDP_BGR_565:
733 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
734 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
735 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
736 MSM_ROTATOR_OUT_PACK_PATTERN1);
737 abits = 0;
738 rbits = COMPONENT_5BITS;
739 gbits = COMPONENT_6BITS;
740 bbits = COMPONENT_5BITS;
741 break;
742
743 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700744 case MDP_YCBCR_H1V1:
745 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700746 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
747 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
748 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
749 MSM_ROTATOR_OUT_PACK_PATTERN1);
750 abits = 0;
751 rbits = COMPONENT_8BITS;
752 gbits = COMPONENT_8BITS;
753 bbits = COMPONENT_8BITS;
754 break;
755
756 case MDP_ARGB_8888:
757 case MDP_RGBA_8888:
758 case MDP_XRGB_8888:
759 case MDP_RGBX_8888:
760 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
761 CLR_B, 8),
762 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
763 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
764 CLR_B, 8),
765 MSM_ROTATOR_OUT_PACK_PATTERN1);
766 abits = COMPONENT_8BITS;
767 rbits = COMPONENT_8BITS;
768 gbits = COMPONENT_8BITS;
769 bbits = COMPONENT_8BITS;
770 break;
771
772 case MDP_BGRA_8888:
773 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
774 CLR_R, 8),
775 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
776 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
777 CLR_R, 8),
778 MSM_ROTATOR_OUT_PACK_PATTERN1);
779 abits = COMPONENT_8BITS;
780 rbits = COMPONENT_8BITS;
781 gbits = COMPONENT_8BITS;
782 bbits = COMPONENT_8BITS;
783 break;
784
785 default:
786 return -EINVAL;
787 }
788 iowrite32(0 << 29 | /* frame format 0 = linear */
789 (use_imem ? 0 : 1) << 22 | /* tile size */
790 0 << 19 | /* fetch planes 0=interleaved */
791 0 << 18 | /* unpack align */
792 1 << 17 | /* unpack tight */
793 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
794 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
795 (abits ? 1 : 0) << 8 | /* has alpha */
796 abits << 6 | /* alpha bits 3=8bits */
797 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
798 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
799 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
800 MSM_ROTATOR_SRC_FORMAT);
801 }
802
803 return 0;
804}
805
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700806static int get_img(struct msmfb_data *fbd, unsigned char src,
807 unsigned long *start, unsigned long *len, struct file **p_file,
808 int *p_need, struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700809{
810 int ret = 0;
811#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700812 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813 int put_needed, fb_num;
814#endif
815#ifdef CONFIG_ANDROID_PMEM
816 unsigned long vstart;
817#endif
818
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800819 *p_need = 0;
820
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700821#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700822 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
823 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700824 if (file == NULL) {
825 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700826 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700827 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828
Naseer Ahmed18018602011-10-25 13:32:58 -0700829 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
830 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700831 if (get_fb_phys_info(start, len, fb_num,
832 ROTATOR_SUBSYSTEM_ID)) {
833 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700834 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700835 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700836 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800837 *p_need = put_needed;
838 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700839 } else {
840 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700842 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700843 if (ret)
844 fput_light(file, put_needed);
845 return ret;
846 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700848
849#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700850 return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
851 len, p_ihdl);
Naseer Ahmed18018602011-10-25 13:32:58 -0700852#endif
853#ifdef CONFIG_ANDROID_PMEM
854 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
855 return 0;
856 else
857 return -ENOMEM;
858#endif
859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860}
861
Naseer Ahmed18018602011-10-25 13:32:58 -0700862static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
863{
864#ifdef CONFIG_ANDROID_PMEM
865 if (p_file != NULL)
866 put_pmem_file(p_file);
867#endif
868#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700869 if (!IS_ERR_OR_NULL(p_ihdl)) {
870 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
871 ion_unmap_iommu(msm_rotator_dev->client,
872 p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
873
Naseer Ahmed18018602011-10-25 13:32:58 -0700874 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700875 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700876#endif
877}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700878static int msm_rotator_do_rotate(unsigned long arg)
879{
Naseer Ahmed18018602011-10-25 13:32:58 -0700880 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881 struct msm_rotator_data_info info;
882 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700883 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700884 int use_imem = 0, rc = 0, s;
885 struct file *srcp0_file = NULL, *dstp0_file = NULL;
886 struct file *srcp1_file = NULL, *dstp1_file = NULL;
887 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
888 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800889 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700891 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700892 struct msm_rotator_img_info *img_info;
893 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700894
895 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
896 return -EFAULT;
897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 mutex_lock(&msm_rotator_dev->rotator_lock);
899 for (s = 0; s < MAX_SESSIONS; s++)
900 if ((msm_rotator_dev->img_info[s] != NULL) &&
901 (info.session_id ==
902 (unsigned int)msm_rotator_dev->img_info[s]
903 ))
904 break;
905
906 if (s == MAX_SESSIONS) {
907 dev_dbg(msm_rotator_dev->device,
908 "%s() : Attempt to use invalid session_id %d\n",
909 __func__, s);
910 rc = -EINVAL;
911 goto do_rotate_unlock_mutex;
912 }
913
914 if (msm_rotator_dev->img_info[s]->enable == 0) {
915 dev_dbg(msm_rotator_dev->device,
916 "%s() : Session_id %d not enabled \n",
917 __func__, s);
918 rc = -EINVAL;
919 goto do_rotate_unlock_mutex;
920 }
921
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700922 img_info = msm_rotator_dev->img_info[s];
923 if (msm_rotator_get_plane_sizes(img_info->src.format,
924 img_info->src.width,
925 img_info->src.height,
926 &src_planes)) {
927 pr_err("%s: invalid src format\n", __func__);
928 rc = -EINVAL;
929 goto do_rotate_unlock_mutex;
930 }
931 if (msm_rotator_get_plane_sizes(img_info->dst.format,
932 img_info->dst.width,
933 img_info->dst.height,
934 &dst_planes)) {
935 pr_err("%s: invalid dst format\n", __func__);
936 rc = -EINVAL;
937 goto do_rotate_unlock_mutex;
938 }
939
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700940 rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
941 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
942 &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700943 if (rc) {
944 pr_err("%s: in get_img() failed id=0x%08x\n",
945 DRIVER_NAME, info.src.memory_id);
946 goto do_rotate_unlock_mutex;
947 }
948
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700949 rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
950 (unsigned long *)&dst_len, &dstp0_file, &p_need,
951 &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700952 if (rc) {
953 pr_err("%s: out get_img() failed id=0x%08x\n",
954 DRIVER_NAME, info.dst.memory_id);
955 goto do_rotate_unlock_mutex;
956 }
957
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700958 format = msm_rotator_dev->img_info[s]->src.format;
959 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700960 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
961 (src_planes.num_planes == 2)) {
962 if (checkoffset(info.src.offset,
963 src_planes.plane_size[0],
964 src_len)) {
965 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
966 __func__, src_len, info.src.offset);
967 rc = -ERANGE;
968 goto do_rotate_unlock_mutex;
969 }
970 if (checkoffset(info.dst.offset,
971 dst_planes.plane_size[0],
972 dst_len)) {
973 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
974 __func__, dst_len, info.dst.offset);
975 rc = -ERANGE;
976 goto do_rotate_unlock_mutex;
977 }
978
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700979 rc = get_img(&info.src_chroma, 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700980 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800981 (unsigned long *)&src_len, &srcp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700982 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700983 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700984 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700985 DRIVER_NAME, info.src_chroma.memory_id);
986 goto do_rotate_unlock_mutex;
987 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700989 rc = get_img(&info.dst_chroma, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700990 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800991 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700992 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700994 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700996 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700997 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700998
999 if (checkoffset(info.src_chroma.offset,
1000 src_planes.plane_size[1],
1001 src_len)) {
1002 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1003 __func__, src_len, info.src_chroma.offset);
1004 rc = -ERANGE;
1005 goto do_rotate_unlock_mutex;
1006 }
1007
1008 if (checkoffset(info.dst_chroma.offset,
1009 src_planes.plane_size[1],
1010 dst_len)) {
1011 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1012 __func__, dst_len, info.dst_chroma.offset);
1013 rc = -ERANGE;
1014 goto do_rotate_unlock_mutex;
1015 }
1016
1017 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001019 } else {
1020 if (checkoffset(info.src.offset,
1021 src_planes.total_size,
1022 src_len)) {
1023 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1024 __func__, src_len, info.src.offset);
1025 rc = -ERANGE;
1026 goto do_rotate_unlock_mutex;
1027 }
1028 if (checkoffset(info.dst.offset,
1029 dst_planes.total_size,
1030 dst_len)) {
1031 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1032 __func__, dst_len, info.dst.offset);
1033 rc = -ERANGE;
1034 goto do_rotate_unlock_mutex;
1035 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036 }
1037
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001038 in_paddr += info.src.offset;
1039 out_paddr += info.dst.offset;
1040
1041 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1042 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1043 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1044 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1045 if (src_planes.num_planes >= 3)
1046 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1047
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1049 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1050 enable_rot_clks();
1051 msm_rotator_dev->rot_clk_state = CLK_EN;
1052 }
1053 enable_irq(msm_rotator_dev->irq);
1054
1055#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1056 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1057#else
1058 use_imem = 0;
1059#endif
1060 /*
1061 * workaround for a hardware bug. rotator hardware hangs when we
1062 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1063 * temporary fix use 0x42 for BURST_SIZE when imem used.
1064 */
1065 if (use_imem)
1066 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1067
1068 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1069 << 16) |
1070 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1071 MSM_ROTATOR_SRC_SIZE);
1072 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1073 << 16) |
1074 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1075 MSM_ROTATOR_SRC_XY);
1076 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1077 << 16) |
1078 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1079 MSM_ROTATOR_SRC_IMAGE_SIZE);
1080
1081 switch (format) {
1082 case MDP_RGB_565:
1083 case MDP_BGR_565:
1084 case MDP_RGB_888:
1085 case MDP_ARGB_8888:
1086 case MDP_RGBA_8888:
1087 case MDP_XRGB_8888:
1088 case MDP_BGRA_8888:
1089 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001090 case MDP_YCBCR_H1V1:
1091 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1093 in_paddr, out_paddr,
1094 use_imem,
1095 msm_rotator_dev->last_session_idx
1096 != s);
1097 break;
1098 case MDP_Y_CBCR_H2V2:
1099 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001100 case MDP_Y_CB_CR_H2V2:
1101 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301102 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001103 case MDP_Y_CRCB_H2V2_TILE:
1104 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001105 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1106 in_paddr, out_paddr, use_imem,
1107 msm_rotator_dev->last_session_idx
1108 != s,
1109 in_chroma_paddr,
1110 out_chroma_paddr,
1111 in_chroma2_paddr);
1112 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001113 case MDP_Y_CBCR_H2V1:
1114 case MDP_Y_CRCB_H2V1:
1115 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1116 in_paddr, out_paddr, use_imem,
1117 msm_rotator_dev->last_session_idx
1118 != s,
1119 in_chroma_paddr,
1120 out_chroma_paddr);
1121 break;
1122 case MDP_YCRYCB_H2V1:
1123 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1124 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301125 msm_rotator_dev->last_session_idx != s,
1126 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 break;
1128 default:
1129 rc = -EINVAL;
1130 goto do_rotate_exit;
1131 }
1132
1133 if (rc != 0) {
1134 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1135 goto do_rotate_exit;
1136 }
1137
1138 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1139
1140 msm_rotator_dev->processing = 1;
1141 iowrite32(0x1, MSM_ROTATOR_START);
1142
1143 wait_event(msm_rotator_dev->wq,
1144 (msm_rotator_dev->processing == 0));
1145 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
1146 if ((status & 0x03) != 0x01)
1147 rc = -EFAULT;
1148 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1149 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1150
1151do_rotate_exit:
1152 disable_irq(msm_rotator_dev->irq);
1153#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1154 msm_rotator_imem_free(ROTATOR_REQUEST);
1155#endif
1156 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001157do_rotate_unlock_mutex:
Naseer Ahmed18018602011-10-25 13:32:58 -07001158 put_img(dstp1_file, dstp1_ihdl);
1159 put_img(srcp1_file, srcp1_ihdl);
1160 put_img(dstp0_file, dstp0_ihdl);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001161
1162 /* only source may use frame buffer */
1163 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1164 fput_light(srcp0_file, ps0_need);
1165 else
1166 put_img(srcp0_file, srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001167 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001168 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1169 __func__, rc);
1170 return rc;
1171}
1172
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001173static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1174{
1175 u32 perf_level;
1176
1177 if (is_rgb)
1178 perf_level = 1;
1179 else if (wh <= (640 * 480))
1180 perf_level = 2;
1181 else if (wh <= (736 * 1280))
1182 perf_level = 3;
1183 else
1184 perf_level = 4;
1185
1186#ifdef CONFIG_MSM_BUS_SCALING
1187 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1188 perf_level);
1189#endif
1190
1191}
1192
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001193static int msm_rotator_start(unsigned long arg,
1194 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195{
1196 struct msm_rotator_img_info info;
1197 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001198 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001199 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001200 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001201
1202 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1203 return -EFAULT;
1204
1205 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1206 (info.src.height > MSM_ROTATOR_MAX_H) ||
1207 (info.src.width > MSM_ROTATOR_MAX_W) ||
1208 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1209 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001210 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1211 pr_err("%s: Invalid parameters\n", __func__);
1212 return -EINVAL;
1213 }
1214
1215 if (info.rotations & MDP_ROT_90) {
1216 dst_w = info.src_rect.h >> info.downscale_ratio;
1217 dst_h = info.src_rect.w >> info.downscale_ratio;
1218 } else {
1219 dst_w = info.src_rect.w >> info.downscale_ratio;
1220 dst_h = info.src_rect.h >> info.downscale_ratio;
1221 }
1222
1223 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001224 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1225 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001226 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1227 pr_err("%s: Invalid src or dst rect\n", __func__);
1228 return -ERANGE;
1229 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001230
1231 switch (info.src.format) {
1232 case MDP_RGB_565:
1233 case MDP_BGR_565:
1234 case MDP_RGB_888:
1235 case MDP_ARGB_8888:
1236 case MDP_RGBA_8888:
1237 case MDP_XRGB_8888:
1238 case MDP_RGBX_8888:
1239 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001240 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301241 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001242 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243 case MDP_Y_CBCR_H2V2:
1244 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301245 case MDP_Y_CBCR_H2V1:
1246 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001247 case MDP_YCBCR_H1V1:
1248 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301249 info.dst.format = info.src.format;
1250 break;
1251 case MDP_YCRYCB_H2V1:
1252 info.dst.format = MDP_Y_CRCB_H2V1;
1253 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001254 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301255 case MDP_Y_CBCR_H2V2_TILE:
1256 info.dst.format = MDP_Y_CBCR_H2V2;
1257 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001258 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301259 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301261 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001262 break;
1263 default:
1264 return -EINVAL;
1265 }
1266
1267 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001268
1269 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1270
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001271 for (s = 0; s < MAX_SESSIONS; s++) {
1272 if ((msm_rotator_dev->img_info[s] != NULL) &&
1273 (info.session_id ==
1274 (unsigned int)msm_rotator_dev->img_info[s]
1275 )) {
1276 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001277 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278
1279 if (msm_rotator_dev->last_session_idx == s)
1280 msm_rotator_dev->last_session_idx =
1281 INVALID_SESSION;
1282 break;
1283 }
1284
1285 if ((msm_rotator_dev->img_info[s] == NULL) &&
1286 (first_free_index ==
1287 INVALID_SESSION))
1288 first_free_index = s;
1289 }
1290
1291 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1292 /* allocate a session id */
1293 msm_rotator_dev->img_info[first_free_index] =
1294 kzalloc(sizeof(struct msm_rotator_img_info),
1295 GFP_KERNEL);
1296 if (!msm_rotator_dev->img_info[first_free_index]) {
1297 printk(KERN_ERR "%s : unable to alloc mem\n",
1298 __func__);
1299 rc = -ENOMEM;
1300 goto rotator_start_exit;
1301 }
1302 info.session_id = (unsigned int)
1303 msm_rotator_dev->img_info[first_free_index];
1304 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001305 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001306
1307 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1308 rc = -EFAULT;
1309 } else if (s == MAX_SESSIONS) {
1310 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1311 __func__);
1312 rc = -EBUSY;
1313 }
1314
1315rotator_start_exit:
1316 mutex_unlock(&msm_rotator_dev->rotator_lock);
1317
1318 return rc;
1319}
1320
1321static int msm_rotator_finish(unsigned long arg)
1322{
1323 int rc = 0;
1324 int s;
1325 unsigned int session_id;
1326
1327 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1328 return -EFAULT;
1329
1330 mutex_lock(&msm_rotator_dev->rotator_lock);
1331 for (s = 0; s < MAX_SESSIONS; s++) {
1332 if ((msm_rotator_dev->img_info[s] != NULL) &&
1333 (session_id ==
1334 (unsigned int)msm_rotator_dev->img_info[s])) {
1335 if (msm_rotator_dev->last_session_idx == s)
1336 msm_rotator_dev->last_session_idx =
1337 INVALID_SESSION;
1338 kfree(msm_rotator_dev->img_info[s]);
1339 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001340 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 break;
1342 }
1343 }
1344
1345 if (s == MAX_SESSIONS)
1346 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001347#ifdef CONFIG_MSM_BUS_SCALING
1348 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1349 0);
1350#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351 mutex_unlock(&msm_rotator_dev->rotator_lock);
1352 return rc;
1353}
1354
1355static int
1356msm_rotator_open(struct inode *inode, struct file *filp)
1357{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001358 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001359 int i;
1360
1361 if (filp->private_data)
1362 return -EBUSY;
1363
1364 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001365 for (i = 0; i < MAX_SESSIONS; i++) {
1366 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 break;
1368 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001369
1370 if (i == MAX_SESSIONS) {
1371 mutex_unlock(&msm_rotator_dev->rotator_lock);
1372 return -EBUSY;
1373 }
1374
1375 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1376 if (tmp->pid == current->pid) {
1377 fd_info = tmp;
1378 break;
1379 }
1380 }
1381
1382 if (!fd_info) {
1383 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1384 if (!fd_info) {
1385 mutex_unlock(&msm_rotator_dev->rotator_lock);
1386 pr_err("%s: insufficient memory to alloc resources\n",
1387 __func__);
1388 return -ENOMEM;
1389 }
1390 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1391 fd_info->pid = current->pid;
1392 }
1393 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001394 mutex_unlock(&msm_rotator_dev->rotator_lock);
1395
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001396 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001397
1398 return 0;
1399}
1400
1401static int
1402msm_rotator_close(struct inode *inode, struct file *filp)
1403{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001404 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001406
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001407 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1408
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001409 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001410 if (--fd_info->ref_cnt > 0) {
1411 mutex_unlock(&msm_rotator_dev->rotator_lock);
1412 return 0;
1413 }
1414
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415 for (s = 0; s < MAX_SESSIONS; s++) {
1416 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001417 msm_rotator_dev->fd_info[s] == fd_info) {
1418 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1419 __func__, msm_rotator_dev->img_info[s],
1420 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 kfree(msm_rotator_dev->img_info[s]);
1422 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001423 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001424 if (msm_rotator_dev->last_session_idx == s)
1425 msm_rotator_dev->last_session_idx =
1426 INVALID_SESSION;
1427 }
1428 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001429 list_del(&fd_info->list);
1430 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001431 mutex_unlock(&msm_rotator_dev->rotator_lock);
1432
1433 return 0;
1434}
1435
1436static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1437 unsigned long arg)
1438{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001439 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001440
1441 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1442 return -ENOTTY;
1443
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001444 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445
1446 switch (cmd) {
1447 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001448 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001449 case MSM_ROTATOR_IOCTL_ROTATE:
1450 return msm_rotator_do_rotate(arg);
1451 case MSM_ROTATOR_IOCTL_FINISH:
1452 return msm_rotator_finish(arg);
1453
1454 default:
1455 dev_dbg(msm_rotator_dev->device,
1456 "unexpected IOCTL %d\n", cmd);
1457 return -ENOTTY;
1458 }
1459}
1460
1461static const struct file_operations msm_rotator_fops = {
1462 .owner = THIS_MODULE,
1463 .open = msm_rotator_open,
1464 .release = msm_rotator_close,
1465 .unlocked_ioctl = msm_rotator_ioctl,
1466};
1467
1468static int __devinit msm_rotator_probe(struct platform_device *pdev)
1469{
1470 int rc = 0;
1471 struct resource *res;
1472 struct msm_rotator_platform_data *pdata = NULL;
1473 int i, number_of_clks;
1474 uint32_t ver;
1475
1476 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1477 if (!msm_rotator_dev) {
1478 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1479 __func__);
1480 return -ENOMEM;
1481 }
1482 for (i = 0; i < MAX_SESSIONS; i++)
1483 msm_rotator_dev->img_info[i] = NULL;
1484 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1485
1486 pdata = pdev->dev.platform_data;
1487 number_of_clks = pdata->number_of_clocks;
1488
1489 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1490 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001491 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001492 msm_rotator_dev->imem_clk_state = CLK_DIS;
1493 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1494 msm_rotator_imem_clk_work_f);
1495 msm_rotator_dev->imem_clk = NULL;
1496 msm_rotator_dev->pdev = pdev;
1497
1498 msm_rotator_dev->core_clk = NULL;
1499 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001501#ifdef CONFIG_MSM_BUS_SCALING
1502 if (!msm_rotator_dev->bus_client_handle && pdata &&
1503 pdata->bus_scale_table) {
1504 msm_rotator_dev->bus_client_handle =
1505 msm_bus_scale_register_client(
1506 pdata->bus_scale_table);
1507 if (!msm_rotator_dev->bus_client_handle) {
1508 pr_err("%s not able to get bus scale handle\n",
1509 __func__);
1510 }
1511 }
1512#endif
1513
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514 for (i = 0; i < number_of_clks; i++) {
1515 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1516 msm_rotator_dev->imem_clk =
1517 clk_get(&msm_rotator_dev->pdev->dev,
1518 pdata->rotator_clks[i].clk_name);
1519 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1520 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1521 msm_rotator_dev->imem_clk = NULL;
1522 printk(KERN_ERR "%s: cannot get imem_clk "
1523 "rc=%d\n", DRIVER_NAME, rc);
1524 goto error_imem_clk;
1525 }
1526 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001527 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001528 pdata->rotator_clks[i].clk_rate);
1529 }
1530 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1531 msm_rotator_dev->pclk =
1532 clk_get(&msm_rotator_dev->pdev->dev,
1533 pdata->rotator_clks[i].clk_name);
1534 if (IS_ERR(msm_rotator_dev->pclk)) {
1535 rc = PTR_ERR(msm_rotator_dev->pclk);
1536 msm_rotator_dev->pclk = NULL;
1537 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1538 DRIVER_NAME, rc);
1539 goto error_pclk;
1540 }
1541
1542 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001543 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 pdata->rotator_clks[i].clk_rate);
1545 }
1546
1547 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1548 msm_rotator_dev->core_clk =
1549 clk_get(&msm_rotator_dev->pdev->dev,
1550 pdata->rotator_clks[i].clk_name);
1551 if (IS_ERR(msm_rotator_dev->core_clk)) {
1552 rc = PTR_ERR(msm_rotator_dev->core_clk);
1553 msm_rotator_dev->core_clk = NULL;
1554 printk(KERN_ERR "%s: cannot get core clk "
1555 "rc=%d\n", DRIVER_NAME, rc);
1556 goto error_core_clk;
1557 }
1558
1559 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001560 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001561 pdata->rotator_clks[i].clk_rate);
1562 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 }
1564
1565 msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
1566 if (IS_ERR(msm_rotator_dev->regulator))
1567 msm_rotator_dev->regulator = NULL;
1568
1569 msm_rotator_dev->rot_clk_state = CLK_DIS;
1570 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1571 msm_rotator_rot_clk_work_f);
1572
1573 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001574#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1575 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1576#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001577 platform_set_drvdata(pdev, msm_rotator_dev);
1578
1579
1580 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1581 if (!res) {
1582 printk(KERN_ALERT
1583 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1584 rc = -ENODEV;
1585 goto error_get_resource;
1586 }
1587 msm_rotator_dev->io_base = ioremap(res->start,
1588 resource_size(res));
1589
1590#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1591 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001592 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001593#endif
1594 enable_rot_clks();
1595 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1596 disable_rot_clks();
1597
1598#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1599 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001600 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001601#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001602 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301603 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001604 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001605
Mayank Chopra012a8e72012-04-11 10:41:13 +05301606 rotator_hw_revision = ver;
1607 rotator_hw_revision >>= 16; /* bit 31:16 */
1608 rotator_hw_revision &= 0xff;
1609
1610 pr_info("%s: rotator_hw_revision=%x\n",
1611 __func__, rotator_hw_revision);
1612
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1614 if (msm_rotator_dev->irq < 0) {
1615 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1616 DRIVER_NAME);
1617 rc = -ENODEV;
1618 goto error_get_irq;
1619 }
1620 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1621 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1622 if (rc) {
1623 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1624 goto error_get_irq;
1625 }
1626 /* we enable the IRQ when we need it in the ioctl */
1627 disable_irq(msm_rotator_dev->irq);
1628
1629 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1630 if (rc < 0) {
1631 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1632 __func__, rc);
1633 goto error_get_irq;
1634 }
1635
1636 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1637 if (IS_ERR(msm_rotator_dev->class)) {
1638 rc = PTR_ERR(msm_rotator_dev->class);
1639 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1640 DRIVER_NAME, rc);
1641 goto error_class_create;
1642 }
1643
1644 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1645 msm_rotator_dev->dev_num, NULL,
1646 DRIVER_NAME);
1647 if (IS_ERR(msm_rotator_dev->device)) {
1648 rc = PTR_ERR(msm_rotator_dev->device);
1649 printk(KERN_ERR "%s: device_create failed %d\n",
1650 DRIVER_NAME, rc);
1651 goto error_class_device_create;
1652 }
1653
1654 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1655 rc = cdev_add(&msm_rotator_dev->cdev,
1656 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1657 1);
1658 if (rc < 0) {
1659 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1660 goto error_cdev_add;
1661 }
1662
1663 init_waitqueue_head(&msm_rotator_dev->wq);
1664
1665 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1666 return rc;
1667
1668error_cdev_add:
1669 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1670error_class_device_create:
1671 class_destroy(msm_rotator_dev->class);
1672error_class_create:
1673 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1674error_get_irq:
1675 iounmap(msm_rotator_dev->io_base);
1676error_get_resource:
1677 mutex_destroy(&msm_rotator_dev->rotator_lock);
1678 if (msm_rotator_dev->regulator)
1679 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001680 clk_put(msm_rotator_dev->core_clk);
1681error_core_clk:
1682 clk_put(msm_rotator_dev->pclk);
1683error_pclk:
1684 if (msm_rotator_dev->imem_clk)
1685 clk_put(msm_rotator_dev->imem_clk);
1686error_imem_clk:
1687 mutex_destroy(&msm_rotator_dev->imem_lock);
1688 kfree(msm_rotator_dev);
1689 return rc;
1690}
1691
1692static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1693{
1694 int i;
1695
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001696#ifdef CONFIG_MSM_BUS_SCALING
1697 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1698#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 free_irq(msm_rotator_dev->irq, NULL);
1700 mutex_destroy(&msm_rotator_dev->rotator_lock);
1701 cdev_del(&msm_rotator_dev->cdev);
1702 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1703 class_destroy(msm_rotator_dev->class);
1704 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1705 iounmap(msm_rotator_dev->io_base);
1706 if (msm_rotator_dev->imem_clk) {
1707 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001708 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001709 clk_put(msm_rotator_dev->imem_clk);
1710 msm_rotator_dev->imem_clk = NULL;
1711 }
1712 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1713 disable_rot_clks();
1714 clk_put(msm_rotator_dev->core_clk);
1715 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001716 if (msm_rotator_dev->regulator)
1717 regulator_put(msm_rotator_dev->regulator);
1718 msm_rotator_dev->core_clk = NULL;
1719 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001720 mutex_destroy(&msm_rotator_dev->imem_lock);
1721 for (i = 0; i < MAX_SESSIONS; i++)
1722 if (msm_rotator_dev->img_info[i] != NULL)
1723 kfree(msm_rotator_dev->img_info[i]);
1724 kfree(msm_rotator_dev);
1725 return 0;
1726}
1727
1728#ifdef CONFIG_PM
1729static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1730{
1731 mutex_lock(&msm_rotator_dev->imem_lock);
1732 if (msm_rotator_dev->imem_clk_state == CLK_EN
1733 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001734 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001735 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1736 }
1737 mutex_unlock(&msm_rotator_dev->imem_lock);
1738 mutex_lock(&msm_rotator_dev->rotator_lock);
1739 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1740 disable_rot_clks();
1741 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1742 }
1743 mutex_unlock(&msm_rotator_dev->rotator_lock);
1744 return 0;
1745}
1746
1747static int msm_rotator_resume(struct platform_device *dev)
1748{
1749 mutex_lock(&msm_rotator_dev->imem_lock);
1750 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1751 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001752 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001753 msm_rotator_dev->imem_clk_state = CLK_EN;
1754 }
1755 mutex_unlock(&msm_rotator_dev->imem_lock);
1756 mutex_lock(&msm_rotator_dev->rotator_lock);
1757 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1758 enable_rot_clks();
1759 msm_rotator_dev->rot_clk_state = CLK_EN;
1760 }
1761 mutex_unlock(&msm_rotator_dev->rotator_lock);
1762 return 0;
1763}
1764#endif
1765
1766static struct platform_driver msm_rotator_platform_driver = {
1767 .probe = msm_rotator_probe,
1768 .remove = __devexit_p(msm_rotator_remove),
1769#ifdef CONFIG_PM
1770 .suspend = msm_rotator_suspend,
1771 .resume = msm_rotator_resume,
1772#endif
1773 .driver = {
1774 .owner = THIS_MODULE,
1775 .name = DRIVER_NAME
1776 }
1777};
1778
1779static int __init msm_rotator_init(void)
1780{
1781 return platform_driver_register(&msm_rotator_platform_driver);
1782}
1783
1784static void __exit msm_rotator_exit(void)
1785{
1786 return platform_driver_unregister(&msm_rotator_platform_driver);
1787}
1788
1789module_init(msm_rotator_init);
1790module_exit(msm_rotator_exit);
1791
1792MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1793MODULE_VERSION("1.0");
1794MODULE_LICENSE("GPL v2");