blob: 2f87803ecea93d8ec648eb75b30971c61d2b9d35 [file] [log] [blame]
Duy Truong790f06d2013-02-13 16:38:12 -08001/* Copyright (c) 2009-2012, 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 Humpherys6c7b2d32012-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
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 }
Laura Abbottb14ed962012-01-30 14:18:08 -0800186 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl,
187 ion_share_dma_buf(msm_rotator_dev->client, *pihdl));
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700188
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700189 if (rot_iommu_split_domain) {
190 if (secure) {
191 if (ion_phys(msm_rotator_dev->client,
192 *pihdl, start, (unsigned *)len)) {
193 pr_err("%s:%d: ion_phys map failed\n",
194 __func__, __LINE__);
195 return -ENOMEM;
196 }
197 } else {
198 if (ion_map_iommu(msm_rotator_dev->client,
199 *pihdl, domain, GEN_POOL,
200 SZ_4K, 0, start, len, 0,
201 ION_IOMMU_UNMAP_DELAYED)) {
202 pr_err("ion_map_iommu() failed\n");
203 return -EINVAL;
204 }
205 }
206 } else {
207 if (ion_map_iommu(msm_rotator_dev->client,
208 *pihdl, ROTATOR_SRC_DOMAIN, GEN_POOL,
209 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
210 pr_err("ion_map_iommu() failed\n");
211 return -EINVAL;
212 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700213 }
214
215 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
216 __func__, mem_id, *start, *len);
217 return 0;
218}
219
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700220int msm_rotator_imem_allocate(int requestor)
221{
222 int rc = 0;
223
224#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
225 switch (requestor) {
226 case ROTATOR_REQUEST:
227 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
228 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
229 rc = 1;
230 } else
231 rc = 0;
232 break;
233 case JPEG_REQUEST:
234 mutex_lock(&msm_rotator_dev->imem_lock);
235 msm_rotator_dev->imem_owner = JPEG_REQUEST;
236 rc = 1;
237 break;
238 default:
239 rc = 0;
240 }
241#else
242 if (requestor == JPEG_REQUEST)
243 rc = 1;
244#endif
245 if (rc == 1) {
246 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
247 if (msm_rotator_dev->imem_clk_state != CLK_EN
248 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700249 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250 msm_rotator_dev->imem_clk_state = CLK_EN;
251 }
252 }
253
254 return rc;
255}
256EXPORT_SYMBOL(msm_rotator_imem_allocate);
257
258void msm_rotator_imem_free(int requestor)
259{
260#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
261 if (msm_rotator_dev->imem_owner == requestor) {
262 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
263 mutex_unlock(&msm_rotator_dev->imem_lock);
264 }
265#else
266 if (requestor == JPEG_REQUEST)
267 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
268#endif
269}
270EXPORT_SYMBOL(msm_rotator_imem_free);
271
272static void msm_rotator_imem_clk_work_f(struct work_struct *work)
273{
274#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
275 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
276 if (msm_rotator_dev->imem_clk_state == CLK_EN
277 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700278 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700279 msm_rotator_dev->imem_clk_state = CLK_DIS;
280 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
281 msm_rotator_dev->imem_clk_state = CLK_DIS;
282 mutex_unlock(&msm_rotator_dev->imem_lock);
283 }
284#endif
285}
286
287/* enable clocks needed by rotator block */
288static void enable_rot_clks(void)
289{
290 if (msm_rotator_dev->regulator)
291 regulator_enable(msm_rotator_dev->regulator);
292 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700293 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700294 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700295 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296}
297
298/* disable clocks needed by rotator block */
299static void disable_rot_clks(void)
300{
301 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700302 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700303 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700304 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700305 if (msm_rotator_dev->regulator)
306 regulator_disable(msm_rotator_dev->regulator);
307}
308
309static void msm_rotator_rot_clk_work_f(struct work_struct *work)
310{
311 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
312 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
313 disable_rot_clks();
314 msm_rotator_dev->rot_clk_state = CLK_DIS;
315 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
316 msm_rotator_dev->rot_clk_state = CLK_DIS;
317 mutex_unlock(&msm_rotator_dev->rotator_lock);
318 }
319}
320
321static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
322{
323 if (msm_rotator_dev->processing) {
324 msm_rotator_dev->processing = 0;
325 wake_up(&msm_rotator_dev->wq);
326 } else
327 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
328
329 return IRQ_HANDLED;
330}
331
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700332static unsigned int tile_size(unsigned int src_width,
333 unsigned int src_height,
334 const struct tile_parm *tp)
335{
336 unsigned int tile_w, tile_h;
337 unsigned int row_num_w, row_num_h;
338 tile_w = tp->width * tp->row_tile_w;
339 tile_h = tp->height * tp->row_tile_h;
340 row_num_w = (src_width + tile_w - 1) / tile_w;
341 row_num_h = (src_height + tile_h - 1) / tile_h;
342 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
343}
344
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700345static int get_bpp(int format)
346{
347 switch (format) {
348 case MDP_RGB_565:
349 case MDP_BGR_565:
350 return 2;
351
352 case MDP_XRGB_8888:
353 case MDP_ARGB_8888:
354 case MDP_RGBA_8888:
355 case MDP_BGRA_8888:
356 case MDP_RGBX_8888:
357 return 4;
358
359 case MDP_Y_CBCR_H2V2:
360 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700361 case MDP_Y_CB_CR_H2V2:
362 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530363 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700364 case MDP_Y_CRCB_H2V2_TILE:
365 case MDP_Y_CBCR_H2V2_TILE:
366 return 1;
367
368 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700369 case MDP_YCBCR_H1V1:
370 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700371 return 3;
372
373 case MDP_YCRYCB_H2V1:
374 return 2;/* YCrYCb interleave */
375
376 case MDP_Y_CRCB_H2V1:
377 case MDP_Y_CBCR_H2V1:
378 return 1;
379
380 default:
381 return -1;
382 }
383
384}
385
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700386static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
387 struct msm_rotator_mem_planes *p)
388{
389 /*
390 * each row of samsung tile consists of two tiles in height
391 * and two tiles in width which means width should align to
392 * 64 x 2 bytes and height should align to 32 x 2 bytes.
393 * video decoder generate two tiles in width and one tile
394 * in height which ends up height align to 32 X 1 bytes.
395 */
396 const struct tile_parm tile = {64, 32, 2, 1};
397 int i;
398
399 if (p == NULL)
400 return -EINVAL;
401
402 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
403 return -ERANGE;
404
405 memset(p, 0, sizeof(*p));
406
407 switch (format) {
408 case MDP_XRGB_8888:
409 case MDP_ARGB_8888:
410 case MDP_RGBA_8888:
411 case MDP_BGRA_8888:
412 case MDP_RGBX_8888:
413 case MDP_RGB_888:
414 case MDP_RGB_565:
415 case MDP_BGR_565:
416 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700417 case MDP_YCBCR_H1V1:
418 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700419 p->num_planes = 1;
420 p->plane_size[0] = w * h * get_bpp(format);
421 break;
422 case MDP_Y_CRCB_H2V1:
423 case MDP_Y_CBCR_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +0530424 case MDP_Y_CRCB_H1V2:
Mayank Goyal5f91c922012-11-07 16:58:09 +0530425 case MDP_Y_CBCR_H1V2:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700426 p->num_planes = 2;
427 p->plane_size[0] = w * h;
428 p->plane_size[1] = w * h;
429 break;
430 case MDP_Y_CBCR_H2V2:
431 case MDP_Y_CRCB_H2V2:
432 p->num_planes = 2;
433 p->plane_size[0] = w * h;
434 p->plane_size[1] = w * h / 2;
435 break;
436 case MDP_Y_CRCB_H2V2_TILE:
437 case MDP_Y_CBCR_H2V2_TILE:
438 p->num_planes = 2;
439 p->plane_size[0] = tile_size(w, h, &tile);
440 p->plane_size[1] = tile_size(w, h/2, &tile);
441 break;
442 case MDP_Y_CB_CR_H2V2:
443 case MDP_Y_CR_CB_H2V2:
444 p->num_planes = 3;
445 p->plane_size[0] = w * h;
446 p->plane_size[1] = (w / 2) * (h / 2);
447 p->plane_size[2] = (w / 2) * (h / 2);
448 break;
449 case MDP_Y_CR_CB_GH2V2:
450 p->num_planes = 3;
451 p->plane_size[0] = ALIGN(w, 16) * h;
452 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
453 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
454 break;
455 default:
456 return -EINVAL;
457 }
458
459 for (i = 0; i < p->num_planes; i++)
460 p->total_size += p->plane_size[i];
461
462 return 0;
463}
464
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700465static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
466 unsigned int in_paddr,
467 unsigned int out_paddr,
468 unsigned int use_imem,
469 int new_session,
470 unsigned int in_chroma_paddr,
471 unsigned int out_chroma_paddr)
472{
473 int bpp;
Mayank Goyal5f91c922012-11-07 16:58:09 +0530474 uint32_t dst_format;
475 switch (info->src.format) {
476 case MDP_Y_CRCB_H2V1:
477 if (info->rotations & MDP_ROT_90)
478 dst_format = MDP_Y_CRCB_H1V2;
479 else
480 dst_format = info->src.format;
481 break;
482 case MDP_Y_CBCR_H2V1:
483 if (info->rotations & MDP_ROT_90)
484 dst_format = MDP_Y_CBCR_H1V2;
485 else
486 dst_format = info->src.format;
487 break;
488 default:
489 return -EINVAL;
490 }
491 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700492 return -EINVAL;
493
494 bpp = get_bpp(info->src.format);
495 if (bpp < 0)
496 return -ENOTTY;
497
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700498 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700499 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700500 iowrite32(out_paddr +
501 ((info->dst_y * info->dst.width) + info->dst_x),
502 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700503 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700504 ((info->dst_y * info->dst.width) + info->dst_x),
505 MSM_ROTATOR_OUTP1_ADDR);
506
507 if (new_session) {
508 iowrite32(info->src.width |
509 info->src.width << 16,
510 MSM_ROTATOR_SRC_YSTRIDE1);
511 if (info->rotations & MDP_ROT_90)
512 iowrite32(info->dst.width |
513 info->dst.width*2 << 16,
514 MSM_ROTATOR_OUT_YSTRIDE1);
515 else
516 iowrite32(info->dst.width |
517 info->dst.width << 16,
518 MSM_ROTATOR_OUT_YSTRIDE1);
519 if (info->src.format == MDP_Y_CBCR_H2V1) {
520 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
521 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
522 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
523 MSM_ROTATOR_OUT_PACK_PATTERN1);
524 } else {
525 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
526 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
527 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
528 MSM_ROTATOR_OUT_PACK_PATTERN1);
529 }
530 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
531 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700532 1 << 8 | /* ROT_EN */
533 info->downscale_ratio << 2 | /* downscale v ratio */
534 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700535 MSM_ROTATOR_SUB_BLOCK_CFG);
536 iowrite32(0 << 29 | /* frame format 0 = linear */
537 (use_imem ? 0 : 1) << 22 | /* tile size */
538 2 << 19 | /* fetch planes 2 = pseudo */
539 0 << 18 | /* unpack align */
540 1 << 17 | /* unpack tight */
541 1 << 13 | /* unpack count 0=1 component */
542 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
543 0 << 8 | /* has alpha */
544 0 << 6 | /* alpha bits 3=8bits */
545 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
546 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
547 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
548 MSM_ROTATOR_SRC_FORMAT);
549 }
550
551 return 0;
552}
553
554static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
555 unsigned int in_paddr,
556 unsigned int out_paddr,
557 unsigned int use_imem,
558 int new_session,
559 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700560 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700561 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700562{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700563 uint32_t dst_format;
564 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700565
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700566 switch (info->src.format) {
567 case MDP_Y_CRCB_H2V2_TILE:
568 is_tile = 1;
569 case MDP_Y_CR_CB_H2V2:
570 case MDP_Y_CR_CB_GH2V2:
571 case MDP_Y_CRCB_H2V2:
572 dst_format = MDP_Y_CRCB_H2V2;
573 break;
574 case MDP_Y_CBCR_H2V2_TILE:
575 is_tile = 1;
576 case MDP_Y_CB_CR_H2V2:
577 case MDP_Y_CBCR_H2V2:
578 dst_format = MDP_Y_CBCR_H2V2;
579 break;
580 default:
581 return -EINVAL;
582 }
583 if (info->dst.format != dst_format)
584 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700585
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800586 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530587 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
588 info->src.format == MDP_Y_CR_CB_GH2V2) &&
589 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800590 swap(in_chroma_paddr, in_chroma2_paddr);
591
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700592 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700593 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
594 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
595
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700596 iowrite32(out_paddr +
597 ((info->dst_y * info->dst.width) + info->dst_x),
598 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700599 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700600 ((info->dst_y * info->dst.width)/2 + info->dst_x),
601 MSM_ROTATOR_OUTP1_ADDR);
602
603 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700604 if (in_chroma2_paddr) {
605 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530606 iowrite32(ALIGN(info->src.width, 16) |
607 ALIGN((info->src.width / 2), 16) << 16,
608 MSM_ROTATOR_SRC_YSTRIDE1);
609 iowrite32(ALIGN((info->src.width / 2), 16),
610 MSM_ROTATOR_SRC_YSTRIDE2);
611 } else {
612 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700613 (info->src.width / 2) << 16,
614 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530615 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700616 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530617 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700618 } else {
619 iowrite32(info->src.width |
620 info->src.width << 16,
621 MSM_ROTATOR_SRC_YSTRIDE1);
622 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700623 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700624 info->dst.width << 16,
625 MSM_ROTATOR_OUT_YSTRIDE1);
626
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700627 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700628 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
629 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
630 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
631 MSM_ROTATOR_OUT_PACK_PATTERN1);
632 } else {
633 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
634 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
635 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
636 MSM_ROTATOR_OUT_PACK_PATTERN1);
637 }
638 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
639 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700640 1 << 8 | /* ROT_EN */
641 info->downscale_ratio << 2 | /* downscale v ratio */
642 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700643 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700644
645 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700646 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700647 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700648 0 << 18 | /* unpack align */
649 1 << 17 | /* unpack tight */
650 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700651 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700652 0 << 8 | /* has alpha */
653 0 << 6 | /* alpha bits 3=8bits */
654 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
655 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
656 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
657 MSM_ROTATOR_SRC_FORMAT);
658 }
659 return 0;
660}
661
662static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
663 unsigned int in_paddr,
664 unsigned int out_paddr,
665 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530666 int new_session,
667 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700668{
669 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530670 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700671
Mayank Chopra797bdb72012-03-03 06:29:40 +0530672 if (info->src.format == MDP_YCRYCB_H2V1) {
673 if (info->rotations & MDP_ROT_90)
674 dst_format = MDP_Y_CRCB_H1V2;
675 else
676 dst_format = MDP_Y_CRCB_H2V1;
677 } else
Mayank Chopra732dcd62012-01-09 20:53:39 +0530678 return -EINVAL;
679
680 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700681 return -EINVAL;
682
683 bpp = get_bpp(info->src.format);
684 if (bpp < 0)
685 return -ENOTTY;
686
687 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
688 iowrite32(out_paddr +
689 ((info->dst_y * info->dst.width) + info->dst_x),
690 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530691 iowrite32(out_chroma_paddr +
692 ((info->dst_y * info->dst.width)/2 + info->dst_x),
693 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700694
695 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530696 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700697 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530698 if (info->rotations & MDP_ROT_90)
699 iowrite32(info->dst.width |
700 (info->dst.width*2) << 16,
701 MSM_ROTATOR_OUT_YSTRIDE1);
702 else
703 iowrite32(info->dst.width |
704 (info->dst.width) << 16,
705 MSM_ROTATOR_OUT_YSTRIDE1);
706
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700707 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
708 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530709 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700710 MSM_ROTATOR_OUT_PACK_PATTERN1);
711 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
712 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700713 1 << 8 | /* ROT_EN */
714 info->downscale_ratio << 2 | /* downscale v ratio */
715 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700716 MSM_ROTATOR_SUB_BLOCK_CFG);
717 iowrite32(0 << 29 | /* frame format 0 = linear */
718 (use_imem ? 0 : 1) << 22 | /* tile size */
719 0 << 19 | /* fetch planes 0=interleaved */
720 0 << 18 | /* unpack align */
721 1 << 17 | /* unpack tight */
722 3 << 13 | /* unpack count 0=1 component */
723 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
724 0 << 8 | /* has alpha */
725 0 << 6 | /* alpha bits 3=8bits */
726 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
727 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
728 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
729 MSM_ROTATOR_SRC_FORMAT);
730 }
731
732 return 0;
733}
734
735static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
736 unsigned int in_paddr,
737 unsigned int out_paddr,
738 unsigned int use_imem,
739 int new_session)
740{
741 int bpp, abits, rbits, gbits, bbits;
742
743 if (info->src.format != info->dst.format)
744 return -EINVAL;
745
746 bpp = get_bpp(info->src.format);
747 if (bpp < 0)
748 return -ENOTTY;
749
750 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
751 iowrite32(out_paddr +
752 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
753 MSM_ROTATOR_OUTP0_ADDR);
754
755 if (new_session) {
756 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
757 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
758 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
759 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700760 1 << 8 | /* ROT_EN */
761 info->downscale_ratio << 2 | /* downscale v ratio */
762 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700763 MSM_ROTATOR_SUB_BLOCK_CFG);
764 switch (info->src.format) {
765 case MDP_RGB_565:
766 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
767 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
768 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
769 MSM_ROTATOR_OUT_PACK_PATTERN1);
770 abits = 0;
771 rbits = COMPONENT_5BITS;
772 gbits = COMPONENT_6BITS;
773 bbits = COMPONENT_5BITS;
774 break;
775
776 case MDP_BGR_565:
777 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
778 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
779 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
780 MSM_ROTATOR_OUT_PACK_PATTERN1);
781 abits = 0;
782 rbits = COMPONENT_5BITS;
783 gbits = COMPONENT_6BITS;
784 bbits = COMPONENT_5BITS;
785 break;
786
787 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700788 case MDP_YCBCR_H1V1:
789 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700790 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
791 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
792 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
793 MSM_ROTATOR_OUT_PACK_PATTERN1);
794 abits = 0;
795 rbits = COMPONENT_8BITS;
796 gbits = COMPONENT_8BITS;
797 bbits = COMPONENT_8BITS;
798 break;
799
800 case MDP_ARGB_8888:
801 case MDP_RGBA_8888:
802 case MDP_XRGB_8888:
803 case MDP_RGBX_8888:
804 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
805 CLR_B, 8),
806 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
807 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
808 CLR_B, 8),
809 MSM_ROTATOR_OUT_PACK_PATTERN1);
810 abits = COMPONENT_8BITS;
811 rbits = COMPONENT_8BITS;
812 gbits = COMPONENT_8BITS;
813 bbits = COMPONENT_8BITS;
814 break;
815
816 case MDP_BGRA_8888:
817 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
818 CLR_R, 8),
819 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
820 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
821 CLR_R, 8),
822 MSM_ROTATOR_OUT_PACK_PATTERN1);
823 abits = COMPONENT_8BITS;
824 rbits = COMPONENT_8BITS;
825 gbits = COMPONENT_8BITS;
826 bbits = COMPONENT_8BITS;
827 break;
828
829 default:
830 return -EINVAL;
831 }
832 iowrite32(0 << 29 | /* frame format 0 = linear */
833 (use_imem ? 0 : 1) << 22 | /* tile size */
834 0 << 19 | /* fetch planes 0=interleaved */
835 0 << 18 | /* unpack align */
836 1 << 17 | /* unpack tight */
837 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
838 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
839 (abits ? 1 : 0) << 8 | /* has alpha */
840 abits << 6 | /* alpha bits 3=8bits */
841 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
842 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
843 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
844 MSM_ROTATOR_SRC_FORMAT);
845 }
846
847 return 0;
848}
849
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700850static int get_img(struct msmfb_data *fbd, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700851 unsigned long *start, unsigned long *len, struct file **p_file,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700852 int *p_need, struct ion_handle **p_ihdl, unsigned int secure)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853{
854 int ret = 0;
855#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700856 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700857 int put_needed, fb_num;
858#endif
859#ifdef CONFIG_ANDROID_PMEM
860 unsigned long vstart;
861#endif
862
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800863 *p_need = 0;
864
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700865#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700866 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
867 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700868 if (file == NULL) {
869 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700870 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700871 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700872
Naseer Ahmed18018602011-10-25 13:32:58 -0700873 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
874 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700875 if (get_fb_phys_info(start, len, fb_num,
876 ROTATOR_SUBSYSTEM_ID)) {
877 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700878 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700879 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700880 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800881 *p_need = put_needed;
882 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700883 } else {
884 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700886 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700887 if (ret)
888 fput_light(file, put_needed);
889 return ret;
890 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700892
893#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700894 return msm_rotator_iommu_map_buf(fbd->memory_id, domain, start,
895 len, p_ihdl, secure);
Naseer Ahmed18018602011-10-25 13:32:58 -0700896#endif
897#ifdef CONFIG_ANDROID_PMEM
898 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
899 return 0;
900 else
901 return -ENOMEM;
902#endif
903
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700904}
905
Olav Hauganef95ae32012-05-15 09:50:30 -0700906static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700907 int domain, unsigned int secure)
Naseer Ahmed18018602011-10-25 13:32:58 -0700908{
909#ifdef CONFIG_ANDROID_PMEM
910 if (p_file != NULL)
911 put_pmem_file(p_file);
912#endif
Olav Hauganef95ae32012-05-15 09:50:30 -0700913
Naseer Ahmed18018602011-10-25 13:32:58 -0700914#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700915 if (!IS_ERR_OR_NULL(p_ihdl)) {
916 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700917 if (rot_iommu_split_domain) {
918 if (!secure)
919 ion_unmap_iommu(msm_rotator_dev->client,
920 p_ihdl, domain, GEN_POOL);
921 } else {
922 ion_unmap_iommu(msm_rotator_dev->client,
923 p_ihdl, ROTATOR_SRC_DOMAIN, GEN_POOL);
924 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700925
Naseer Ahmed18018602011-10-25 13:32:58 -0700926 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700927 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700928#endif
929}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700930static int msm_rotator_do_rotate(unsigned long arg)
931{
Naseer Ahmed18018602011-10-25 13:32:58 -0700932 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 struct msm_rotator_data_info info;
934 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700935 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700936 int use_imem = 0, rc = 0, s;
937 struct file *srcp0_file = NULL, *dstp0_file = NULL;
938 struct file *srcp1_file = NULL, *dstp1_file = NULL;
939 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
940 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800941 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700943 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700944 struct msm_rotator_img_info *img_info;
945 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700946
947 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
948 return -EFAULT;
949
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700950 mutex_lock(&msm_rotator_dev->rotator_lock);
951 for (s = 0; s < MAX_SESSIONS; s++)
952 if ((msm_rotator_dev->img_info[s] != NULL) &&
953 (info.session_id ==
954 (unsigned int)msm_rotator_dev->img_info[s]
955 ))
956 break;
957
958 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700959 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960 __func__, s);
961 rc = -EINVAL;
962 goto do_rotate_unlock_mutex;
963 }
964
965 if (msm_rotator_dev->img_info[s]->enable == 0) {
966 dev_dbg(msm_rotator_dev->device,
967 "%s() : Session_id %d not enabled \n",
968 __func__, s);
969 rc = -EINVAL;
970 goto do_rotate_unlock_mutex;
971 }
972
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700973 img_info = msm_rotator_dev->img_info[s];
974 if (msm_rotator_get_plane_sizes(img_info->src.format,
975 img_info->src.width,
976 img_info->src.height,
977 &src_planes)) {
978 pr_err("%s: invalid src format\n", __func__);
979 rc = -EINVAL;
980 goto do_rotate_unlock_mutex;
981 }
982 if (msm_rotator_get_plane_sizes(img_info->dst.format,
983 img_info->dst.width,
984 img_info->dst.height,
985 &dst_planes)) {
986 pr_err("%s: invalid dst format\n", __func__);
987 rc = -EINVAL;
988 goto do_rotate_unlock_mutex;
989 }
990
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700991 rc = get_img(&info.src, ROTATOR_SRC_DOMAIN, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700992 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700993 &srcp0_ihdl, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700994 if (rc) {
995 pr_err("%s: in get_img() failed id=0x%08x\n",
996 DRIVER_NAME, info.src.memory_id);
997 goto do_rotate_unlock_mutex;
998 }
999
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001000 rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001001 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001002 &dstp0_ihdl, img_info->secure);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001003 if (rc) {
1004 pr_err("%s: out get_img() failed id=0x%08x\n",
1005 DRIVER_NAME, info.dst.memory_id);
1006 goto do_rotate_unlock_mutex;
1007 }
1008
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001009 format = msm_rotator_dev->img_info[s]->src.format;
1010 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001011 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
1012 (src_planes.num_planes == 2)) {
1013 if (checkoffset(info.src.offset,
1014 src_planes.plane_size[0],
1015 src_len)) {
1016 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1017 __func__, src_len, info.src.offset);
1018 rc = -ERANGE;
1019 goto do_rotate_unlock_mutex;
1020 }
1021 if (checkoffset(info.dst.offset,
1022 dst_planes.plane_size[0],
1023 dst_len)) {
1024 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1025 __func__, dst_len, info.dst.offset);
1026 rc = -ERANGE;
1027 goto do_rotate_unlock_mutex;
1028 }
1029
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001030 rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001032 (unsigned long *)&src_len, &srcp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001033 &srcp1_ihdl, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001034 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001035 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001036 DRIVER_NAME, info.src_chroma.memory_id);
1037 goto do_rotate_unlock_mutex;
1038 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001040 rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001041 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001042 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001043 &dstp1_ihdl, img_info->secure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001044 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001045 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001046 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001047 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001048 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001049
1050 if (checkoffset(info.src_chroma.offset,
1051 src_planes.plane_size[1],
1052 src_len)) {
1053 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1054 __func__, src_len, info.src_chroma.offset);
1055 rc = -ERANGE;
1056 goto do_rotate_unlock_mutex;
1057 }
1058
1059 if (checkoffset(info.dst_chroma.offset,
1060 src_planes.plane_size[1],
1061 dst_len)) {
1062 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1063 __func__, dst_len, info.dst_chroma.offset);
1064 rc = -ERANGE;
1065 goto do_rotate_unlock_mutex;
1066 }
1067
1068 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001070 } else {
1071 if (checkoffset(info.src.offset,
1072 src_planes.total_size,
1073 src_len)) {
1074 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1075 __func__, src_len, info.src.offset);
1076 rc = -ERANGE;
1077 goto do_rotate_unlock_mutex;
1078 }
1079 if (checkoffset(info.dst.offset,
1080 dst_planes.total_size,
1081 dst_len)) {
1082 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1083 __func__, dst_len, info.dst.offset);
1084 rc = -ERANGE;
1085 goto do_rotate_unlock_mutex;
1086 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001087 }
1088
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001089 in_paddr += info.src.offset;
1090 out_paddr += info.dst.offset;
1091
1092 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1093 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1094 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1095 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1096 if (src_planes.num_planes >= 3)
1097 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1098
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001099 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1100 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1101 enable_rot_clks();
1102 msm_rotator_dev->rot_clk_state = CLK_EN;
1103 }
1104 enable_irq(msm_rotator_dev->irq);
1105
1106#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1107 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1108#else
1109 use_imem = 0;
1110#endif
1111 /*
1112 * workaround for a hardware bug. rotator hardware hangs when we
1113 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1114 * temporary fix use 0x42 for BURST_SIZE when imem used.
1115 */
1116 if (use_imem)
1117 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1118
1119 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1120 << 16) |
1121 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1122 MSM_ROTATOR_SRC_SIZE);
1123 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1124 << 16) |
1125 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1126 MSM_ROTATOR_SRC_XY);
1127 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1128 << 16) |
1129 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1130 MSM_ROTATOR_SRC_IMAGE_SIZE);
1131
1132 switch (format) {
1133 case MDP_RGB_565:
1134 case MDP_BGR_565:
1135 case MDP_RGB_888:
1136 case MDP_ARGB_8888:
1137 case MDP_RGBA_8888:
1138 case MDP_XRGB_8888:
1139 case MDP_BGRA_8888:
1140 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001141 case MDP_YCBCR_H1V1:
1142 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001143 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1144 in_paddr, out_paddr,
1145 use_imem,
1146 msm_rotator_dev->last_session_idx
1147 != s);
1148 break;
1149 case MDP_Y_CBCR_H2V2:
1150 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001151 case MDP_Y_CB_CR_H2V2:
1152 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301153 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001154 case MDP_Y_CRCB_H2V2_TILE:
1155 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001156 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1157 in_paddr, out_paddr, use_imem,
1158 msm_rotator_dev->last_session_idx
1159 != s,
1160 in_chroma_paddr,
1161 out_chroma_paddr,
1162 in_chroma2_paddr);
1163 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 case MDP_Y_CBCR_H2V1:
1165 case MDP_Y_CRCB_H2V1:
1166 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1167 in_paddr, out_paddr, use_imem,
1168 msm_rotator_dev->last_session_idx
1169 != s,
1170 in_chroma_paddr,
1171 out_chroma_paddr);
1172 break;
1173 case MDP_YCRYCB_H2V1:
1174 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1175 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301176 msm_rotator_dev->last_session_idx != s,
1177 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001178 break;
1179 default:
1180 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001181 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001182 goto do_rotate_exit;
1183 }
1184
1185 if (rc != 0) {
1186 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001187 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 goto do_rotate_exit;
1189 }
1190
1191 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1192
1193 msm_rotator_dev->processing = 1;
1194 iowrite32(0x1, MSM_ROTATOR_START);
1195
1196 wait_event(msm_rotator_dev->wq,
1197 (msm_rotator_dev->processing == 0));
1198 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001199 if ((status & 0x03) != 0x01) {
1200 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1201 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001202 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001203 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001204 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1205 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1206
1207do_rotate_exit:
1208 disable_irq(msm_rotator_dev->irq);
1209#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1210 msm_rotator_imem_free(ROTATOR_REQUEST);
1211#endif
1212 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001213do_rotate_unlock_mutex:
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001214 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
1215 msm_rotator_dev->img_info[s]->secure);
1216 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1217 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
1218 msm_rotator_dev->img_info[s]->secure);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001219
1220 /* only source may use frame buffer */
1221 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1222 fput_light(srcp0_file, ps0_need);
1223 else
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001224 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001225 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1227 __func__, rc);
1228 return rc;
1229}
1230
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001231static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1232{
1233 u32 perf_level;
1234
1235 if (is_rgb)
1236 perf_level = 1;
1237 else if (wh <= (640 * 480))
1238 perf_level = 2;
1239 else if (wh <= (736 * 1280))
1240 perf_level = 3;
1241 else
1242 perf_level = 4;
1243
1244#ifdef CONFIG_MSM_BUS_SCALING
1245 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1246 perf_level);
1247#endif
1248
1249}
1250
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001251static int msm_rotator_start(unsigned long arg,
1252 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253{
1254 struct msm_rotator_img_info info;
1255 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001256 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001257 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001258 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001259
1260 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1261 return -EFAULT;
1262
1263 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1264 (info.src.height > MSM_ROTATOR_MAX_H) ||
1265 (info.src.width > MSM_ROTATOR_MAX_W) ||
1266 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1267 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001268 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1269 pr_err("%s: Invalid parameters\n", __func__);
1270 return -EINVAL;
1271 }
1272
1273 if (info.rotations & MDP_ROT_90) {
1274 dst_w = info.src_rect.h >> info.downscale_ratio;
1275 dst_h = info.src_rect.w >> info.downscale_ratio;
1276 } else {
1277 dst_w = info.src_rect.w >> info.downscale_ratio;
1278 dst_h = info.src_rect.h >> info.downscale_ratio;
1279 }
1280
1281 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001282 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1283 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001284 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1285 pr_err("%s: Invalid src or dst rect\n", __func__);
1286 return -ERANGE;
1287 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001288
1289 switch (info.src.format) {
1290 case MDP_RGB_565:
1291 case MDP_BGR_565:
1292 case MDP_RGB_888:
1293 case MDP_ARGB_8888:
1294 case MDP_RGBA_8888:
1295 case MDP_XRGB_8888:
1296 case MDP_RGBX_8888:
1297 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001298 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301299 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001300 break;
Mayank Goyal5f91c922012-11-07 16:58:09 +05301301 case MDP_Y_CBCR_H2V1:
1302 if (info.rotations & MDP_ROT_90) {
1303 info.dst.format = MDP_Y_CBCR_H1V2;
1304 break;
1305 }
1306 case MDP_Y_CRCB_H2V1:
1307 if (info.rotations & MDP_ROT_90) {
1308 info.dst.format = MDP_Y_CRCB_H1V2;
1309 break;
1310 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 case MDP_Y_CBCR_H2V2:
1312 case MDP_Y_CRCB_H2V2:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001313 case MDP_YCBCR_H1V1:
1314 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301315 info.dst.format = info.src.format;
1316 break;
1317 case MDP_YCRYCB_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +05301318 if (info.rotations & MDP_ROT_90)
1319 info.dst.format = MDP_Y_CRCB_H1V2;
1320 else
1321 info.dst.format = MDP_Y_CRCB_H2V1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301322 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001323 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301324 case MDP_Y_CBCR_H2V2_TILE:
1325 info.dst.format = MDP_Y_CBCR_H2V2;
1326 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001327 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301328 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001329 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301330 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 break;
1332 default:
1333 return -EINVAL;
1334 }
1335
1336 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001337
1338 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1339
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001340 for (s = 0; s < MAX_SESSIONS; s++) {
1341 if ((msm_rotator_dev->img_info[s] != NULL) &&
1342 (info.session_id ==
1343 (unsigned int)msm_rotator_dev->img_info[s]
1344 )) {
1345 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001346 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001347
1348 if (msm_rotator_dev->last_session_idx == s)
1349 msm_rotator_dev->last_session_idx =
1350 INVALID_SESSION;
1351 break;
1352 }
1353
1354 if ((msm_rotator_dev->img_info[s] == NULL) &&
1355 (first_free_index ==
1356 INVALID_SESSION))
1357 first_free_index = s;
1358 }
1359
1360 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1361 /* allocate a session id */
1362 msm_rotator_dev->img_info[first_free_index] =
1363 kzalloc(sizeof(struct msm_rotator_img_info),
1364 GFP_KERNEL);
1365 if (!msm_rotator_dev->img_info[first_free_index]) {
1366 printk(KERN_ERR "%s : unable to alloc mem\n",
1367 __func__);
1368 rc = -ENOMEM;
1369 goto rotator_start_exit;
1370 }
1371 info.session_id = (unsigned int)
1372 msm_rotator_dev->img_info[first_free_index];
1373 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001374 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001375 } else if (s == MAX_SESSIONS) {
1376 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1377 __func__);
1378 rc = -EBUSY;
1379 }
1380
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001381 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1382 rc = -EFAULT;
1383
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384rotator_start_exit:
1385 mutex_unlock(&msm_rotator_dev->rotator_lock);
1386
1387 return rc;
1388}
1389
1390static int msm_rotator_finish(unsigned long arg)
1391{
1392 int rc = 0;
1393 int s;
1394 unsigned int session_id;
1395
1396 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1397 return -EFAULT;
1398
1399 mutex_lock(&msm_rotator_dev->rotator_lock);
1400 for (s = 0; s < MAX_SESSIONS; s++) {
1401 if ((msm_rotator_dev->img_info[s] != NULL) &&
1402 (session_id ==
1403 (unsigned int)msm_rotator_dev->img_info[s])) {
1404 if (msm_rotator_dev->last_session_idx == s)
1405 msm_rotator_dev->last_session_idx =
1406 INVALID_SESSION;
1407 kfree(msm_rotator_dev->img_info[s]);
1408 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001409 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 break;
1411 }
1412 }
1413
1414 if (s == MAX_SESSIONS)
1415 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001416#ifdef CONFIG_MSM_BUS_SCALING
1417 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1418 0);
1419#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 mutex_unlock(&msm_rotator_dev->rotator_lock);
1421 return rc;
1422}
1423
1424static int
1425msm_rotator_open(struct inode *inode, struct file *filp)
1426{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001427 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001428 int i;
1429
1430 if (filp->private_data)
1431 return -EBUSY;
1432
1433 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001434 for (i = 0; i < MAX_SESSIONS; i++) {
1435 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001436 break;
1437 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001438
1439 if (i == MAX_SESSIONS) {
1440 mutex_unlock(&msm_rotator_dev->rotator_lock);
1441 return -EBUSY;
1442 }
1443
1444 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1445 if (tmp->pid == current->pid) {
1446 fd_info = tmp;
1447 break;
1448 }
1449 }
1450
1451 if (!fd_info) {
1452 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1453 if (!fd_info) {
1454 mutex_unlock(&msm_rotator_dev->rotator_lock);
1455 pr_err("%s: insufficient memory to alloc resources\n",
1456 __func__);
1457 return -ENOMEM;
1458 }
1459 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1460 fd_info->pid = current->pid;
1461 }
1462 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 mutex_unlock(&msm_rotator_dev->rotator_lock);
1464
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001465 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466
1467 return 0;
1468}
1469
1470static int
1471msm_rotator_close(struct inode *inode, struct file *filp)
1472{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001473 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001476 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1477
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001478 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001479 if (--fd_info->ref_cnt > 0) {
1480 mutex_unlock(&msm_rotator_dev->rotator_lock);
1481 return 0;
1482 }
1483
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 for (s = 0; s < MAX_SESSIONS; s++) {
1485 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001486 msm_rotator_dev->fd_info[s] == fd_info) {
1487 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1488 __func__, msm_rotator_dev->img_info[s],
1489 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001490 kfree(msm_rotator_dev->img_info[s]);
1491 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001492 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001493 if (msm_rotator_dev->last_session_idx == s)
1494 msm_rotator_dev->last_session_idx =
1495 INVALID_SESSION;
1496 }
1497 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001498 list_del(&fd_info->list);
1499 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 mutex_unlock(&msm_rotator_dev->rotator_lock);
1501
1502 return 0;
1503}
1504
1505static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1506 unsigned long arg)
1507{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001508 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509
1510 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1511 return -ENOTTY;
1512
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001513 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001514
1515 switch (cmd) {
1516 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001517 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001518 case MSM_ROTATOR_IOCTL_ROTATE:
1519 return msm_rotator_do_rotate(arg);
1520 case MSM_ROTATOR_IOCTL_FINISH:
1521 return msm_rotator_finish(arg);
1522
1523 default:
1524 dev_dbg(msm_rotator_dev->device,
1525 "unexpected IOCTL %d\n", cmd);
1526 return -ENOTTY;
1527 }
1528}
1529
1530static const struct file_operations msm_rotator_fops = {
1531 .owner = THIS_MODULE,
1532 .open = msm_rotator_open,
1533 .release = msm_rotator_close,
1534 .unlocked_ioctl = msm_rotator_ioctl,
1535};
1536
1537static int __devinit msm_rotator_probe(struct platform_device *pdev)
1538{
1539 int rc = 0;
1540 struct resource *res;
1541 struct msm_rotator_platform_data *pdata = NULL;
1542 int i, number_of_clks;
1543 uint32_t ver;
1544
1545 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1546 if (!msm_rotator_dev) {
1547 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1548 __func__);
1549 return -ENOMEM;
1550 }
1551 for (i = 0; i < MAX_SESSIONS; i++)
1552 msm_rotator_dev->img_info[i] = NULL;
1553 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1554
1555 pdata = pdev->dev.platform_data;
1556 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07001557 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558
1559 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1560 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001561 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001562 msm_rotator_dev->imem_clk_state = CLK_DIS;
1563 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1564 msm_rotator_imem_clk_work_f);
1565 msm_rotator_dev->imem_clk = NULL;
1566 msm_rotator_dev->pdev = pdev;
1567
1568 msm_rotator_dev->core_clk = NULL;
1569 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001570
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001571#ifdef CONFIG_MSM_BUS_SCALING
1572 if (!msm_rotator_dev->bus_client_handle && pdata &&
1573 pdata->bus_scale_table) {
1574 msm_rotator_dev->bus_client_handle =
1575 msm_bus_scale_register_client(
1576 pdata->bus_scale_table);
1577 if (!msm_rotator_dev->bus_client_handle) {
1578 pr_err("%s not able to get bus scale handle\n",
1579 __func__);
1580 }
1581 }
1582#endif
1583
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001584 for (i = 0; i < number_of_clks; i++) {
1585 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1586 msm_rotator_dev->imem_clk =
1587 clk_get(&msm_rotator_dev->pdev->dev,
1588 pdata->rotator_clks[i].clk_name);
1589 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1590 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1591 msm_rotator_dev->imem_clk = NULL;
1592 printk(KERN_ERR "%s: cannot get imem_clk "
1593 "rc=%d\n", DRIVER_NAME, rc);
1594 goto error_imem_clk;
1595 }
1596 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001597 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001598 pdata->rotator_clks[i].clk_rate);
1599 }
1600 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1601 msm_rotator_dev->pclk =
1602 clk_get(&msm_rotator_dev->pdev->dev,
1603 pdata->rotator_clks[i].clk_name);
1604 if (IS_ERR(msm_rotator_dev->pclk)) {
1605 rc = PTR_ERR(msm_rotator_dev->pclk);
1606 msm_rotator_dev->pclk = NULL;
1607 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1608 DRIVER_NAME, rc);
1609 goto error_pclk;
1610 }
1611
1612 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001613 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001614 pdata->rotator_clks[i].clk_rate);
1615 }
1616
1617 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1618 msm_rotator_dev->core_clk =
1619 clk_get(&msm_rotator_dev->pdev->dev,
1620 pdata->rotator_clks[i].clk_name);
1621 if (IS_ERR(msm_rotator_dev->core_clk)) {
1622 rc = PTR_ERR(msm_rotator_dev->core_clk);
1623 msm_rotator_dev->core_clk = NULL;
1624 printk(KERN_ERR "%s: cannot get core clk "
1625 "rc=%d\n", DRIVER_NAME, rc);
1626 goto error_core_clk;
1627 }
1628
1629 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001630 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001631 pdata->rotator_clks[i].clk_rate);
1632 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 }
1634
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001635 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1636 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001637 if (IS_ERR(msm_rotator_dev->regulator))
1638 msm_rotator_dev->regulator = NULL;
1639
1640 msm_rotator_dev->rot_clk_state = CLK_DIS;
1641 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1642 msm_rotator_rot_clk_work_f);
1643
1644 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001645#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1646 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1647#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001648 platform_set_drvdata(pdev, msm_rotator_dev);
1649
1650
1651 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1652 if (!res) {
1653 printk(KERN_ALERT
1654 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1655 rc = -ENODEV;
1656 goto error_get_resource;
1657 }
1658 msm_rotator_dev->io_base = ioremap(res->start,
1659 resource_size(res));
1660
1661#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1662 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001663 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664#endif
1665 enable_rot_clks();
1666 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1667 disable_rot_clks();
1668
1669#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1670 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001671 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001672#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001673 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301674 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001675 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001676
Mayank Chopra012a8e72012-04-11 10:41:13 +05301677 rotator_hw_revision = ver;
1678 rotator_hw_revision >>= 16; /* bit 31:16 */
1679 rotator_hw_revision &= 0xff;
1680
1681 pr_info("%s: rotator_hw_revision=%x\n",
1682 __func__, rotator_hw_revision);
1683
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001684 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1685 if (msm_rotator_dev->irq < 0) {
1686 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1687 DRIVER_NAME);
1688 rc = -ENODEV;
1689 goto error_get_irq;
1690 }
1691 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1692 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1693 if (rc) {
1694 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1695 goto error_get_irq;
1696 }
1697 /* we enable the IRQ when we need it in the ioctl */
1698 disable_irq(msm_rotator_dev->irq);
1699
1700 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1701 if (rc < 0) {
1702 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1703 __func__, rc);
1704 goto error_get_irq;
1705 }
1706
1707 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1708 if (IS_ERR(msm_rotator_dev->class)) {
1709 rc = PTR_ERR(msm_rotator_dev->class);
1710 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1711 DRIVER_NAME, rc);
1712 goto error_class_create;
1713 }
1714
1715 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1716 msm_rotator_dev->dev_num, NULL,
1717 DRIVER_NAME);
1718 if (IS_ERR(msm_rotator_dev->device)) {
1719 rc = PTR_ERR(msm_rotator_dev->device);
1720 printk(KERN_ERR "%s: device_create failed %d\n",
1721 DRIVER_NAME, rc);
1722 goto error_class_device_create;
1723 }
1724
1725 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1726 rc = cdev_add(&msm_rotator_dev->cdev,
1727 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1728 1);
1729 if (rc < 0) {
1730 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1731 goto error_cdev_add;
1732 }
1733
1734 init_waitqueue_head(&msm_rotator_dev->wq);
1735
1736 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1737 return rc;
1738
1739error_cdev_add:
1740 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1741error_class_device_create:
1742 class_destroy(msm_rotator_dev->class);
1743error_class_create:
1744 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1745error_get_irq:
1746 iounmap(msm_rotator_dev->io_base);
1747error_get_resource:
1748 mutex_destroy(&msm_rotator_dev->rotator_lock);
1749 if (msm_rotator_dev->regulator)
1750 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001751 clk_put(msm_rotator_dev->core_clk);
1752error_core_clk:
1753 clk_put(msm_rotator_dev->pclk);
1754error_pclk:
1755 if (msm_rotator_dev->imem_clk)
1756 clk_put(msm_rotator_dev->imem_clk);
1757error_imem_clk:
1758 mutex_destroy(&msm_rotator_dev->imem_lock);
1759 kfree(msm_rotator_dev);
1760 return rc;
1761}
1762
1763static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1764{
1765 int i;
1766
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001767#ifdef CONFIG_MSM_BUS_SCALING
1768 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1769#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 free_irq(msm_rotator_dev->irq, NULL);
1771 mutex_destroy(&msm_rotator_dev->rotator_lock);
1772 cdev_del(&msm_rotator_dev->cdev);
1773 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1774 class_destroy(msm_rotator_dev->class);
1775 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1776 iounmap(msm_rotator_dev->io_base);
1777 if (msm_rotator_dev->imem_clk) {
1778 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001779 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001780 clk_put(msm_rotator_dev->imem_clk);
1781 msm_rotator_dev->imem_clk = NULL;
1782 }
1783 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1784 disable_rot_clks();
1785 clk_put(msm_rotator_dev->core_clk);
1786 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001787 if (msm_rotator_dev->regulator)
1788 regulator_put(msm_rotator_dev->regulator);
1789 msm_rotator_dev->core_clk = NULL;
1790 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791 mutex_destroy(&msm_rotator_dev->imem_lock);
1792 for (i = 0; i < MAX_SESSIONS; i++)
1793 if (msm_rotator_dev->img_info[i] != NULL)
1794 kfree(msm_rotator_dev->img_info[i]);
1795 kfree(msm_rotator_dev);
1796 return 0;
1797}
1798
1799#ifdef CONFIG_PM
1800static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1801{
1802 mutex_lock(&msm_rotator_dev->imem_lock);
1803 if (msm_rotator_dev->imem_clk_state == CLK_EN
1804 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001805 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1807 }
1808 mutex_unlock(&msm_rotator_dev->imem_lock);
1809 mutex_lock(&msm_rotator_dev->rotator_lock);
1810 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1811 disable_rot_clks();
1812 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1813 }
1814 mutex_unlock(&msm_rotator_dev->rotator_lock);
1815 return 0;
1816}
1817
1818static int msm_rotator_resume(struct platform_device *dev)
1819{
1820 mutex_lock(&msm_rotator_dev->imem_lock);
1821 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1822 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001823 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001824 msm_rotator_dev->imem_clk_state = CLK_EN;
1825 }
1826 mutex_unlock(&msm_rotator_dev->imem_lock);
1827 mutex_lock(&msm_rotator_dev->rotator_lock);
1828 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1829 enable_rot_clks();
1830 msm_rotator_dev->rot_clk_state = CLK_EN;
1831 }
1832 mutex_unlock(&msm_rotator_dev->rotator_lock);
1833 return 0;
1834}
1835#endif
1836
1837static struct platform_driver msm_rotator_platform_driver = {
1838 .probe = msm_rotator_probe,
1839 .remove = __devexit_p(msm_rotator_remove),
1840#ifdef CONFIG_PM
1841 .suspend = msm_rotator_suspend,
1842 .resume = msm_rotator_resume,
1843#endif
1844 .driver = {
1845 .owner = THIS_MODULE,
1846 .name = DRIVER_NAME
1847 }
1848};
1849
1850static int __init msm_rotator_init(void)
1851{
1852 return platform_driver_register(&msm_rotator_platform_driver);
1853}
1854
1855static void __exit msm_rotator_exit(void)
1856{
1857 return platform_driver_unregister(&msm_rotator_platform_driver);
1858}
1859
1860module_init(msm_rotator_init);
1861module_exit(msm_rotator_exit);
1862
1863MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1864MODULE_VERSION("1.0");
1865MODULE_LICENSE("GPL v2");