blob: a0a6380d8d5df1250b07ca300b847944f3e643ce [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
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700174int msm_rotator_iommu_map_buf(int mem_id, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700175 unsigned long *start, unsigned long *len,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700176 struct ion_handle **pihdl, unsigned int secure)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700177{
178 if (!msm_rotator_dev->client)
179 return -EINVAL;
180
Laura Abbottb14ed962012-01-30 14:18:08 -0800181 *pihdl = ion_import_dma_buf(msm_rotator_dev->client, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700182 if (IS_ERR_OR_NULL(*pihdl)) {
Laura Abbottb14ed962012-01-30 14:18:08 -0800183 pr_err("ion_import_dma_buf() failed\n");
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700184 return PTR_ERR(*pihdl);
185 }
taeyol.kim69400442012-08-03 19:15:10 -0700186 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700187
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700188 if (rot_iommu_split_domain) {
189 if (secure) {
190 if (ion_phys(msm_rotator_dev->client,
191 *pihdl, start, (unsigned *)len)) {
192 pr_err("%s:%d: ion_phys map failed\n",
193 __func__, __LINE__);
194 return -ENOMEM;
195 }
196 } else {
197 if (ion_map_iommu(msm_rotator_dev->client,
198 *pihdl, domain, GEN_POOL,
199 SZ_4K, 0, start, len, 0,
200 ION_IOMMU_UNMAP_DELAYED)) {
201 pr_err("ion_map_iommu() failed\n");
202 return -EINVAL;
203 }
204 }
205 } else {
206 if (ion_map_iommu(msm_rotator_dev->client,
207 *pihdl, ROTATOR_SRC_DOMAIN, GEN_POOL,
208 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
209 pr_err("ion_map_iommu() failed\n");
210 return -EINVAL;
211 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700212 }
213
214 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
215 __func__, mem_id, *start, *len);
216 return 0;
217}
218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219int msm_rotator_imem_allocate(int requestor)
220{
221 int rc = 0;
222
223#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
224 switch (requestor) {
225 case ROTATOR_REQUEST:
226 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
227 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
228 rc = 1;
229 } else
230 rc = 0;
231 break;
232 case JPEG_REQUEST:
233 mutex_lock(&msm_rotator_dev->imem_lock);
234 msm_rotator_dev->imem_owner = JPEG_REQUEST;
235 rc = 1;
236 break;
237 default:
238 rc = 0;
239 }
240#else
241 if (requestor == JPEG_REQUEST)
242 rc = 1;
243#endif
244 if (rc == 1) {
245 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
246 if (msm_rotator_dev->imem_clk_state != CLK_EN
247 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700248 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 msm_rotator_dev->imem_clk_state = CLK_EN;
250 }
251 }
252
253 return rc;
254}
255EXPORT_SYMBOL(msm_rotator_imem_allocate);
256
257void msm_rotator_imem_free(int requestor)
258{
259#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
260 if (msm_rotator_dev->imem_owner == requestor) {
261 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
262 mutex_unlock(&msm_rotator_dev->imem_lock);
263 }
264#else
265 if (requestor == JPEG_REQUEST)
266 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
267#endif
268}
269EXPORT_SYMBOL(msm_rotator_imem_free);
270
271static void msm_rotator_imem_clk_work_f(struct work_struct *work)
272{
273#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
274 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
275 if (msm_rotator_dev->imem_clk_state == CLK_EN
276 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700277 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 msm_rotator_dev->imem_clk_state = CLK_DIS;
279 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
280 msm_rotator_dev->imem_clk_state = CLK_DIS;
281 mutex_unlock(&msm_rotator_dev->imem_lock);
282 }
283#endif
284}
285
286/* enable clocks needed by rotator block */
287static void enable_rot_clks(void)
288{
289 if (msm_rotator_dev->regulator)
290 regulator_enable(msm_rotator_dev->regulator);
291 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700292 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700294 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295}
296
297/* disable clocks needed by rotator block */
298static void disable_rot_clks(void)
299{
300 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700301 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700303 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 if (msm_rotator_dev->regulator)
305 regulator_disable(msm_rotator_dev->regulator);
306}
307
308static void msm_rotator_rot_clk_work_f(struct work_struct *work)
309{
310 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
311 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
312 disable_rot_clks();
313 msm_rotator_dev->rot_clk_state = CLK_DIS;
314 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
315 msm_rotator_dev->rot_clk_state = CLK_DIS;
316 mutex_unlock(&msm_rotator_dev->rotator_lock);
317 }
318}
319
320static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
321{
322 if (msm_rotator_dev->processing) {
323 msm_rotator_dev->processing = 0;
324 wake_up(&msm_rotator_dev->wq);
325 } else
326 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
327
328 return IRQ_HANDLED;
329}
330
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700331static unsigned int tile_size(unsigned int src_width,
332 unsigned int src_height,
333 const struct tile_parm *tp)
334{
335 unsigned int tile_w, tile_h;
336 unsigned int row_num_w, row_num_h;
337 tile_w = tp->width * tp->row_tile_w;
338 tile_h = tp->height * tp->row_tile_h;
339 row_num_w = (src_width + tile_w - 1) / tile_w;
340 row_num_h = (src_height + tile_h - 1) / tile_h;
341 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
342}
343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344static int get_bpp(int format)
345{
346 switch (format) {
347 case MDP_RGB_565:
348 case MDP_BGR_565:
349 return 2;
350
351 case MDP_XRGB_8888:
352 case MDP_ARGB_8888:
353 case MDP_RGBA_8888:
354 case MDP_BGRA_8888:
355 case MDP_RGBX_8888:
356 return 4;
357
358 case MDP_Y_CBCR_H2V2:
359 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700360 case MDP_Y_CB_CR_H2V2:
361 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530362 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 case MDP_Y_CRCB_H2V2_TILE:
364 case MDP_Y_CBCR_H2V2_TILE:
365 return 1;
366
367 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700368 case MDP_YCBCR_H1V1:
369 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 return 3;
371
372 case MDP_YCRYCB_H2V1:
373 return 2;/* YCrYCb interleave */
374
375 case MDP_Y_CRCB_H2V1:
376 case MDP_Y_CBCR_H2V1:
377 return 1;
378
379 default:
380 return -1;
381 }
382
383}
384
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700385static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
386 struct msm_rotator_mem_planes *p)
387{
388 /*
389 * each row of samsung tile consists of two tiles in height
390 * and two tiles in width which means width should align to
391 * 64 x 2 bytes and height should align to 32 x 2 bytes.
392 * video decoder generate two tiles in width and one tile
393 * in height which ends up height align to 32 X 1 bytes.
394 */
395 const struct tile_parm tile = {64, 32, 2, 1};
396 int i;
397
398 if (p == NULL)
399 return -EINVAL;
400
401 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
402 return -ERANGE;
403
404 memset(p, 0, sizeof(*p));
405
406 switch (format) {
407 case MDP_XRGB_8888:
408 case MDP_ARGB_8888:
409 case MDP_RGBA_8888:
410 case MDP_BGRA_8888:
411 case MDP_RGBX_8888:
412 case MDP_RGB_888:
413 case MDP_RGB_565:
414 case MDP_BGR_565:
415 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700416 case MDP_YCBCR_H1V1:
417 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700418 p->num_planes = 1;
419 p->plane_size[0] = w * h * get_bpp(format);
420 break;
421 case MDP_Y_CRCB_H2V1:
422 case MDP_Y_CBCR_H2V1:
423 p->num_planes = 2;
424 p->plane_size[0] = w * h;
425 p->plane_size[1] = w * h;
426 break;
427 case MDP_Y_CBCR_H2V2:
428 case MDP_Y_CRCB_H2V2:
429 p->num_planes = 2;
430 p->plane_size[0] = w * h;
431 p->plane_size[1] = w * h / 2;
432 break;
433 case MDP_Y_CRCB_H2V2_TILE:
434 case MDP_Y_CBCR_H2V2_TILE:
435 p->num_planes = 2;
436 p->plane_size[0] = tile_size(w, h, &tile);
437 p->plane_size[1] = tile_size(w, h/2, &tile);
438 break;
439 case MDP_Y_CB_CR_H2V2:
440 case MDP_Y_CR_CB_H2V2:
441 p->num_planes = 3;
442 p->plane_size[0] = w * h;
443 p->plane_size[1] = (w / 2) * (h / 2);
444 p->plane_size[2] = (w / 2) * (h / 2);
445 break;
446 case MDP_Y_CR_CB_GH2V2:
447 p->num_planes = 3;
448 p->plane_size[0] = ALIGN(w, 16) * h;
449 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
450 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
451 break;
452 default:
453 return -EINVAL;
454 }
455
456 for (i = 0; i < p->num_planes; i++)
457 p->total_size += p->plane_size[i];
458
459 return 0;
460}
461
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700462static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
463 unsigned int in_paddr,
464 unsigned int out_paddr,
465 unsigned int use_imem,
466 int new_session,
467 unsigned int in_chroma_paddr,
468 unsigned int out_chroma_paddr)
469{
470 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700471
472 if (info->src.format != info->dst.format)
473 return -EINVAL;
474
475 bpp = get_bpp(info->src.format);
476 if (bpp < 0)
477 return -ENOTTY;
478
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700479 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700480 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700481 iowrite32(out_paddr +
482 ((info->dst_y * info->dst.width) + info->dst_x),
483 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700484 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700485 ((info->dst_y * info->dst.width) + info->dst_x),
486 MSM_ROTATOR_OUTP1_ADDR);
487
488 if (new_session) {
489 iowrite32(info->src.width |
490 info->src.width << 16,
491 MSM_ROTATOR_SRC_YSTRIDE1);
492 if (info->rotations & MDP_ROT_90)
493 iowrite32(info->dst.width |
494 info->dst.width*2 << 16,
495 MSM_ROTATOR_OUT_YSTRIDE1);
496 else
497 iowrite32(info->dst.width |
498 info->dst.width << 16,
499 MSM_ROTATOR_OUT_YSTRIDE1);
500 if (info->src.format == MDP_Y_CBCR_H2V1) {
501 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
502 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
503 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
504 MSM_ROTATOR_OUT_PACK_PATTERN1);
505 } else {
506 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
507 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
508 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
509 MSM_ROTATOR_OUT_PACK_PATTERN1);
510 }
511 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
512 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700513 1 << 8 | /* ROT_EN */
514 info->downscale_ratio << 2 | /* downscale v ratio */
515 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700516 MSM_ROTATOR_SUB_BLOCK_CFG);
517 iowrite32(0 << 29 | /* frame format 0 = linear */
518 (use_imem ? 0 : 1) << 22 | /* tile size */
519 2 << 19 | /* fetch planes 2 = pseudo */
520 0 << 18 | /* unpack align */
521 1 << 17 | /* unpack tight */
522 1 << 13 | /* unpack count 0=1 component */
523 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
524 0 << 8 | /* has alpha */
525 0 << 6 | /* alpha bits 3=8bits */
526 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
527 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
528 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
529 MSM_ROTATOR_SRC_FORMAT);
530 }
531
532 return 0;
533}
534
535static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
536 unsigned int in_paddr,
537 unsigned int out_paddr,
538 unsigned int use_imem,
539 int new_session,
540 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700541 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700542 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700543{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700544 uint32_t dst_format;
545 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700546
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700547 switch (info->src.format) {
548 case MDP_Y_CRCB_H2V2_TILE:
549 is_tile = 1;
550 case MDP_Y_CR_CB_H2V2:
551 case MDP_Y_CR_CB_GH2V2:
552 case MDP_Y_CRCB_H2V2:
553 dst_format = MDP_Y_CRCB_H2V2;
554 break;
555 case MDP_Y_CBCR_H2V2_TILE:
556 is_tile = 1;
557 case MDP_Y_CB_CR_H2V2:
558 case MDP_Y_CBCR_H2V2:
559 dst_format = MDP_Y_CBCR_H2V2;
560 break;
561 default:
562 return -EINVAL;
563 }
564 if (info->dst.format != dst_format)
565 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700566
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800567 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530568 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
569 info->src.format == MDP_Y_CR_CB_GH2V2) &&
570 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800571 swap(in_chroma_paddr, in_chroma2_paddr);
572
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700573 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700574 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
575 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
576
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700577 iowrite32(out_paddr +
578 ((info->dst_y * info->dst.width) + info->dst_x),
579 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700580 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700581 ((info->dst_y * info->dst.width)/2 + info->dst_x),
582 MSM_ROTATOR_OUTP1_ADDR);
583
584 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700585 if (in_chroma2_paddr) {
586 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530587 iowrite32(ALIGN(info->src.width, 16) |
588 ALIGN((info->src.width / 2), 16) << 16,
589 MSM_ROTATOR_SRC_YSTRIDE1);
590 iowrite32(ALIGN((info->src.width / 2), 16),
591 MSM_ROTATOR_SRC_YSTRIDE2);
592 } else {
593 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700594 (info->src.width / 2) << 16,
595 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530596 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700597 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530598 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700599 } else {
600 iowrite32(info->src.width |
601 info->src.width << 16,
602 MSM_ROTATOR_SRC_YSTRIDE1);
603 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700604 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700605 info->dst.width << 16,
606 MSM_ROTATOR_OUT_YSTRIDE1);
607
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700608 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
610 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
611 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
612 MSM_ROTATOR_OUT_PACK_PATTERN1);
613 } else {
614 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
615 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
616 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
617 MSM_ROTATOR_OUT_PACK_PATTERN1);
618 }
619 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
620 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700621 1 << 8 | /* ROT_EN */
622 info->downscale_ratio << 2 | /* downscale v ratio */
623 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700624 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700625
626 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700628 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700629 0 << 18 | /* unpack align */
630 1 << 17 | /* unpack tight */
631 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700632 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700633 0 << 8 | /* has alpha */
634 0 << 6 | /* alpha bits 3=8bits */
635 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
636 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
637 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
638 MSM_ROTATOR_SRC_FORMAT);
639 }
640 return 0;
641}
642
643static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
644 unsigned int in_paddr,
645 unsigned int out_paddr,
646 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530647 int new_session,
648 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700649{
650 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530651 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652
Mayank Chopra732dcd62012-01-09 20:53:39 +0530653 if (info->src.format == MDP_YCRYCB_H2V1)
654 dst_format = MDP_Y_CRCB_H2V1;
655 else
656 return -EINVAL;
657
658 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700659 return -EINVAL;
660
661 bpp = get_bpp(info->src.format);
662 if (bpp < 0)
663 return -ENOTTY;
664
665 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
666 iowrite32(out_paddr +
667 ((info->dst_y * info->dst.width) + info->dst_x),
668 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530669 iowrite32(out_chroma_paddr +
670 ((info->dst_y * info->dst.width)/2 + info->dst_x),
671 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700672
673 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530674 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530676 if (info->rotations & MDP_ROT_90)
677 iowrite32(info->dst.width |
678 (info->dst.width*2) << 16,
679 MSM_ROTATOR_OUT_YSTRIDE1);
680 else
681 iowrite32(info->dst.width |
682 (info->dst.width) << 16,
683 MSM_ROTATOR_OUT_YSTRIDE1);
684
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700685 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
686 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530687 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688 MSM_ROTATOR_OUT_PACK_PATTERN1);
689 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
690 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700691 1 << 8 | /* ROT_EN */
692 info->downscale_ratio << 2 | /* downscale v ratio */
693 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694 MSM_ROTATOR_SUB_BLOCK_CFG);
695 iowrite32(0 << 29 | /* frame format 0 = linear */
696 (use_imem ? 0 : 1) << 22 | /* tile size */
697 0 << 19 | /* fetch planes 0=interleaved */
698 0 << 18 | /* unpack align */
699 1 << 17 | /* unpack tight */
700 3 << 13 | /* unpack count 0=1 component */
701 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
702 0 << 8 | /* has alpha */
703 0 << 6 | /* alpha bits 3=8bits */
704 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
705 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
706 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
707 MSM_ROTATOR_SRC_FORMAT);
708 }
709
710 return 0;
711}
712
713static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
714 unsigned int in_paddr,
715 unsigned int out_paddr,
716 unsigned int use_imem,
717 int new_session)
718{
719 int bpp, abits, rbits, gbits, bbits;
720
721 if (info->src.format != info->dst.format)
722 return -EINVAL;
723
724 bpp = get_bpp(info->src.format);
725 if (bpp < 0)
726 return -ENOTTY;
727
728 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
729 iowrite32(out_paddr +
730 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
731 MSM_ROTATOR_OUTP0_ADDR);
732
733 if (new_session) {
734 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
735 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
736 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
737 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700738 1 << 8 | /* ROT_EN */
739 info->downscale_ratio << 2 | /* downscale v ratio */
740 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700741 MSM_ROTATOR_SUB_BLOCK_CFG);
742 switch (info->src.format) {
743 case MDP_RGB_565:
744 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
745 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
746 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
747 MSM_ROTATOR_OUT_PACK_PATTERN1);
748 abits = 0;
749 rbits = COMPONENT_5BITS;
750 gbits = COMPONENT_6BITS;
751 bbits = COMPONENT_5BITS;
752 break;
753
754 case MDP_BGR_565:
755 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
756 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
757 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
758 MSM_ROTATOR_OUT_PACK_PATTERN1);
759 abits = 0;
760 rbits = COMPONENT_5BITS;
761 gbits = COMPONENT_6BITS;
762 bbits = COMPONENT_5BITS;
763 break;
764
765 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700766 case MDP_YCBCR_H1V1:
767 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700768 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
769 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
770 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
771 MSM_ROTATOR_OUT_PACK_PATTERN1);
772 abits = 0;
773 rbits = COMPONENT_8BITS;
774 gbits = COMPONENT_8BITS;
775 bbits = COMPONENT_8BITS;
776 break;
777
778 case MDP_ARGB_8888:
779 case MDP_RGBA_8888:
780 case MDP_XRGB_8888:
781 case MDP_RGBX_8888:
782 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
783 CLR_B, 8),
784 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
785 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
786 CLR_B, 8),
787 MSM_ROTATOR_OUT_PACK_PATTERN1);
788 abits = COMPONENT_8BITS;
789 rbits = COMPONENT_8BITS;
790 gbits = COMPONENT_8BITS;
791 bbits = COMPONENT_8BITS;
792 break;
793
794 case MDP_BGRA_8888:
795 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
796 CLR_R, 8),
797 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
798 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
799 CLR_R, 8),
800 MSM_ROTATOR_OUT_PACK_PATTERN1);
801 abits = COMPONENT_8BITS;
802 rbits = COMPONENT_8BITS;
803 gbits = COMPONENT_8BITS;
804 bbits = COMPONENT_8BITS;
805 break;
806
807 default:
808 return -EINVAL;
809 }
810 iowrite32(0 << 29 | /* frame format 0 = linear */
811 (use_imem ? 0 : 1) << 22 | /* tile size */
812 0 << 19 | /* fetch planes 0=interleaved */
813 0 << 18 | /* unpack align */
814 1 << 17 | /* unpack tight */
815 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
816 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
817 (abits ? 1 : 0) << 8 | /* has alpha */
818 abits << 6 | /* alpha bits 3=8bits */
819 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
820 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
821 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
822 MSM_ROTATOR_SRC_FORMAT);
823 }
824
825 return 0;
826}
827
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700828static int get_img(struct msmfb_data *fbd, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700829 unsigned long *start, unsigned long *len, struct file **p_file,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700830 int *p_need, struct ion_handle **p_ihdl, unsigned int secure)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700831{
832 int ret = 0;
833#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700834 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700835 int put_needed, fb_num;
836#endif
837#ifdef CONFIG_ANDROID_PMEM
838 unsigned long vstart;
839#endif
840
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800841 *p_need = 0;
842
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700843#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700844 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
845 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700846 if (file == NULL) {
847 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700848 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700849 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700850
Naseer Ahmed18018602011-10-25 13:32:58 -0700851 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
852 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700853 if (get_fb_phys_info(start, len, fb_num,
854 ROTATOR_SUBSYSTEM_ID)) {
855 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700856 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700857 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700858 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800859 *p_need = put_needed;
860 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700861 } else {
862 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700863 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700864 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700865 if (ret)
866 fput_light(file, put_needed);
867 return ret;
868 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700869#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700870
871#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700872 return msm_rotator_iommu_map_buf(fbd->memory_id, domain, start,
873 len, p_ihdl, secure);
Naseer Ahmed18018602011-10-25 13:32:58 -0700874#endif
875#ifdef CONFIG_ANDROID_PMEM
876 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
877 return 0;
878 else
879 return -ENOMEM;
880#endif
881
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700882}
883
Olav Hauganef95ae32012-05-15 09:50:30 -0700884static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700885 int domain, unsigned int secure)
Naseer Ahmed18018602011-10-25 13:32:58 -0700886{
887#ifdef CONFIG_ANDROID_PMEM
888 if (p_file != NULL)
889 put_pmem_file(p_file);
890#endif
Olav Hauganef95ae32012-05-15 09:50:30 -0700891
Naseer Ahmed18018602011-10-25 13:32:58 -0700892#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700893 if (!IS_ERR_OR_NULL(p_ihdl)) {
894 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700895 if (rot_iommu_split_domain) {
896 if (!secure)
897 ion_unmap_iommu(msm_rotator_dev->client,
898 p_ihdl, domain, GEN_POOL);
899 } else {
900 ion_unmap_iommu(msm_rotator_dev->client,
901 p_ihdl, ROTATOR_SRC_DOMAIN, GEN_POOL);
902 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700903
Naseer Ahmed18018602011-10-25 13:32:58 -0700904 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700905 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700906#endif
907}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700908static int msm_rotator_do_rotate(unsigned long arg)
909{
Naseer Ahmed18018602011-10-25 13:32:58 -0700910 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700911 struct msm_rotator_data_info info;
912 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700913 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700914 int use_imem = 0, rc = 0, s;
915 struct file *srcp0_file = NULL, *dstp0_file = NULL;
916 struct file *srcp1_file = NULL, *dstp1_file = NULL;
917 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
918 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800919 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700920 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700921 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700922 struct msm_rotator_img_info *img_info;
923 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924
925 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
926 return -EFAULT;
927
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928 mutex_lock(&msm_rotator_dev->rotator_lock);
929 for (s = 0; s < MAX_SESSIONS; s++)
930 if ((msm_rotator_dev->img_info[s] != NULL) &&
931 (info.session_id ==
932 (unsigned int)msm_rotator_dev->img_info[s]
933 ))
934 break;
935
936 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700937 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700938 __func__, s);
939 rc = -EINVAL;
940 goto do_rotate_unlock_mutex;
941 }
942
943 if (msm_rotator_dev->img_info[s]->enable == 0) {
944 dev_dbg(msm_rotator_dev->device,
945 "%s() : Session_id %d not enabled \n",
946 __func__, s);
947 rc = -EINVAL;
948 goto do_rotate_unlock_mutex;
949 }
950
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700951 img_info = msm_rotator_dev->img_info[s];
952 if (msm_rotator_get_plane_sizes(img_info->src.format,
953 img_info->src.width,
954 img_info->src.height,
955 &src_planes)) {
956 pr_err("%s: invalid src format\n", __func__);
957 rc = -EINVAL;
958 goto do_rotate_unlock_mutex;
959 }
960 if (msm_rotator_get_plane_sizes(img_info->dst.format,
961 img_info->dst.width,
962 img_info->dst.height,
963 &dst_planes)) {
964 pr_err("%s: invalid dst format\n", __func__);
965 rc = -EINVAL;
966 goto do_rotate_unlock_mutex;
967 }
968
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700969 rc = get_img(&info.src, ROTATOR_SRC_DOMAIN, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700970 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700971 &srcp0_ihdl, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700972 if (rc) {
973 pr_err("%s: in get_img() failed id=0x%08x\n",
974 DRIVER_NAME, info.src.memory_id);
975 goto do_rotate_unlock_mutex;
976 }
977
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700978 rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700979 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700980 &dstp0_ihdl, img_info->secure);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700981 if (rc) {
982 pr_err("%s: out get_img() failed id=0x%08x\n",
983 DRIVER_NAME, info.dst.memory_id);
984 goto do_rotate_unlock_mutex;
985 }
986
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700987 format = msm_rotator_dev->img_info[s]->src.format;
988 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700989 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
990 (src_planes.num_planes == 2)) {
991 if (checkoffset(info.src.offset,
992 src_planes.plane_size[0],
993 src_len)) {
994 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
995 __func__, src_len, info.src.offset);
996 rc = -ERANGE;
997 goto do_rotate_unlock_mutex;
998 }
999 if (checkoffset(info.dst.offset,
1000 dst_planes.plane_size[0],
1001 dst_len)) {
1002 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1003 __func__, dst_len, info.dst.offset);
1004 rc = -ERANGE;
1005 goto do_rotate_unlock_mutex;
1006 }
1007
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001008 rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001010 (unsigned long *)&src_len, &srcp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001011 &srcp1_ihdl, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001013 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 DRIVER_NAME, info.src_chroma.memory_id);
1015 goto do_rotate_unlock_mutex;
1016 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001018 rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001020 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001021 &dstp1_ihdl, img_info->secure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001023 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001025 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001027
1028 if (checkoffset(info.src_chroma.offset,
1029 src_planes.plane_size[1],
1030 src_len)) {
1031 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1032 __func__, src_len, info.src_chroma.offset);
1033 rc = -ERANGE;
1034 goto do_rotate_unlock_mutex;
1035 }
1036
1037 if (checkoffset(info.dst_chroma.offset,
1038 src_planes.plane_size[1],
1039 dst_len)) {
1040 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1041 __func__, dst_len, info.dst_chroma.offset);
1042 rc = -ERANGE;
1043 goto do_rotate_unlock_mutex;
1044 }
1045
1046 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001047 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001048 } else {
1049 if (checkoffset(info.src.offset,
1050 src_planes.total_size,
1051 src_len)) {
1052 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1053 __func__, src_len, info.src.offset);
1054 rc = -ERANGE;
1055 goto do_rotate_unlock_mutex;
1056 }
1057 if (checkoffset(info.dst.offset,
1058 dst_planes.total_size,
1059 dst_len)) {
1060 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1061 __func__, dst_len, info.dst.offset);
1062 rc = -ERANGE;
1063 goto do_rotate_unlock_mutex;
1064 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001065 }
1066
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001067 in_paddr += info.src.offset;
1068 out_paddr += info.dst.offset;
1069
1070 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1071 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1072 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1073 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1074 if (src_planes.num_planes >= 3)
1075 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1076
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001077 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1078 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1079 enable_rot_clks();
1080 msm_rotator_dev->rot_clk_state = CLK_EN;
1081 }
1082 enable_irq(msm_rotator_dev->irq);
1083
1084#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1085 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1086#else
1087 use_imem = 0;
1088#endif
1089 /*
1090 * workaround for a hardware bug. rotator hardware hangs when we
1091 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1092 * temporary fix use 0x42 for BURST_SIZE when imem used.
1093 */
1094 if (use_imem)
1095 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1096
1097 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1098 << 16) |
1099 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1100 MSM_ROTATOR_SRC_SIZE);
1101 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1102 << 16) |
1103 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1104 MSM_ROTATOR_SRC_XY);
1105 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1106 << 16) |
1107 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1108 MSM_ROTATOR_SRC_IMAGE_SIZE);
1109
1110 switch (format) {
1111 case MDP_RGB_565:
1112 case MDP_BGR_565:
1113 case MDP_RGB_888:
1114 case MDP_ARGB_8888:
1115 case MDP_RGBA_8888:
1116 case MDP_XRGB_8888:
1117 case MDP_BGRA_8888:
1118 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001119 case MDP_YCBCR_H1V1:
1120 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001121 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1122 in_paddr, out_paddr,
1123 use_imem,
1124 msm_rotator_dev->last_session_idx
1125 != s);
1126 break;
1127 case MDP_Y_CBCR_H2V2:
1128 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001129 case MDP_Y_CB_CR_H2V2:
1130 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301131 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 case MDP_Y_CRCB_H2V2_TILE:
1133 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001134 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1135 in_paddr, out_paddr, use_imem,
1136 msm_rotator_dev->last_session_idx
1137 != s,
1138 in_chroma_paddr,
1139 out_chroma_paddr,
1140 in_chroma2_paddr);
1141 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001142 case MDP_Y_CBCR_H2V1:
1143 case MDP_Y_CRCB_H2V1:
1144 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1145 in_paddr, out_paddr, use_imem,
1146 msm_rotator_dev->last_session_idx
1147 != s,
1148 in_chroma_paddr,
1149 out_chroma_paddr);
1150 break;
1151 case MDP_YCRYCB_H2V1:
1152 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1153 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301154 msm_rotator_dev->last_session_idx != s,
1155 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001156 break;
1157 default:
1158 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001159 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 goto do_rotate_exit;
1161 }
1162
1163 if (rc != 0) {
1164 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001165 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 goto do_rotate_exit;
1167 }
1168
1169 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1170
1171 msm_rotator_dev->processing = 1;
1172 iowrite32(0x1, MSM_ROTATOR_START);
1173
1174 wait_event(msm_rotator_dev->wq,
1175 (msm_rotator_dev->processing == 0));
1176 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001177 if ((status & 0x03) != 0x01) {
1178 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1179 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001181 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1183 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1184
1185do_rotate_exit:
1186 disable_irq(msm_rotator_dev->irq);
1187#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1188 msm_rotator_imem_free(ROTATOR_REQUEST);
1189#endif
1190 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001191do_rotate_unlock_mutex:
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001192 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
1193 msm_rotator_dev->img_info[s]->secure);
1194 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1195 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
1196 msm_rotator_dev->img_info[s]->secure);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001197
1198 /* only source may use frame buffer */
1199 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1200 fput_light(srcp0_file, ps0_need);
1201 else
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001202 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001203 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1205 __func__, rc);
1206 return rc;
1207}
1208
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001209static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1210{
1211 u32 perf_level;
1212
1213 if (is_rgb)
1214 perf_level = 1;
1215 else if (wh <= (640 * 480))
1216 perf_level = 2;
1217 else if (wh <= (736 * 1280))
1218 perf_level = 3;
1219 else
1220 perf_level = 4;
1221
1222#ifdef CONFIG_MSM_BUS_SCALING
1223 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1224 perf_level);
1225#endif
1226
1227}
1228
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001229static int msm_rotator_start(unsigned long arg,
1230 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001231{
1232 struct msm_rotator_img_info info;
1233 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001234 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001236 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237
1238 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1239 return -EFAULT;
1240
1241 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1242 (info.src.height > MSM_ROTATOR_MAX_H) ||
1243 (info.src.width > MSM_ROTATOR_MAX_W) ||
1244 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1245 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001246 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1247 pr_err("%s: Invalid parameters\n", __func__);
1248 return -EINVAL;
1249 }
1250
1251 if (info.rotations & MDP_ROT_90) {
1252 dst_w = info.src_rect.h >> info.downscale_ratio;
1253 dst_h = info.src_rect.w >> info.downscale_ratio;
1254 } else {
1255 dst_w = info.src_rect.w >> info.downscale_ratio;
1256 dst_h = info.src_rect.h >> info.downscale_ratio;
1257 }
1258
1259 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001260 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1261 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001262 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1263 pr_err("%s: Invalid src or dst rect\n", __func__);
1264 return -ERANGE;
1265 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001266
1267 switch (info.src.format) {
1268 case MDP_RGB_565:
1269 case MDP_BGR_565:
1270 case MDP_RGB_888:
1271 case MDP_ARGB_8888:
1272 case MDP_RGBA_8888:
1273 case MDP_XRGB_8888:
1274 case MDP_RGBX_8888:
1275 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001276 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301277 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001278 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001279 case MDP_Y_CBCR_H2V2:
1280 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301281 case MDP_Y_CBCR_H2V1:
1282 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001283 case MDP_YCBCR_H1V1:
1284 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301285 info.dst.format = info.src.format;
1286 break;
1287 case MDP_YCRYCB_H2V1:
1288 info.dst.format = MDP_Y_CRCB_H2V1;
1289 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001290 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301291 case MDP_Y_CBCR_H2V2_TILE:
1292 info.dst.format = MDP_Y_CBCR_H2V2;
1293 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001294 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301295 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301297 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001298 break;
1299 default:
1300 return -EINVAL;
1301 }
1302
1303 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001304
1305 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1306
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001307 for (s = 0; s < MAX_SESSIONS; s++) {
1308 if ((msm_rotator_dev->img_info[s] != NULL) &&
1309 (info.session_id ==
1310 (unsigned int)msm_rotator_dev->img_info[s]
1311 )) {
1312 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001313 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314
1315 if (msm_rotator_dev->last_session_idx == s)
1316 msm_rotator_dev->last_session_idx =
1317 INVALID_SESSION;
1318 break;
1319 }
1320
1321 if ((msm_rotator_dev->img_info[s] == NULL) &&
1322 (first_free_index ==
1323 INVALID_SESSION))
1324 first_free_index = s;
1325 }
1326
1327 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1328 /* allocate a session id */
1329 msm_rotator_dev->img_info[first_free_index] =
1330 kzalloc(sizeof(struct msm_rotator_img_info),
1331 GFP_KERNEL);
1332 if (!msm_rotator_dev->img_info[first_free_index]) {
1333 printk(KERN_ERR "%s : unable to alloc mem\n",
1334 __func__);
1335 rc = -ENOMEM;
1336 goto rotator_start_exit;
1337 }
1338 info.session_id = (unsigned int)
1339 msm_rotator_dev->img_info[first_free_index];
1340 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001341 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001342 } else if (s == MAX_SESSIONS) {
1343 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1344 __func__);
1345 rc = -EBUSY;
1346 }
1347
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001348 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1349 rc = -EFAULT;
1350
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001351rotator_start_exit:
1352 mutex_unlock(&msm_rotator_dev->rotator_lock);
1353
1354 return rc;
1355}
1356
1357static int msm_rotator_finish(unsigned long arg)
1358{
1359 int rc = 0;
1360 int s;
1361 unsigned int session_id;
1362
1363 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1364 return -EFAULT;
1365
1366 mutex_lock(&msm_rotator_dev->rotator_lock);
1367 for (s = 0; s < MAX_SESSIONS; s++) {
1368 if ((msm_rotator_dev->img_info[s] != NULL) &&
1369 (session_id ==
1370 (unsigned int)msm_rotator_dev->img_info[s])) {
1371 if (msm_rotator_dev->last_session_idx == s)
1372 msm_rotator_dev->last_session_idx =
1373 INVALID_SESSION;
1374 kfree(msm_rotator_dev->img_info[s]);
1375 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001376 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001377 break;
1378 }
1379 }
1380
1381 if (s == MAX_SESSIONS)
1382 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001383#ifdef CONFIG_MSM_BUS_SCALING
1384 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1385 0);
1386#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001387 mutex_unlock(&msm_rotator_dev->rotator_lock);
1388 return rc;
1389}
1390
1391static int
1392msm_rotator_open(struct inode *inode, struct file *filp)
1393{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001394 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 int i;
1396
1397 if (filp->private_data)
1398 return -EBUSY;
1399
1400 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001401 for (i = 0; i < MAX_SESSIONS; i++) {
1402 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001403 break;
1404 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001405
1406 if (i == MAX_SESSIONS) {
1407 mutex_unlock(&msm_rotator_dev->rotator_lock);
1408 return -EBUSY;
1409 }
1410
1411 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1412 if (tmp->pid == current->pid) {
1413 fd_info = tmp;
1414 break;
1415 }
1416 }
1417
1418 if (!fd_info) {
1419 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1420 if (!fd_info) {
1421 mutex_unlock(&msm_rotator_dev->rotator_lock);
1422 pr_err("%s: insufficient memory to alloc resources\n",
1423 __func__);
1424 return -ENOMEM;
1425 }
1426 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1427 fd_info->pid = current->pid;
1428 }
1429 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001430 mutex_unlock(&msm_rotator_dev->rotator_lock);
1431
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001432 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001433
1434 return 0;
1435}
1436
1437static int
1438msm_rotator_close(struct inode *inode, struct file *filp)
1439{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001440 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001441 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001443 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1444
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001446 if (--fd_info->ref_cnt > 0) {
1447 mutex_unlock(&msm_rotator_dev->rotator_lock);
1448 return 0;
1449 }
1450
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451 for (s = 0; s < MAX_SESSIONS; s++) {
1452 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001453 msm_rotator_dev->fd_info[s] == fd_info) {
1454 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1455 __func__, msm_rotator_dev->img_info[s],
1456 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457 kfree(msm_rotator_dev->img_info[s]);
1458 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001459 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 if (msm_rotator_dev->last_session_idx == s)
1461 msm_rotator_dev->last_session_idx =
1462 INVALID_SESSION;
1463 }
1464 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001465 list_del(&fd_info->list);
1466 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001467 mutex_unlock(&msm_rotator_dev->rotator_lock);
1468
1469 return 0;
1470}
1471
1472static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1473 unsigned long arg)
1474{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001475 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001476
1477 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1478 return -ENOTTY;
1479
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001480 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001481
1482 switch (cmd) {
1483 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001484 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 case MSM_ROTATOR_IOCTL_ROTATE:
1486 return msm_rotator_do_rotate(arg);
1487 case MSM_ROTATOR_IOCTL_FINISH:
1488 return msm_rotator_finish(arg);
1489
1490 default:
1491 dev_dbg(msm_rotator_dev->device,
1492 "unexpected IOCTL %d\n", cmd);
1493 return -ENOTTY;
1494 }
1495}
1496
1497static const struct file_operations msm_rotator_fops = {
1498 .owner = THIS_MODULE,
1499 .open = msm_rotator_open,
1500 .release = msm_rotator_close,
1501 .unlocked_ioctl = msm_rotator_ioctl,
1502};
1503
1504static int __devinit msm_rotator_probe(struct platform_device *pdev)
1505{
1506 int rc = 0;
1507 struct resource *res;
1508 struct msm_rotator_platform_data *pdata = NULL;
1509 int i, number_of_clks;
1510 uint32_t ver;
1511
1512 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1513 if (!msm_rotator_dev) {
1514 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1515 __func__);
1516 return -ENOMEM;
1517 }
1518 for (i = 0; i < MAX_SESSIONS; i++)
1519 msm_rotator_dev->img_info[i] = NULL;
1520 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1521
1522 pdata = pdev->dev.platform_data;
1523 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07001524 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001525
1526 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1527 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001528 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001529 msm_rotator_dev->imem_clk_state = CLK_DIS;
1530 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1531 msm_rotator_imem_clk_work_f);
1532 msm_rotator_dev->imem_clk = NULL;
1533 msm_rotator_dev->pdev = pdev;
1534
1535 msm_rotator_dev->core_clk = NULL;
1536 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001537
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001538#ifdef CONFIG_MSM_BUS_SCALING
1539 if (!msm_rotator_dev->bus_client_handle && pdata &&
1540 pdata->bus_scale_table) {
1541 msm_rotator_dev->bus_client_handle =
1542 msm_bus_scale_register_client(
1543 pdata->bus_scale_table);
1544 if (!msm_rotator_dev->bus_client_handle) {
1545 pr_err("%s not able to get bus scale handle\n",
1546 __func__);
1547 }
1548 }
1549#endif
1550
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001551 for (i = 0; i < number_of_clks; i++) {
1552 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1553 msm_rotator_dev->imem_clk =
1554 clk_get(&msm_rotator_dev->pdev->dev,
1555 pdata->rotator_clks[i].clk_name);
1556 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1557 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1558 msm_rotator_dev->imem_clk = NULL;
1559 printk(KERN_ERR "%s: cannot get imem_clk "
1560 "rc=%d\n", DRIVER_NAME, rc);
1561 goto error_imem_clk;
1562 }
1563 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001564 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001565 pdata->rotator_clks[i].clk_rate);
1566 }
1567 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1568 msm_rotator_dev->pclk =
1569 clk_get(&msm_rotator_dev->pdev->dev,
1570 pdata->rotator_clks[i].clk_name);
1571 if (IS_ERR(msm_rotator_dev->pclk)) {
1572 rc = PTR_ERR(msm_rotator_dev->pclk);
1573 msm_rotator_dev->pclk = NULL;
1574 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1575 DRIVER_NAME, rc);
1576 goto error_pclk;
1577 }
1578
1579 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001580 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001581 pdata->rotator_clks[i].clk_rate);
1582 }
1583
1584 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1585 msm_rotator_dev->core_clk =
1586 clk_get(&msm_rotator_dev->pdev->dev,
1587 pdata->rotator_clks[i].clk_name);
1588 if (IS_ERR(msm_rotator_dev->core_clk)) {
1589 rc = PTR_ERR(msm_rotator_dev->core_clk);
1590 msm_rotator_dev->core_clk = NULL;
1591 printk(KERN_ERR "%s: cannot get core clk "
1592 "rc=%d\n", DRIVER_NAME, rc);
1593 goto error_core_clk;
1594 }
1595
1596 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001597 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 pdata->rotator_clks[i].clk_rate);
1599 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001600 }
1601
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001602 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1603 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001604 if (IS_ERR(msm_rotator_dev->regulator))
1605 msm_rotator_dev->regulator = NULL;
1606
1607 msm_rotator_dev->rot_clk_state = CLK_DIS;
1608 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1609 msm_rotator_rot_clk_work_f);
1610
1611 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001612#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1613 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1614#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 platform_set_drvdata(pdev, msm_rotator_dev);
1616
1617
1618 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1619 if (!res) {
1620 printk(KERN_ALERT
1621 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1622 rc = -ENODEV;
1623 goto error_get_resource;
1624 }
1625 msm_rotator_dev->io_base = ioremap(res->start,
1626 resource_size(res));
1627
1628#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1629 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001630 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631#endif
1632 enable_rot_clks();
1633 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1634 disable_rot_clks();
1635
1636#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1637 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001638 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001640 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301641 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001642 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001643
Mayank Chopra012a8e72012-04-11 10:41:13 +05301644 rotator_hw_revision = ver;
1645 rotator_hw_revision >>= 16; /* bit 31:16 */
1646 rotator_hw_revision &= 0xff;
1647
1648 pr_info("%s: rotator_hw_revision=%x\n",
1649 __func__, rotator_hw_revision);
1650
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001651 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1652 if (msm_rotator_dev->irq < 0) {
1653 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1654 DRIVER_NAME);
1655 rc = -ENODEV;
1656 goto error_get_irq;
1657 }
1658 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1659 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1660 if (rc) {
1661 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1662 goto error_get_irq;
1663 }
1664 /* we enable the IRQ when we need it in the ioctl */
1665 disable_irq(msm_rotator_dev->irq);
1666
1667 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1668 if (rc < 0) {
1669 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1670 __func__, rc);
1671 goto error_get_irq;
1672 }
1673
1674 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1675 if (IS_ERR(msm_rotator_dev->class)) {
1676 rc = PTR_ERR(msm_rotator_dev->class);
1677 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1678 DRIVER_NAME, rc);
1679 goto error_class_create;
1680 }
1681
1682 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1683 msm_rotator_dev->dev_num, NULL,
1684 DRIVER_NAME);
1685 if (IS_ERR(msm_rotator_dev->device)) {
1686 rc = PTR_ERR(msm_rotator_dev->device);
1687 printk(KERN_ERR "%s: device_create failed %d\n",
1688 DRIVER_NAME, rc);
1689 goto error_class_device_create;
1690 }
1691
1692 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1693 rc = cdev_add(&msm_rotator_dev->cdev,
1694 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1695 1);
1696 if (rc < 0) {
1697 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1698 goto error_cdev_add;
1699 }
1700
1701 init_waitqueue_head(&msm_rotator_dev->wq);
1702
1703 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1704 return rc;
1705
1706error_cdev_add:
1707 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1708error_class_device_create:
1709 class_destroy(msm_rotator_dev->class);
1710error_class_create:
1711 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1712error_get_irq:
1713 iounmap(msm_rotator_dev->io_base);
1714error_get_resource:
1715 mutex_destroy(&msm_rotator_dev->rotator_lock);
1716 if (msm_rotator_dev->regulator)
1717 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 clk_put(msm_rotator_dev->core_clk);
1719error_core_clk:
1720 clk_put(msm_rotator_dev->pclk);
1721error_pclk:
1722 if (msm_rotator_dev->imem_clk)
1723 clk_put(msm_rotator_dev->imem_clk);
1724error_imem_clk:
1725 mutex_destroy(&msm_rotator_dev->imem_lock);
1726 kfree(msm_rotator_dev);
1727 return rc;
1728}
1729
1730static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1731{
1732 int i;
1733
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001734#ifdef CONFIG_MSM_BUS_SCALING
1735 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1736#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001737 free_irq(msm_rotator_dev->irq, NULL);
1738 mutex_destroy(&msm_rotator_dev->rotator_lock);
1739 cdev_del(&msm_rotator_dev->cdev);
1740 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1741 class_destroy(msm_rotator_dev->class);
1742 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1743 iounmap(msm_rotator_dev->io_base);
1744 if (msm_rotator_dev->imem_clk) {
1745 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001746 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001747 clk_put(msm_rotator_dev->imem_clk);
1748 msm_rotator_dev->imem_clk = NULL;
1749 }
1750 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1751 disable_rot_clks();
1752 clk_put(msm_rotator_dev->core_clk);
1753 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 if (msm_rotator_dev->regulator)
1755 regulator_put(msm_rotator_dev->regulator);
1756 msm_rotator_dev->core_clk = NULL;
1757 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001758 mutex_destroy(&msm_rotator_dev->imem_lock);
1759 for (i = 0; i < MAX_SESSIONS; i++)
1760 if (msm_rotator_dev->img_info[i] != NULL)
1761 kfree(msm_rotator_dev->img_info[i]);
1762 kfree(msm_rotator_dev);
1763 return 0;
1764}
1765
1766#ifdef CONFIG_PM
1767static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1768{
1769 mutex_lock(&msm_rotator_dev->imem_lock);
1770 if (msm_rotator_dev->imem_clk_state == CLK_EN
1771 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001772 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1774 }
1775 mutex_unlock(&msm_rotator_dev->imem_lock);
1776 mutex_lock(&msm_rotator_dev->rotator_lock);
1777 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1778 disable_rot_clks();
1779 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1780 }
1781 mutex_unlock(&msm_rotator_dev->rotator_lock);
1782 return 0;
1783}
1784
1785static int msm_rotator_resume(struct platform_device *dev)
1786{
1787 mutex_lock(&msm_rotator_dev->imem_lock);
1788 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1789 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001790 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791 msm_rotator_dev->imem_clk_state = CLK_EN;
1792 }
1793 mutex_unlock(&msm_rotator_dev->imem_lock);
1794 mutex_lock(&msm_rotator_dev->rotator_lock);
1795 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1796 enable_rot_clks();
1797 msm_rotator_dev->rot_clk_state = CLK_EN;
1798 }
1799 mutex_unlock(&msm_rotator_dev->rotator_lock);
1800 return 0;
1801}
1802#endif
1803
1804static struct platform_driver msm_rotator_platform_driver = {
1805 .probe = msm_rotator_probe,
1806 .remove = __devexit_p(msm_rotator_remove),
1807#ifdef CONFIG_PM
1808 .suspend = msm_rotator_suspend,
1809 .resume = msm_rotator_resume,
1810#endif
1811 .driver = {
1812 .owner = THIS_MODULE,
1813 .name = DRIVER_NAME
1814 }
1815};
1816
1817static int __init msm_rotator_init(void)
1818{
1819 return platform_driver_register(&msm_rotator_platform_driver);
1820}
1821
1822static void __exit msm_rotator_exit(void)
1823{
1824 return platform_driver_unregister(&msm_rotator_platform_driver);
1825}
1826
1827module_init(msm_rotator_init);
1828module_exit(msm_rotator_exit);
1829
1830MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1831MODULE_VERSION("1.0");
1832MODULE_LICENSE("GPL v2");