blob: 205c04d5e457e6efc3066a7a442297134c288ee6 [file] [log] [blame]
Ken Zhangfebeabd2012-12-17 10:35:15 -05001/* Copyright (c) 2009-2013, The Linux Foundation. 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>
Mitchel Humpherys9faf7e12012-09-06 10:33:12 -070031#include <linux/msm_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
Ken Zhangfebeabd2012-12-17 10:35:15 -0500160 u32 sec_mapped;
161 u32 mmu_clk_on;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162};
163
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700164#define COMPONENT_5BITS 1
165#define COMPONENT_6BITS 2
166#define COMPONENT_8BITS 3
167
168static struct msm_rotator_dev *msm_rotator_dev;
169
170enum {
171 CLK_EN,
172 CLK_DIS,
173 CLK_SUSPEND,
174};
Ken Zhangfebeabd2012-12-17 10:35:15 -0500175struct res_mmu_clk {
176 char *mmu_clk_name;
177 struct clk *mmu_clk;
178};
179
180static struct res_mmu_clk rot_mmu_clks[] = {
181 {"mdp_iommu_clk"}, {"rot_iommu_clk"},
182 {"vcodec_iommu0_clk"}, {"vcodec_iommu1_clk"},
183 {"smmu_iface_clk"}
184};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700185
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700186int msm_rotator_iommu_map_buf(int mem_id, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700187 unsigned long *start, unsigned long *len,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700188 struct ion_handle **pihdl, unsigned int secure)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700189{
190 if (!msm_rotator_dev->client)
191 return -EINVAL;
192
Laura Abbottb14ed962012-01-30 14:18:08 -0800193 *pihdl = ion_import_dma_buf(msm_rotator_dev->client, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700194 if (IS_ERR_OR_NULL(*pihdl)) {
Laura Abbottb14ed962012-01-30 14:18:08 -0800195 pr_err("ion_import_dma_buf() failed\n");
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700196 return PTR_ERR(*pihdl);
197 }
taeyol.kim69400442012-08-03 19:15:10 -0700198 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700199
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700200 if (rot_iommu_split_domain) {
201 if (secure) {
202 if (ion_phys(msm_rotator_dev->client,
203 *pihdl, start, (unsigned *)len)) {
204 pr_err("%s:%d: ion_phys map failed\n",
205 __func__, __LINE__);
206 return -ENOMEM;
207 }
208 } else {
209 if (ion_map_iommu(msm_rotator_dev->client,
210 *pihdl, domain, GEN_POOL,
211 SZ_4K, 0, start, len, 0,
212 ION_IOMMU_UNMAP_DELAYED)) {
213 pr_err("ion_map_iommu() failed\n");
214 return -EINVAL;
215 }
216 }
217 } else {
218 if (ion_map_iommu(msm_rotator_dev->client,
219 *pihdl, ROTATOR_SRC_DOMAIN, GEN_POOL,
220 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
221 pr_err("ion_map_iommu() failed\n");
222 return -EINVAL;
223 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700224 }
225
226 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
227 __func__, mem_id, *start, *len);
228 return 0;
229}
230
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700231int msm_rotator_imem_allocate(int requestor)
232{
233 int rc = 0;
234
235#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
236 switch (requestor) {
237 case ROTATOR_REQUEST:
238 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
239 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
240 rc = 1;
241 } else
242 rc = 0;
243 break;
244 case JPEG_REQUEST:
245 mutex_lock(&msm_rotator_dev->imem_lock);
246 msm_rotator_dev->imem_owner = JPEG_REQUEST;
247 rc = 1;
248 break;
249 default:
250 rc = 0;
251 }
252#else
253 if (requestor == JPEG_REQUEST)
254 rc = 1;
255#endif
256 if (rc == 1) {
257 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
258 if (msm_rotator_dev->imem_clk_state != CLK_EN
259 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700260 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700261 msm_rotator_dev->imem_clk_state = CLK_EN;
262 }
263 }
264
265 return rc;
266}
267EXPORT_SYMBOL(msm_rotator_imem_allocate);
268
269void msm_rotator_imem_free(int requestor)
270{
271#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
272 if (msm_rotator_dev->imem_owner == requestor) {
273 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
274 mutex_unlock(&msm_rotator_dev->imem_lock);
275 }
276#else
277 if (requestor == JPEG_REQUEST)
278 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
279#endif
280}
281EXPORT_SYMBOL(msm_rotator_imem_free);
282
283static void msm_rotator_imem_clk_work_f(struct work_struct *work)
284{
285#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
286 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
287 if (msm_rotator_dev->imem_clk_state == CLK_EN
288 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700289 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700290 msm_rotator_dev->imem_clk_state = CLK_DIS;
291 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
292 msm_rotator_dev->imem_clk_state = CLK_DIS;
293 mutex_unlock(&msm_rotator_dev->imem_lock);
294 }
295#endif
296}
297
298/* enable clocks needed by rotator block */
299static void enable_rot_clks(void)
300{
301 if (msm_rotator_dev->regulator)
302 regulator_enable(msm_rotator_dev->regulator);
303 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700304 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700306 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700307}
308
309/* disable clocks needed by rotator block */
310static void disable_rot_clks(void)
311{
312 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700313 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700314 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700315 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700316 if (msm_rotator_dev->regulator)
317 regulator_disable(msm_rotator_dev->regulator);
318}
319
320static void msm_rotator_rot_clk_work_f(struct work_struct *work)
321{
322 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
323 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
324 disable_rot_clks();
325 msm_rotator_dev->rot_clk_state = CLK_DIS;
326 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
327 msm_rotator_dev->rot_clk_state = CLK_DIS;
328 mutex_unlock(&msm_rotator_dev->rotator_lock);
329 }
330}
331
332static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
333{
334 if (msm_rotator_dev->processing) {
335 msm_rotator_dev->processing = 0;
336 wake_up(&msm_rotator_dev->wq);
337 } else
338 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
339
340 return IRQ_HANDLED;
341}
342
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700343static unsigned int tile_size(unsigned int src_width,
344 unsigned int src_height,
345 const struct tile_parm *tp)
346{
347 unsigned int tile_w, tile_h;
348 unsigned int row_num_w, row_num_h;
349 tile_w = tp->width * tp->row_tile_w;
350 tile_h = tp->height * tp->row_tile_h;
351 row_num_w = (src_width + tile_w - 1) / tile_w;
352 row_num_h = (src_height + tile_h - 1) / tile_h;
353 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
354}
355
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700356static int get_bpp(int format)
357{
358 switch (format) {
359 case MDP_RGB_565:
360 case MDP_BGR_565:
361 return 2;
362
363 case MDP_XRGB_8888:
364 case MDP_ARGB_8888:
365 case MDP_RGBA_8888:
366 case MDP_BGRA_8888:
367 case MDP_RGBX_8888:
368 return 4;
369
370 case MDP_Y_CBCR_H2V2:
371 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700372 case MDP_Y_CB_CR_H2V2:
373 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530374 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700375 case MDP_Y_CRCB_H2V2_TILE:
376 case MDP_Y_CBCR_H2V2_TILE:
377 return 1;
378
379 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700380 case MDP_YCBCR_H1V1:
381 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700382 return 3;
383
384 case MDP_YCRYCB_H2V1:
385 return 2;/* YCrYCb interleave */
386
387 case MDP_Y_CRCB_H2V1:
388 case MDP_Y_CBCR_H2V1:
389 return 1;
390
391 default:
392 return -1;
393 }
394
395}
396
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700397static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
398 struct msm_rotator_mem_planes *p)
399{
400 /*
401 * each row of samsung tile consists of two tiles in height
402 * and two tiles in width which means width should align to
403 * 64 x 2 bytes and height should align to 32 x 2 bytes.
404 * video decoder generate two tiles in width and one tile
405 * in height which ends up height align to 32 X 1 bytes.
406 */
407 const struct tile_parm tile = {64, 32, 2, 1};
408 int i;
409
410 if (p == NULL)
411 return -EINVAL;
412
413 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
414 return -ERANGE;
415
416 memset(p, 0, sizeof(*p));
417
418 switch (format) {
419 case MDP_XRGB_8888:
420 case MDP_ARGB_8888:
421 case MDP_RGBA_8888:
422 case MDP_BGRA_8888:
423 case MDP_RGBX_8888:
424 case MDP_RGB_888:
425 case MDP_RGB_565:
426 case MDP_BGR_565:
427 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700428 case MDP_YCBCR_H1V1:
429 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700430 p->num_planes = 1;
431 p->plane_size[0] = w * h * get_bpp(format);
432 break;
433 case MDP_Y_CRCB_H2V1:
434 case MDP_Y_CBCR_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +0530435 case MDP_Y_CRCB_H1V2:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700436 p->num_planes = 2;
437 p->plane_size[0] = w * h;
438 p->plane_size[1] = w * h;
439 break;
440 case MDP_Y_CBCR_H2V2:
441 case MDP_Y_CRCB_H2V2:
442 p->num_planes = 2;
443 p->plane_size[0] = w * h;
444 p->plane_size[1] = w * h / 2;
445 break;
446 case MDP_Y_CRCB_H2V2_TILE:
447 case MDP_Y_CBCR_H2V2_TILE:
448 p->num_planes = 2;
449 p->plane_size[0] = tile_size(w, h, &tile);
450 p->plane_size[1] = tile_size(w, h/2, &tile);
451 break;
452 case MDP_Y_CB_CR_H2V2:
453 case MDP_Y_CR_CB_H2V2:
454 p->num_planes = 3;
455 p->plane_size[0] = w * h;
456 p->plane_size[1] = (w / 2) * (h / 2);
457 p->plane_size[2] = (w / 2) * (h / 2);
458 break;
459 case MDP_Y_CR_CB_GH2V2:
460 p->num_planes = 3;
461 p->plane_size[0] = ALIGN(w, 16) * h;
462 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
463 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
464 break;
465 default:
466 return -EINVAL;
467 }
468
469 for (i = 0; i < p->num_planes; i++)
470 p->total_size += p->plane_size[i];
471
472 return 0;
473}
474
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700475static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
476 unsigned int in_paddr,
477 unsigned int out_paddr,
478 unsigned int use_imem,
479 int new_session,
480 unsigned int in_chroma_paddr,
481 unsigned int out_chroma_paddr)
482{
483 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700484
485 if (info->src.format != info->dst.format)
486 return -EINVAL;
487
488 bpp = get_bpp(info->src.format);
489 if (bpp < 0)
490 return -ENOTTY;
491
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700493 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700494 iowrite32(out_paddr +
495 ((info->dst_y * info->dst.width) + info->dst_x),
496 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700497 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498 ((info->dst_y * info->dst.width) + info->dst_x),
499 MSM_ROTATOR_OUTP1_ADDR);
500
501 if (new_session) {
502 iowrite32(info->src.width |
503 info->src.width << 16,
504 MSM_ROTATOR_SRC_YSTRIDE1);
505 if (info->rotations & MDP_ROT_90)
506 iowrite32(info->dst.width |
507 info->dst.width*2 << 16,
508 MSM_ROTATOR_OUT_YSTRIDE1);
509 else
510 iowrite32(info->dst.width |
511 info->dst.width << 16,
512 MSM_ROTATOR_OUT_YSTRIDE1);
513 if (info->src.format == MDP_Y_CBCR_H2V1) {
514 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
515 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
516 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
517 MSM_ROTATOR_OUT_PACK_PATTERN1);
518 } else {
519 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
520 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
521 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
522 MSM_ROTATOR_OUT_PACK_PATTERN1);
523 }
524 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
525 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700526 1 << 8 | /* ROT_EN */
527 info->downscale_ratio << 2 | /* downscale v ratio */
528 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700529 MSM_ROTATOR_SUB_BLOCK_CFG);
530 iowrite32(0 << 29 | /* frame format 0 = linear */
531 (use_imem ? 0 : 1) << 22 | /* tile size */
532 2 << 19 | /* fetch planes 2 = pseudo */
533 0 << 18 | /* unpack align */
534 1 << 17 | /* unpack tight */
535 1 << 13 | /* unpack count 0=1 component */
536 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
537 0 << 8 | /* has alpha */
538 0 << 6 | /* alpha bits 3=8bits */
539 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
540 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
541 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
542 MSM_ROTATOR_SRC_FORMAT);
543 }
544
545 return 0;
546}
547
548static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
549 unsigned int in_paddr,
550 unsigned int out_paddr,
551 unsigned int use_imem,
552 int new_session,
553 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700554 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700555 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700556{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700557 uint32_t dst_format;
558 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700559
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700560 switch (info->src.format) {
561 case MDP_Y_CRCB_H2V2_TILE:
562 is_tile = 1;
563 case MDP_Y_CR_CB_H2V2:
564 case MDP_Y_CR_CB_GH2V2:
565 case MDP_Y_CRCB_H2V2:
566 dst_format = MDP_Y_CRCB_H2V2;
567 break;
568 case MDP_Y_CBCR_H2V2_TILE:
569 is_tile = 1;
570 case MDP_Y_CB_CR_H2V2:
571 case MDP_Y_CBCR_H2V2:
572 dst_format = MDP_Y_CBCR_H2V2;
573 break;
574 default:
575 return -EINVAL;
576 }
577 if (info->dst.format != dst_format)
578 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700579
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800580 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530581 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
582 info->src.format == MDP_Y_CR_CB_GH2V2) &&
583 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800584 swap(in_chroma_paddr, in_chroma2_paddr);
585
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700586 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700587 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
588 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590 iowrite32(out_paddr +
591 ((info->dst_y * info->dst.width) + info->dst_x),
592 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700593 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700594 ((info->dst_y * info->dst.width)/2 + info->dst_x),
595 MSM_ROTATOR_OUTP1_ADDR);
596
597 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700598 if (in_chroma2_paddr) {
599 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530600 iowrite32(ALIGN(info->src.width, 16) |
601 ALIGN((info->src.width / 2), 16) << 16,
602 MSM_ROTATOR_SRC_YSTRIDE1);
603 iowrite32(ALIGN((info->src.width / 2), 16),
604 MSM_ROTATOR_SRC_YSTRIDE2);
605 } else {
606 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700607 (info->src.width / 2) << 16,
608 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530609 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700610 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530611 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700612 } else {
613 iowrite32(info->src.width |
614 info->src.width << 16,
615 MSM_ROTATOR_SRC_YSTRIDE1);
616 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700617 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700618 info->dst.width << 16,
619 MSM_ROTATOR_OUT_YSTRIDE1);
620
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700621 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
623 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
624 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
625 MSM_ROTATOR_OUT_PACK_PATTERN1);
626 } else {
627 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
628 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
629 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
630 MSM_ROTATOR_OUT_PACK_PATTERN1);
631 }
632 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
633 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700634 1 << 8 | /* ROT_EN */
635 info->downscale_ratio << 2 | /* downscale v ratio */
636 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700637 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700638
639 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700640 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700641 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 0 << 18 | /* unpack align */
643 1 << 17 | /* unpack tight */
644 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700645 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 0 << 8 | /* has alpha */
647 0 << 6 | /* alpha bits 3=8bits */
648 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
649 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
650 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
651 MSM_ROTATOR_SRC_FORMAT);
652 }
653 return 0;
654}
655
656static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
657 unsigned int in_paddr,
658 unsigned int out_paddr,
659 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530660 int new_session,
661 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700662{
663 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530664 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700665
Mayank Chopra797bdb72012-03-03 06:29:40 +0530666 if (info->src.format == MDP_YCRYCB_H2V1) {
667 if (info->rotations & MDP_ROT_90)
668 dst_format = MDP_Y_CRCB_H1V2;
669 else
670 dst_format = MDP_Y_CRCB_H2V1;
671 } else
Mayank Chopra732dcd62012-01-09 20:53:39 +0530672 return -EINVAL;
673
674 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700675 return -EINVAL;
676
677 bpp = get_bpp(info->src.format);
678 if (bpp < 0)
679 return -ENOTTY;
680
681 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
682 iowrite32(out_paddr +
683 ((info->dst_y * info->dst.width) + info->dst_x),
684 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530685 iowrite32(out_chroma_paddr +
686 ((info->dst_y * info->dst.width)/2 + info->dst_x),
687 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700688
689 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530690 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700691 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530692 if (info->rotations & MDP_ROT_90)
693 iowrite32(info->dst.width |
694 (info->dst.width*2) << 16,
695 MSM_ROTATOR_OUT_YSTRIDE1);
696 else
697 iowrite32(info->dst.width |
698 (info->dst.width) << 16,
699 MSM_ROTATOR_OUT_YSTRIDE1);
700
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700701 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
702 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530703 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700704 MSM_ROTATOR_OUT_PACK_PATTERN1);
705 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
706 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700707 1 << 8 | /* ROT_EN */
708 info->downscale_ratio << 2 | /* downscale v ratio */
709 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 MSM_ROTATOR_SUB_BLOCK_CFG);
711 iowrite32(0 << 29 | /* frame format 0 = linear */
712 (use_imem ? 0 : 1) << 22 | /* tile size */
713 0 << 19 | /* fetch planes 0=interleaved */
714 0 << 18 | /* unpack align */
715 1 << 17 | /* unpack tight */
716 3 << 13 | /* unpack count 0=1 component */
717 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
718 0 << 8 | /* has alpha */
719 0 << 6 | /* alpha bits 3=8bits */
720 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
721 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
722 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
723 MSM_ROTATOR_SRC_FORMAT);
724 }
725
726 return 0;
727}
728
729static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
730 unsigned int in_paddr,
731 unsigned int out_paddr,
732 unsigned int use_imem,
733 int new_session)
734{
735 int bpp, abits, rbits, gbits, bbits;
736
737 if (info->src.format != info->dst.format)
738 return -EINVAL;
739
740 bpp = get_bpp(info->src.format);
741 if (bpp < 0)
742 return -ENOTTY;
743
744 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
745 iowrite32(out_paddr +
746 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
747 MSM_ROTATOR_OUTP0_ADDR);
748
749 if (new_session) {
750 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
751 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
752 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
753 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700754 1 << 8 | /* ROT_EN */
755 info->downscale_ratio << 2 | /* downscale v ratio */
756 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700757 MSM_ROTATOR_SUB_BLOCK_CFG);
758 switch (info->src.format) {
759 case MDP_RGB_565:
760 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
761 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
762 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
763 MSM_ROTATOR_OUT_PACK_PATTERN1);
764 abits = 0;
765 rbits = COMPONENT_5BITS;
766 gbits = COMPONENT_6BITS;
767 bbits = COMPONENT_5BITS;
768 break;
769
770 case MDP_BGR_565:
771 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
772 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
773 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
774 MSM_ROTATOR_OUT_PACK_PATTERN1);
775 abits = 0;
776 rbits = COMPONENT_5BITS;
777 gbits = COMPONENT_6BITS;
778 bbits = COMPONENT_5BITS;
779 break;
780
781 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700782 case MDP_YCBCR_H1V1:
783 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700784 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
785 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
786 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
787 MSM_ROTATOR_OUT_PACK_PATTERN1);
788 abits = 0;
789 rbits = COMPONENT_8BITS;
790 gbits = COMPONENT_8BITS;
791 bbits = COMPONENT_8BITS;
792 break;
793
794 case MDP_ARGB_8888:
795 case MDP_RGBA_8888:
796 case MDP_XRGB_8888:
797 case MDP_RGBX_8888:
798 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
799 CLR_B, 8),
800 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
801 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
802 CLR_B, 8),
803 MSM_ROTATOR_OUT_PACK_PATTERN1);
804 abits = COMPONENT_8BITS;
805 rbits = COMPONENT_8BITS;
806 gbits = COMPONENT_8BITS;
807 bbits = COMPONENT_8BITS;
808 break;
809
810 case MDP_BGRA_8888:
811 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
812 CLR_R, 8),
813 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
814 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
815 CLR_R, 8),
816 MSM_ROTATOR_OUT_PACK_PATTERN1);
817 abits = COMPONENT_8BITS;
818 rbits = COMPONENT_8BITS;
819 gbits = COMPONENT_8BITS;
820 bbits = COMPONENT_8BITS;
821 break;
822
823 default:
824 return -EINVAL;
825 }
826 iowrite32(0 << 29 | /* frame format 0 = linear */
827 (use_imem ? 0 : 1) << 22 | /* tile size */
828 0 << 19 | /* fetch planes 0=interleaved */
829 0 << 18 | /* unpack align */
830 1 << 17 | /* unpack tight */
831 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
832 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
833 (abits ? 1 : 0) << 8 | /* has alpha */
834 abits << 6 | /* alpha bits 3=8bits */
835 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
836 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
837 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
838 MSM_ROTATOR_SRC_FORMAT);
839 }
840
841 return 0;
842}
843
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700844static int get_img(struct msmfb_data *fbd, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700845 unsigned long *start, unsigned long *len, struct file **p_file,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700846 int *p_need, struct ion_handle **p_ihdl, unsigned int secure)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847{
848 int ret = 0;
849#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700850 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700851 int put_needed, fb_num;
852#endif
853#ifdef CONFIG_ANDROID_PMEM
854 unsigned long vstart;
855#endif
856
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800857 *p_need = 0;
858
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700859#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700860 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
861 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700862 if (file == NULL) {
863 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700864 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700865 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700866
Naseer Ahmed18018602011-10-25 13:32:58 -0700867 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
868 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700869 if (get_fb_phys_info(start, len, fb_num,
870 ROTATOR_SUBSYSTEM_ID)) {
871 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700872 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700873 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700874 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800875 *p_need = put_needed;
876 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700877 } else {
878 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700879 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700880 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700881 if (ret)
882 fput_light(file, put_needed);
883 return ret;
884 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700886
887#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700888 return msm_rotator_iommu_map_buf(fbd->memory_id, domain, start,
889 len, p_ihdl, secure);
Naseer Ahmed18018602011-10-25 13:32:58 -0700890#endif
891#ifdef CONFIG_ANDROID_PMEM
892 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
893 return 0;
894 else
895 return -ENOMEM;
896#endif
897
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700898}
899
Olav Hauganef95ae32012-05-15 09:50:30 -0700900static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700901 int domain, unsigned int secure)
Naseer Ahmed18018602011-10-25 13:32:58 -0700902{
903#ifdef CONFIG_ANDROID_PMEM
904 if (p_file != NULL)
905 put_pmem_file(p_file);
906#endif
Olav Hauganef95ae32012-05-15 09:50:30 -0700907
Naseer Ahmed18018602011-10-25 13:32:58 -0700908#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700909 if (!IS_ERR_OR_NULL(p_ihdl)) {
910 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700911 if (rot_iommu_split_domain) {
912 if (!secure)
913 ion_unmap_iommu(msm_rotator_dev->client,
914 p_ihdl, domain, GEN_POOL);
915 } else {
916 ion_unmap_iommu(msm_rotator_dev->client,
917 p_ihdl, ROTATOR_SRC_DOMAIN, GEN_POOL);
918 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700919
Naseer Ahmed18018602011-10-25 13:32:58 -0700920 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700921 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700922#endif
923}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924static int msm_rotator_do_rotate(unsigned long arg)
925{
Naseer Ahmed18018602011-10-25 13:32:58 -0700926 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700927 struct msm_rotator_data_info info;
928 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700929 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700930 int use_imem = 0, rc = 0, s;
931 struct file *srcp0_file = NULL, *dstp0_file = NULL;
932 struct file *srcp1_file = NULL, *dstp1_file = NULL;
933 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
934 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800935 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700936 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700937 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700938 struct msm_rotator_img_info *img_info;
939 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700940
941 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
942 return -EFAULT;
943
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700944 mutex_lock(&msm_rotator_dev->rotator_lock);
945 for (s = 0; s < MAX_SESSIONS; s++)
946 if ((msm_rotator_dev->img_info[s] != NULL) &&
947 (info.session_id ==
948 (unsigned int)msm_rotator_dev->img_info[s]
949 ))
950 break;
951
952 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700953 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700954 __func__, s);
955 rc = -EINVAL;
956 goto do_rotate_unlock_mutex;
957 }
958
959 if (msm_rotator_dev->img_info[s]->enable == 0) {
960 dev_dbg(msm_rotator_dev->device,
961 "%s() : Session_id %d not enabled \n",
962 __func__, s);
963 rc = -EINVAL;
964 goto do_rotate_unlock_mutex;
965 }
966
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700967 img_info = msm_rotator_dev->img_info[s];
968 if (msm_rotator_get_plane_sizes(img_info->src.format,
969 img_info->src.width,
970 img_info->src.height,
971 &src_planes)) {
972 pr_err("%s: invalid src format\n", __func__);
973 rc = -EINVAL;
974 goto do_rotate_unlock_mutex;
975 }
976 if (msm_rotator_get_plane_sizes(img_info->dst.format,
977 img_info->dst.width,
978 img_info->dst.height,
979 &dst_planes)) {
980 pr_err("%s: invalid dst format\n", __func__);
981 rc = -EINVAL;
982 goto do_rotate_unlock_mutex;
983 }
984
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700985 rc = get_img(&info.src, ROTATOR_SRC_DOMAIN, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700986 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700987 &srcp0_ihdl, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700988 if (rc) {
989 pr_err("%s: in get_img() failed id=0x%08x\n",
990 DRIVER_NAME, info.src.memory_id);
991 goto do_rotate_unlock_mutex;
992 }
993
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700994 rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700995 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700996 &dstp0_ihdl, img_info->secure);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700997 if (rc) {
998 pr_err("%s: out get_img() failed id=0x%08x\n",
999 DRIVER_NAME, info.dst.memory_id);
1000 goto do_rotate_unlock_mutex;
1001 }
1002
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001003 format = msm_rotator_dev->img_info[s]->src.format;
1004 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001005 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
1006 (src_planes.num_planes == 2)) {
1007 if (checkoffset(info.src.offset,
1008 src_planes.plane_size[0],
1009 src_len)) {
1010 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1011 __func__, src_len, info.src.offset);
1012 rc = -ERANGE;
1013 goto do_rotate_unlock_mutex;
1014 }
1015 if (checkoffset(info.dst.offset,
1016 dst_planes.plane_size[0],
1017 dst_len)) {
1018 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1019 __func__, dst_len, info.dst.offset);
1020 rc = -ERANGE;
1021 goto do_rotate_unlock_mutex;
1022 }
1023
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001024 rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001025 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001026 (unsigned long *)&src_len, &srcp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001027 &srcp1_ihdl, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001029 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030 DRIVER_NAME, info.src_chroma.memory_id);
1031 goto do_rotate_unlock_mutex;
1032 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001034 rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001035 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001036 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001037 &dstp1_ihdl, img_info->secure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001038 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001039 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001041 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001042 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001043
1044 if (checkoffset(info.src_chroma.offset,
1045 src_planes.plane_size[1],
1046 src_len)) {
1047 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1048 __func__, src_len, info.src_chroma.offset);
1049 rc = -ERANGE;
1050 goto do_rotate_unlock_mutex;
1051 }
1052
1053 if (checkoffset(info.dst_chroma.offset,
1054 src_planes.plane_size[1],
1055 dst_len)) {
1056 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1057 __func__, dst_len, info.dst_chroma.offset);
1058 rc = -ERANGE;
1059 goto do_rotate_unlock_mutex;
1060 }
1061
1062 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001064 } else {
1065 if (checkoffset(info.src.offset,
1066 src_planes.total_size,
1067 src_len)) {
1068 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1069 __func__, src_len, info.src.offset);
1070 rc = -ERANGE;
1071 goto do_rotate_unlock_mutex;
1072 }
1073 if (checkoffset(info.dst.offset,
1074 dst_planes.total_size,
1075 dst_len)) {
1076 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1077 __func__, dst_len, info.dst.offset);
1078 rc = -ERANGE;
1079 goto do_rotate_unlock_mutex;
1080 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 }
1082
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001083 in_paddr += info.src.offset;
1084 out_paddr += info.dst.offset;
1085
1086 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1087 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1088 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1089 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1090 if (src_planes.num_planes >= 3)
1091 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1092
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001093 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1094 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1095 enable_rot_clks();
1096 msm_rotator_dev->rot_clk_state = CLK_EN;
1097 }
1098 enable_irq(msm_rotator_dev->irq);
1099
1100#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1101 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1102#else
1103 use_imem = 0;
1104#endif
1105 /*
1106 * workaround for a hardware bug. rotator hardware hangs when we
1107 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1108 * temporary fix use 0x42 for BURST_SIZE when imem used.
1109 */
1110 if (use_imem)
1111 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1112
1113 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1114 << 16) |
1115 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1116 MSM_ROTATOR_SRC_SIZE);
1117 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1118 << 16) |
1119 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1120 MSM_ROTATOR_SRC_XY);
1121 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1122 << 16) |
1123 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1124 MSM_ROTATOR_SRC_IMAGE_SIZE);
1125
1126 switch (format) {
1127 case MDP_RGB_565:
1128 case MDP_BGR_565:
1129 case MDP_RGB_888:
1130 case MDP_ARGB_8888:
1131 case MDP_RGBA_8888:
1132 case MDP_XRGB_8888:
1133 case MDP_BGRA_8888:
1134 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001135 case MDP_YCBCR_H1V1:
1136 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001137 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1138 in_paddr, out_paddr,
1139 use_imem,
1140 msm_rotator_dev->last_session_idx
1141 != s);
1142 break;
1143 case MDP_Y_CBCR_H2V2:
1144 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001145 case MDP_Y_CB_CR_H2V2:
1146 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301147 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 case MDP_Y_CRCB_H2V2_TILE:
1149 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001150 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1151 in_paddr, out_paddr, use_imem,
1152 msm_rotator_dev->last_session_idx
1153 != s,
1154 in_chroma_paddr,
1155 out_chroma_paddr,
1156 in_chroma2_paddr);
1157 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001158 case MDP_Y_CBCR_H2V1:
1159 case MDP_Y_CRCB_H2V1:
1160 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1161 in_paddr, out_paddr, use_imem,
1162 msm_rotator_dev->last_session_idx
1163 != s,
1164 in_chroma_paddr,
1165 out_chroma_paddr);
1166 break;
1167 case MDP_YCRYCB_H2V1:
1168 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1169 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301170 msm_rotator_dev->last_session_idx != s,
1171 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 break;
1173 default:
1174 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001175 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176 goto do_rotate_exit;
1177 }
1178
1179 if (rc != 0) {
1180 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001181 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 goto do_rotate_exit;
1183 }
1184
1185 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1186
1187 msm_rotator_dev->processing = 1;
1188 iowrite32(0x1, MSM_ROTATOR_START);
1189
1190 wait_event(msm_rotator_dev->wq,
1191 (msm_rotator_dev->processing == 0));
1192 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001193 if ((status & 0x03) != 0x01) {
1194 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1195 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001196 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001197 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001198 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1199 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1200
1201do_rotate_exit:
1202 disable_irq(msm_rotator_dev->irq);
1203#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1204 msm_rotator_imem_free(ROTATOR_REQUEST);
1205#endif
1206 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001207do_rotate_unlock_mutex:
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001208 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
1209 msm_rotator_dev->img_info[s]->secure);
1210 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1211 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
1212 msm_rotator_dev->img_info[s]->secure);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001213
1214 /* only source may use frame buffer */
1215 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1216 fput_light(srcp0_file, ps0_need);
1217 else
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001218 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001219 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001220 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1221 __func__, rc);
1222 return rc;
1223}
1224
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001225static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1226{
1227 u32 perf_level;
1228
1229 if (is_rgb)
1230 perf_level = 1;
1231 else if (wh <= (640 * 480))
1232 perf_level = 2;
1233 else if (wh <= (736 * 1280))
1234 perf_level = 3;
1235 else
1236 perf_level = 4;
1237
1238#ifdef CONFIG_MSM_BUS_SCALING
1239 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1240 perf_level);
1241#endif
1242
1243}
1244
Ken Zhangfebeabd2012-12-17 10:35:15 -05001245static int rot_enable_iommu_clocks(struct msm_rotator_dev *rot_dev)
1246{
1247 int ret = 0, i;
1248 if (rot_dev->mmu_clk_on)
1249 return 0;
1250 for (i = 0; i < ARRAY_SIZE(rot_mmu_clks); i++) {
1251 rot_mmu_clks[i].mmu_clk = clk_get(&msm_rotator_dev->pdev->dev,
1252 rot_mmu_clks[i].mmu_clk_name);
1253 if (IS_ERR(rot_mmu_clks[i].mmu_clk)) {
1254 pr_err(" %s: Get failed for clk %s", __func__,
1255 rot_mmu_clks[i].mmu_clk_name);
1256 ret = PTR_ERR(rot_mmu_clks[i].mmu_clk);
1257 break;
1258 }
1259 ret = clk_prepare_enable(rot_mmu_clks[i].mmu_clk);
1260 if (ret) {
1261 clk_put(rot_mmu_clks[i].mmu_clk);
1262 rot_mmu_clks[i].mmu_clk = NULL;
1263 }
1264 }
1265 if (ret) {
1266 for (i--; i >= 0; i--) {
1267 clk_disable_unprepare(rot_mmu_clks[i].mmu_clk);
1268 clk_put(rot_mmu_clks[i].mmu_clk);
1269 rot_mmu_clks[i].mmu_clk = NULL;
1270 }
1271 } else {
1272 rot_dev->mmu_clk_on = 1;
1273 }
1274 return ret;
1275}
1276
1277static int rot_disable_iommu_clocks(struct msm_rotator_dev *rot_dev)
1278{
1279 int i;
1280 if (!rot_dev->mmu_clk_on)
1281 return 0;
1282 for (i = 0; i < ARRAY_SIZE(rot_mmu_clks); i++) {
1283 clk_disable_unprepare(rot_mmu_clks[i].mmu_clk);
1284 clk_put(rot_mmu_clks[i].mmu_clk);
1285 rot_mmu_clks[i].mmu_clk = NULL;
1286 }
1287 rot_dev->mmu_clk_on = 0;
1288 return 0;
1289}
1290
1291static int map_sec_resource(struct msm_rotator_dev *rot_dev)
1292{
1293 int ret = 0;
1294 if (rot_dev->sec_mapped)
1295 return 0;
1296
1297 ret = rot_enable_iommu_clocks(rot_dev);
1298 if (ret) {
1299 pr_err("IOMMU clock enabled failed while open");
1300 return ret;
1301 }
1302 ret = msm_ion_secure_heap(ION_HEAP(ION_CP_MM_HEAP_ID));
1303 if (ret)
1304 pr_err("ION heap secure failed heap id %d ret %d\n",
1305 ION_CP_MM_HEAP_ID, ret);
1306 else
1307 rot_dev->sec_mapped = 1;
1308 rot_disable_iommu_clocks(rot_dev);
1309 return ret;
1310}
1311
1312static int unmap_sec_resource(struct msm_rotator_dev *rot_dev)
1313{
1314 int ret = 0;
1315 ret = rot_enable_iommu_clocks(rot_dev);
1316 if (ret) {
1317 pr_err("IOMMU clock enabled failed while close\n");
1318 return ret;
1319 }
1320 msm_ion_unsecure_heap(ION_HEAP(ION_CP_MM_HEAP_ID));
1321 rot_dev->sec_mapped = 0;
1322 rot_disable_iommu_clocks(rot_dev);
1323 return ret;
1324}
1325
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001326static int msm_rotator_start(unsigned long arg,
1327 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001328{
1329 struct msm_rotator_img_info info;
1330 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001331 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001333 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001334
1335 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1336 return -EFAULT;
1337
1338 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1339 (info.src.height > MSM_ROTATOR_MAX_H) ||
1340 (info.src.width > MSM_ROTATOR_MAX_W) ||
1341 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1342 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001343 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1344 pr_err("%s: Invalid parameters\n", __func__);
1345 return -EINVAL;
1346 }
1347
1348 if (info.rotations & MDP_ROT_90) {
1349 dst_w = info.src_rect.h >> info.downscale_ratio;
1350 dst_h = info.src_rect.w >> info.downscale_ratio;
1351 } else {
1352 dst_w = info.src_rect.w >> info.downscale_ratio;
1353 dst_h = info.src_rect.h >> info.downscale_ratio;
1354 }
1355
1356 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001357 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1358 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001359 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1360 pr_err("%s: Invalid src or dst rect\n", __func__);
1361 return -ERANGE;
1362 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001363
1364 switch (info.src.format) {
1365 case MDP_RGB_565:
1366 case MDP_BGR_565:
1367 case MDP_RGB_888:
1368 case MDP_ARGB_8888:
1369 case MDP_RGBA_8888:
1370 case MDP_XRGB_8888:
1371 case MDP_RGBX_8888:
1372 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001373 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301374 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001375 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001376 case MDP_Y_CBCR_H2V2:
1377 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301378 case MDP_Y_CBCR_H2V1:
1379 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001380 case MDP_YCBCR_H1V1:
1381 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301382 info.dst.format = info.src.format;
1383 break;
1384 case MDP_YCRYCB_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +05301385 if (info.rotations & MDP_ROT_90)
1386 info.dst.format = MDP_Y_CRCB_H1V2;
1387 else
1388 info.dst.format = MDP_Y_CRCB_H2V1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301389 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001390 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301391 case MDP_Y_CBCR_H2V2_TILE:
1392 info.dst.format = MDP_Y_CBCR_H2V2;
1393 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001394 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301395 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001396 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301397 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001398 break;
1399 default:
1400 return -EINVAL;
1401 }
1402
1403 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001404
1405 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1406
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001407 for (s = 0; s < MAX_SESSIONS; s++) {
1408 if ((msm_rotator_dev->img_info[s] != NULL) &&
1409 (info.session_id ==
1410 (unsigned int)msm_rotator_dev->img_info[s]
1411 )) {
1412 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001413 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001414
1415 if (msm_rotator_dev->last_session_idx == s)
1416 msm_rotator_dev->last_session_idx =
1417 INVALID_SESSION;
1418 break;
1419 }
1420
1421 if ((msm_rotator_dev->img_info[s] == NULL) &&
1422 (first_free_index ==
1423 INVALID_SESSION))
1424 first_free_index = s;
1425 }
1426
1427 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1428 /* allocate a session id */
1429 msm_rotator_dev->img_info[first_free_index] =
1430 kzalloc(sizeof(struct msm_rotator_img_info),
1431 GFP_KERNEL);
1432 if (!msm_rotator_dev->img_info[first_free_index]) {
1433 printk(KERN_ERR "%s : unable to alloc mem\n",
1434 __func__);
1435 rc = -ENOMEM;
1436 goto rotator_start_exit;
1437 }
1438 info.session_id = (unsigned int)
1439 msm_rotator_dev->img_info[first_free_index];
1440 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001441 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001442 } else if (s == MAX_SESSIONS) {
1443 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1444 __func__);
1445 rc = -EBUSY;
1446 }
1447
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001448 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1449 rc = -EFAULT;
Ken Zhangfebeabd2012-12-17 10:35:15 -05001450 if ((rc == 0) && (info.secure))
1451 map_sec_resource(msm_rotator_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452rotator_start_exit:
1453 mutex_unlock(&msm_rotator_dev->rotator_lock);
1454
1455 return rc;
1456}
1457
1458static int msm_rotator_finish(unsigned long arg)
1459{
1460 int rc = 0;
1461 int s;
1462 unsigned int session_id;
1463
1464 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1465 return -EFAULT;
1466
1467 mutex_lock(&msm_rotator_dev->rotator_lock);
1468 for (s = 0; s < MAX_SESSIONS; s++) {
1469 if ((msm_rotator_dev->img_info[s] != NULL) &&
1470 (session_id ==
1471 (unsigned int)msm_rotator_dev->img_info[s])) {
1472 if (msm_rotator_dev->last_session_idx == s)
1473 msm_rotator_dev->last_session_idx =
1474 INVALID_SESSION;
1475 kfree(msm_rotator_dev->img_info[s]);
1476 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001477 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 break;
1479 }
1480 }
1481
1482 if (s == MAX_SESSIONS)
1483 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001484#ifdef CONFIG_MSM_BUS_SCALING
1485 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1486 0);
1487#endif
Ken Zhangfebeabd2012-12-17 10:35:15 -05001488 if (msm_rotator_dev->sec_mapped)
1489 unmap_sec_resource(msm_rotator_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490 mutex_unlock(&msm_rotator_dev->rotator_lock);
1491 return rc;
1492}
1493
1494static int
1495msm_rotator_open(struct inode *inode, struct file *filp)
1496{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001497 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498 int i;
1499
1500 if (filp->private_data)
1501 return -EBUSY;
1502
1503 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001504 for (i = 0; i < MAX_SESSIONS; i++) {
1505 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506 break;
1507 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001508
1509 if (i == MAX_SESSIONS) {
1510 mutex_unlock(&msm_rotator_dev->rotator_lock);
1511 return -EBUSY;
1512 }
1513
1514 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1515 if (tmp->pid == current->pid) {
1516 fd_info = tmp;
1517 break;
1518 }
1519 }
1520
1521 if (!fd_info) {
1522 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1523 if (!fd_info) {
1524 mutex_unlock(&msm_rotator_dev->rotator_lock);
1525 pr_err("%s: insufficient memory to alloc resources\n",
1526 __func__);
1527 return -ENOMEM;
1528 }
1529 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1530 fd_info->pid = current->pid;
1531 }
1532 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 mutex_unlock(&msm_rotator_dev->rotator_lock);
1534
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001535 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001536
1537 return 0;
1538}
1539
1540static int
1541msm_rotator_close(struct inode *inode, struct file *filp)
1542{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001543 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001545
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001546 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1547
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001548 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001549 if (--fd_info->ref_cnt > 0) {
1550 mutex_unlock(&msm_rotator_dev->rotator_lock);
1551 return 0;
1552 }
1553
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001554 for (s = 0; s < MAX_SESSIONS; s++) {
1555 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001556 msm_rotator_dev->fd_info[s] == fd_info) {
1557 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1558 __func__, msm_rotator_dev->img_info[s],
1559 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001560 kfree(msm_rotator_dev->img_info[s]);
1561 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001562 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001563 if (msm_rotator_dev->last_session_idx == s)
1564 msm_rotator_dev->last_session_idx =
1565 INVALID_SESSION;
1566 }
1567 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001568 list_del(&fd_info->list);
1569 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570 mutex_unlock(&msm_rotator_dev->rotator_lock);
1571
1572 return 0;
1573}
1574
1575static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1576 unsigned long arg)
1577{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001578 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579
1580 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1581 return -ENOTTY;
1582
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001583 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584
1585 switch (cmd) {
1586 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001587 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001588 case MSM_ROTATOR_IOCTL_ROTATE:
1589 return msm_rotator_do_rotate(arg);
1590 case MSM_ROTATOR_IOCTL_FINISH:
1591 return msm_rotator_finish(arg);
1592
1593 default:
1594 dev_dbg(msm_rotator_dev->device,
1595 "unexpected IOCTL %d\n", cmd);
1596 return -ENOTTY;
1597 }
1598}
1599
1600static const struct file_operations msm_rotator_fops = {
1601 .owner = THIS_MODULE,
1602 .open = msm_rotator_open,
1603 .release = msm_rotator_close,
1604 .unlocked_ioctl = msm_rotator_ioctl,
1605};
1606
1607static int __devinit msm_rotator_probe(struct platform_device *pdev)
1608{
1609 int rc = 0;
1610 struct resource *res;
1611 struct msm_rotator_platform_data *pdata = NULL;
1612 int i, number_of_clks;
1613 uint32_t ver;
1614
1615 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1616 if (!msm_rotator_dev) {
1617 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1618 __func__);
1619 return -ENOMEM;
1620 }
1621 for (i = 0; i < MAX_SESSIONS; i++)
1622 msm_rotator_dev->img_info[i] = NULL;
1623 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1624
1625 pdata = pdev->dev.platform_data;
1626 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07001627 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628
1629 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1630 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001631 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001632 msm_rotator_dev->imem_clk_state = CLK_DIS;
1633 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1634 msm_rotator_imem_clk_work_f);
1635 msm_rotator_dev->imem_clk = NULL;
1636 msm_rotator_dev->pdev = pdev;
1637
1638 msm_rotator_dev->core_clk = NULL;
1639 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001640
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001641#ifdef CONFIG_MSM_BUS_SCALING
1642 if (!msm_rotator_dev->bus_client_handle && pdata &&
1643 pdata->bus_scale_table) {
1644 msm_rotator_dev->bus_client_handle =
1645 msm_bus_scale_register_client(
1646 pdata->bus_scale_table);
1647 if (!msm_rotator_dev->bus_client_handle) {
1648 pr_err("%s not able to get bus scale handle\n",
1649 __func__);
1650 }
1651 }
1652#endif
1653
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654 for (i = 0; i < number_of_clks; i++) {
1655 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1656 msm_rotator_dev->imem_clk =
1657 clk_get(&msm_rotator_dev->pdev->dev,
1658 pdata->rotator_clks[i].clk_name);
1659 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1660 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1661 msm_rotator_dev->imem_clk = NULL;
1662 printk(KERN_ERR "%s: cannot get imem_clk "
1663 "rc=%d\n", DRIVER_NAME, rc);
1664 goto error_imem_clk;
1665 }
1666 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001667 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001668 pdata->rotator_clks[i].clk_rate);
1669 }
1670 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1671 msm_rotator_dev->pclk =
1672 clk_get(&msm_rotator_dev->pdev->dev,
1673 pdata->rotator_clks[i].clk_name);
1674 if (IS_ERR(msm_rotator_dev->pclk)) {
1675 rc = PTR_ERR(msm_rotator_dev->pclk);
1676 msm_rotator_dev->pclk = NULL;
1677 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1678 DRIVER_NAME, rc);
1679 goto error_pclk;
1680 }
1681
1682 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001683 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684 pdata->rotator_clks[i].clk_rate);
1685 }
1686
1687 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1688 msm_rotator_dev->core_clk =
1689 clk_get(&msm_rotator_dev->pdev->dev,
1690 pdata->rotator_clks[i].clk_name);
1691 if (IS_ERR(msm_rotator_dev->core_clk)) {
1692 rc = PTR_ERR(msm_rotator_dev->core_clk);
1693 msm_rotator_dev->core_clk = NULL;
1694 printk(KERN_ERR "%s: cannot get core clk "
1695 "rc=%d\n", DRIVER_NAME, rc);
1696 goto error_core_clk;
1697 }
1698
1699 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001700 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001701 pdata->rotator_clks[i].clk_rate);
1702 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001703 }
1704
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001705 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1706 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001707 if (IS_ERR(msm_rotator_dev->regulator))
1708 msm_rotator_dev->regulator = NULL;
1709
1710 msm_rotator_dev->rot_clk_state = CLK_DIS;
1711 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1712 msm_rotator_rot_clk_work_f);
1713
1714 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001715#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1716 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1717#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001718 platform_set_drvdata(pdev, msm_rotator_dev);
1719
1720
1721 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1722 if (!res) {
1723 printk(KERN_ALERT
1724 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1725 rc = -ENODEV;
1726 goto error_get_resource;
1727 }
1728 msm_rotator_dev->io_base = ioremap(res->start,
1729 resource_size(res));
1730
1731#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1732 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001733 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001734#endif
1735 enable_rot_clks();
1736 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1737 disable_rot_clks();
1738
1739#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1740 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001741 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001743 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301744 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001745 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001746
Mayank Chopra012a8e72012-04-11 10:41:13 +05301747 rotator_hw_revision = ver;
1748 rotator_hw_revision >>= 16; /* bit 31:16 */
1749 rotator_hw_revision &= 0xff;
1750
1751 pr_info("%s: rotator_hw_revision=%x\n",
1752 __func__, rotator_hw_revision);
1753
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001754 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1755 if (msm_rotator_dev->irq < 0) {
1756 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1757 DRIVER_NAME);
1758 rc = -ENODEV;
1759 goto error_get_irq;
1760 }
1761 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1762 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1763 if (rc) {
1764 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1765 goto error_get_irq;
1766 }
1767 /* we enable the IRQ when we need it in the ioctl */
1768 disable_irq(msm_rotator_dev->irq);
1769
1770 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1771 if (rc < 0) {
1772 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1773 __func__, rc);
1774 goto error_get_irq;
1775 }
1776
1777 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1778 if (IS_ERR(msm_rotator_dev->class)) {
1779 rc = PTR_ERR(msm_rotator_dev->class);
1780 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1781 DRIVER_NAME, rc);
1782 goto error_class_create;
1783 }
1784
1785 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1786 msm_rotator_dev->dev_num, NULL,
1787 DRIVER_NAME);
1788 if (IS_ERR(msm_rotator_dev->device)) {
1789 rc = PTR_ERR(msm_rotator_dev->device);
1790 printk(KERN_ERR "%s: device_create failed %d\n",
1791 DRIVER_NAME, rc);
1792 goto error_class_device_create;
1793 }
1794
1795 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1796 rc = cdev_add(&msm_rotator_dev->cdev,
1797 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1798 1);
1799 if (rc < 0) {
1800 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1801 goto error_cdev_add;
1802 }
1803
1804 init_waitqueue_head(&msm_rotator_dev->wq);
1805
1806 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1807 return rc;
1808
1809error_cdev_add:
1810 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1811error_class_device_create:
1812 class_destroy(msm_rotator_dev->class);
1813error_class_create:
1814 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1815error_get_irq:
1816 iounmap(msm_rotator_dev->io_base);
1817error_get_resource:
1818 mutex_destroy(&msm_rotator_dev->rotator_lock);
1819 if (msm_rotator_dev->regulator)
1820 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 clk_put(msm_rotator_dev->core_clk);
1822error_core_clk:
1823 clk_put(msm_rotator_dev->pclk);
1824error_pclk:
1825 if (msm_rotator_dev->imem_clk)
1826 clk_put(msm_rotator_dev->imem_clk);
1827error_imem_clk:
1828 mutex_destroy(&msm_rotator_dev->imem_lock);
1829 kfree(msm_rotator_dev);
1830 return rc;
1831}
1832
1833static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1834{
1835 int i;
1836
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001837#ifdef CONFIG_MSM_BUS_SCALING
1838 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1839#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001840 free_irq(msm_rotator_dev->irq, NULL);
1841 mutex_destroy(&msm_rotator_dev->rotator_lock);
1842 cdev_del(&msm_rotator_dev->cdev);
1843 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1844 class_destroy(msm_rotator_dev->class);
1845 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1846 iounmap(msm_rotator_dev->io_base);
1847 if (msm_rotator_dev->imem_clk) {
1848 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001849 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001850 clk_put(msm_rotator_dev->imem_clk);
1851 msm_rotator_dev->imem_clk = NULL;
1852 }
1853 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1854 disable_rot_clks();
1855 clk_put(msm_rotator_dev->core_clk);
1856 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001857 if (msm_rotator_dev->regulator)
1858 regulator_put(msm_rotator_dev->regulator);
1859 msm_rotator_dev->core_clk = NULL;
1860 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001861 mutex_destroy(&msm_rotator_dev->imem_lock);
1862 for (i = 0; i < MAX_SESSIONS; i++)
1863 if (msm_rotator_dev->img_info[i] != NULL)
1864 kfree(msm_rotator_dev->img_info[i]);
1865 kfree(msm_rotator_dev);
1866 return 0;
1867}
1868
1869#ifdef CONFIG_PM
1870static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1871{
1872 mutex_lock(&msm_rotator_dev->imem_lock);
1873 if (msm_rotator_dev->imem_clk_state == CLK_EN
1874 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001875 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1877 }
1878 mutex_unlock(&msm_rotator_dev->imem_lock);
1879 mutex_lock(&msm_rotator_dev->rotator_lock);
1880 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1881 disable_rot_clks();
1882 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1883 }
1884 mutex_unlock(&msm_rotator_dev->rotator_lock);
1885 return 0;
1886}
1887
1888static int msm_rotator_resume(struct platform_device *dev)
1889{
1890 mutex_lock(&msm_rotator_dev->imem_lock);
1891 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1892 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001893 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001894 msm_rotator_dev->imem_clk_state = CLK_EN;
1895 }
1896 mutex_unlock(&msm_rotator_dev->imem_lock);
1897 mutex_lock(&msm_rotator_dev->rotator_lock);
1898 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1899 enable_rot_clks();
1900 msm_rotator_dev->rot_clk_state = CLK_EN;
1901 }
1902 mutex_unlock(&msm_rotator_dev->rotator_lock);
1903 return 0;
1904}
1905#endif
1906
1907static struct platform_driver msm_rotator_platform_driver = {
1908 .probe = msm_rotator_probe,
1909 .remove = __devexit_p(msm_rotator_remove),
1910#ifdef CONFIG_PM
1911 .suspend = msm_rotator_suspend,
1912 .resume = msm_rotator_resume,
1913#endif
1914 .driver = {
1915 .owner = THIS_MODULE,
1916 .name = DRIVER_NAME
1917 }
1918};
1919
1920static int __init msm_rotator_init(void)
1921{
1922 return platform_driver_register(&msm_rotator_platform_driver);
1923}
1924
1925static void __exit msm_rotator_exit(void)
1926{
1927 return platform_driver_unregister(&msm_rotator_platform_driver);
1928}
1929
1930module_init(msm_rotator_init);
1931module_exit(msm_rotator_exit);
1932
1933MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1934MODULE_VERSION("1.0");
1935MODULE_LICENSE("GPL v2");