blob: dae64cbc67090d617e3e988f52633fc7d6e6255b [file] [log] [blame]
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -08001/* Copyright (c) 2009-2012, Code Aurora Forum. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/platform_device.h>
14#include <linux/cdev.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/uaccess.h>
21#include <linux/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/android_pmem.h>
23#include <linux/msm_rotator.h>
24#include <linux/io.h>
25#include <mach/msm_rotator_imem.h>
26#include <linux/ktime.h>
27#include <linux/workqueue.h>
28#include <linux/file.h>
29#include <linux/major.h>
30#include <linux/regulator/consumer.h>
Naseer Ahmed18018602011-10-25 13:32:58 -070031#include <linux/ion.h>
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080032#ifdef CONFIG_MSM_BUS_SCALING
33#include <mach/msm_bus.h>
34#include <mach/msm_bus_board.h>
35#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070036#include <mach/msm_subsystem_map.h>
37#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070038
39#define DRIVER_NAME "msm_rotator"
40
41#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
42#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
43#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
44#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
45#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
46#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
47#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -070048#define MSM_ROTATOR_SW_RESET (MSM_ROTATOR_BASE+0x0074)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070049#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
50#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
51#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070052#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070053#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
54#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
55#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
56#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
57#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
58#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
59#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
60#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070061#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070062#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
63#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
64#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
65#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
66
67#define MSM_ROTATOR_MAX_ROT 0x07
68#define MSM_ROTATOR_MAX_H 0x1fff
69#define MSM_ROTATOR_MAX_W 0x1fff
70
71/* from lsb to msb */
72#define GET_PACK_PATTERN(a, x, y, z, bit) \
73 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
74#define CLR_G 0x0
75#define CLR_B 0x1
76#define CLR_R 0x2
77#define CLR_ALPHA 0x3
78
79#define CLR_Y CLR_G
80#define CLR_CB CLR_B
81#define CLR_CR CLR_R
82
83#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
84 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
85 (((r) & MDP_FLIP_UD) ? 4 : 0))
86
87#define IMEM_NO_OWNER -1;
88
89#define MAX_SESSIONS 16
90#define INVALID_SESSION -1
91#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070092#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070093
Mayank Chopra012a8e72012-04-11 10:41:13 +053094#define ROTATOR_REVISION_V0 0
95#define ROTATOR_REVISION_V1 1
96#define ROTATOR_REVISION_V2 2
97#define ROTATOR_REVISION_NONE 0xffffffff
98
99uint32_t rotator_hw_revision;
100
101/*
102 * rotator_hw_revision:
103 * 0 == 7x30
104 * 1 == 8x60
105 * 2 == 8960
106 *
107 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108struct tile_parm {
109 unsigned int width; /* tile's width */
110 unsigned int height; /* tile's height */
111 unsigned int row_tile_w; /* tiles per row's width */
112 unsigned int row_tile_h; /* tiles per row's height */
113};
114
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700115struct msm_rotator_mem_planes {
116 unsigned int num_planes;
117 unsigned int plane_size[4];
118 unsigned int total_size;
119};
120
121#define checkoffset(offset, size, max_size) \
122 ((size) > (max_size) || (offset) > ((max_size) - (size)))
123
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700124struct msm_rotator_fd_info {
125 int pid;
126 int ref_cnt;
127 struct list_head list;
128};
129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130struct msm_rotator_dev {
131 void __iomem *io_base;
132 int irq;
133 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
134 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700135 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
136 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 int rot_clk_state;
139 struct regulator *regulator;
140 struct delayed_work rot_clk_work;
141 struct clk *imem_clk;
142 int imem_clk_state;
143 struct delayed_work imem_clk_work;
144 struct platform_device *pdev;
145 struct cdev cdev;
146 struct device *device;
147 struct class *class;
148 dev_t dev_num;
149 int processing;
150 int last_session_idx;
151 struct mutex rotator_lock;
152 struct mutex imem_lock;
153 int imem_owner;
154 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700155 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800156 #ifdef CONFIG_MSM_BUS_SCALING
157 uint32_t bus_client_handle;
158 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159};
160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161#define COMPONENT_5BITS 1
162#define COMPONENT_6BITS 2
163#define COMPONENT_8BITS 3
164
165static struct msm_rotator_dev *msm_rotator_dev;
166
167enum {
168 CLK_EN,
169 CLK_DIS,
170 CLK_SUSPEND,
171};
172
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530173int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700174 unsigned long *start, unsigned long *len,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530175 struct ion_handle **pihdl)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700176{
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530177 int domain;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700178 if (!msm_rotator_dev->client)
179 return -EINVAL;
180
181 *pihdl = ion_import_fd(msm_rotator_dev->client, mem_id);
182 if (IS_ERR_OR_NULL(*pihdl)) {
183 pr_err("ion_import_fd() failed\n");
184 return PTR_ERR(*pihdl);
185 }
186 pr_debug("%s(): ion_hdl %p, ion_buf %p\n", __func__, *pihdl,
187 ion_share(msm_rotator_dev->client, *pihdl));
188
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530189 domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
190 if (ion_map_iommu(msm_rotator_dev->client,
191 *pihdl, domain, GEN_POOL,
192 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
193 pr_err("ion_map_iommu() failed\n");
194 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700195 }
196
197 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
198 __func__, mem_id, *start, *len);
199 return 0;
200}
201
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700202int msm_rotator_imem_allocate(int requestor)
203{
204 int rc = 0;
205
206#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
207 switch (requestor) {
208 case ROTATOR_REQUEST:
209 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
210 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
211 rc = 1;
212 } else
213 rc = 0;
214 break;
215 case JPEG_REQUEST:
216 mutex_lock(&msm_rotator_dev->imem_lock);
217 msm_rotator_dev->imem_owner = JPEG_REQUEST;
218 rc = 1;
219 break;
220 default:
221 rc = 0;
222 }
223#else
224 if (requestor == JPEG_REQUEST)
225 rc = 1;
226#endif
227 if (rc == 1) {
228 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
229 if (msm_rotator_dev->imem_clk_state != CLK_EN
230 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700231 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700232 msm_rotator_dev->imem_clk_state = CLK_EN;
233 }
234 }
235
236 return rc;
237}
238EXPORT_SYMBOL(msm_rotator_imem_allocate);
239
240void msm_rotator_imem_free(int requestor)
241{
242#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
243 if (msm_rotator_dev->imem_owner == requestor) {
244 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
245 mutex_unlock(&msm_rotator_dev->imem_lock);
246 }
247#else
248 if (requestor == JPEG_REQUEST)
249 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
250#endif
251}
252EXPORT_SYMBOL(msm_rotator_imem_free);
253
254static void msm_rotator_imem_clk_work_f(struct work_struct *work)
255{
256#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
257 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
258 if (msm_rotator_dev->imem_clk_state == CLK_EN
259 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700260 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 msm_rotator_dev->imem_clk_state = CLK_DIS;
262 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
263 msm_rotator_dev->imem_clk_state = CLK_DIS;
264 mutex_unlock(&msm_rotator_dev->imem_lock);
265 }
266#endif
267}
268
269/* enable clocks needed by rotator block */
270static void enable_rot_clks(void)
271{
272 if (msm_rotator_dev->regulator)
273 regulator_enable(msm_rotator_dev->regulator);
274 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700275 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700277 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278}
279
280/* disable clocks needed by rotator block */
281static void disable_rot_clks(void)
282{
283 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700284 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700285 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700286 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700287 if (msm_rotator_dev->regulator)
288 regulator_disable(msm_rotator_dev->regulator);
289}
290
291static void msm_rotator_rot_clk_work_f(struct work_struct *work)
292{
293 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
294 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
295 disable_rot_clks();
296 msm_rotator_dev->rot_clk_state = CLK_DIS;
297 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
298 msm_rotator_dev->rot_clk_state = CLK_DIS;
299 mutex_unlock(&msm_rotator_dev->rotator_lock);
300 }
301}
302
303static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
304{
305 if (msm_rotator_dev->processing) {
306 msm_rotator_dev->processing = 0;
307 wake_up(&msm_rotator_dev->wq);
308 } else
309 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
310
311 return IRQ_HANDLED;
312}
313
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700314static unsigned int tile_size(unsigned int src_width,
315 unsigned int src_height,
316 const struct tile_parm *tp)
317{
318 unsigned int tile_w, tile_h;
319 unsigned int row_num_w, row_num_h;
320 tile_w = tp->width * tp->row_tile_w;
321 tile_h = tp->height * tp->row_tile_h;
322 row_num_w = (src_width + tile_w - 1) / tile_w;
323 row_num_h = (src_height + tile_h - 1) / tile_h;
324 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
325}
326
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700327static int get_bpp(int format)
328{
329 switch (format) {
330 case MDP_RGB_565:
331 case MDP_BGR_565:
332 return 2;
333
334 case MDP_XRGB_8888:
335 case MDP_ARGB_8888:
336 case MDP_RGBA_8888:
337 case MDP_BGRA_8888:
338 case MDP_RGBX_8888:
339 return 4;
340
341 case MDP_Y_CBCR_H2V2:
342 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700343 case MDP_Y_CB_CR_H2V2:
344 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530345 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700346 case MDP_Y_CRCB_H2V2_TILE:
347 case MDP_Y_CBCR_H2V2_TILE:
348 return 1;
349
350 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700351 case MDP_YCBCR_H1V1:
352 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700353 return 3;
354
355 case MDP_YCRYCB_H2V1:
356 return 2;/* YCrYCb interleave */
357
358 case MDP_Y_CRCB_H2V1:
359 case MDP_Y_CBCR_H2V1:
360 return 1;
361
362 default:
363 return -1;
364 }
365
366}
367
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700368static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
369 struct msm_rotator_mem_planes *p)
370{
371 /*
372 * each row of samsung tile consists of two tiles in height
373 * and two tiles in width which means width should align to
374 * 64 x 2 bytes and height should align to 32 x 2 bytes.
375 * video decoder generate two tiles in width and one tile
376 * in height which ends up height align to 32 X 1 bytes.
377 */
378 const struct tile_parm tile = {64, 32, 2, 1};
379 int i;
380
381 if (p == NULL)
382 return -EINVAL;
383
384 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
385 return -ERANGE;
386
387 memset(p, 0, sizeof(*p));
388
389 switch (format) {
390 case MDP_XRGB_8888:
391 case MDP_ARGB_8888:
392 case MDP_RGBA_8888:
393 case MDP_BGRA_8888:
394 case MDP_RGBX_8888:
395 case MDP_RGB_888:
396 case MDP_RGB_565:
397 case MDP_BGR_565:
398 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700399 case MDP_YCBCR_H1V1:
400 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700401 p->num_planes = 1;
402 p->plane_size[0] = w * h * get_bpp(format);
403 break;
404 case MDP_Y_CRCB_H2V1:
405 case MDP_Y_CBCR_H2V1:
406 p->num_planes = 2;
407 p->plane_size[0] = w * h;
408 p->plane_size[1] = w * h;
409 break;
410 case MDP_Y_CBCR_H2V2:
411 case MDP_Y_CRCB_H2V2:
412 p->num_planes = 2;
413 p->plane_size[0] = w * h;
414 p->plane_size[1] = w * h / 2;
415 break;
416 case MDP_Y_CRCB_H2V2_TILE:
417 case MDP_Y_CBCR_H2V2_TILE:
418 p->num_planes = 2;
419 p->plane_size[0] = tile_size(w, h, &tile);
420 p->plane_size[1] = tile_size(w, h/2, &tile);
421 break;
422 case MDP_Y_CB_CR_H2V2:
423 case MDP_Y_CR_CB_H2V2:
424 p->num_planes = 3;
425 p->plane_size[0] = w * h;
426 p->plane_size[1] = (w / 2) * (h / 2);
427 p->plane_size[2] = (w / 2) * (h / 2);
428 break;
429 case MDP_Y_CR_CB_GH2V2:
430 p->num_planes = 3;
431 p->plane_size[0] = ALIGN(w, 16) * h;
432 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
433 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
434 break;
435 default:
436 return -EINVAL;
437 }
438
439 for (i = 0; i < p->num_planes; i++)
440 p->total_size += p->plane_size[i];
441
442 return 0;
443}
444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700445static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
446 unsigned int in_paddr,
447 unsigned int out_paddr,
448 unsigned int use_imem,
449 int new_session,
450 unsigned int in_chroma_paddr,
451 unsigned int out_chroma_paddr)
452{
453 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700454
455 if (info->src.format != info->dst.format)
456 return -EINVAL;
457
458 bpp = get_bpp(info->src.format);
459 if (bpp < 0)
460 return -ENOTTY;
461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700463 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464 iowrite32(out_paddr +
465 ((info->dst_y * info->dst.width) + info->dst_x),
466 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700467 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700468 ((info->dst_y * info->dst.width) + info->dst_x),
469 MSM_ROTATOR_OUTP1_ADDR);
470
471 if (new_session) {
472 iowrite32(info->src.width |
473 info->src.width << 16,
474 MSM_ROTATOR_SRC_YSTRIDE1);
475 if (info->rotations & MDP_ROT_90)
476 iowrite32(info->dst.width |
477 info->dst.width*2 << 16,
478 MSM_ROTATOR_OUT_YSTRIDE1);
479 else
480 iowrite32(info->dst.width |
481 info->dst.width << 16,
482 MSM_ROTATOR_OUT_YSTRIDE1);
483 if (info->src.format == MDP_Y_CBCR_H2V1) {
484 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
485 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
486 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
487 MSM_ROTATOR_OUT_PACK_PATTERN1);
488 } else {
489 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
490 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
491 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
492 MSM_ROTATOR_OUT_PACK_PATTERN1);
493 }
494 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
495 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700496 1 << 8 | /* ROT_EN */
497 info->downscale_ratio << 2 | /* downscale v ratio */
498 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 MSM_ROTATOR_SUB_BLOCK_CFG);
500 iowrite32(0 << 29 | /* frame format 0 = linear */
501 (use_imem ? 0 : 1) << 22 | /* tile size */
502 2 << 19 | /* fetch planes 2 = pseudo */
503 0 << 18 | /* unpack align */
504 1 << 17 | /* unpack tight */
505 1 << 13 | /* unpack count 0=1 component */
506 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
507 0 << 8 | /* has alpha */
508 0 << 6 | /* alpha bits 3=8bits */
509 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
510 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
511 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
512 MSM_ROTATOR_SRC_FORMAT);
513 }
514
515 return 0;
516}
517
518static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
519 unsigned int in_paddr,
520 unsigned int out_paddr,
521 unsigned int use_imem,
522 int new_session,
523 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700524 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700525 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700526{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700527 uint32_t dst_format;
528 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700530 switch (info->src.format) {
531 case MDP_Y_CRCB_H2V2_TILE:
532 is_tile = 1;
533 case MDP_Y_CR_CB_H2V2:
534 case MDP_Y_CR_CB_GH2V2:
535 case MDP_Y_CRCB_H2V2:
536 dst_format = MDP_Y_CRCB_H2V2;
537 break;
538 case MDP_Y_CBCR_H2V2_TILE:
539 is_tile = 1;
540 case MDP_Y_CB_CR_H2V2:
541 case MDP_Y_CBCR_H2V2:
542 dst_format = MDP_Y_CBCR_H2V2;
543 break;
544 default:
545 return -EINVAL;
546 }
547 if (info->dst.format != dst_format)
548 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700549
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800550 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530551 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
552 info->src.format == MDP_Y_CR_CB_GH2V2) &&
553 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800554 swap(in_chroma_paddr, in_chroma2_paddr);
555
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700557 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
558 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
559
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700560 iowrite32(out_paddr +
561 ((info->dst_y * info->dst.width) + info->dst_x),
562 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700563 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564 ((info->dst_y * info->dst.width)/2 + info->dst_x),
565 MSM_ROTATOR_OUTP1_ADDR);
566
567 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700568 if (in_chroma2_paddr) {
569 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530570 iowrite32(ALIGN(info->src.width, 16) |
571 ALIGN((info->src.width / 2), 16) << 16,
572 MSM_ROTATOR_SRC_YSTRIDE1);
573 iowrite32(ALIGN((info->src.width / 2), 16),
574 MSM_ROTATOR_SRC_YSTRIDE2);
575 } else {
576 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700577 (info->src.width / 2) << 16,
578 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530579 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700580 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530581 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700582 } else {
583 iowrite32(info->src.width |
584 info->src.width << 16,
585 MSM_ROTATOR_SRC_YSTRIDE1);
586 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700587 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700588 info->dst.width << 16,
589 MSM_ROTATOR_OUT_YSTRIDE1);
590
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700591 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
593 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
594 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
595 MSM_ROTATOR_OUT_PACK_PATTERN1);
596 } else {
597 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
598 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
599 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
600 MSM_ROTATOR_OUT_PACK_PATTERN1);
601 }
602 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
603 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700604 1 << 8 | /* ROT_EN */
605 info->downscale_ratio << 2 | /* downscale v ratio */
606 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700607 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700608
609 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700610 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700611 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 0 << 18 | /* unpack align */
613 1 << 17 | /* unpack tight */
614 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700615 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700616 0 << 8 | /* has alpha */
617 0 << 6 | /* alpha bits 3=8bits */
618 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
619 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
620 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
621 MSM_ROTATOR_SRC_FORMAT);
622 }
623 return 0;
624}
625
626static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
627 unsigned int in_paddr,
628 unsigned int out_paddr,
629 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530630 int new_session,
631 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700632{
633 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530634 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700635
Mayank Chopra732dcd62012-01-09 20:53:39 +0530636 if (info->src.format == MDP_YCRYCB_H2V1)
637 dst_format = MDP_Y_CRCB_H2V1;
638 else
639 return -EINVAL;
640
641 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 return -EINVAL;
643
644 bpp = get_bpp(info->src.format);
645 if (bpp < 0)
646 return -ENOTTY;
647
648 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
649 iowrite32(out_paddr +
650 ((info->dst_y * info->dst.width) + info->dst_x),
651 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530652 iowrite32(out_chroma_paddr +
653 ((info->dst_y * info->dst.width)/2 + info->dst_x),
654 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700655
656 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530657 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700658 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530659 if (info->rotations & MDP_ROT_90)
660 iowrite32(info->dst.width |
661 (info->dst.width*2) << 16,
662 MSM_ROTATOR_OUT_YSTRIDE1);
663 else
664 iowrite32(info->dst.width |
665 (info->dst.width) << 16,
666 MSM_ROTATOR_OUT_YSTRIDE1);
667
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
669 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530670 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671 MSM_ROTATOR_OUT_PACK_PATTERN1);
672 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
673 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700674 1 << 8 | /* ROT_EN */
675 info->downscale_ratio << 2 | /* downscale v ratio */
676 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700677 MSM_ROTATOR_SUB_BLOCK_CFG);
678 iowrite32(0 << 29 | /* frame format 0 = linear */
679 (use_imem ? 0 : 1) << 22 | /* tile size */
680 0 << 19 | /* fetch planes 0=interleaved */
681 0 << 18 | /* unpack align */
682 1 << 17 | /* unpack tight */
683 3 << 13 | /* unpack count 0=1 component */
684 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
685 0 << 8 | /* has alpha */
686 0 << 6 | /* alpha bits 3=8bits */
687 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
688 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
689 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
690 MSM_ROTATOR_SRC_FORMAT);
691 }
692
693 return 0;
694}
695
696static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
697 unsigned int in_paddr,
698 unsigned int out_paddr,
699 unsigned int use_imem,
700 int new_session)
701{
702 int bpp, abits, rbits, gbits, bbits;
703
704 if (info->src.format != info->dst.format)
705 return -EINVAL;
706
707 bpp = get_bpp(info->src.format);
708 if (bpp < 0)
709 return -ENOTTY;
710
711 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
712 iowrite32(out_paddr +
713 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
714 MSM_ROTATOR_OUTP0_ADDR);
715
716 if (new_session) {
717 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
718 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
719 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
720 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700721 1 << 8 | /* ROT_EN */
722 info->downscale_ratio << 2 | /* downscale v ratio */
723 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700724 MSM_ROTATOR_SUB_BLOCK_CFG);
725 switch (info->src.format) {
726 case MDP_RGB_565:
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_5BITS;
733 gbits = COMPONENT_6BITS;
734 bbits = COMPONENT_5BITS;
735 break;
736
737 case MDP_BGR_565:
738 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
739 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
740 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
741 MSM_ROTATOR_OUT_PACK_PATTERN1);
742 abits = 0;
743 rbits = COMPONENT_5BITS;
744 gbits = COMPONENT_6BITS;
745 bbits = COMPONENT_5BITS;
746 break;
747
748 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700749 case MDP_YCBCR_H1V1:
750 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700751 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
752 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
753 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
754 MSM_ROTATOR_OUT_PACK_PATTERN1);
755 abits = 0;
756 rbits = COMPONENT_8BITS;
757 gbits = COMPONENT_8BITS;
758 bbits = COMPONENT_8BITS;
759 break;
760
761 case MDP_ARGB_8888:
762 case MDP_RGBA_8888:
763 case MDP_XRGB_8888:
764 case MDP_RGBX_8888:
765 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
766 CLR_B, 8),
767 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
768 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
769 CLR_B, 8),
770 MSM_ROTATOR_OUT_PACK_PATTERN1);
771 abits = COMPONENT_8BITS;
772 rbits = COMPONENT_8BITS;
773 gbits = COMPONENT_8BITS;
774 bbits = COMPONENT_8BITS;
775 break;
776
777 case MDP_BGRA_8888:
778 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
779 CLR_R, 8),
780 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
781 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
782 CLR_R, 8),
783 MSM_ROTATOR_OUT_PACK_PATTERN1);
784 abits = COMPONENT_8BITS;
785 rbits = COMPONENT_8BITS;
786 gbits = COMPONENT_8BITS;
787 bbits = COMPONENT_8BITS;
788 break;
789
790 default:
791 return -EINVAL;
792 }
793 iowrite32(0 << 29 | /* frame format 0 = linear */
794 (use_imem ? 0 : 1) << 22 | /* tile size */
795 0 << 19 | /* fetch planes 0=interleaved */
796 0 << 18 | /* unpack align */
797 1 << 17 | /* unpack tight */
798 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
799 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
800 (abits ? 1 : 0) << 8 | /* has alpha */
801 abits << 6 | /* alpha bits 3=8bits */
802 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
803 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
804 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
805 MSM_ROTATOR_SRC_FORMAT);
806 }
807
808 return 0;
809}
810
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530811static int get_img(struct msmfb_data *fbd, unsigned char src,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700812 unsigned long *start, unsigned long *len, struct file **p_file,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530813 int *p_need, struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700814{
815 int ret = 0;
816#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700817 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700818 int put_needed, fb_num;
819#endif
820#ifdef CONFIG_ANDROID_PMEM
821 unsigned long vstart;
822#endif
823
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800824 *p_need = 0;
825
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700826#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700827 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
828 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700829 if (file == NULL) {
830 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700831 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700832 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700833
Naseer Ahmed18018602011-10-25 13:32:58 -0700834 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
835 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700836 if (get_fb_phys_info(start, len, fb_num,
837 ROTATOR_SUBSYSTEM_ID)) {
838 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700839 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700840 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700841 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800842 *p_need = put_needed;
843 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700844 } else {
845 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700846 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700847 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700848 if (ret)
849 fput_light(file, put_needed);
850 return ret;
851 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700853
854#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530855 return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
856 len, p_ihdl);
Naseer Ahmed18018602011-10-25 13:32:58 -0700857#endif
858#ifdef CONFIG_ANDROID_PMEM
859 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
860 return 0;
861 else
862 return -ENOMEM;
863#endif
864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865}
866
Olav Haugan9ae9bea2012-05-15 09:50:30 -0700867static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530868 unsigned char src)
Naseer Ahmed18018602011-10-25 13:32:58 -0700869{
870#ifdef CONFIG_ANDROID_PMEM
871 if (p_file != NULL)
872 put_pmem_file(p_file);
873#endif
Olav Haugan9ae9bea2012-05-15 09:50:30 -0700874
Naseer Ahmed18018602011-10-25 13:32:58 -0700875#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700876 if (!IS_ERR_OR_NULL(p_ihdl)) {
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530877 int domain = src ? ROTATOR_SRC_DOMAIN : \
878 ROTATOR_DST_DOMAIN;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700879 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530880 ion_unmap_iommu(msm_rotator_dev->client,
881 p_ihdl, domain, GEN_POOL);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700882
Naseer Ahmed18018602011-10-25 13:32:58 -0700883 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700884 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700885#endif
886}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887static int msm_rotator_do_rotate(unsigned long arg)
888{
Naseer Ahmed18018602011-10-25 13:32:58 -0700889 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700890 struct msm_rotator_data_info info;
891 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700892 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700893 int use_imem = 0, rc = 0, s;
894 struct file *srcp0_file = NULL, *dstp0_file = NULL;
895 struct file *srcp1_file = NULL, *dstp1_file = NULL;
896 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
897 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800898 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700900 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700901 struct msm_rotator_img_info *img_info;
902 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700903
904 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
905 return -EFAULT;
906
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 mutex_lock(&msm_rotator_dev->rotator_lock);
908 for (s = 0; s < MAX_SESSIONS; s++)
909 if ((msm_rotator_dev->img_info[s] != NULL) &&
910 (info.session_id ==
911 (unsigned int)msm_rotator_dev->img_info[s]
912 ))
913 break;
914
915 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700916 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700917 __func__, s);
918 rc = -EINVAL;
919 goto do_rotate_unlock_mutex;
920 }
921
922 if (msm_rotator_dev->img_info[s]->enable == 0) {
923 dev_dbg(msm_rotator_dev->device,
924 "%s() : Session_id %d not enabled \n",
925 __func__, s);
926 rc = -EINVAL;
927 goto do_rotate_unlock_mutex;
928 }
929
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700930 img_info = msm_rotator_dev->img_info[s];
931 if (msm_rotator_get_plane_sizes(img_info->src.format,
932 img_info->src.width,
933 img_info->src.height,
934 &src_planes)) {
935 pr_err("%s: invalid src format\n", __func__);
936 rc = -EINVAL;
937 goto do_rotate_unlock_mutex;
938 }
939 if (msm_rotator_get_plane_sizes(img_info->dst.format,
940 img_info->dst.width,
941 img_info->dst.height,
942 &dst_planes)) {
943 pr_err("%s: invalid dst format\n", __func__);
944 rc = -EINVAL;
945 goto do_rotate_unlock_mutex;
946 }
947
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530948 rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700949 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530950 &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700951 if (rc) {
952 pr_err("%s: in get_img() failed id=0x%08x\n",
953 DRIVER_NAME, info.src.memory_id);
954 goto do_rotate_unlock_mutex;
955 }
956
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530957 rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700958 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530959 &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700960 if (rc) {
961 pr_err("%s: out get_img() failed id=0x%08x\n",
962 DRIVER_NAME, info.dst.memory_id);
963 goto do_rotate_unlock_mutex;
964 }
965
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 format = msm_rotator_dev->img_info[s]->src.format;
967 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700968 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
969 (src_planes.num_planes == 2)) {
970 if (checkoffset(info.src.offset,
971 src_planes.plane_size[0],
972 src_len)) {
973 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
974 __func__, src_len, info.src.offset);
975 rc = -ERANGE;
976 goto do_rotate_unlock_mutex;
977 }
978 if (checkoffset(info.dst.offset,
979 dst_planes.plane_size[0],
980 dst_len)) {
981 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
982 __func__, dst_len, info.dst.offset);
983 rc = -ERANGE;
984 goto do_rotate_unlock_mutex;
985 }
986
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530987 rc = get_img(&info.src_chroma, 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700988 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800989 (unsigned long *)&src_len, &srcp1_file, &p_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530990 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700992 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700993 DRIVER_NAME, info.src_chroma.memory_id);
994 goto do_rotate_unlock_mutex;
995 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530997 rc = get_img(&info.dst_chroma, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700998 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800999 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +05301000 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001002 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001004 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001005 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001006
1007 if (checkoffset(info.src_chroma.offset,
1008 src_planes.plane_size[1],
1009 src_len)) {
1010 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1011 __func__, src_len, info.src_chroma.offset);
1012 rc = -ERANGE;
1013 goto do_rotate_unlock_mutex;
1014 }
1015
1016 if (checkoffset(info.dst_chroma.offset,
1017 src_planes.plane_size[1],
1018 dst_len)) {
1019 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1020 __func__, dst_len, info.dst_chroma.offset);
1021 rc = -ERANGE;
1022 goto do_rotate_unlock_mutex;
1023 }
1024
1025 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001027 } else {
1028 if (checkoffset(info.src.offset,
1029 src_planes.total_size,
1030 src_len)) {
1031 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1032 __func__, src_len, info.src.offset);
1033 rc = -ERANGE;
1034 goto do_rotate_unlock_mutex;
1035 }
1036 if (checkoffset(info.dst.offset,
1037 dst_planes.total_size,
1038 dst_len)) {
1039 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1040 __func__, dst_len, info.dst.offset);
1041 rc = -ERANGE;
1042 goto do_rotate_unlock_mutex;
1043 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 }
1045
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001046 in_paddr += info.src.offset;
1047 out_paddr += info.dst.offset;
1048
1049 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1050 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1051 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1052 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1053 if (src_planes.num_planes >= 3)
1054 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1055
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001056 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1057 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1058 enable_rot_clks();
1059 msm_rotator_dev->rot_clk_state = CLK_EN;
1060 }
1061 enable_irq(msm_rotator_dev->irq);
1062
1063#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1064 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1065#else
1066 use_imem = 0;
1067#endif
1068 /*
1069 * workaround for a hardware bug. rotator hardware hangs when we
1070 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1071 * temporary fix use 0x42 for BURST_SIZE when imem used.
1072 */
1073 if (use_imem)
1074 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1075
1076 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1077 << 16) |
1078 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1079 MSM_ROTATOR_SRC_SIZE);
1080 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1081 << 16) |
1082 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1083 MSM_ROTATOR_SRC_XY);
1084 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1085 << 16) |
1086 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1087 MSM_ROTATOR_SRC_IMAGE_SIZE);
1088
1089 switch (format) {
1090 case MDP_RGB_565:
1091 case MDP_BGR_565:
1092 case MDP_RGB_888:
1093 case MDP_ARGB_8888:
1094 case MDP_RGBA_8888:
1095 case MDP_XRGB_8888:
1096 case MDP_BGRA_8888:
1097 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001098 case MDP_YCBCR_H1V1:
1099 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001100 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1101 in_paddr, out_paddr,
1102 use_imem,
1103 msm_rotator_dev->last_session_idx
1104 != s);
1105 break;
1106 case MDP_Y_CBCR_H2V2:
1107 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001108 case MDP_Y_CB_CR_H2V2:
1109 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301110 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001111 case MDP_Y_CRCB_H2V2_TILE:
1112 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001113 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1114 in_paddr, out_paddr, use_imem,
1115 msm_rotator_dev->last_session_idx
1116 != s,
1117 in_chroma_paddr,
1118 out_chroma_paddr,
1119 in_chroma2_paddr);
1120 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 case MDP_Y_CBCR_H2V1:
1122 case MDP_Y_CRCB_H2V1:
1123 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1124 in_paddr, out_paddr, use_imem,
1125 msm_rotator_dev->last_session_idx
1126 != s,
1127 in_chroma_paddr,
1128 out_chroma_paddr);
1129 break;
1130 case MDP_YCRYCB_H2V1:
1131 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1132 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301133 msm_rotator_dev->last_session_idx != s,
1134 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001135 break;
1136 default:
1137 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001138 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001139 goto do_rotate_exit;
1140 }
1141
1142 if (rc != 0) {
1143 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001144 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001145 goto do_rotate_exit;
1146 }
1147
1148 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1149
1150 msm_rotator_dev->processing = 1;
1151 iowrite32(0x1, MSM_ROTATOR_START);
1152
1153 wait_event(msm_rotator_dev->wq,
1154 (msm_rotator_dev->processing == 0));
1155 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001156 if ((status & 0x03) != 0x01) {
1157 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1158 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001160 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001161 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1162 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1163
1164do_rotate_exit:
1165 disable_irq(msm_rotator_dev->irq);
1166#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1167 msm_rotator_imem_free(ROTATOR_REQUEST);
1168#endif
1169 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001170do_rotate_unlock_mutex:
Mayank Chopraca4d9bc2012-06-27 15:30:19 +05301171 put_img(dstp1_file, dstp1_ihdl, 0);
1172 put_img(srcp1_file, srcp1_ihdl, 1);
1173 put_img(dstp0_file, dstp0_ihdl, 0);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001174
1175 /* only source may use frame buffer */
1176 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1177 fput_light(srcp0_file, ps0_need);
1178 else
Mayank Chopraca4d9bc2012-06-27 15:30:19 +05301179 put_img(srcp0_file, srcp0_ihdl, 1);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001180 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001181 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1182 __func__, rc);
1183 return rc;
1184}
1185
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001186static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1187{
1188 u32 perf_level;
1189
1190 if (is_rgb)
1191 perf_level = 1;
1192 else if (wh <= (640 * 480))
1193 perf_level = 2;
1194 else if (wh <= (736 * 1280))
1195 perf_level = 3;
1196 else
1197 perf_level = 4;
1198
1199#ifdef CONFIG_MSM_BUS_SCALING
1200 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1201 perf_level);
1202#endif
1203
1204}
1205
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001206static int msm_rotator_start(unsigned long arg,
1207 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208{
1209 struct msm_rotator_img_info info;
1210 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001211 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001212 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001213 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214
1215 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1216 return -EFAULT;
1217
1218 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1219 (info.src.height > MSM_ROTATOR_MAX_H) ||
1220 (info.src.width > MSM_ROTATOR_MAX_W) ||
1221 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1222 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001223 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1224 pr_err("%s: Invalid parameters\n", __func__);
1225 return -EINVAL;
1226 }
1227
1228 if (info.rotations & MDP_ROT_90) {
1229 dst_w = info.src_rect.h >> info.downscale_ratio;
1230 dst_h = info.src_rect.w >> info.downscale_ratio;
1231 } else {
1232 dst_w = info.src_rect.w >> info.downscale_ratio;
1233 dst_h = info.src_rect.h >> info.downscale_ratio;
1234 }
1235
1236 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001237 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1238 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001239 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1240 pr_err("%s: Invalid src or dst rect\n", __func__);
1241 return -ERANGE;
1242 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243
1244 switch (info.src.format) {
1245 case MDP_RGB_565:
1246 case MDP_BGR_565:
1247 case MDP_RGB_888:
1248 case MDP_ARGB_8888:
1249 case MDP_RGBA_8888:
1250 case MDP_XRGB_8888:
1251 case MDP_RGBX_8888:
1252 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001253 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301254 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001255 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 case MDP_Y_CBCR_H2V2:
1257 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301258 case MDP_Y_CBCR_H2V1:
1259 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001260 case MDP_YCBCR_H1V1:
1261 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301262 info.dst.format = info.src.format;
1263 break;
1264 case MDP_YCRYCB_H2V1:
1265 info.dst.format = MDP_Y_CRCB_H2V1;
1266 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001267 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301268 case MDP_Y_CBCR_H2V2_TILE:
1269 info.dst.format = MDP_Y_CBCR_H2V2;
1270 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001271 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301272 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301274 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001275 break;
1276 default:
1277 return -EINVAL;
1278 }
1279
1280 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001281
1282 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1283
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001284 for (s = 0; s < MAX_SESSIONS; s++) {
1285 if ((msm_rotator_dev->img_info[s] != NULL) &&
1286 (info.session_id ==
1287 (unsigned int)msm_rotator_dev->img_info[s]
1288 )) {
1289 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001290 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291
1292 if (msm_rotator_dev->last_session_idx == s)
1293 msm_rotator_dev->last_session_idx =
1294 INVALID_SESSION;
1295 break;
1296 }
1297
1298 if ((msm_rotator_dev->img_info[s] == NULL) &&
1299 (first_free_index ==
1300 INVALID_SESSION))
1301 first_free_index = s;
1302 }
1303
1304 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1305 /* allocate a session id */
1306 msm_rotator_dev->img_info[first_free_index] =
1307 kzalloc(sizeof(struct msm_rotator_img_info),
1308 GFP_KERNEL);
1309 if (!msm_rotator_dev->img_info[first_free_index]) {
1310 printk(KERN_ERR "%s : unable to alloc mem\n",
1311 __func__);
1312 rc = -ENOMEM;
1313 goto rotator_start_exit;
1314 }
1315 info.session_id = (unsigned int)
1316 msm_rotator_dev->img_info[first_free_index];
1317 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001318 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 } else if (s == MAX_SESSIONS) {
1320 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1321 __func__);
1322 rc = -EBUSY;
1323 }
1324
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001325 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1326 rc = -EFAULT;
1327
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328rotator_start_exit:
1329 mutex_unlock(&msm_rotator_dev->rotator_lock);
1330
1331 return rc;
1332}
1333
1334static int msm_rotator_finish(unsigned long arg)
1335{
1336 int rc = 0;
1337 int s;
1338 unsigned int session_id;
1339
1340 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1341 return -EFAULT;
1342
1343 mutex_lock(&msm_rotator_dev->rotator_lock);
1344 for (s = 0; s < MAX_SESSIONS; s++) {
1345 if ((msm_rotator_dev->img_info[s] != NULL) &&
1346 (session_id ==
1347 (unsigned int)msm_rotator_dev->img_info[s])) {
1348 if (msm_rotator_dev->last_session_idx == s)
1349 msm_rotator_dev->last_session_idx =
1350 INVALID_SESSION;
1351 kfree(msm_rotator_dev->img_info[s]);
1352 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001353 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001354 break;
1355 }
1356 }
1357
1358 if (s == MAX_SESSIONS)
1359 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001360#ifdef CONFIG_MSM_BUS_SCALING
1361 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1362 0);
1363#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001364 mutex_unlock(&msm_rotator_dev->rotator_lock);
1365 return rc;
1366}
1367
1368static int
1369msm_rotator_open(struct inode *inode, struct file *filp)
1370{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001371 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 int i;
1373
1374 if (filp->private_data)
1375 return -EBUSY;
1376
1377 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001378 for (i = 0; i < MAX_SESSIONS; i++) {
1379 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 break;
1381 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001382
1383 if (i == MAX_SESSIONS) {
1384 mutex_unlock(&msm_rotator_dev->rotator_lock);
1385 return -EBUSY;
1386 }
1387
1388 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1389 if (tmp->pid == current->pid) {
1390 fd_info = tmp;
1391 break;
1392 }
1393 }
1394
1395 if (!fd_info) {
1396 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1397 if (!fd_info) {
1398 mutex_unlock(&msm_rotator_dev->rotator_lock);
1399 pr_err("%s: insufficient memory to alloc resources\n",
1400 __func__);
1401 return -ENOMEM;
1402 }
1403 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1404 fd_info->pid = current->pid;
1405 }
1406 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407 mutex_unlock(&msm_rotator_dev->rotator_lock);
1408
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001409 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410
1411 return 0;
1412}
1413
1414static int
1415msm_rotator_close(struct inode *inode, struct file *filp)
1416{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001417 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001419
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001420 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1421
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001423 if (--fd_info->ref_cnt > 0) {
1424 mutex_unlock(&msm_rotator_dev->rotator_lock);
1425 return 0;
1426 }
1427
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 for (s = 0; s < MAX_SESSIONS; s++) {
1429 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001430 msm_rotator_dev->fd_info[s] == fd_info) {
1431 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1432 __func__, msm_rotator_dev->img_info[s],
1433 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001434 kfree(msm_rotator_dev->img_info[s]);
1435 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001436 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001437 if (msm_rotator_dev->last_session_idx == s)
1438 msm_rotator_dev->last_session_idx =
1439 INVALID_SESSION;
1440 }
1441 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001442 list_del(&fd_info->list);
1443 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001444 mutex_unlock(&msm_rotator_dev->rotator_lock);
1445
1446 return 0;
1447}
1448
1449static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1450 unsigned long arg)
1451{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001452 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001453
1454 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1455 return -ENOTTY;
1456
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001457 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458
1459 switch (cmd) {
1460 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001461 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001462 case MSM_ROTATOR_IOCTL_ROTATE:
1463 return msm_rotator_do_rotate(arg);
1464 case MSM_ROTATOR_IOCTL_FINISH:
1465 return msm_rotator_finish(arg);
1466
1467 default:
1468 dev_dbg(msm_rotator_dev->device,
1469 "unexpected IOCTL %d\n", cmd);
1470 return -ENOTTY;
1471 }
1472}
1473
1474static const struct file_operations msm_rotator_fops = {
1475 .owner = THIS_MODULE,
1476 .open = msm_rotator_open,
1477 .release = msm_rotator_close,
1478 .unlocked_ioctl = msm_rotator_ioctl,
1479};
1480
1481static int __devinit msm_rotator_probe(struct platform_device *pdev)
1482{
1483 int rc = 0;
1484 struct resource *res;
1485 struct msm_rotator_platform_data *pdata = NULL;
1486 int i, number_of_clks;
1487 uint32_t ver;
1488
1489 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1490 if (!msm_rotator_dev) {
1491 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1492 __func__);
1493 return -ENOMEM;
1494 }
1495 for (i = 0; i < MAX_SESSIONS; i++)
1496 msm_rotator_dev->img_info[i] = NULL;
1497 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1498
1499 pdata = pdev->dev.platform_data;
1500 number_of_clks = pdata->number_of_clocks;
1501
1502 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1503 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001504 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001505 msm_rotator_dev->imem_clk_state = CLK_DIS;
1506 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1507 msm_rotator_imem_clk_work_f);
1508 msm_rotator_dev->imem_clk = NULL;
1509 msm_rotator_dev->pdev = pdev;
1510
1511 msm_rotator_dev->core_clk = NULL;
1512 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001514#ifdef CONFIG_MSM_BUS_SCALING
1515 if (!msm_rotator_dev->bus_client_handle && pdata &&
1516 pdata->bus_scale_table) {
1517 msm_rotator_dev->bus_client_handle =
1518 msm_bus_scale_register_client(
1519 pdata->bus_scale_table);
1520 if (!msm_rotator_dev->bus_client_handle) {
1521 pr_err("%s not able to get bus scale handle\n",
1522 __func__);
1523 }
1524 }
1525#endif
1526
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001527 for (i = 0; i < number_of_clks; i++) {
1528 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1529 msm_rotator_dev->imem_clk =
1530 clk_get(&msm_rotator_dev->pdev->dev,
1531 pdata->rotator_clks[i].clk_name);
1532 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1533 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1534 msm_rotator_dev->imem_clk = NULL;
1535 printk(KERN_ERR "%s: cannot get imem_clk "
1536 "rc=%d\n", DRIVER_NAME, rc);
1537 goto error_imem_clk;
1538 }
1539 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001540 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001541 pdata->rotator_clks[i].clk_rate);
1542 }
1543 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1544 msm_rotator_dev->pclk =
1545 clk_get(&msm_rotator_dev->pdev->dev,
1546 pdata->rotator_clks[i].clk_name);
1547 if (IS_ERR(msm_rotator_dev->pclk)) {
1548 rc = PTR_ERR(msm_rotator_dev->pclk);
1549 msm_rotator_dev->pclk = NULL;
1550 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1551 DRIVER_NAME, rc);
1552 goto error_pclk;
1553 }
1554
1555 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001556 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001557 pdata->rotator_clks[i].clk_rate);
1558 }
1559
1560 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1561 msm_rotator_dev->core_clk =
1562 clk_get(&msm_rotator_dev->pdev->dev,
1563 pdata->rotator_clks[i].clk_name);
1564 if (IS_ERR(msm_rotator_dev->core_clk)) {
1565 rc = PTR_ERR(msm_rotator_dev->core_clk);
1566 msm_rotator_dev->core_clk = NULL;
1567 printk(KERN_ERR "%s: cannot get core clk "
1568 "rc=%d\n", DRIVER_NAME, rc);
1569 goto error_core_clk;
1570 }
1571
1572 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001573 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001574 pdata->rotator_clks[i].clk_rate);
1575 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001576 }
1577
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001578 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1579 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 if (IS_ERR(msm_rotator_dev->regulator))
1581 msm_rotator_dev->regulator = NULL;
1582
1583 msm_rotator_dev->rot_clk_state = CLK_DIS;
1584 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1585 msm_rotator_rot_clk_work_f);
1586
1587 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001588#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1589 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1590#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001591 platform_set_drvdata(pdev, msm_rotator_dev);
1592
1593
1594 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1595 if (!res) {
1596 printk(KERN_ALERT
1597 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1598 rc = -ENODEV;
1599 goto error_get_resource;
1600 }
1601 msm_rotator_dev->io_base = ioremap(res->start,
1602 resource_size(res));
1603
1604#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1605 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001606 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001607#endif
1608 enable_rot_clks();
1609 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1610 disable_rot_clks();
1611
1612#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1613 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001614 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001616 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301617 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001618 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001619
Mayank Chopra012a8e72012-04-11 10:41:13 +05301620 rotator_hw_revision = ver;
1621 rotator_hw_revision >>= 16; /* bit 31:16 */
1622 rotator_hw_revision &= 0xff;
1623
1624 pr_info("%s: rotator_hw_revision=%x\n",
1625 __func__, rotator_hw_revision);
1626
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001627 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1628 if (msm_rotator_dev->irq < 0) {
1629 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1630 DRIVER_NAME);
1631 rc = -ENODEV;
1632 goto error_get_irq;
1633 }
1634 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1635 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1636 if (rc) {
1637 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1638 goto error_get_irq;
1639 }
1640 /* we enable the IRQ when we need it in the ioctl */
1641 disable_irq(msm_rotator_dev->irq);
1642
1643 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1644 if (rc < 0) {
1645 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1646 __func__, rc);
1647 goto error_get_irq;
1648 }
1649
1650 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1651 if (IS_ERR(msm_rotator_dev->class)) {
1652 rc = PTR_ERR(msm_rotator_dev->class);
1653 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1654 DRIVER_NAME, rc);
1655 goto error_class_create;
1656 }
1657
1658 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1659 msm_rotator_dev->dev_num, NULL,
1660 DRIVER_NAME);
1661 if (IS_ERR(msm_rotator_dev->device)) {
1662 rc = PTR_ERR(msm_rotator_dev->device);
1663 printk(KERN_ERR "%s: device_create failed %d\n",
1664 DRIVER_NAME, rc);
1665 goto error_class_device_create;
1666 }
1667
1668 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1669 rc = cdev_add(&msm_rotator_dev->cdev,
1670 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1671 1);
1672 if (rc < 0) {
1673 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1674 goto error_cdev_add;
1675 }
1676
1677 init_waitqueue_head(&msm_rotator_dev->wq);
1678
1679 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1680 return rc;
1681
1682error_cdev_add:
1683 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1684error_class_device_create:
1685 class_destroy(msm_rotator_dev->class);
1686error_class_create:
1687 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1688error_get_irq:
1689 iounmap(msm_rotator_dev->io_base);
1690error_get_resource:
1691 mutex_destroy(&msm_rotator_dev->rotator_lock);
1692 if (msm_rotator_dev->regulator)
1693 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001694 clk_put(msm_rotator_dev->core_clk);
1695error_core_clk:
1696 clk_put(msm_rotator_dev->pclk);
1697error_pclk:
1698 if (msm_rotator_dev->imem_clk)
1699 clk_put(msm_rotator_dev->imem_clk);
1700error_imem_clk:
1701 mutex_destroy(&msm_rotator_dev->imem_lock);
1702 kfree(msm_rotator_dev);
1703 return rc;
1704}
1705
1706static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1707{
1708 int i;
1709
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001710#ifdef CONFIG_MSM_BUS_SCALING
1711 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1712#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001713 free_irq(msm_rotator_dev->irq, NULL);
1714 mutex_destroy(&msm_rotator_dev->rotator_lock);
1715 cdev_del(&msm_rotator_dev->cdev);
1716 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1717 class_destroy(msm_rotator_dev->class);
1718 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1719 iounmap(msm_rotator_dev->io_base);
1720 if (msm_rotator_dev->imem_clk) {
1721 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001722 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001723 clk_put(msm_rotator_dev->imem_clk);
1724 msm_rotator_dev->imem_clk = NULL;
1725 }
1726 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1727 disable_rot_clks();
1728 clk_put(msm_rotator_dev->core_clk);
1729 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001730 if (msm_rotator_dev->regulator)
1731 regulator_put(msm_rotator_dev->regulator);
1732 msm_rotator_dev->core_clk = NULL;
1733 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734 mutex_destroy(&msm_rotator_dev->imem_lock);
1735 for (i = 0; i < MAX_SESSIONS; i++)
1736 if (msm_rotator_dev->img_info[i] != NULL)
1737 kfree(msm_rotator_dev->img_info[i]);
1738 kfree(msm_rotator_dev);
1739 return 0;
1740}
1741
1742#ifdef CONFIG_PM
1743static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1744{
1745 mutex_lock(&msm_rotator_dev->imem_lock);
1746 if (msm_rotator_dev->imem_clk_state == CLK_EN
1747 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001748 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001749 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1750 }
1751 mutex_unlock(&msm_rotator_dev->imem_lock);
1752 mutex_lock(&msm_rotator_dev->rotator_lock);
1753 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1754 disable_rot_clks();
1755 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1756 }
1757 mutex_unlock(&msm_rotator_dev->rotator_lock);
1758 return 0;
1759}
1760
1761static int msm_rotator_resume(struct platform_device *dev)
1762{
1763 mutex_lock(&msm_rotator_dev->imem_lock);
1764 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1765 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001766 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001767 msm_rotator_dev->imem_clk_state = CLK_EN;
1768 }
1769 mutex_unlock(&msm_rotator_dev->imem_lock);
1770 mutex_lock(&msm_rotator_dev->rotator_lock);
1771 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1772 enable_rot_clks();
1773 msm_rotator_dev->rot_clk_state = CLK_EN;
1774 }
1775 mutex_unlock(&msm_rotator_dev->rotator_lock);
1776 return 0;
1777}
1778#endif
1779
1780static struct platform_driver msm_rotator_platform_driver = {
1781 .probe = msm_rotator_probe,
1782 .remove = __devexit_p(msm_rotator_remove),
1783#ifdef CONFIG_PM
1784 .suspend = msm_rotator_suspend,
1785 .resume = msm_rotator_resume,
1786#endif
1787 .driver = {
1788 .owner = THIS_MODULE,
1789 .name = DRIVER_NAME
1790 }
1791};
1792
1793static int __init msm_rotator_init(void)
1794{
1795 return platform_driver_register(&msm_rotator_platform_driver);
1796}
1797
1798static void __exit msm_rotator_exit(void)
1799{
1800 return platform_driver_unregister(&msm_rotator_platform_driver);
1801}
1802
1803module_init(msm_rotator_init);
1804module_exit(msm_rotator_exit);
1805
1806MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1807MODULE_VERSION("1.0");
1808MODULE_LICENSE("GPL v2");