blob: e783a1a4ad081f86769404c4656ffb82bb3d2a37 [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;
Olav Hauganef95ae32012-05-15 09:50:30 -0700100static char rot_iommu_split_domain;
Mayank Chopra012a8e72012-04-11 10:41:13 +0530101
102/*
103 * rotator_hw_revision:
104 * 0 == 7x30
105 * 1 == 8x60
106 * 2 == 8960
107 *
108 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700109struct tile_parm {
110 unsigned int width; /* tile's width */
111 unsigned int height; /* tile's height */
112 unsigned int row_tile_w; /* tiles per row's width */
113 unsigned int row_tile_h; /* tiles per row's height */
114};
115
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700116struct msm_rotator_mem_planes {
117 unsigned int num_planes;
118 unsigned int plane_size[4];
119 unsigned int total_size;
120};
121
122#define checkoffset(offset, size, max_size) \
123 ((size) > (max_size) || (offset) > ((max_size) - (size)))
124
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700125struct msm_rotator_fd_info {
126 int pid;
127 int ref_cnt;
128 struct list_head list;
129};
130
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700131struct msm_rotator_dev {
132 void __iomem *io_base;
133 int irq;
134 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
135 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700136 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
137 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700139 int rot_clk_state;
140 struct regulator *regulator;
141 struct delayed_work rot_clk_work;
142 struct clk *imem_clk;
143 int imem_clk_state;
144 struct delayed_work imem_clk_work;
145 struct platform_device *pdev;
146 struct cdev cdev;
147 struct device *device;
148 struct class *class;
149 dev_t dev_num;
150 int processing;
151 int last_session_idx;
152 struct mutex rotator_lock;
153 struct mutex imem_lock;
154 int imem_owner;
155 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700156 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800157 #ifdef CONFIG_MSM_BUS_SCALING
158 uint32_t bus_client_handle;
159 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160};
161
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162#define COMPONENT_5BITS 1
163#define COMPONENT_6BITS 2
164#define COMPONENT_8BITS 3
165
166static struct msm_rotator_dev *msm_rotator_dev;
167
168enum {
169 CLK_EN,
170 CLK_DIS,
171 CLK_SUSPEND,
172};
173
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530174int msm_rotator_iommu_map_buf(int mem_id, unsigned char src,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700175 unsigned long *start, unsigned long *len,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530176 struct ion_handle **pihdl)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700177{
Olav Hauganef95ae32012-05-15 09:50:30 -0700178 int domain;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700179 if (!msm_rotator_dev->client)
180 return -EINVAL;
181
Laura Abbottb14ed962012-01-30 14:18:08 -0800182 *pihdl = ion_import_dma_buf(msm_rotator_dev->client, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700183 if (IS_ERR_OR_NULL(*pihdl)) {
Laura Abbottb14ed962012-01-30 14:18:08 -0800184 pr_err("ion_import_dma_buf() failed\n");
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700185 return PTR_ERR(*pihdl);
186 }
Laura Abbottb14ed962012-01-30 14:18:08 -0800187 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl,
188 ion_share_dma_buf(msm_rotator_dev->client, *pihdl));
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700189
Olav Hauganef95ae32012-05-15 09:50:30 -0700190 if (rot_iommu_split_domain)
191 domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
192 else
193 domain = ROTATOR_SRC_DOMAIN;
194
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530195 if (ion_map_iommu(msm_rotator_dev->client,
Olav Hauganef95ae32012-05-15 09:50:30 -0700196 *pihdl, domain, GEN_POOL,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530197 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
198 pr_err("ion_map_iommu() failed\n");
199 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700200 }
201
202 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
203 __func__, mem_id, *start, *len);
204 return 0;
205}
206
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700207int msm_rotator_imem_allocate(int requestor)
208{
209 int rc = 0;
210
211#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
212 switch (requestor) {
213 case ROTATOR_REQUEST:
214 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
215 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
216 rc = 1;
217 } else
218 rc = 0;
219 break;
220 case JPEG_REQUEST:
221 mutex_lock(&msm_rotator_dev->imem_lock);
222 msm_rotator_dev->imem_owner = JPEG_REQUEST;
223 rc = 1;
224 break;
225 default:
226 rc = 0;
227 }
228#else
229 if (requestor == JPEG_REQUEST)
230 rc = 1;
231#endif
232 if (rc == 1) {
233 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
234 if (msm_rotator_dev->imem_clk_state != CLK_EN
235 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700236 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700237 msm_rotator_dev->imem_clk_state = CLK_EN;
238 }
239 }
240
241 return rc;
242}
243EXPORT_SYMBOL(msm_rotator_imem_allocate);
244
245void msm_rotator_imem_free(int requestor)
246{
247#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
248 if (msm_rotator_dev->imem_owner == requestor) {
249 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
250 mutex_unlock(&msm_rotator_dev->imem_lock);
251 }
252#else
253 if (requestor == JPEG_REQUEST)
254 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
255#endif
256}
257EXPORT_SYMBOL(msm_rotator_imem_free);
258
259static void msm_rotator_imem_clk_work_f(struct work_struct *work)
260{
261#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
262 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
263 if (msm_rotator_dev->imem_clk_state == CLK_EN
264 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700265 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700266 msm_rotator_dev->imem_clk_state = CLK_DIS;
267 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
268 msm_rotator_dev->imem_clk_state = CLK_DIS;
269 mutex_unlock(&msm_rotator_dev->imem_lock);
270 }
271#endif
272}
273
274/* enable clocks needed by rotator block */
275static void enable_rot_clks(void)
276{
277 if (msm_rotator_dev->regulator)
278 regulator_enable(msm_rotator_dev->regulator);
279 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700280 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700281 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700282 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700283}
284
285/* disable clocks needed by rotator block */
286static void disable_rot_clks(void)
287{
288 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700289 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700291 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700292 if (msm_rotator_dev->regulator)
293 regulator_disable(msm_rotator_dev->regulator);
294}
295
296static void msm_rotator_rot_clk_work_f(struct work_struct *work)
297{
298 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
299 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
300 disable_rot_clks();
301 msm_rotator_dev->rot_clk_state = CLK_DIS;
302 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
303 msm_rotator_dev->rot_clk_state = CLK_DIS;
304 mutex_unlock(&msm_rotator_dev->rotator_lock);
305 }
306}
307
308static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
309{
310 if (msm_rotator_dev->processing) {
311 msm_rotator_dev->processing = 0;
312 wake_up(&msm_rotator_dev->wq);
313 } else
314 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
315
316 return IRQ_HANDLED;
317}
318
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700319static unsigned int tile_size(unsigned int src_width,
320 unsigned int src_height,
321 const struct tile_parm *tp)
322{
323 unsigned int tile_w, tile_h;
324 unsigned int row_num_w, row_num_h;
325 tile_w = tp->width * tp->row_tile_w;
326 tile_h = tp->height * tp->row_tile_h;
327 row_num_w = (src_width + tile_w - 1) / tile_w;
328 row_num_h = (src_height + tile_h - 1) / tile_h;
329 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
330}
331
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700332static int get_bpp(int format)
333{
334 switch (format) {
335 case MDP_RGB_565:
336 case MDP_BGR_565:
337 return 2;
338
339 case MDP_XRGB_8888:
340 case MDP_ARGB_8888:
341 case MDP_RGBA_8888:
342 case MDP_BGRA_8888:
343 case MDP_RGBX_8888:
344 return 4;
345
346 case MDP_Y_CBCR_H2V2:
347 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700348 case MDP_Y_CB_CR_H2V2:
349 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530350 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700351 case MDP_Y_CRCB_H2V2_TILE:
352 case MDP_Y_CBCR_H2V2_TILE:
353 return 1;
354
355 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700356 case MDP_YCBCR_H1V1:
357 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700358 return 3;
359
360 case MDP_YCRYCB_H2V1:
361 return 2;/* YCrYCb interleave */
362
363 case MDP_Y_CRCB_H2V1:
364 case MDP_Y_CBCR_H2V1:
365 return 1;
366
367 default:
368 return -1;
369 }
370
371}
372
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700373static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
374 struct msm_rotator_mem_planes *p)
375{
376 /*
377 * each row of samsung tile consists of two tiles in height
378 * and two tiles in width which means width should align to
379 * 64 x 2 bytes and height should align to 32 x 2 bytes.
380 * video decoder generate two tiles in width and one tile
381 * in height which ends up height align to 32 X 1 bytes.
382 */
383 const struct tile_parm tile = {64, 32, 2, 1};
384 int i;
385
386 if (p == NULL)
387 return -EINVAL;
388
389 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
390 return -ERANGE;
391
392 memset(p, 0, sizeof(*p));
393
394 switch (format) {
395 case MDP_XRGB_8888:
396 case MDP_ARGB_8888:
397 case MDP_RGBA_8888:
398 case MDP_BGRA_8888:
399 case MDP_RGBX_8888:
400 case MDP_RGB_888:
401 case MDP_RGB_565:
402 case MDP_BGR_565:
403 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700404 case MDP_YCBCR_H1V1:
405 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700406 p->num_planes = 1;
407 p->plane_size[0] = w * h * get_bpp(format);
408 break;
409 case MDP_Y_CRCB_H2V1:
410 case MDP_Y_CBCR_H2V1:
411 p->num_planes = 2;
412 p->plane_size[0] = w * h;
413 p->plane_size[1] = w * h;
414 break;
415 case MDP_Y_CBCR_H2V2:
416 case MDP_Y_CRCB_H2V2:
417 p->num_planes = 2;
418 p->plane_size[0] = w * h;
419 p->plane_size[1] = w * h / 2;
420 break;
421 case MDP_Y_CRCB_H2V2_TILE:
422 case MDP_Y_CBCR_H2V2_TILE:
423 p->num_planes = 2;
424 p->plane_size[0] = tile_size(w, h, &tile);
425 p->plane_size[1] = tile_size(w, h/2, &tile);
426 break;
427 case MDP_Y_CB_CR_H2V2:
428 case MDP_Y_CR_CB_H2V2:
429 p->num_planes = 3;
430 p->plane_size[0] = w * h;
431 p->plane_size[1] = (w / 2) * (h / 2);
432 p->plane_size[2] = (w / 2) * (h / 2);
433 break;
434 case MDP_Y_CR_CB_GH2V2:
435 p->num_planes = 3;
436 p->plane_size[0] = ALIGN(w, 16) * h;
437 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
438 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
439 break;
440 default:
441 return -EINVAL;
442 }
443
444 for (i = 0; i < p->num_planes; i++)
445 p->total_size += p->plane_size[i];
446
447 return 0;
448}
449
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700450static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
451 unsigned int in_paddr,
452 unsigned int out_paddr,
453 unsigned int use_imem,
454 int new_session,
455 unsigned int in_chroma_paddr,
456 unsigned int out_chroma_paddr)
457{
458 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700459
460 if (info->src.format != info->dst.format)
461 return -EINVAL;
462
463 bpp = get_bpp(info->src.format);
464 if (bpp < 0)
465 return -ENOTTY;
466
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700467 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700468 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700469 iowrite32(out_paddr +
470 ((info->dst_y * info->dst.width) + info->dst_x),
471 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700472 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700473 ((info->dst_y * info->dst.width) + info->dst_x),
474 MSM_ROTATOR_OUTP1_ADDR);
475
476 if (new_session) {
477 iowrite32(info->src.width |
478 info->src.width << 16,
479 MSM_ROTATOR_SRC_YSTRIDE1);
480 if (info->rotations & MDP_ROT_90)
481 iowrite32(info->dst.width |
482 info->dst.width*2 << 16,
483 MSM_ROTATOR_OUT_YSTRIDE1);
484 else
485 iowrite32(info->dst.width |
486 info->dst.width << 16,
487 MSM_ROTATOR_OUT_YSTRIDE1);
488 if (info->src.format == MDP_Y_CBCR_H2V1) {
489 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
490 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
491 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
492 MSM_ROTATOR_OUT_PACK_PATTERN1);
493 } else {
494 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
495 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
496 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
497 MSM_ROTATOR_OUT_PACK_PATTERN1);
498 }
499 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
500 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700501 1 << 8 | /* ROT_EN */
502 info->downscale_ratio << 2 | /* downscale v ratio */
503 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 MSM_ROTATOR_SUB_BLOCK_CFG);
505 iowrite32(0 << 29 | /* frame format 0 = linear */
506 (use_imem ? 0 : 1) << 22 | /* tile size */
507 2 << 19 | /* fetch planes 2 = pseudo */
508 0 << 18 | /* unpack align */
509 1 << 17 | /* unpack tight */
510 1 << 13 | /* unpack count 0=1 component */
511 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
512 0 << 8 | /* has alpha */
513 0 << 6 | /* alpha bits 3=8bits */
514 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
515 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
516 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
517 MSM_ROTATOR_SRC_FORMAT);
518 }
519
520 return 0;
521}
522
523static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
524 unsigned int in_paddr,
525 unsigned int out_paddr,
526 unsigned int use_imem,
527 int new_session,
528 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700529 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700530 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700531{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700532 uint32_t dst_format;
533 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700535 switch (info->src.format) {
536 case MDP_Y_CRCB_H2V2_TILE:
537 is_tile = 1;
538 case MDP_Y_CR_CB_H2V2:
539 case MDP_Y_CR_CB_GH2V2:
540 case MDP_Y_CRCB_H2V2:
541 dst_format = MDP_Y_CRCB_H2V2;
542 break;
543 case MDP_Y_CBCR_H2V2_TILE:
544 is_tile = 1;
545 case MDP_Y_CB_CR_H2V2:
546 case MDP_Y_CBCR_H2V2:
547 dst_format = MDP_Y_CBCR_H2V2;
548 break;
549 default:
550 return -EINVAL;
551 }
552 if (info->dst.format != dst_format)
553 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700554
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800555 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530556 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
557 info->src.format == MDP_Y_CR_CB_GH2V2) &&
558 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800559 swap(in_chroma_paddr, in_chroma2_paddr);
560
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700562 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
563 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
564
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565 iowrite32(out_paddr +
566 ((info->dst_y * info->dst.width) + info->dst_x),
567 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700568 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700569 ((info->dst_y * info->dst.width)/2 + info->dst_x),
570 MSM_ROTATOR_OUTP1_ADDR);
571
572 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700573 if (in_chroma2_paddr) {
574 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530575 iowrite32(ALIGN(info->src.width, 16) |
576 ALIGN((info->src.width / 2), 16) << 16,
577 MSM_ROTATOR_SRC_YSTRIDE1);
578 iowrite32(ALIGN((info->src.width / 2), 16),
579 MSM_ROTATOR_SRC_YSTRIDE2);
580 } else {
581 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700582 (info->src.width / 2) << 16,
583 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530584 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700585 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530586 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700587 } else {
588 iowrite32(info->src.width |
589 info->src.width << 16,
590 MSM_ROTATOR_SRC_YSTRIDE1);
591 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700593 info->dst.width << 16,
594 MSM_ROTATOR_OUT_YSTRIDE1);
595
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700596 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700597 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
598 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
599 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
600 MSM_ROTATOR_OUT_PACK_PATTERN1);
601 } else {
602 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
603 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
604 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
605 MSM_ROTATOR_OUT_PACK_PATTERN1);
606 }
607 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
608 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700609 1 << 8 | /* ROT_EN */
610 info->downscale_ratio << 2 | /* downscale v ratio */
611 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700612 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700613
614 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700615 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700616 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 0 << 18 | /* unpack align */
618 1 << 17 | /* unpack tight */
619 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700620 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700621 0 << 8 | /* has alpha */
622 0 << 6 | /* alpha bits 3=8bits */
623 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
624 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
625 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
626 MSM_ROTATOR_SRC_FORMAT);
627 }
628 return 0;
629}
630
631static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
632 unsigned int in_paddr,
633 unsigned int out_paddr,
634 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530635 int new_session,
636 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637{
638 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530639 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640
Mayank Chopra732dcd62012-01-09 20:53:39 +0530641 if (info->src.format == MDP_YCRYCB_H2V1)
642 dst_format = MDP_Y_CRCB_H2V1;
643 else
644 return -EINVAL;
645
646 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 return -EINVAL;
648
649 bpp = get_bpp(info->src.format);
650 if (bpp < 0)
651 return -ENOTTY;
652
653 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
654 iowrite32(out_paddr +
655 ((info->dst_y * info->dst.width) + info->dst_x),
656 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530657 iowrite32(out_chroma_paddr +
658 ((info->dst_y * info->dst.width)/2 + info->dst_x),
659 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700660
661 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530662 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700663 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530664 if (info->rotations & MDP_ROT_90)
665 iowrite32(info->dst.width |
666 (info->dst.width*2) << 16,
667 MSM_ROTATOR_OUT_YSTRIDE1);
668 else
669 iowrite32(info->dst.width |
670 (info->dst.width) << 16,
671 MSM_ROTATOR_OUT_YSTRIDE1);
672
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700673 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
674 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530675 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700676 MSM_ROTATOR_OUT_PACK_PATTERN1);
677 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
678 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700679 1 << 8 | /* ROT_EN */
680 info->downscale_ratio << 2 | /* downscale v ratio */
681 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700682 MSM_ROTATOR_SUB_BLOCK_CFG);
683 iowrite32(0 << 29 | /* frame format 0 = linear */
684 (use_imem ? 0 : 1) << 22 | /* tile size */
685 0 << 19 | /* fetch planes 0=interleaved */
686 0 << 18 | /* unpack align */
687 1 << 17 | /* unpack tight */
688 3 << 13 | /* unpack count 0=1 component */
689 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
690 0 << 8 | /* has alpha */
691 0 << 6 | /* alpha bits 3=8bits */
692 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
693 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
694 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
695 MSM_ROTATOR_SRC_FORMAT);
696 }
697
698 return 0;
699}
700
701static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
702 unsigned int in_paddr,
703 unsigned int out_paddr,
704 unsigned int use_imem,
705 int new_session)
706{
707 int bpp, abits, rbits, gbits, bbits;
708
709 if (info->src.format != info->dst.format)
710 return -EINVAL;
711
712 bpp = get_bpp(info->src.format);
713 if (bpp < 0)
714 return -ENOTTY;
715
716 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
717 iowrite32(out_paddr +
718 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
719 MSM_ROTATOR_OUTP0_ADDR);
720
721 if (new_session) {
722 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
723 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
724 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
725 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700726 1 << 8 | /* ROT_EN */
727 info->downscale_ratio << 2 | /* downscale v ratio */
728 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700729 MSM_ROTATOR_SUB_BLOCK_CFG);
730 switch (info->src.format) {
731 case MDP_RGB_565:
732 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
733 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
734 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
735 MSM_ROTATOR_OUT_PACK_PATTERN1);
736 abits = 0;
737 rbits = COMPONENT_5BITS;
738 gbits = COMPONENT_6BITS;
739 bbits = COMPONENT_5BITS;
740 break;
741
742 case MDP_BGR_565:
743 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
744 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
745 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
746 MSM_ROTATOR_OUT_PACK_PATTERN1);
747 abits = 0;
748 rbits = COMPONENT_5BITS;
749 gbits = COMPONENT_6BITS;
750 bbits = COMPONENT_5BITS;
751 break;
752
753 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700754 case MDP_YCBCR_H1V1:
755 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700756 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
757 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
758 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
759 MSM_ROTATOR_OUT_PACK_PATTERN1);
760 abits = 0;
761 rbits = COMPONENT_8BITS;
762 gbits = COMPONENT_8BITS;
763 bbits = COMPONENT_8BITS;
764 break;
765
766 case MDP_ARGB_8888:
767 case MDP_RGBA_8888:
768 case MDP_XRGB_8888:
769 case MDP_RGBX_8888:
770 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
771 CLR_B, 8),
772 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
773 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
774 CLR_B, 8),
775 MSM_ROTATOR_OUT_PACK_PATTERN1);
776 abits = COMPONENT_8BITS;
777 rbits = COMPONENT_8BITS;
778 gbits = COMPONENT_8BITS;
779 bbits = COMPONENT_8BITS;
780 break;
781
782 case MDP_BGRA_8888:
783 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
784 CLR_R, 8),
785 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
786 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
787 CLR_R, 8),
788 MSM_ROTATOR_OUT_PACK_PATTERN1);
789 abits = COMPONENT_8BITS;
790 rbits = COMPONENT_8BITS;
791 gbits = COMPONENT_8BITS;
792 bbits = COMPONENT_8BITS;
793 break;
794
795 default:
796 return -EINVAL;
797 }
798 iowrite32(0 << 29 | /* frame format 0 = linear */
799 (use_imem ? 0 : 1) << 22 | /* tile size */
800 0 << 19 | /* fetch planes 0=interleaved */
801 0 << 18 | /* unpack align */
802 1 << 17 | /* unpack tight */
803 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
804 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
805 (abits ? 1 : 0) << 8 | /* has alpha */
806 abits << 6 | /* alpha bits 3=8bits */
807 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
808 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
809 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
810 MSM_ROTATOR_SRC_FORMAT);
811 }
812
813 return 0;
814}
815
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530816static int get_img(struct msmfb_data *fbd, unsigned char src,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700817 unsigned long *start, unsigned long *len, struct file **p_file,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530818 int *p_need, struct ion_handle **p_ihdl)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819{
820 int ret = 0;
821#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700822 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700823 int put_needed, fb_num;
824#endif
825#ifdef CONFIG_ANDROID_PMEM
826 unsigned long vstart;
827#endif
828
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800829 *p_need = 0;
830
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700832 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
833 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700834 if (file == NULL) {
835 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700836 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700837 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700838
Naseer Ahmed18018602011-10-25 13:32:58 -0700839 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
840 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700841 if (get_fb_phys_info(start, len, fb_num,
842 ROTATOR_SUBSYSTEM_ID)) {
843 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700844 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700845 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700846 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800847 *p_need = put_needed;
848 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700849 } else {
850 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700852 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700853 if (ret)
854 fput_light(file, put_needed);
855 return ret;
856 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700858
859#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530860 return msm_rotator_iommu_map_buf(fbd->memory_id, src, start,
861 len, p_ihdl);
Naseer Ahmed18018602011-10-25 13:32:58 -0700862#endif
863#ifdef CONFIG_ANDROID_PMEM
864 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
865 return 0;
866 else
867 return -ENOMEM;
868#endif
869
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700870}
871
Olav Hauganef95ae32012-05-15 09:50:30 -0700872static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
873 unsigned char src)
Naseer Ahmed18018602011-10-25 13:32:58 -0700874{
875#ifdef CONFIG_ANDROID_PMEM
876 if (p_file != NULL)
877 put_pmem_file(p_file);
878#endif
Olav Hauganef95ae32012-05-15 09:50:30 -0700879
Naseer Ahmed18018602011-10-25 13:32:58 -0700880#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700881 if (!IS_ERR_OR_NULL(p_ihdl)) {
Olav Hauganef95ae32012-05-15 09:50:30 -0700882 int domain;
883 if (rot_iommu_split_domain)
884 domain = src ? ROTATOR_SRC_DOMAIN : ROTATOR_DST_DOMAIN;
885 else
886 domain = ROTATOR_SRC_DOMAIN;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700887 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530888 ion_unmap_iommu(msm_rotator_dev->client,
Olav Hauganef95ae32012-05-15 09:50:30 -0700889 p_ihdl, domain, GEN_POOL);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700890
Naseer Ahmed18018602011-10-25 13:32:58 -0700891 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700892 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700893#endif
894}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700895static int msm_rotator_do_rotate(unsigned long arg)
896{
Naseer Ahmed18018602011-10-25 13:32:58 -0700897 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898 struct msm_rotator_data_info info;
899 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700900 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700901 int use_imem = 0, rc = 0, s;
902 struct file *srcp0_file = NULL, *dstp0_file = NULL;
903 struct file *srcp1_file = NULL, *dstp1_file = NULL;
904 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
905 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800906 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700907 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700908 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700909 struct msm_rotator_img_info *img_info;
910 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911
912 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
913 return -EFAULT;
914
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 mutex_lock(&msm_rotator_dev->rotator_lock);
916 for (s = 0; s < MAX_SESSIONS; s++)
917 if ((msm_rotator_dev->img_info[s] != NULL) &&
918 (info.session_id ==
919 (unsigned int)msm_rotator_dev->img_info[s]
920 ))
921 break;
922
923 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700924 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925 __func__, s);
926 rc = -EINVAL;
927 goto do_rotate_unlock_mutex;
928 }
929
930 if (msm_rotator_dev->img_info[s]->enable == 0) {
931 dev_dbg(msm_rotator_dev->device,
932 "%s() : Session_id %d not enabled \n",
933 __func__, s);
934 rc = -EINVAL;
935 goto do_rotate_unlock_mutex;
936 }
937
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700938 img_info = msm_rotator_dev->img_info[s];
939 if (msm_rotator_get_plane_sizes(img_info->src.format,
940 img_info->src.width,
941 img_info->src.height,
942 &src_planes)) {
943 pr_err("%s: invalid src format\n", __func__);
944 rc = -EINVAL;
945 goto do_rotate_unlock_mutex;
946 }
947 if (msm_rotator_get_plane_sizes(img_info->dst.format,
948 img_info->dst.width,
949 img_info->dst.height,
950 &dst_planes)) {
951 pr_err("%s: invalid dst format\n", __func__);
952 rc = -EINVAL;
953 goto do_rotate_unlock_mutex;
954 }
955
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530956 rc = get_img(&info.src, 1, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700957 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530958 &srcp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700959 if (rc) {
960 pr_err("%s: in get_img() failed id=0x%08x\n",
961 DRIVER_NAME, info.src.memory_id);
962 goto do_rotate_unlock_mutex;
963 }
964
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530965 rc = get_img(&info.dst, 0, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700966 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530967 &dstp0_ihdl);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700968 if (rc) {
969 pr_err("%s: out get_img() failed id=0x%08x\n",
970 DRIVER_NAME, info.dst.memory_id);
971 goto do_rotate_unlock_mutex;
972 }
973
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700974 format = msm_rotator_dev->img_info[s]->src.format;
975 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700976 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
977 (src_planes.num_planes == 2)) {
978 if (checkoffset(info.src.offset,
979 src_planes.plane_size[0],
980 src_len)) {
981 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
982 __func__, src_len, info.src.offset);
983 rc = -ERANGE;
984 goto do_rotate_unlock_mutex;
985 }
986 if (checkoffset(info.dst.offset,
987 dst_planes.plane_size[0],
988 dst_len)) {
989 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
990 __func__, dst_len, info.dst.offset);
991 rc = -ERANGE;
992 goto do_rotate_unlock_mutex;
993 }
994
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530995 rc = get_img(&info.src_chroma, 1,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700996 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800997 (unsigned long *)&src_len, &srcp1_file, &p_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +0530998 &srcp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700999 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001000 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001001 DRIVER_NAME, info.src_chroma.memory_id);
1002 goto do_rotate_unlock_mutex;
1003 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004
Mayank Chopraca4d9bc2012-06-27 15:30:19 +05301005 rc = get_img(&info.dst_chroma, 0,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001007 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Mayank Chopraca4d9bc2012-06-27 15:30:19 +05301008 &dstp1_ihdl);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001010 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001011 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001012 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001014
1015 if (checkoffset(info.src_chroma.offset,
1016 src_planes.plane_size[1],
1017 src_len)) {
1018 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1019 __func__, src_len, info.src_chroma.offset);
1020 rc = -ERANGE;
1021 goto do_rotate_unlock_mutex;
1022 }
1023
1024 if (checkoffset(info.dst_chroma.offset,
1025 src_planes.plane_size[1],
1026 dst_len)) {
1027 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1028 __func__, dst_len, info.dst_chroma.offset);
1029 rc = -ERANGE;
1030 goto do_rotate_unlock_mutex;
1031 }
1032
1033 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001035 } else {
1036 if (checkoffset(info.src.offset,
1037 src_planes.total_size,
1038 src_len)) {
1039 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1040 __func__, src_len, info.src.offset);
1041 rc = -ERANGE;
1042 goto do_rotate_unlock_mutex;
1043 }
1044 if (checkoffset(info.dst.offset,
1045 dst_planes.total_size,
1046 dst_len)) {
1047 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1048 __func__, dst_len, info.dst.offset);
1049 rc = -ERANGE;
1050 goto do_rotate_unlock_mutex;
1051 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 }
1053
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001054 in_paddr += info.src.offset;
1055 out_paddr += info.dst.offset;
1056
1057 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1058 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1059 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1060 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1061 if (src_planes.num_planes >= 3)
1062 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1063
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001064 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1065 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1066 enable_rot_clks();
1067 msm_rotator_dev->rot_clk_state = CLK_EN;
1068 }
1069 enable_irq(msm_rotator_dev->irq);
1070
1071#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1072 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1073#else
1074 use_imem = 0;
1075#endif
1076 /*
1077 * workaround for a hardware bug. rotator hardware hangs when we
1078 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1079 * temporary fix use 0x42 for BURST_SIZE when imem used.
1080 */
1081 if (use_imem)
1082 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1083
1084 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1085 << 16) |
1086 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1087 MSM_ROTATOR_SRC_SIZE);
1088 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1089 << 16) |
1090 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1091 MSM_ROTATOR_SRC_XY);
1092 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1093 << 16) |
1094 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1095 MSM_ROTATOR_SRC_IMAGE_SIZE);
1096
1097 switch (format) {
1098 case MDP_RGB_565:
1099 case MDP_BGR_565:
1100 case MDP_RGB_888:
1101 case MDP_ARGB_8888:
1102 case MDP_RGBA_8888:
1103 case MDP_XRGB_8888:
1104 case MDP_BGRA_8888:
1105 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001106 case MDP_YCBCR_H1V1:
1107 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001108 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1109 in_paddr, out_paddr,
1110 use_imem,
1111 msm_rotator_dev->last_session_idx
1112 != s);
1113 break;
1114 case MDP_Y_CBCR_H2V2:
1115 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001116 case MDP_Y_CB_CR_H2V2:
1117 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301118 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001119 case MDP_Y_CRCB_H2V2_TILE:
1120 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001121 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1122 in_paddr, out_paddr, use_imem,
1123 msm_rotator_dev->last_session_idx
1124 != s,
1125 in_chroma_paddr,
1126 out_chroma_paddr,
1127 in_chroma2_paddr);
1128 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001129 case MDP_Y_CBCR_H2V1:
1130 case MDP_Y_CRCB_H2V1:
1131 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1132 in_paddr, out_paddr, use_imem,
1133 msm_rotator_dev->last_session_idx
1134 != s,
1135 in_chroma_paddr,
1136 out_chroma_paddr);
1137 break;
1138 case MDP_YCRYCB_H2V1:
1139 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1140 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301141 msm_rotator_dev->last_session_idx != s,
1142 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 break;
1144 default:
1145 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001146 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001147 goto do_rotate_exit;
1148 }
1149
1150 if (rc != 0) {
1151 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001152 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001153 goto do_rotate_exit;
1154 }
1155
1156 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1157
1158 msm_rotator_dev->processing = 1;
1159 iowrite32(0x1, MSM_ROTATOR_START);
1160
1161 wait_event(msm_rotator_dev->wq,
1162 (msm_rotator_dev->processing == 0));
1163 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001164 if ((status & 0x03) != 0x01) {
1165 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1166 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001167 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001168 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001169 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1170 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1171
1172do_rotate_exit:
1173 disable_irq(msm_rotator_dev->irq);
1174#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1175 msm_rotator_imem_free(ROTATOR_REQUEST);
1176#endif
1177 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001178do_rotate_unlock_mutex:
Olav Hauganef95ae32012-05-15 09:50:30 -07001179 put_img(dstp1_file, dstp1_ihdl, 0);
1180 put_img(srcp1_file, srcp1_ihdl, 1);
1181 put_img(dstp0_file, dstp0_ihdl, 0);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001182
1183 /* only source may use frame buffer */
1184 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1185 fput_light(srcp0_file, ps0_need);
1186 else
Olav Hauganef95ae32012-05-15 09:50:30 -07001187 put_img(srcp0_file, srcp0_ihdl, 1);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001188 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001189 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1190 __func__, rc);
1191 return rc;
1192}
1193
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001194static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1195{
1196 u32 perf_level;
1197
1198 if (is_rgb)
1199 perf_level = 1;
1200 else if (wh <= (640 * 480))
1201 perf_level = 2;
1202 else if (wh <= (736 * 1280))
1203 perf_level = 3;
1204 else
1205 perf_level = 4;
1206
1207#ifdef CONFIG_MSM_BUS_SCALING
1208 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1209 perf_level);
1210#endif
1211
1212}
1213
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001214static int msm_rotator_start(unsigned long arg,
1215 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001216{
1217 struct msm_rotator_img_info info;
1218 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001219 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001221 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222
1223 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1224 return -EFAULT;
1225
1226 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1227 (info.src.height > MSM_ROTATOR_MAX_H) ||
1228 (info.src.width > MSM_ROTATOR_MAX_W) ||
1229 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1230 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001231 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1232 pr_err("%s: Invalid parameters\n", __func__);
1233 return -EINVAL;
1234 }
1235
1236 if (info.rotations & MDP_ROT_90) {
1237 dst_w = info.src_rect.h >> info.downscale_ratio;
1238 dst_h = info.src_rect.w >> info.downscale_ratio;
1239 } else {
1240 dst_w = info.src_rect.w >> info.downscale_ratio;
1241 dst_h = info.src_rect.h >> info.downscale_ratio;
1242 }
1243
1244 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001245 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1246 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001247 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1248 pr_err("%s: Invalid src or dst rect\n", __func__);
1249 return -ERANGE;
1250 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001251
1252 switch (info.src.format) {
1253 case MDP_RGB_565:
1254 case MDP_BGR_565:
1255 case MDP_RGB_888:
1256 case MDP_ARGB_8888:
1257 case MDP_RGBA_8888:
1258 case MDP_XRGB_8888:
1259 case MDP_RGBX_8888:
1260 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001261 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301262 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001263 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001264 case MDP_Y_CBCR_H2V2:
1265 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301266 case MDP_Y_CBCR_H2V1:
1267 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001268 case MDP_YCBCR_H1V1:
1269 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301270 info.dst.format = info.src.format;
1271 break;
1272 case MDP_YCRYCB_H2V1:
1273 info.dst.format = MDP_Y_CRCB_H2V1;
1274 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001275 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301276 case MDP_Y_CBCR_H2V2_TILE:
1277 info.dst.format = MDP_Y_CBCR_H2V2;
1278 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001279 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301280 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001281 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301282 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 break;
1284 default:
1285 return -EINVAL;
1286 }
1287
1288 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001289
1290 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1291
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001292 for (s = 0; s < MAX_SESSIONS; s++) {
1293 if ((msm_rotator_dev->img_info[s] != NULL) &&
1294 (info.session_id ==
1295 (unsigned int)msm_rotator_dev->img_info[s]
1296 )) {
1297 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001298 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001299
1300 if (msm_rotator_dev->last_session_idx == s)
1301 msm_rotator_dev->last_session_idx =
1302 INVALID_SESSION;
1303 break;
1304 }
1305
1306 if ((msm_rotator_dev->img_info[s] == NULL) &&
1307 (first_free_index ==
1308 INVALID_SESSION))
1309 first_free_index = s;
1310 }
1311
1312 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1313 /* allocate a session id */
1314 msm_rotator_dev->img_info[first_free_index] =
1315 kzalloc(sizeof(struct msm_rotator_img_info),
1316 GFP_KERNEL);
1317 if (!msm_rotator_dev->img_info[first_free_index]) {
1318 printk(KERN_ERR "%s : unable to alloc mem\n",
1319 __func__);
1320 rc = -ENOMEM;
1321 goto rotator_start_exit;
1322 }
1323 info.session_id = (unsigned int)
1324 msm_rotator_dev->img_info[first_free_index];
1325 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001326 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001327 } else if (s == MAX_SESSIONS) {
1328 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1329 __func__);
1330 rc = -EBUSY;
1331 }
1332
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001333 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1334 rc = -EFAULT;
1335
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336rotator_start_exit:
1337 mutex_unlock(&msm_rotator_dev->rotator_lock);
1338
1339 return rc;
1340}
1341
1342static int msm_rotator_finish(unsigned long arg)
1343{
1344 int rc = 0;
1345 int s;
1346 unsigned int session_id;
1347
1348 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1349 return -EFAULT;
1350
1351 mutex_lock(&msm_rotator_dev->rotator_lock);
1352 for (s = 0; s < MAX_SESSIONS; s++) {
1353 if ((msm_rotator_dev->img_info[s] != NULL) &&
1354 (session_id ==
1355 (unsigned int)msm_rotator_dev->img_info[s])) {
1356 if (msm_rotator_dev->last_session_idx == s)
1357 msm_rotator_dev->last_session_idx =
1358 INVALID_SESSION;
1359 kfree(msm_rotator_dev->img_info[s]);
1360 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001361 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 break;
1363 }
1364 }
1365
1366 if (s == MAX_SESSIONS)
1367 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001368#ifdef CONFIG_MSM_BUS_SCALING
1369 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1370 0);
1371#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 mutex_unlock(&msm_rotator_dev->rotator_lock);
1373 return rc;
1374}
1375
1376static int
1377msm_rotator_open(struct inode *inode, struct file *filp)
1378{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001379 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001380 int i;
1381
1382 if (filp->private_data)
1383 return -EBUSY;
1384
1385 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001386 for (i = 0; i < MAX_SESSIONS; i++) {
1387 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001388 break;
1389 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001390
1391 if (i == MAX_SESSIONS) {
1392 mutex_unlock(&msm_rotator_dev->rotator_lock);
1393 return -EBUSY;
1394 }
1395
1396 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1397 if (tmp->pid == current->pid) {
1398 fd_info = tmp;
1399 break;
1400 }
1401 }
1402
1403 if (!fd_info) {
1404 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1405 if (!fd_info) {
1406 mutex_unlock(&msm_rotator_dev->rotator_lock);
1407 pr_err("%s: insufficient memory to alloc resources\n",
1408 __func__);
1409 return -ENOMEM;
1410 }
1411 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1412 fd_info->pid = current->pid;
1413 }
1414 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415 mutex_unlock(&msm_rotator_dev->rotator_lock);
1416
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001417 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418
1419 return 0;
1420}
1421
1422static int
1423msm_rotator_close(struct inode *inode, struct file *filp)
1424{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001425 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001426 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001427
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001428 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1429
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001431 if (--fd_info->ref_cnt > 0) {
1432 mutex_unlock(&msm_rotator_dev->rotator_lock);
1433 return 0;
1434 }
1435
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 for (s = 0; s < MAX_SESSIONS; s++) {
1437 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001438 msm_rotator_dev->fd_info[s] == fd_info) {
1439 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1440 __func__, msm_rotator_dev->img_info[s],
1441 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 kfree(msm_rotator_dev->img_info[s]);
1443 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001444 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 if (msm_rotator_dev->last_session_idx == s)
1446 msm_rotator_dev->last_session_idx =
1447 INVALID_SESSION;
1448 }
1449 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001450 list_del(&fd_info->list);
1451 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 mutex_unlock(&msm_rotator_dev->rotator_lock);
1453
1454 return 0;
1455}
1456
1457static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1458 unsigned long arg)
1459{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001460 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461
1462 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1463 return -ENOTTY;
1464
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001465 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466
1467 switch (cmd) {
1468 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001469 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001470 case MSM_ROTATOR_IOCTL_ROTATE:
1471 return msm_rotator_do_rotate(arg);
1472 case MSM_ROTATOR_IOCTL_FINISH:
1473 return msm_rotator_finish(arg);
1474
1475 default:
1476 dev_dbg(msm_rotator_dev->device,
1477 "unexpected IOCTL %d\n", cmd);
1478 return -ENOTTY;
1479 }
1480}
1481
1482static const struct file_operations msm_rotator_fops = {
1483 .owner = THIS_MODULE,
1484 .open = msm_rotator_open,
1485 .release = msm_rotator_close,
1486 .unlocked_ioctl = msm_rotator_ioctl,
1487};
1488
1489static int __devinit msm_rotator_probe(struct platform_device *pdev)
1490{
1491 int rc = 0;
1492 struct resource *res;
1493 struct msm_rotator_platform_data *pdata = NULL;
1494 int i, number_of_clks;
1495 uint32_t ver;
1496
1497 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1498 if (!msm_rotator_dev) {
1499 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1500 __func__);
1501 return -ENOMEM;
1502 }
1503 for (i = 0; i < MAX_SESSIONS; i++)
1504 msm_rotator_dev->img_info[i] = NULL;
1505 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1506
1507 pdata = pdev->dev.platform_data;
1508 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07001509 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001510
1511 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1512 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001513 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514 msm_rotator_dev->imem_clk_state = CLK_DIS;
1515 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1516 msm_rotator_imem_clk_work_f);
1517 msm_rotator_dev->imem_clk = NULL;
1518 msm_rotator_dev->pdev = pdev;
1519
1520 msm_rotator_dev->core_clk = NULL;
1521 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001522
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001523#ifdef CONFIG_MSM_BUS_SCALING
1524 if (!msm_rotator_dev->bus_client_handle && pdata &&
1525 pdata->bus_scale_table) {
1526 msm_rotator_dev->bus_client_handle =
1527 msm_bus_scale_register_client(
1528 pdata->bus_scale_table);
1529 if (!msm_rotator_dev->bus_client_handle) {
1530 pr_err("%s not able to get bus scale handle\n",
1531 __func__);
1532 }
1533 }
1534#endif
1535
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536 for (i = 0; i < number_of_clks; i++) {
1537 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1538 msm_rotator_dev->imem_clk =
1539 clk_get(&msm_rotator_dev->pdev->dev,
1540 pdata->rotator_clks[i].clk_name);
1541 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1542 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1543 msm_rotator_dev->imem_clk = NULL;
1544 printk(KERN_ERR "%s: cannot get imem_clk "
1545 "rc=%d\n", DRIVER_NAME, rc);
1546 goto error_imem_clk;
1547 }
1548 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001549 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001550 pdata->rotator_clks[i].clk_rate);
1551 }
1552 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1553 msm_rotator_dev->pclk =
1554 clk_get(&msm_rotator_dev->pdev->dev,
1555 pdata->rotator_clks[i].clk_name);
1556 if (IS_ERR(msm_rotator_dev->pclk)) {
1557 rc = PTR_ERR(msm_rotator_dev->pclk);
1558 msm_rotator_dev->pclk = NULL;
1559 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1560 DRIVER_NAME, rc);
1561 goto error_pclk;
1562 }
1563
1564 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001565 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 pdata->rotator_clks[i].clk_rate);
1567 }
1568
1569 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1570 msm_rotator_dev->core_clk =
1571 clk_get(&msm_rotator_dev->pdev->dev,
1572 pdata->rotator_clks[i].clk_name);
1573 if (IS_ERR(msm_rotator_dev->core_clk)) {
1574 rc = PTR_ERR(msm_rotator_dev->core_clk);
1575 msm_rotator_dev->core_clk = NULL;
1576 printk(KERN_ERR "%s: cannot get core clk "
1577 "rc=%d\n", DRIVER_NAME, rc);
1578 goto error_core_clk;
1579 }
1580
1581 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001582 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 pdata->rotator_clks[i].clk_rate);
1584 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 }
1586
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001587 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1588 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 if (IS_ERR(msm_rotator_dev->regulator))
1590 msm_rotator_dev->regulator = NULL;
1591
1592 msm_rotator_dev->rot_clk_state = CLK_DIS;
1593 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1594 msm_rotator_rot_clk_work_f);
1595
1596 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001597#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1598 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1599#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 platform_set_drvdata(pdev, msm_rotator_dev);
1601
1602
1603 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1604 if (!res) {
1605 printk(KERN_ALERT
1606 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1607 rc = -ENODEV;
1608 goto error_get_resource;
1609 }
1610 msm_rotator_dev->io_base = ioremap(res->start,
1611 resource_size(res));
1612
1613#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1614 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001615 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616#endif
1617 enable_rot_clks();
1618 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1619 disable_rot_clks();
1620
1621#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1622 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001623 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001624#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001625 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301626 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001627 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001628
Mayank Chopra012a8e72012-04-11 10:41:13 +05301629 rotator_hw_revision = ver;
1630 rotator_hw_revision >>= 16; /* bit 31:16 */
1631 rotator_hw_revision &= 0xff;
1632
1633 pr_info("%s: rotator_hw_revision=%x\n",
1634 __func__, rotator_hw_revision);
1635
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1637 if (msm_rotator_dev->irq < 0) {
1638 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1639 DRIVER_NAME);
1640 rc = -ENODEV;
1641 goto error_get_irq;
1642 }
1643 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1644 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1645 if (rc) {
1646 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1647 goto error_get_irq;
1648 }
1649 /* we enable the IRQ when we need it in the ioctl */
1650 disable_irq(msm_rotator_dev->irq);
1651
1652 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1653 if (rc < 0) {
1654 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1655 __func__, rc);
1656 goto error_get_irq;
1657 }
1658
1659 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1660 if (IS_ERR(msm_rotator_dev->class)) {
1661 rc = PTR_ERR(msm_rotator_dev->class);
1662 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1663 DRIVER_NAME, rc);
1664 goto error_class_create;
1665 }
1666
1667 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1668 msm_rotator_dev->dev_num, NULL,
1669 DRIVER_NAME);
1670 if (IS_ERR(msm_rotator_dev->device)) {
1671 rc = PTR_ERR(msm_rotator_dev->device);
1672 printk(KERN_ERR "%s: device_create failed %d\n",
1673 DRIVER_NAME, rc);
1674 goto error_class_device_create;
1675 }
1676
1677 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1678 rc = cdev_add(&msm_rotator_dev->cdev,
1679 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1680 1);
1681 if (rc < 0) {
1682 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1683 goto error_cdev_add;
1684 }
1685
1686 init_waitqueue_head(&msm_rotator_dev->wq);
1687
1688 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1689 return rc;
1690
1691error_cdev_add:
1692 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1693error_class_device_create:
1694 class_destroy(msm_rotator_dev->class);
1695error_class_create:
1696 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1697error_get_irq:
1698 iounmap(msm_rotator_dev->io_base);
1699error_get_resource:
1700 mutex_destroy(&msm_rotator_dev->rotator_lock);
1701 if (msm_rotator_dev->regulator)
1702 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 clk_put(msm_rotator_dev->core_clk);
1704error_core_clk:
1705 clk_put(msm_rotator_dev->pclk);
1706error_pclk:
1707 if (msm_rotator_dev->imem_clk)
1708 clk_put(msm_rotator_dev->imem_clk);
1709error_imem_clk:
1710 mutex_destroy(&msm_rotator_dev->imem_lock);
1711 kfree(msm_rotator_dev);
1712 return rc;
1713}
1714
1715static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1716{
1717 int i;
1718
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001719#ifdef CONFIG_MSM_BUS_SCALING
1720 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1721#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001722 free_irq(msm_rotator_dev->irq, NULL);
1723 mutex_destroy(&msm_rotator_dev->rotator_lock);
1724 cdev_del(&msm_rotator_dev->cdev);
1725 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1726 class_destroy(msm_rotator_dev->class);
1727 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1728 iounmap(msm_rotator_dev->io_base);
1729 if (msm_rotator_dev->imem_clk) {
1730 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001731 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001732 clk_put(msm_rotator_dev->imem_clk);
1733 msm_rotator_dev->imem_clk = NULL;
1734 }
1735 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1736 disable_rot_clks();
1737 clk_put(msm_rotator_dev->core_clk);
1738 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001739 if (msm_rotator_dev->regulator)
1740 regulator_put(msm_rotator_dev->regulator);
1741 msm_rotator_dev->core_clk = NULL;
1742 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001743 mutex_destroy(&msm_rotator_dev->imem_lock);
1744 for (i = 0; i < MAX_SESSIONS; i++)
1745 if (msm_rotator_dev->img_info[i] != NULL)
1746 kfree(msm_rotator_dev->img_info[i]);
1747 kfree(msm_rotator_dev);
1748 return 0;
1749}
1750
1751#ifdef CONFIG_PM
1752static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1753{
1754 mutex_lock(&msm_rotator_dev->imem_lock);
1755 if (msm_rotator_dev->imem_clk_state == CLK_EN
1756 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001757 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1759 }
1760 mutex_unlock(&msm_rotator_dev->imem_lock);
1761 mutex_lock(&msm_rotator_dev->rotator_lock);
1762 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1763 disable_rot_clks();
1764 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1765 }
1766 mutex_unlock(&msm_rotator_dev->rotator_lock);
1767 return 0;
1768}
1769
1770static int msm_rotator_resume(struct platform_device *dev)
1771{
1772 mutex_lock(&msm_rotator_dev->imem_lock);
1773 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1774 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001775 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 msm_rotator_dev->imem_clk_state = CLK_EN;
1777 }
1778 mutex_unlock(&msm_rotator_dev->imem_lock);
1779 mutex_lock(&msm_rotator_dev->rotator_lock);
1780 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1781 enable_rot_clks();
1782 msm_rotator_dev->rot_clk_state = CLK_EN;
1783 }
1784 mutex_unlock(&msm_rotator_dev->rotator_lock);
1785 return 0;
1786}
1787#endif
1788
1789static struct platform_driver msm_rotator_platform_driver = {
1790 .probe = msm_rotator_probe,
1791 .remove = __devexit_p(msm_rotator_remove),
1792#ifdef CONFIG_PM
1793 .suspend = msm_rotator_suspend,
1794 .resume = msm_rotator_resume,
1795#endif
1796 .driver = {
1797 .owner = THIS_MODULE,
1798 .name = DRIVER_NAME
1799 }
1800};
1801
1802static int __init msm_rotator_init(void)
1803{
1804 return platform_driver_register(&msm_rotator_platform_driver);
1805}
1806
1807static void __exit msm_rotator_exit(void)
1808{
1809 return platform_driver_unregister(&msm_rotator_platform_driver);
1810}
1811
1812module_init(msm_rotator_init);
1813module_exit(msm_rotator_exit);
1814
1815MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1816MODULE_VERSION("1.0");
1817MODULE_LICENSE("GPL v2");