blob: aec041cbb500538cc76913bc1d19955d944071fe [file] [log] [blame]
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/platform_device.h>
14#include <linux/cdev.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/uaccess.h>
21#include <linux/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/android_pmem.h>
23#include <linux/msm_rotator.h>
24#include <linux/io.h>
25#include <mach/msm_rotator_imem.h>
26#include <linux/ktime.h>
27#include <linux/workqueue.h>
28#include <linux/file.h>
29#include <linux/major.h>
30#include <linux/regulator/consumer.h>
Naseer Ahmed18018602011-10-25 13:32:58 -070031#include <linux/ion.h>
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080032#ifdef CONFIG_MSM_BUS_SCALING
33#include <mach/msm_bus.h>
34#include <mach/msm_bus_board.h>
35#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070036#include <mach/msm_subsystem_map.h>
37#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#define DRIVER_NAME "msm_rotator"
40
41#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
42#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
43#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
44#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
45#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
46#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
47#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
48#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
49#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
50#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070051#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
53#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
54#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
55#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
56#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
57#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
58#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
59#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070060#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
62#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
63#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
64#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
65
66#define MSM_ROTATOR_MAX_ROT 0x07
67#define MSM_ROTATOR_MAX_H 0x1fff
68#define MSM_ROTATOR_MAX_W 0x1fff
69
70/* from lsb to msb */
71#define GET_PACK_PATTERN(a, x, y, z, bit) \
72 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
73#define CLR_G 0x0
74#define CLR_B 0x1
75#define CLR_R 0x2
76#define CLR_ALPHA 0x3
77
78#define CLR_Y CLR_G
79#define CLR_CB CLR_B
80#define CLR_CR CLR_R
81
82#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
83 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
84 (((r) & MDP_FLIP_UD) ? 4 : 0))
85
86#define IMEM_NO_OWNER -1;
87
88#define MAX_SESSIONS 16
89#define INVALID_SESSION -1
90#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070091#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092
93struct tile_parm {
94 unsigned int width; /* tile's width */
95 unsigned int height; /* tile's height */
96 unsigned int row_tile_w; /* tiles per row's width */
97 unsigned int row_tile_h; /* tiles per row's height */
98};
99
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700100struct msm_rotator_mem_planes {
101 unsigned int num_planes;
102 unsigned int plane_size[4];
103 unsigned int total_size;
104};
105
106#define checkoffset(offset, size, max_size) \
107 ((size) > (max_size) || (offset) > ((max_size) - (size)))
108
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700109struct msm_rotator_fd_info {
110 int pid;
111 int ref_cnt;
112 struct list_head list;
113};
114
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700115struct msm_rotator_dev {
116 void __iomem *io_base;
117 int irq;
118 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
119 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700120 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
121 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700122 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700123 int rot_clk_state;
124 struct regulator *regulator;
125 struct delayed_work rot_clk_work;
126 struct clk *imem_clk;
127 int imem_clk_state;
128 struct delayed_work imem_clk_work;
129 struct platform_device *pdev;
130 struct cdev cdev;
131 struct device *device;
132 struct class *class;
133 dev_t dev_num;
134 int processing;
135 int last_session_idx;
136 struct mutex rotator_lock;
137 struct mutex imem_lock;
138 int imem_owner;
139 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700140 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800141 #ifdef CONFIG_MSM_BUS_SCALING
142 uint32_t bus_client_handle;
143 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700144};
145
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700146#define COMPONENT_5BITS 1
147#define COMPONENT_6BITS 2
148#define COMPONENT_8BITS 3
149
150static struct msm_rotator_dev *msm_rotator_dev;
151
152enum {
153 CLK_EN,
154 CLK_DIS,
155 CLK_SUSPEND,
156};
157
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700158int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
159 unsigned long *start, unsigned long *len,
160 struct ion_handle **pihdl)
161{
162 if (!msm_rotator_dev->client)
163 return -EINVAL;
164
165 *pihdl = ion_import_fd(msm_rotator_dev->client, mem_id);
166 if (IS_ERR_OR_NULL(*pihdl)) {
167 pr_err("ion_import_fd() failed\n");
168 return PTR_ERR(*pihdl);
169 }
170 pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
171 ion_share(msm_rotator_dev->client, *pihdl));
172
173 if (ion_map_iommu(msm_rotator_dev->client,
174 *pihdl, ROTATOR_DOMAIN, GEN_POOL,
175 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
176 pr_err("ion_map_iommu() failed\n");
177 return -EINVAL;
178 }
179
180 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
181 __func__, mem_id, *start, *len);
182 return 0;
183}
184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185int msm_rotator_imem_allocate(int requestor)
186{
187 int rc = 0;
188
189#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
190 switch (requestor) {
191 case ROTATOR_REQUEST:
192 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
193 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
194 rc = 1;
195 } else
196 rc = 0;
197 break;
198 case JPEG_REQUEST:
199 mutex_lock(&msm_rotator_dev->imem_lock);
200 msm_rotator_dev->imem_owner = JPEG_REQUEST;
201 rc = 1;
202 break;
203 default:
204 rc = 0;
205 }
206#else
207 if (requestor == JPEG_REQUEST)
208 rc = 1;
209#endif
210 if (rc == 1) {
211 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
212 if (msm_rotator_dev->imem_clk_state != CLK_EN
213 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700214 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700215 msm_rotator_dev->imem_clk_state = CLK_EN;
216 }
217 }
218
219 return rc;
220}
221EXPORT_SYMBOL(msm_rotator_imem_allocate);
222
223void msm_rotator_imem_free(int requestor)
224{
225#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
226 if (msm_rotator_dev->imem_owner == requestor) {
227 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
228 mutex_unlock(&msm_rotator_dev->imem_lock);
229 }
230#else
231 if (requestor == JPEG_REQUEST)
232 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
233#endif
234}
235EXPORT_SYMBOL(msm_rotator_imem_free);
236
237static void msm_rotator_imem_clk_work_f(struct work_struct *work)
238{
239#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
240 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
241 if (msm_rotator_dev->imem_clk_state == CLK_EN
242 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700243 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700244 msm_rotator_dev->imem_clk_state = CLK_DIS;
245 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
246 msm_rotator_dev->imem_clk_state = CLK_DIS;
247 mutex_unlock(&msm_rotator_dev->imem_lock);
248 }
249#endif
250}
251
252/* enable clocks needed by rotator block */
253static void enable_rot_clks(void)
254{
255 if (msm_rotator_dev->regulator)
256 regulator_enable(msm_rotator_dev->regulator);
257 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700258 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700260 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261}
262
263/* disable clocks needed by rotator block */
264static void disable_rot_clks(void)
265{
266 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700267 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700268 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700269 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700270 if (msm_rotator_dev->regulator)
271 regulator_disable(msm_rotator_dev->regulator);
272}
273
274static void msm_rotator_rot_clk_work_f(struct work_struct *work)
275{
276 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
277 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
278 disable_rot_clks();
279 msm_rotator_dev->rot_clk_state = CLK_DIS;
280 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
281 msm_rotator_dev->rot_clk_state = CLK_DIS;
282 mutex_unlock(&msm_rotator_dev->rotator_lock);
283 }
284}
285
286static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
287{
288 if (msm_rotator_dev->processing) {
289 msm_rotator_dev->processing = 0;
290 wake_up(&msm_rotator_dev->wq);
291 } else
292 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
293
294 return IRQ_HANDLED;
295}
296
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700297static unsigned int tile_size(unsigned int src_width,
298 unsigned int src_height,
299 const struct tile_parm *tp)
300{
301 unsigned int tile_w, tile_h;
302 unsigned int row_num_w, row_num_h;
303 tile_w = tp->width * tp->row_tile_w;
304 tile_h = tp->height * tp->row_tile_h;
305 row_num_w = (src_width + tile_w - 1) / tile_w;
306 row_num_h = (src_height + tile_h - 1) / tile_h;
307 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
308}
309
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700310static int get_bpp(int format)
311{
312 switch (format) {
313 case MDP_RGB_565:
314 case MDP_BGR_565:
315 return 2;
316
317 case MDP_XRGB_8888:
318 case MDP_ARGB_8888:
319 case MDP_RGBA_8888:
320 case MDP_BGRA_8888:
321 case MDP_RGBX_8888:
322 return 4;
323
324 case MDP_Y_CBCR_H2V2:
325 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700326 case MDP_Y_CB_CR_H2V2:
327 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530328 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700329 case MDP_Y_CRCB_H2V2_TILE:
330 case MDP_Y_CBCR_H2V2_TILE:
331 return 1;
332
333 case MDP_RGB_888:
334 return 3;
335
336 case MDP_YCRYCB_H2V1:
337 return 2;/* YCrYCb interleave */
338
339 case MDP_Y_CRCB_H2V1:
340 case MDP_Y_CBCR_H2V1:
341 return 1;
342
343 default:
344 return -1;
345 }
346
347}
348
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700349static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
350 struct msm_rotator_mem_planes *p)
351{
352 /*
353 * each row of samsung tile consists of two tiles in height
354 * and two tiles in width which means width should align to
355 * 64 x 2 bytes and height should align to 32 x 2 bytes.
356 * video decoder generate two tiles in width and one tile
357 * in height which ends up height align to 32 X 1 bytes.
358 */
359 const struct tile_parm tile = {64, 32, 2, 1};
360 int i;
361
362 if (p == NULL)
363 return -EINVAL;
364
365 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
366 return -ERANGE;
367
368 memset(p, 0, sizeof(*p));
369
370 switch (format) {
371 case MDP_XRGB_8888:
372 case MDP_ARGB_8888:
373 case MDP_RGBA_8888:
374 case MDP_BGRA_8888:
375 case MDP_RGBX_8888:
376 case MDP_RGB_888:
377 case MDP_RGB_565:
378 case MDP_BGR_565:
379 case MDP_YCRYCB_H2V1:
380 p->num_planes = 1;
381 p->plane_size[0] = w * h * get_bpp(format);
382 break;
383 case MDP_Y_CRCB_H2V1:
384 case MDP_Y_CBCR_H2V1:
385 p->num_planes = 2;
386 p->plane_size[0] = w * h;
387 p->plane_size[1] = w * h;
388 break;
389 case MDP_Y_CBCR_H2V2:
390 case MDP_Y_CRCB_H2V2:
391 p->num_planes = 2;
392 p->plane_size[0] = w * h;
393 p->plane_size[1] = w * h / 2;
394 break;
395 case MDP_Y_CRCB_H2V2_TILE:
396 case MDP_Y_CBCR_H2V2_TILE:
397 p->num_planes = 2;
398 p->plane_size[0] = tile_size(w, h, &tile);
399 p->plane_size[1] = tile_size(w, h/2, &tile);
400 break;
401 case MDP_Y_CB_CR_H2V2:
402 case MDP_Y_CR_CB_H2V2:
403 p->num_planes = 3;
404 p->plane_size[0] = w * h;
405 p->plane_size[1] = (w / 2) * (h / 2);
406 p->plane_size[2] = (w / 2) * (h / 2);
407 break;
408 case MDP_Y_CR_CB_GH2V2:
409 p->num_planes = 3;
410 p->plane_size[0] = ALIGN(w, 16) * h;
411 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
412 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
413 break;
414 default:
415 return -EINVAL;
416 }
417
418 for (i = 0; i < p->num_planes; i++)
419 p->total_size += p->plane_size[i];
420
421 return 0;
422}
423
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700424static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
425 unsigned int in_paddr,
426 unsigned int out_paddr,
427 unsigned int use_imem,
428 int new_session,
429 unsigned int in_chroma_paddr,
430 unsigned int out_chroma_paddr)
431{
432 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700433
434 if (info->src.format != info->dst.format)
435 return -EINVAL;
436
437 bpp = get_bpp(info->src.format);
438 if (bpp < 0)
439 return -ENOTTY;
440
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700441 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700442 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700443 iowrite32(out_paddr +
444 ((info->dst_y * info->dst.width) + info->dst_x),
445 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700446 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700447 ((info->dst_y * info->dst.width) + info->dst_x),
448 MSM_ROTATOR_OUTP1_ADDR);
449
450 if (new_session) {
451 iowrite32(info->src.width |
452 info->src.width << 16,
453 MSM_ROTATOR_SRC_YSTRIDE1);
454 if (info->rotations & MDP_ROT_90)
455 iowrite32(info->dst.width |
456 info->dst.width*2 << 16,
457 MSM_ROTATOR_OUT_YSTRIDE1);
458 else
459 iowrite32(info->dst.width |
460 info->dst.width << 16,
461 MSM_ROTATOR_OUT_YSTRIDE1);
462 if (info->src.format == MDP_Y_CBCR_H2V1) {
463 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
464 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
465 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
466 MSM_ROTATOR_OUT_PACK_PATTERN1);
467 } else {
468 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
469 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
470 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
471 MSM_ROTATOR_OUT_PACK_PATTERN1);
472 }
473 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
474 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700475 1 << 8 | /* ROT_EN */
476 info->downscale_ratio << 2 | /* downscale v ratio */
477 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700478 MSM_ROTATOR_SUB_BLOCK_CFG);
479 iowrite32(0 << 29 | /* frame format 0 = linear */
480 (use_imem ? 0 : 1) << 22 | /* tile size */
481 2 << 19 | /* fetch planes 2 = pseudo */
482 0 << 18 | /* unpack align */
483 1 << 17 | /* unpack tight */
484 1 << 13 | /* unpack count 0=1 component */
485 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
486 0 << 8 | /* has alpha */
487 0 << 6 | /* alpha bits 3=8bits */
488 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
489 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
490 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
491 MSM_ROTATOR_SRC_FORMAT);
492 }
493
494 return 0;
495}
496
497static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
498 unsigned int in_paddr,
499 unsigned int out_paddr,
500 unsigned int use_imem,
501 int new_session,
502 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700503 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700504 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700505{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700506 uint32_t dst_format;
507 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700508
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700509 switch (info->src.format) {
510 case MDP_Y_CRCB_H2V2_TILE:
511 is_tile = 1;
512 case MDP_Y_CR_CB_H2V2:
513 case MDP_Y_CR_CB_GH2V2:
514 case MDP_Y_CRCB_H2V2:
515 dst_format = MDP_Y_CRCB_H2V2;
516 break;
517 case MDP_Y_CBCR_H2V2_TILE:
518 is_tile = 1;
519 case MDP_Y_CB_CR_H2V2:
520 case MDP_Y_CBCR_H2V2:
521 dst_format = MDP_Y_CBCR_H2V2;
522 break;
523 default:
524 return -EINVAL;
525 }
526 if (info->dst.format != dst_format)
527 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700528
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800529 /* rotator expects YCbCr for planar input format */
530 if (info->src.format == MDP_Y_CR_CB_H2V2 ||
531 info->src.format == MDP_Y_CR_CB_GH2V2)
532 swap(in_chroma_paddr, in_chroma2_paddr);
533
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700535 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
536 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
537
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700538 iowrite32(out_paddr +
539 ((info->dst_y * info->dst.width) + info->dst_x),
540 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700541 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542 ((info->dst_y * info->dst.width)/2 + info->dst_x),
543 MSM_ROTATOR_OUTP1_ADDR);
544
545 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700546 if (in_chroma2_paddr) {
547 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530548 iowrite32(ALIGN(info->src.width, 16) |
549 ALIGN((info->src.width / 2), 16) << 16,
550 MSM_ROTATOR_SRC_YSTRIDE1);
551 iowrite32(ALIGN((info->src.width / 2), 16),
552 MSM_ROTATOR_SRC_YSTRIDE2);
553 } else {
554 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700555 (info->src.width / 2) << 16,
556 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530557 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700558 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530559 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700560 } else {
561 iowrite32(info->src.width |
562 info->src.width << 16,
563 MSM_ROTATOR_SRC_YSTRIDE1);
564 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700566 info->dst.width << 16,
567 MSM_ROTATOR_OUT_YSTRIDE1);
568
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700569 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700570 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
571 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
572 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
573 MSM_ROTATOR_OUT_PACK_PATTERN1);
574 } else {
575 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
576 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
577 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
578 MSM_ROTATOR_OUT_PACK_PATTERN1);
579 }
580 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
581 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700582 1 << 8 | /* ROT_EN */
583 info->downscale_ratio << 2 | /* downscale v ratio */
584 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700586
587 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700588 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700589 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 0 << 18 | /* unpack align */
591 1 << 17 | /* unpack tight */
592 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700593 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 0 << 8 | /* has alpha */
595 0 << 6 | /* alpha bits 3=8bits */
596 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
597 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
598 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
599 MSM_ROTATOR_SRC_FORMAT);
600 }
601 return 0;
602}
603
604static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
605 unsigned int in_paddr,
606 unsigned int out_paddr,
607 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530608 int new_session,
609 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610{
611 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530612 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700613
Mayank Chopra732dcd62012-01-09 20:53:39 +0530614 if (info->src.format == MDP_YCRYCB_H2V1)
615 dst_format = MDP_Y_CRCB_H2V1;
616 else
617 return -EINVAL;
618
619 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700620 return -EINVAL;
621
622 bpp = get_bpp(info->src.format);
623 if (bpp < 0)
624 return -ENOTTY;
625
626 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
627 iowrite32(out_paddr +
628 ((info->dst_y * info->dst.width) + info->dst_x),
629 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530630 iowrite32(out_chroma_paddr +
631 ((info->dst_y * info->dst.width)/2 + info->dst_x),
632 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633
634 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530635 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700636 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530637 if (info->rotations & MDP_ROT_90)
638 iowrite32(info->dst.width |
639 (info->dst.width*2) << 16,
640 MSM_ROTATOR_OUT_YSTRIDE1);
641 else
642 iowrite32(info->dst.width |
643 (info->dst.width) << 16,
644 MSM_ROTATOR_OUT_YSTRIDE1);
645
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
647 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530648 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649 MSM_ROTATOR_OUT_PACK_PATTERN1);
650 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
651 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700652 1 << 8 | /* ROT_EN */
653 info->downscale_ratio << 2 | /* downscale v ratio */
654 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655 MSM_ROTATOR_SUB_BLOCK_CFG);
656 iowrite32(0 << 29 | /* frame format 0 = linear */
657 (use_imem ? 0 : 1) << 22 | /* tile size */
658 0 << 19 | /* fetch planes 0=interleaved */
659 0 << 18 | /* unpack align */
660 1 << 17 | /* unpack tight */
661 3 << 13 | /* unpack count 0=1 component */
662 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
663 0 << 8 | /* has alpha */
664 0 << 6 | /* alpha bits 3=8bits */
665 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
666 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
667 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
668 MSM_ROTATOR_SRC_FORMAT);
669 }
670
671 return 0;
672}
673
674static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
675 unsigned int in_paddr,
676 unsigned int out_paddr,
677 unsigned int use_imem,
678 int new_session)
679{
680 int bpp, abits, rbits, gbits, bbits;
681
682 if (info->src.format != info->dst.format)
683 return -EINVAL;
684
685 bpp = get_bpp(info->src.format);
686 if (bpp < 0)
687 return -ENOTTY;
688
689 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
690 iowrite32(out_paddr +
691 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
692 MSM_ROTATOR_OUTP0_ADDR);
693
694 if (new_session) {
695 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
696 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
697 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
698 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700699 1 << 8 | /* ROT_EN */
700 info->downscale_ratio << 2 | /* downscale v ratio */
701 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700702 MSM_ROTATOR_SUB_BLOCK_CFG);
703 switch (info->src.format) {
704 case MDP_RGB_565:
705 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
706 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
707 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
708 MSM_ROTATOR_OUT_PACK_PATTERN1);
709 abits = 0;
710 rbits = COMPONENT_5BITS;
711 gbits = COMPONENT_6BITS;
712 bbits = COMPONENT_5BITS;
713 break;
714
715 case MDP_BGR_565:
716 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
717 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
718 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
719 MSM_ROTATOR_OUT_PACK_PATTERN1);
720 abits = 0;
721 rbits = COMPONENT_5BITS;
722 gbits = COMPONENT_6BITS;
723 bbits = COMPONENT_5BITS;
724 break;
725
726 case MDP_RGB_888:
727 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
728 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
729 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
730 MSM_ROTATOR_OUT_PACK_PATTERN1);
731 abits = 0;
732 rbits = COMPONENT_8BITS;
733 gbits = COMPONENT_8BITS;
734 bbits = COMPONENT_8BITS;
735 break;
736
737 case MDP_ARGB_8888:
738 case MDP_RGBA_8888:
739 case MDP_XRGB_8888:
740 case MDP_RGBX_8888:
741 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
742 CLR_B, 8),
743 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
744 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
745 CLR_B, 8),
746 MSM_ROTATOR_OUT_PACK_PATTERN1);
747 abits = COMPONENT_8BITS;
748 rbits = COMPONENT_8BITS;
749 gbits = COMPONENT_8BITS;
750 bbits = COMPONENT_8BITS;
751 break;
752
753 case MDP_BGRA_8888:
754 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
755 CLR_R, 8),
756 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
757 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
758 CLR_R, 8),
759 MSM_ROTATOR_OUT_PACK_PATTERN1);
760 abits = COMPONENT_8BITS;
761 rbits = COMPONENT_8BITS;
762 gbits = COMPONENT_8BITS;
763 bbits = COMPONENT_8BITS;
764 break;
765
766 default:
767 return -EINVAL;
768 }
769 iowrite32(0 << 29 | /* frame format 0 = linear */
770 (use_imem ? 0 : 1) << 22 | /* tile size */
771 0 << 19 | /* fetch planes 0=interleaved */
772 0 << 18 | /* unpack align */
773 1 << 17 | /* unpack tight */
774 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
775 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
776 (abits ? 1 : 0) << 8 | /* has alpha */
777 abits << 6 | /* alpha bits 3=8bits */
778 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
779 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
780 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
781 MSM_ROTATOR_SRC_FORMAT);
782 }
783
784 return 0;
785}
786
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700787static int get_img(struct msmfb_data *fbd, unsigned char src,
788 unsigned long *start, unsigned long *len, struct file **p_file,
789 int *p_need, struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790{
791 int ret = 0;
792#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700793 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700794 int put_needed, fb_num;
795#endif
796#ifdef CONFIG_ANDROID_PMEM
797 unsigned long vstart;
798#endif
799
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800800 *p_need = 0;
801
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700802#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700803 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
804 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700805 if (file == NULL) {
806 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700807 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700808 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700809
Naseer Ahmed18018602011-10-25 13:32:58 -0700810 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
811 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700812 if (get_fb_phys_info(start, len, fb_num,
813 ROTATOR_SUBSYSTEM_ID)) {
814 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700815 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700816 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700817 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800818 *p_need = put_needed;
819 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700820 } else {
821 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700823 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700824 if (ret)
825 fput_light(file, put_needed);
826 return ret;
827 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700828#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700829
830#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700831 return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
832 len, p_ihdl);
Naseer Ahmed18018602011-10-25 13:32:58 -0700833#endif
834#ifdef CONFIG_ANDROID_PMEM
835 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
836 return 0;
837 else
838 return -ENOMEM;
839#endif
840
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700841}
842
Naseer Ahmed18018602011-10-25 13:32:58 -0700843static void put_img(struct file *p_file, struct ion_handle *p_ihdl)
844{
845#ifdef CONFIG_ANDROID_PMEM
846 if (p_file != NULL)
847 put_pmem_file(p_file);
848#endif
849#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700850 if (!IS_ERR_OR_NULL(p_ihdl)) {
851 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
852 ion_unmap_iommu(msm_rotator_dev->client,
853 p_ihdl, ROTATOR_DOMAIN, GEN_POOL);
854
Naseer Ahmed18018602011-10-25 13:32:58 -0700855 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700856 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700857#endif
858}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859static int msm_rotator_do_rotate(unsigned long arg)
860{
Naseer Ahmed18018602011-10-25 13:32:58 -0700861 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700862 struct msm_rotator_data_info info;
863 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700864 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700865 int use_imem = 0, rc = 0, s;
866 struct file *srcp0_file = NULL, *dstp0_file = NULL;
867 struct file *srcp1_file = NULL, *dstp1_file = NULL;
868 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
869 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800870 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700871 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700872 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700873 struct msm_rotator_img_info *img_info;
874 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700875
876 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
877 return -EFAULT;
878
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 mutex_lock(&msm_rotator_dev->rotator_lock);
880 for (s = 0; s < MAX_SESSIONS; s++)
881 if ((msm_rotator_dev->img_info[s] != NULL) &&
882 (info.session_id ==
883 (unsigned int)msm_rotator_dev->img_info[s]
884 ))
885 break;
886
887 if (s == MAX_SESSIONS) {
888 dev_dbg(msm_rotator_dev->device,
889 "%s() : Attempt to use invalid session_id %d\n",
890 __func__, s);
891 rc = -EINVAL;
892 goto do_rotate_unlock_mutex;
893 }
894
895 if (msm_rotator_dev->img_info[s]->enable == 0) {
896 dev_dbg(msm_rotator_dev->device,
897 "%s() : Session_id %d not enabled \n",
898 __func__, s);
899 rc = -EINVAL;
900 goto do_rotate_unlock_mutex;
901 }
902
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700903 img_info = msm_rotator_dev->img_info[s];
904 if (msm_rotator_get_plane_sizes(img_info->src.format,
905 img_info->src.width,
906 img_info->src.height,
907 &src_planes)) {
908 pr_err("%s: invalid src format\n", __func__);
909 rc = -EINVAL;
910 goto do_rotate_unlock_mutex;
911 }
912 if (msm_rotator_get_plane_sizes(img_info->dst.format,
913 img_info->dst.width,
914 img_info->dst.height,
915 &dst_planes)) {
916 pr_err("%s: invalid dst format\n", __func__);
917 rc = -EINVAL;
918 goto do_rotate_unlock_mutex;
919 }
920
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700921 rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
922 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
923 &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700924 if (rc) {
925 pr_err("%s: in get_img() failed id=0x%08x\n",
926 DRIVER_NAME, info.src.memory_id);
927 goto do_rotate_unlock_mutex;
928 }
929
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700930 rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
931 (unsigned long *)&dst_len, &dstp0_file, &p_need,
932 &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700933 if (rc) {
934 pr_err("%s: out get_img() failed id=0x%08x\n",
935 DRIVER_NAME, info.dst.memory_id);
936 goto do_rotate_unlock_mutex;
937 }
938
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700939 format = msm_rotator_dev->img_info[s]->src.format;
940 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700941 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
942 (src_planes.num_planes == 2)) {
943 if (checkoffset(info.src.offset,
944 src_planes.plane_size[0],
945 src_len)) {
946 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
947 __func__, src_len, info.src.offset);
948 rc = -ERANGE;
949 goto do_rotate_unlock_mutex;
950 }
951 if (checkoffset(info.dst.offset,
952 dst_planes.plane_size[0],
953 dst_len)) {
954 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
955 __func__, dst_len, info.dst.offset);
956 rc = -ERANGE;
957 goto do_rotate_unlock_mutex;
958 }
959
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700960 rc = get_img(&info.src_chroma, 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700961 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800962 (unsigned long *)&src_len, &srcp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700963 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700964 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700965 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 DRIVER_NAME, info.src_chroma.memory_id);
967 goto do_rotate_unlock_mutex;
968 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700970 rc = get_img(&info.dst_chroma, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800972 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Naseer Ahmed18018602011-10-25 13:32:58 -0700973 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700975 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700976 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700977 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700978 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700979
980 if (checkoffset(info.src_chroma.offset,
981 src_planes.plane_size[1],
982 src_len)) {
983 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
984 __func__, src_len, info.src_chroma.offset);
985 rc = -ERANGE;
986 goto do_rotate_unlock_mutex;
987 }
988
989 if (checkoffset(info.dst_chroma.offset,
990 src_planes.plane_size[1],
991 dst_len)) {
992 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
993 __func__, dst_len, info.dst_chroma.offset);
994 rc = -ERANGE;
995 goto do_rotate_unlock_mutex;
996 }
997
998 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001000 } else {
1001 if (checkoffset(info.src.offset,
1002 src_planes.total_size,
1003 src_len)) {
1004 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1005 __func__, src_len, info.src.offset);
1006 rc = -ERANGE;
1007 goto do_rotate_unlock_mutex;
1008 }
1009 if (checkoffset(info.dst.offset,
1010 dst_planes.total_size,
1011 dst_len)) {
1012 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1013 __func__, dst_len, info.dst.offset);
1014 rc = -ERANGE;
1015 goto do_rotate_unlock_mutex;
1016 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017 }
1018
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001019 in_paddr += info.src.offset;
1020 out_paddr += info.dst.offset;
1021
1022 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1023 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1024 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1025 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1026 if (src_planes.num_planes >= 3)
1027 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1028
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1030 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1031 enable_rot_clks();
1032 msm_rotator_dev->rot_clk_state = CLK_EN;
1033 }
1034 enable_irq(msm_rotator_dev->irq);
1035
1036#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1037 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1038#else
1039 use_imem = 0;
1040#endif
1041 /*
1042 * workaround for a hardware bug. rotator hardware hangs when we
1043 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1044 * temporary fix use 0x42 for BURST_SIZE when imem used.
1045 */
1046 if (use_imem)
1047 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1048
1049 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1050 << 16) |
1051 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1052 MSM_ROTATOR_SRC_SIZE);
1053 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1054 << 16) |
1055 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1056 MSM_ROTATOR_SRC_XY);
1057 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1058 << 16) |
1059 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1060 MSM_ROTATOR_SRC_IMAGE_SIZE);
1061
1062 switch (format) {
1063 case MDP_RGB_565:
1064 case MDP_BGR_565:
1065 case MDP_RGB_888:
1066 case MDP_ARGB_8888:
1067 case MDP_RGBA_8888:
1068 case MDP_XRGB_8888:
1069 case MDP_BGRA_8888:
1070 case MDP_RGBX_8888:
1071 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1072 in_paddr, out_paddr,
1073 use_imem,
1074 msm_rotator_dev->last_session_idx
1075 != s);
1076 break;
1077 case MDP_Y_CBCR_H2V2:
1078 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001079 case MDP_Y_CB_CR_H2V2:
1080 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301081 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 case MDP_Y_CRCB_H2V2_TILE:
1083 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001084 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1085 in_paddr, out_paddr, use_imem,
1086 msm_rotator_dev->last_session_idx
1087 != s,
1088 in_chroma_paddr,
1089 out_chroma_paddr,
1090 in_chroma2_paddr);
1091 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001092 case MDP_Y_CBCR_H2V1:
1093 case MDP_Y_CRCB_H2V1:
1094 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1095 in_paddr, out_paddr, use_imem,
1096 msm_rotator_dev->last_session_idx
1097 != s,
1098 in_chroma_paddr,
1099 out_chroma_paddr);
1100 break;
1101 case MDP_YCRYCB_H2V1:
1102 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1103 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301104 msm_rotator_dev->last_session_idx != s,
1105 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001106 break;
1107 default:
1108 rc = -EINVAL;
1109 goto do_rotate_exit;
1110 }
1111
1112 if (rc != 0) {
1113 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1114 goto do_rotate_exit;
1115 }
1116
1117 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1118
1119 msm_rotator_dev->processing = 1;
1120 iowrite32(0x1, MSM_ROTATOR_START);
1121
1122 wait_event(msm_rotator_dev->wq,
1123 (msm_rotator_dev->processing == 0));
1124 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
1125 if ((status & 0x03) != 0x01)
1126 rc = -EFAULT;
1127 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1128 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1129
1130do_rotate_exit:
1131 disable_irq(msm_rotator_dev->irq);
1132#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1133 msm_rotator_imem_free(ROTATOR_REQUEST);
1134#endif
1135 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001136do_rotate_unlock_mutex:
Naseer Ahmed18018602011-10-25 13:32:58 -07001137 put_img(dstp1_file, dstp1_ihdl);
1138 put_img(srcp1_file, srcp1_ihdl);
1139 put_img(dstp0_file, dstp0_ihdl);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001140
1141 /* only source may use frame buffer */
1142 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1143 fput_light(srcp0_file, ps0_need);
1144 else
1145 put_img(srcp0_file, srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001146 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1148 __func__, rc);
1149 return rc;
1150}
1151
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001152static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1153{
1154 u32 perf_level;
1155
1156 if (is_rgb)
1157 perf_level = 1;
1158 else if (wh <= (640 * 480))
1159 perf_level = 2;
1160 else if (wh <= (736 * 1280))
1161 perf_level = 3;
1162 else
1163 perf_level = 4;
1164
1165#ifdef CONFIG_MSM_BUS_SCALING
1166 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1167 perf_level);
1168#endif
1169
1170}
1171
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001172static int msm_rotator_start(unsigned long arg,
1173 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001174{
1175 struct msm_rotator_img_info info;
1176 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001177 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001179 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180
1181 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1182 return -EFAULT;
1183
1184 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1185 (info.src.height > MSM_ROTATOR_MAX_H) ||
1186 (info.src.width > MSM_ROTATOR_MAX_W) ||
1187 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1188 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001189 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1190 pr_err("%s: Invalid parameters\n", __func__);
1191 return -EINVAL;
1192 }
1193
1194 if (info.rotations & MDP_ROT_90) {
1195 dst_w = info.src_rect.h >> info.downscale_ratio;
1196 dst_h = info.src_rect.w >> info.downscale_ratio;
1197 } else {
1198 dst_w = info.src_rect.w >> info.downscale_ratio;
1199 dst_h = info.src_rect.h >> info.downscale_ratio;
1200 }
1201
1202 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001203 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1204 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001205 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1206 pr_err("%s: Invalid src or dst rect\n", __func__);
1207 return -ERANGE;
1208 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001209
1210 switch (info.src.format) {
1211 case MDP_RGB_565:
1212 case MDP_BGR_565:
1213 case MDP_RGB_888:
1214 case MDP_ARGB_8888:
1215 case MDP_RGBA_8888:
1216 case MDP_XRGB_8888:
1217 case MDP_RGBX_8888:
1218 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001219 is_rgb = 1;
1220 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001221 case MDP_Y_CBCR_H2V2:
1222 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001223 case MDP_Y_CB_CR_H2V2:
1224 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301225 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 case MDP_Y_CBCR_H2V1:
1227 case MDP_Y_CRCB_H2V1:
1228 case MDP_YCRYCB_H2V1:
1229 case MDP_Y_CRCB_H2V2_TILE:
1230 case MDP_Y_CBCR_H2V2_TILE:
1231 break;
1232 default:
1233 return -EINVAL;
1234 }
1235
1236 switch (info.dst.format) {
1237 case MDP_RGB_565:
1238 case MDP_BGR_565:
1239 case MDP_RGB_888:
1240 case MDP_ARGB_8888:
1241 case MDP_RGBA_8888:
1242 case MDP_XRGB_8888:
1243 case MDP_RGBX_8888:
1244 case MDP_BGRA_8888:
1245 case MDP_Y_CBCR_H2V2:
1246 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001247 case MDP_Y_CB_CR_H2V2:
1248 case MDP_Y_CR_CB_H2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001249 case MDP_Y_CBCR_H2V1:
1250 case MDP_Y_CRCB_H2V1:
1251 case MDP_YCRYCB_H2V1:
1252 break;
1253 default:
1254 return -EINVAL;
1255 }
1256
1257 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001258
1259 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1260
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001261 for (s = 0; s < MAX_SESSIONS; s++) {
1262 if ((msm_rotator_dev->img_info[s] != NULL) &&
1263 (info.session_id ==
1264 (unsigned int)msm_rotator_dev->img_info[s]
1265 )) {
1266 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001267 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001268
1269 if (msm_rotator_dev->last_session_idx == s)
1270 msm_rotator_dev->last_session_idx =
1271 INVALID_SESSION;
1272 break;
1273 }
1274
1275 if ((msm_rotator_dev->img_info[s] == NULL) &&
1276 (first_free_index ==
1277 INVALID_SESSION))
1278 first_free_index = s;
1279 }
1280
1281 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1282 /* allocate a session id */
1283 msm_rotator_dev->img_info[first_free_index] =
1284 kzalloc(sizeof(struct msm_rotator_img_info),
1285 GFP_KERNEL);
1286 if (!msm_rotator_dev->img_info[first_free_index]) {
1287 printk(KERN_ERR "%s : unable to alloc mem\n",
1288 __func__);
1289 rc = -ENOMEM;
1290 goto rotator_start_exit;
1291 }
1292 info.session_id = (unsigned int)
1293 msm_rotator_dev->img_info[first_free_index];
1294 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001295 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296
1297 if (copy_to_user((void __user *)arg, &info, sizeof(info)))
1298 rc = -EFAULT;
1299 } else if (s == MAX_SESSIONS) {
1300 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1301 __func__);
1302 rc = -EBUSY;
1303 }
1304
1305rotator_start_exit:
1306 mutex_unlock(&msm_rotator_dev->rotator_lock);
1307
1308 return rc;
1309}
1310
1311static int msm_rotator_finish(unsigned long arg)
1312{
1313 int rc = 0;
1314 int s;
1315 unsigned int session_id;
1316
1317 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1318 return -EFAULT;
1319
1320 mutex_lock(&msm_rotator_dev->rotator_lock);
1321 for (s = 0; s < MAX_SESSIONS; s++) {
1322 if ((msm_rotator_dev->img_info[s] != NULL) &&
1323 (session_id ==
1324 (unsigned int)msm_rotator_dev->img_info[s])) {
1325 if (msm_rotator_dev->last_session_idx == s)
1326 msm_rotator_dev->last_session_idx =
1327 INVALID_SESSION;
1328 kfree(msm_rotator_dev->img_info[s]);
1329 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001330 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 break;
1332 }
1333 }
1334
1335 if (s == MAX_SESSIONS)
1336 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001337#ifdef CONFIG_MSM_BUS_SCALING
1338 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1339 0);
1340#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 mutex_unlock(&msm_rotator_dev->rotator_lock);
1342 return rc;
1343}
1344
1345static int
1346msm_rotator_open(struct inode *inode, struct file *filp)
1347{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001348 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001349 int i;
1350
1351 if (filp->private_data)
1352 return -EBUSY;
1353
1354 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001355 for (i = 0; i < MAX_SESSIONS; i++) {
1356 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 break;
1358 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001359
1360 if (i == MAX_SESSIONS) {
1361 mutex_unlock(&msm_rotator_dev->rotator_lock);
1362 return -EBUSY;
1363 }
1364
1365 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1366 if (tmp->pid == current->pid) {
1367 fd_info = tmp;
1368 break;
1369 }
1370 }
1371
1372 if (!fd_info) {
1373 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1374 if (!fd_info) {
1375 mutex_unlock(&msm_rotator_dev->rotator_lock);
1376 pr_err("%s: insufficient memory to alloc resources\n",
1377 __func__);
1378 return -ENOMEM;
1379 }
1380 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1381 fd_info->pid = current->pid;
1382 }
1383 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 mutex_unlock(&msm_rotator_dev->rotator_lock);
1385
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001386 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387
1388 return 0;
1389}
1390
1391static int
1392msm_rotator_close(struct inode *inode, struct file *filp)
1393{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001394 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001397 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1398
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001399 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001400 if (--fd_info->ref_cnt > 0) {
1401 mutex_unlock(&msm_rotator_dev->rotator_lock);
1402 return 0;
1403 }
1404
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 for (s = 0; s < MAX_SESSIONS; s++) {
1406 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001407 msm_rotator_dev->fd_info[s] == fd_info) {
1408 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1409 __func__, msm_rotator_dev->img_info[s],
1410 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001411 kfree(msm_rotator_dev->img_info[s]);
1412 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001413 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414 if (msm_rotator_dev->last_session_idx == s)
1415 msm_rotator_dev->last_session_idx =
1416 INVALID_SESSION;
1417 }
1418 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001419 list_del(&fd_info->list);
1420 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 mutex_unlock(&msm_rotator_dev->rotator_lock);
1422
1423 return 0;
1424}
1425
1426static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1427 unsigned long arg)
1428{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001429 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430
1431 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1432 return -ENOTTY;
1433
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001434 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001435
1436 switch (cmd) {
1437 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001438 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001439 case MSM_ROTATOR_IOCTL_ROTATE:
1440 return msm_rotator_do_rotate(arg);
1441 case MSM_ROTATOR_IOCTL_FINISH:
1442 return msm_rotator_finish(arg);
1443
1444 default:
1445 dev_dbg(msm_rotator_dev->device,
1446 "unexpected IOCTL %d\n", cmd);
1447 return -ENOTTY;
1448 }
1449}
1450
1451static const struct file_operations msm_rotator_fops = {
1452 .owner = THIS_MODULE,
1453 .open = msm_rotator_open,
1454 .release = msm_rotator_close,
1455 .unlocked_ioctl = msm_rotator_ioctl,
1456};
1457
1458static int __devinit msm_rotator_probe(struct platform_device *pdev)
1459{
1460 int rc = 0;
1461 struct resource *res;
1462 struct msm_rotator_platform_data *pdata = NULL;
1463 int i, number_of_clks;
1464 uint32_t ver;
1465
1466 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1467 if (!msm_rotator_dev) {
1468 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1469 __func__);
1470 return -ENOMEM;
1471 }
1472 for (i = 0; i < MAX_SESSIONS; i++)
1473 msm_rotator_dev->img_info[i] = NULL;
1474 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1475
1476 pdata = pdev->dev.platform_data;
1477 number_of_clks = pdata->number_of_clocks;
1478
1479 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1480 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001481 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482 msm_rotator_dev->imem_clk_state = CLK_DIS;
1483 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1484 msm_rotator_imem_clk_work_f);
1485 msm_rotator_dev->imem_clk = NULL;
1486 msm_rotator_dev->pdev = pdev;
1487
1488 msm_rotator_dev->core_clk = NULL;
1489 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001491#ifdef CONFIG_MSM_BUS_SCALING
1492 if (!msm_rotator_dev->bus_client_handle && pdata &&
1493 pdata->bus_scale_table) {
1494 msm_rotator_dev->bus_client_handle =
1495 msm_bus_scale_register_client(
1496 pdata->bus_scale_table);
1497 if (!msm_rotator_dev->bus_client_handle) {
1498 pr_err("%s not able to get bus scale handle\n",
1499 __func__);
1500 }
1501 }
1502#endif
1503
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001504 for (i = 0; i < number_of_clks; i++) {
1505 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1506 msm_rotator_dev->imem_clk =
1507 clk_get(&msm_rotator_dev->pdev->dev,
1508 pdata->rotator_clks[i].clk_name);
1509 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1510 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1511 msm_rotator_dev->imem_clk = NULL;
1512 printk(KERN_ERR "%s: cannot get imem_clk "
1513 "rc=%d\n", DRIVER_NAME, rc);
1514 goto error_imem_clk;
1515 }
1516 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001517 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 pdata->rotator_clks[i].clk_rate);
1519 }
1520 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1521 msm_rotator_dev->pclk =
1522 clk_get(&msm_rotator_dev->pdev->dev,
1523 pdata->rotator_clks[i].clk_name);
1524 if (IS_ERR(msm_rotator_dev->pclk)) {
1525 rc = PTR_ERR(msm_rotator_dev->pclk);
1526 msm_rotator_dev->pclk = NULL;
1527 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1528 DRIVER_NAME, rc);
1529 goto error_pclk;
1530 }
1531
1532 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001533 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001534 pdata->rotator_clks[i].clk_rate);
1535 }
1536
1537 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1538 msm_rotator_dev->core_clk =
1539 clk_get(&msm_rotator_dev->pdev->dev,
1540 pdata->rotator_clks[i].clk_name);
1541 if (IS_ERR(msm_rotator_dev->core_clk)) {
1542 rc = PTR_ERR(msm_rotator_dev->core_clk);
1543 msm_rotator_dev->core_clk = NULL;
1544 printk(KERN_ERR "%s: cannot get core clk "
1545 "rc=%d\n", DRIVER_NAME, rc);
1546 goto error_core_clk;
1547 }
1548
1549 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001550 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 pdata->rotator_clks[i].clk_rate);
1552 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001553 }
1554
1555 msm_rotator_dev->regulator = regulator_get(NULL, pdata->regulator_name);
1556 if (IS_ERR(msm_rotator_dev->regulator))
1557 msm_rotator_dev->regulator = NULL;
1558
1559 msm_rotator_dev->rot_clk_state = CLK_DIS;
1560 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1561 msm_rotator_rot_clk_work_f);
1562
1563 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001564#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1565 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1566#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001567 platform_set_drvdata(pdev, msm_rotator_dev);
1568
1569
1570 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1571 if (!res) {
1572 printk(KERN_ALERT
1573 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1574 rc = -ENODEV;
1575 goto error_get_resource;
1576 }
1577 msm_rotator_dev->io_base = ioremap(res->start,
1578 resource_size(res));
1579
1580#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1581 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001582 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583#endif
1584 enable_rot_clks();
1585 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1586 disable_rot_clks();
1587
1588#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1589 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001590 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001592 if (ver != pdata->hardware_version_number)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001593 pr_info("%s: invalid HW version ver 0x%x\n",
1594 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1597 if (msm_rotator_dev->irq < 0) {
1598 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1599 DRIVER_NAME);
1600 rc = -ENODEV;
1601 goto error_get_irq;
1602 }
1603 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1604 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1605 if (rc) {
1606 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1607 goto error_get_irq;
1608 }
1609 /* we enable the IRQ when we need it in the ioctl */
1610 disable_irq(msm_rotator_dev->irq);
1611
1612 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1613 if (rc < 0) {
1614 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1615 __func__, rc);
1616 goto error_get_irq;
1617 }
1618
1619 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1620 if (IS_ERR(msm_rotator_dev->class)) {
1621 rc = PTR_ERR(msm_rotator_dev->class);
1622 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1623 DRIVER_NAME, rc);
1624 goto error_class_create;
1625 }
1626
1627 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1628 msm_rotator_dev->dev_num, NULL,
1629 DRIVER_NAME);
1630 if (IS_ERR(msm_rotator_dev->device)) {
1631 rc = PTR_ERR(msm_rotator_dev->device);
1632 printk(KERN_ERR "%s: device_create failed %d\n",
1633 DRIVER_NAME, rc);
1634 goto error_class_device_create;
1635 }
1636
1637 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1638 rc = cdev_add(&msm_rotator_dev->cdev,
1639 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1640 1);
1641 if (rc < 0) {
1642 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1643 goto error_cdev_add;
1644 }
1645
1646 init_waitqueue_head(&msm_rotator_dev->wq);
1647
1648 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1649 return rc;
1650
1651error_cdev_add:
1652 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1653error_class_device_create:
1654 class_destroy(msm_rotator_dev->class);
1655error_class_create:
1656 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1657error_get_irq:
1658 iounmap(msm_rotator_dev->io_base);
1659error_get_resource:
1660 mutex_destroy(&msm_rotator_dev->rotator_lock);
1661 if (msm_rotator_dev->regulator)
1662 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001663 clk_put(msm_rotator_dev->core_clk);
1664error_core_clk:
1665 clk_put(msm_rotator_dev->pclk);
1666error_pclk:
1667 if (msm_rotator_dev->imem_clk)
1668 clk_put(msm_rotator_dev->imem_clk);
1669error_imem_clk:
1670 mutex_destroy(&msm_rotator_dev->imem_lock);
1671 kfree(msm_rotator_dev);
1672 return rc;
1673}
1674
1675static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1676{
1677 int i;
1678
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001679#ifdef CONFIG_MSM_BUS_SCALING
1680 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1681#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001682 free_irq(msm_rotator_dev->irq, NULL);
1683 mutex_destroy(&msm_rotator_dev->rotator_lock);
1684 cdev_del(&msm_rotator_dev->cdev);
1685 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1686 class_destroy(msm_rotator_dev->class);
1687 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1688 iounmap(msm_rotator_dev->io_base);
1689 if (msm_rotator_dev->imem_clk) {
1690 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001691 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001692 clk_put(msm_rotator_dev->imem_clk);
1693 msm_rotator_dev->imem_clk = NULL;
1694 }
1695 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1696 disable_rot_clks();
1697 clk_put(msm_rotator_dev->core_clk);
1698 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001699 if (msm_rotator_dev->regulator)
1700 regulator_put(msm_rotator_dev->regulator);
1701 msm_rotator_dev->core_clk = NULL;
1702 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 mutex_destroy(&msm_rotator_dev->imem_lock);
1704 for (i = 0; i < MAX_SESSIONS; i++)
1705 if (msm_rotator_dev->img_info[i] != NULL)
1706 kfree(msm_rotator_dev->img_info[i]);
1707 kfree(msm_rotator_dev);
1708 return 0;
1709}
1710
1711#ifdef CONFIG_PM
1712static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1713{
1714 mutex_lock(&msm_rotator_dev->imem_lock);
1715 if (msm_rotator_dev->imem_clk_state == CLK_EN
1716 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001717 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1719 }
1720 mutex_unlock(&msm_rotator_dev->imem_lock);
1721 mutex_lock(&msm_rotator_dev->rotator_lock);
1722 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1723 disable_rot_clks();
1724 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1725 }
1726 mutex_unlock(&msm_rotator_dev->rotator_lock);
1727 return 0;
1728}
1729
1730static int msm_rotator_resume(struct platform_device *dev)
1731{
1732 mutex_lock(&msm_rotator_dev->imem_lock);
1733 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1734 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001735 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 msm_rotator_dev->imem_clk_state = CLK_EN;
1737 }
1738 mutex_unlock(&msm_rotator_dev->imem_lock);
1739 mutex_lock(&msm_rotator_dev->rotator_lock);
1740 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1741 enable_rot_clks();
1742 msm_rotator_dev->rot_clk_state = CLK_EN;
1743 }
1744 mutex_unlock(&msm_rotator_dev->rotator_lock);
1745 return 0;
1746}
1747#endif
1748
1749static struct platform_driver msm_rotator_platform_driver = {
1750 .probe = msm_rotator_probe,
1751 .remove = __devexit_p(msm_rotator_remove),
1752#ifdef CONFIG_PM
1753 .suspend = msm_rotator_suspend,
1754 .resume = msm_rotator_resume,
1755#endif
1756 .driver = {
1757 .owner = THIS_MODULE,
1758 .name = DRIVER_NAME
1759 }
1760};
1761
1762static int __init msm_rotator_init(void)
1763{
1764 return platform_driver_register(&msm_rotator_platform_driver);
1765}
1766
1767static void __exit msm_rotator_exit(void)
1768{
1769 return platform_driver_unregister(&msm_rotator_platform_driver);
1770}
1771
1772module_init(msm_rotator_init);
1773module_exit(msm_rotator_exit);
1774
1775MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1776MODULE_VERSION("1.0");
1777MODULE_LICENSE("GPL v2");