blob: 156a2a59a7053425566aa939100821f4472f626a [file] [log] [blame]
Pawan Kumar7b5297f2013-05-27 11:54:27 +05301/* 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/msm_rotator.h>
23#include <linux/io.h>
24#include <mach/msm_rotator_imem.h>
25#include <linux/ktime.h>
26#include <linux/workqueue.h>
27#include <linux/file.h>
28#include <linux/major.h>
29#include <linux/regulator/consumer.h>
Mitchel Humpherys6c7b2d32012-09-06 10:33:12 -070030#include <linux/msm_ion.h>
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080031#ifdef CONFIG_MSM_BUS_SCALING
32#include <mach/msm_bus.h>
33#include <mach/msm_bus_board.h>
34#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070035#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070036
37#define DRIVER_NAME "msm_rotator"
38
39#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
40#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
41#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
42#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
43#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
44#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
45#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -070046#define MSM_ROTATOR_SW_RESET (MSM_ROTATOR_BASE+0x0074)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070047#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
48#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
49#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070050#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070051#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
52#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
53#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
54#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
55#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
56#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
57#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
58#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070059#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070060#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
61#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
62#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
63#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
64
65#define MSM_ROTATOR_MAX_ROT 0x07
66#define MSM_ROTATOR_MAX_H 0x1fff
67#define MSM_ROTATOR_MAX_W 0x1fff
68
69/* from lsb to msb */
70#define GET_PACK_PATTERN(a, x, y, z, bit) \
71 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
72#define CLR_G 0x0
73#define CLR_B 0x1
74#define CLR_R 0x2
75#define CLR_ALPHA 0x3
76
77#define CLR_Y CLR_G
78#define CLR_CB CLR_B
79#define CLR_CR CLR_R
80
81#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
82 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
83 (((r) & MDP_FLIP_UD) ? 4 : 0))
84
85#define IMEM_NO_OWNER -1;
86
87#define MAX_SESSIONS 16
88#define INVALID_SESSION -1
89#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070090#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070091
Mayank Chopra012a8e72012-04-11 10:41:13 +053092#define ROTATOR_REVISION_V0 0
93#define ROTATOR_REVISION_V1 1
94#define ROTATOR_REVISION_V2 2
95#define ROTATOR_REVISION_NONE 0xffffffff
96
97uint32_t rotator_hw_revision;
Olav Hauganef95ae32012-05-15 09:50:30 -070098static char rot_iommu_split_domain;
Mayank Chopra012a8e72012-04-11 10:41:13 +053099
100/*
101 * rotator_hw_revision:
102 * 0 == 7x30
103 * 1 == 8x60
104 * 2 == 8960
105 *
106 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700107struct tile_parm {
108 unsigned int width; /* tile's width */
109 unsigned int height; /* tile's height */
110 unsigned int row_tile_w; /* tiles per row's width */
111 unsigned int row_tile_h; /* tiles per row's height */
112};
113
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700114struct msm_rotator_mem_planes {
115 unsigned int num_planes;
116 unsigned int plane_size[4];
117 unsigned int total_size;
118};
119
120#define checkoffset(offset, size, max_size) \
121 ((size) > (max_size) || (offset) > ((max_size) - (size)))
122
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700123struct msm_rotator_fd_info {
124 int pid;
125 int ref_cnt;
126 struct list_head list;
127};
128
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700129struct msm_rotator_dev {
130 void __iomem *io_base;
131 int irq;
132 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
133 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700134 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
135 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700136 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 int rot_clk_state;
138 struct regulator *regulator;
139 struct delayed_work rot_clk_work;
140 struct clk *imem_clk;
141 int imem_clk_state;
142 struct delayed_work imem_clk_work;
143 struct platform_device *pdev;
144 struct cdev cdev;
145 struct device *device;
146 struct class *class;
147 dev_t dev_num;
148 int processing;
149 int last_session_idx;
150 struct mutex rotator_lock;
151 struct mutex imem_lock;
152 int imem_owner;
153 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700154 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800155 #ifdef CONFIG_MSM_BUS_SCALING
156 uint32_t bus_client_handle;
157 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700158};
159
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700160#define COMPONENT_5BITS 1
161#define COMPONENT_6BITS 2
162#define COMPONENT_8BITS 3
163
164static struct msm_rotator_dev *msm_rotator_dev;
165
166enum {
167 CLK_EN,
168 CLK_DIS,
169 CLK_SUSPEND,
170};
171
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700172int msm_rotator_iommu_map_buf(int mem_id, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700173 unsigned long *start, unsigned long *len,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700174 struct ion_handle **pihdl, unsigned int secure)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700175{
176 if (!msm_rotator_dev->client)
177 return -EINVAL;
178
Laura Abbottb14ed962012-01-30 14:18:08 -0800179 *pihdl = ion_import_dma_buf(msm_rotator_dev->client, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700180 if (IS_ERR_OR_NULL(*pihdl)) {
Laura Abbottb14ed962012-01-30 14:18:08 -0800181 pr_err("ion_import_dma_buf() failed\n");
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700182 return PTR_ERR(*pihdl);
183 }
Johan Mossberg748c11d2013-01-11 13:38:13 +0100184 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700185
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700186 if (rot_iommu_split_domain) {
187 if (secure) {
188 if (ion_phys(msm_rotator_dev->client,
189 *pihdl, start, (unsigned *)len)) {
190 pr_err("%s:%d: ion_phys map failed\n",
191 __func__, __LINE__);
192 return -ENOMEM;
193 }
194 } else {
195 if (ion_map_iommu(msm_rotator_dev->client,
196 *pihdl, domain, GEN_POOL,
197 SZ_4K, 0, start, len, 0,
198 ION_IOMMU_UNMAP_DELAYED)) {
199 pr_err("ion_map_iommu() failed\n");
200 return -EINVAL;
201 }
202 }
203 } else {
204 if (ion_map_iommu(msm_rotator_dev->client,
205 *pihdl, ROTATOR_SRC_DOMAIN, GEN_POOL,
206 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
207 pr_err("ion_map_iommu() failed\n");
208 return -EINVAL;
209 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700210 }
211
212 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
213 __func__, mem_id, *start, *len);
214 return 0;
215}
216
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700217int msm_rotator_imem_allocate(int requestor)
218{
219 int rc = 0;
220
221#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
222 switch (requestor) {
223 case ROTATOR_REQUEST:
224 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
225 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
226 rc = 1;
227 } else
228 rc = 0;
229 break;
230 case JPEG_REQUEST:
231 mutex_lock(&msm_rotator_dev->imem_lock);
232 msm_rotator_dev->imem_owner = JPEG_REQUEST;
233 rc = 1;
234 break;
235 default:
236 rc = 0;
237 }
238#else
239 if (requestor == JPEG_REQUEST)
240 rc = 1;
241#endif
242 if (rc == 1) {
243 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
244 if (msm_rotator_dev->imem_clk_state != CLK_EN
245 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700246 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700247 msm_rotator_dev->imem_clk_state = CLK_EN;
248 }
249 }
250
251 return rc;
252}
253EXPORT_SYMBOL(msm_rotator_imem_allocate);
254
255void msm_rotator_imem_free(int requestor)
256{
257#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
258 if (msm_rotator_dev->imem_owner == requestor) {
259 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
260 mutex_unlock(&msm_rotator_dev->imem_lock);
261 }
262#else
263 if (requestor == JPEG_REQUEST)
264 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
265#endif
266}
267EXPORT_SYMBOL(msm_rotator_imem_free);
268
269static void msm_rotator_imem_clk_work_f(struct work_struct *work)
270{
271#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
272 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
273 if (msm_rotator_dev->imem_clk_state == CLK_EN
274 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700275 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700276 msm_rotator_dev->imem_clk_state = CLK_DIS;
277 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
278 msm_rotator_dev->imem_clk_state = CLK_DIS;
279 mutex_unlock(&msm_rotator_dev->imem_lock);
280 }
281#endif
282}
283
284/* enable clocks needed by rotator block */
285static void enable_rot_clks(void)
286{
287 if (msm_rotator_dev->regulator)
288 regulator_enable(msm_rotator_dev->regulator);
289 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700290 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700291 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700292 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293}
294
295/* disable clocks needed by rotator block */
296static void disable_rot_clks(void)
297{
298 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700299 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700300 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700301 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 if (msm_rotator_dev->regulator)
303 regulator_disable(msm_rotator_dev->regulator);
304}
305
306static void msm_rotator_rot_clk_work_f(struct work_struct *work)
307{
308 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
309 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
310 disable_rot_clks();
311 msm_rotator_dev->rot_clk_state = CLK_DIS;
312 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
313 msm_rotator_dev->rot_clk_state = CLK_DIS;
314 mutex_unlock(&msm_rotator_dev->rotator_lock);
315 }
316}
317
318static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
319{
320 if (msm_rotator_dev->processing) {
321 msm_rotator_dev->processing = 0;
322 wake_up(&msm_rotator_dev->wq);
323 } else
324 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
325
326 return IRQ_HANDLED;
327}
328
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700329static unsigned int tile_size(unsigned int src_width,
330 unsigned int src_height,
331 const struct tile_parm *tp)
332{
333 unsigned int tile_w, tile_h;
334 unsigned int row_num_w, row_num_h;
335 tile_w = tp->width * tp->row_tile_w;
336 tile_h = tp->height * tp->row_tile_h;
337 row_num_w = (src_width + tile_w - 1) / tile_w;
338 row_num_h = (src_height + tile_h - 1) / tile_h;
339 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
340}
341
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342static int get_bpp(int format)
343{
344 switch (format) {
345 case MDP_RGB_565:
346 case MDP_BGR_565:
347 return 2;
348
349 case MDP_XRGB_8888:
350 case MDP_ARGB_8888:
351 case MDP_RGBA_8888:
352 case MDP_BGRA_8888:
353 case MDP_RGBX_8888:
Pawan Kumar7b5297f2013-05-27 11:54:27 +0530354 case MDP_BGRX_8888:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355 return 4;
356
357 case MDP_Y_CBCR_H2V2:
358 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700359 case MDP_Y_CB_CR_H2V2:
360 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530361 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700362 case MDP_Y_CRCB_H2V2_TILE:
363 case MDP_Y_CBCR_H2V2_TILE:
364 return 1;
365
366 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700367 case MDP_YCBCR_H1V1:
368 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700369 return 3;
370
371 case MDP_YCRYCB_H2V1:
372 return 2;/* YCrYCb interleave */
373
374 case MDP_Y_CRCB_H2V1:
375 case MDP_Y_CBCR_H2V1:
376 return 1;
377
378 default:
379 return -1;
380 }
381
382}
383
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700384static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
385 struct msm_rotator_mem_planes *p)
386{
387 /*
388 * each row of samsung tile consists of two tiles in height
389 * and two tiles in width which means width should align to
390 * 64 x 2 bytes and height should align to 32 x 2 bytes.
391 * video decoder generate two tiles in width and one tile
392 * in height which ends up height align to 32 X 1 bytes.
393 */
394 const struct tile_parm tile = {64, 32, 2, 1};
395 int i;
396
397 if (p == NULL)
398 return -EINVAL;
399
400 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
401 return -ERANGE;
402
403 memset(p, 0, sizeof(*p));
404
405 switch (format) {
406 case MDP_XRGB_8888:
407 case MDP_ARGB_8888:
408 case MDP_RGBA_8888:
409 case MDP_BGRA_8888:
410 case MDP_RGBX_8888:
Pawan Kumar7b5297f2013-05-27 11:54:27 +0530411 case MDP_BGRX_8888:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700412 case MDP_RGB_888:
413 case MDP_RGB_565:
414 case MDP_BGR_565:
415 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700416 case MDP_YCBCR_H1V1:
417 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700418 p->num_planes = 1;
419 p->plane_size[0] = w * h * get_bpp(format);
420 break;
421 case MDP_Y_CRCB_H2V1:
422 case MDP_Y_CBCR_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +0530423 case MDP_Y_CRCB_H1V2:
Mayank Goyal5f91c922012-11-07 16:58:09 +0530424 case MDP_Y_CBCR_H1V2:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700425 p->num_planes = 2;
426 p->plane_size[0] = w * h;
427 p->plane_size[1] = w * h;
428 break;
429 case MDP_Y_CBCR_H2V2:
430 case MDP_Y_CRCB_H2V2:
431 p->num_planes = 2;
432 p->plane_size[0] = w * h;
433 p->plane_size[1] = w * h / 2;
434 break;
435 case MDP_Y_CRCB_H2V2_TILE:
436 case MDP_Y_CBCR_H2V2_TILE:
437 p->num_planes = 2;
438 p->plane_size[0] = tile_size(w, h, &tile);
439 p->plane_size[1] = tile_size(w, h/2, &tile);
440 break;
441 case MDP_Y_CB_CR_H2V2:
442 case MDP_Y_CR_CB_H2V2:
443 p->num_planes = 3;
444 p->plane_size[0] = w * h;
445 p->plane_size[1] = (w / 2) * (h / 2);
446 p->plane_size[2] = (w / 2) * (h / 2);
447 break;
448 case MDP_Y_CR_CB_GH2V2:
449 p->num_planes = 3;
450 p->plane_size[0] = ALIGN(w, 16) * h;
451 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
452 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
453 break;
454 default:
455 return -EINVAL;
456 }
457
458 for (i = 0; i < p->num_planes; i++)
459 p->total_size += p->plane_size[i];
460
461 return 0;
462}
463
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700464static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
465 unsigned int in_paddr,
466 unsigned int out_paddr,
467 unsigned int use_imem,
468 int new_session,
469 unsigned int in_chroma_paddr,
470 unsigned int out_chroma_paddr)
471{
472 int bpp;
Mayank Goyal5f91c922012-11-07 16:58:09 +0530473 uint32_t dst_format;
474 switch (info->src.format) {
475 case MDP_Y_CRCB_H2V1:
476 if (info->rotations & MDP_ROT_90)
477 dst_format = MDP_Y_CRCB_H1V2;
478 else
479 dst_format = info->src.format;
480 break;
481 case MDP_Y_CBCR_H2V1:
482 if (info->rotations & MDP_ROT_90)
483 dst_format = MDP_Y_CBCR_H1V2;
484 else
485 dst_format = info->src.format;
486 break;
487 default:
488 return -EINVAL;
489 }
490 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700491 return -EINVAL;
492
493 bpp = get_bpp(info->src.format);
494 if (bpp < 0)
495 return -ENOTTY;
496
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700497 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700498 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700499 iowrite32(out_paddr +
500 ((info->dst_y * info->dst.width) + info->dst_x),
501 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700502 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700503 ((info->dst_y * info->dst.width) + info->dst_x),
504 MSM_ROTATOR_OUTP1_ADDR);
505
506 if (new_session) {
507 iowrite32(info->src.width |
508 info->src.width << 16,
509 MSM_ROTATOR_SRC_YSTRIDE1);
510 if (info->rotations & MDP_ROT_90)
511 iowrite32(info->dst.width |
512 info->dst.width*2 << 16,
513 MSM_ROTATOR_OUT_YSTRIDE1);
514 else
515 iowrite32(info->dst.width |
516 info->dst.width << 16,
517 MSM_ROTATOR_OUT_YSTRIDE1);
518 if (info->src.format == MDP_Y_CBCR_H2V1) {
519 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
520 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
521 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
522 MSM_ROTATOR_OUT_PACK_PATTERN1);
523 } else {
524 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
525 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
526 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
527 MSM_ROTATOR_OUT_PACK_PATTERN1);
528 }
529 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
530 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700531 1 << 8 | /* ROT_EN */
532 info->downscale_ratio << 2 | /* downscale v ratio */
533 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700534 MSM_ROTATOR_SUB_BLOCK_CFG);
535 iowrite32(0 << 29 | /* frame format 0 = linear */
536 (use_imem ? 0 : 1) << 22 | /* tile size */
537 2 << 19 | /* fetch planes 2 = pseudo */
538 0 << 18 | /* unpack align */
539 1 << 17 | /* unpack tight */
540 1 << 13 | /* unpack count 0=1 component */
541 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
542 0 << 8 | /* has alpha */
543 0 << 6 | /* alpha bits 3=8bits */
544 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
545 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
546 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
547 MSM_ROTATOR_SRC_FORMAT);
548 }
549
550 return 0;
551}
552
553static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
554 unsigned int in_paddr,
555 unsigned int out_paddr,
556 unsigned int use_imem,
557 int new_session,
558 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700559 unsigned int out_chroma_paddr,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700560 unsigned int in_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700562 uint32_t dst_format;
563 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700564
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700565 switch (info->src.format) {
566 case MDP_Y_CRCB_H2V2_TILE:
567 is_tile = 1;
568 case MDP_Y_CR_CB_H2V2:
569 case MDP_Y_CR_CB_GH2V2:
570 case MDP_Y_CRCB_H2V2:
571 dst_format = MDP_Y_CRCB_H2V2;
572 break;
573 case MDP_Y_CBCR_H2V2_TILE:
574 is_tile = 1;
575 case MDP_Y_CB_CR_H2V2:
576 case MDP_Y_CBCR_H2V2:
577 dst_format = MDP_Y_CBCR_H2V2;
578 break;
579 default:
580 return -EINVAL;
581 }
582 if (info->dst.format != dst_format)
583 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700584
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800585 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530586 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
587 info->src.format == MDP_Y_CR_CB_GH2V2) &&
588 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800589 swap(in_chroma_paddr, in_chroma2_paddr);
590
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700591 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700592 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
593 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
594
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700595 iowrite32(out_paddr +
596 ((info->dst_y * info->dst.width) + info->dst_x),
597 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700598 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700599 ((info->dst_y * info->dst.width)/2 + info->dst_x),
600 MSM_ROTATOR_OUTP1_ADDR);
601
602 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700603 if (in_chroma2_paddr) {
604 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530605 iowrite32(ALIGN(info->src.width, 16) |
606 ALIGN((info->src.width / 2), 16) << 16,
607 MSM_ROTATOR_SRC_YSTRIDE1);
608 iowrite32(ALIGN((info->src.width / 2), 16),
609 MSM_ROTATOR_SRC_YSTRIDE2);
610 } else {
611 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700612 (info->src.width / 2) << 16,
613 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530614 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700615 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530616 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700617 } else {
618 iowrite32(info->src.width |
619 info->src.width << 16,
620 MSM_ROTATOR_SRC_YSTRIDE1);
621 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700622 iowrite32(info->dst.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700623 info->dst.width << 16,
624 MSM_ROTATOR_OUT_YSTRIDE1);
625
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700626 if (dst_format == MDP_Y_CBCR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700627 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
628 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
629 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
630 MSM_ROTATOR_OUT_PACK_PATTERN1);
631 } else {
632 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
633 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
634 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
635 MSM_ROTATOR_OUT_PACK_PATTERN1);
636 }
637 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
638 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700639 1 << 8 | /* ROT_EN */
640 info->downscale_ratio << 2 | /* downscale v ratio */
641 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700642 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700643
644 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700645 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700646 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700647 0 << 18 | /* unpack align */
648 1 << 17 | /* unpack tight */
649 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700650 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700651 0 << 8 | /* has alpha */
652 0 << 6 | /* alpha bits 3=8bits */
653 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
654 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
655 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
656 MSM_ROTATOR_SRC_FORMAT);
657 }
658 return 0;
659}
660
661static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
662 unsigned int in_paddr,
663 unsigned int out_paddr,
664 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530665 int new_session,
666 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700667{
668 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530669 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700670
Mayank Chopra797bdb72012-03-03 06:29:40 +0530671 if (info->src.format == MDP_YCRYCB_H2V1) {
672 if (info->rotations & MDP_ROT_90)
673 dst_format = MDP_Y_CRCB_H1V2;
674 else
675 dst_format = MDP_Y_CRCB_H2V1;
676 } else
Mayank Chopra732dcd62012-01-09 20:53:39 +0530677 return -EINVAL;
678
679 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700680 return -EINVAL;
681
682 bpp = get_bpp(info->src.format);
683 if (bpp < 0)
684 return -ENOTTY;
685
686 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
687 iowrite32(out_paddr +
688 ((info->dst_y * info->dst.width) + info->dst_x),
689 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530690 iowrite32(out_chroma_paddr +
691 ((info->dst_y * info->dst.width)/2 + info->dst_x),
692 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700693
694 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +0530695 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700696 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530697 if (info->rotations & MDP_ROT_90)
698 iowrite32(info->dst.width |
699 (info->dst.width*2) << 16,
700 MSM_ROTATOR_OUT_YSTRIDE1);
701 else
702 iowrite32(info->dst.width |
703 (info->dst.width) << 16,
704 MSM_ROTATOR_OUT_YSTRIDE1);
705
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700706 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
707 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +0530708 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700709 MSM_ROTATOR_OUT_PACK_PATTERN1);
710 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
711 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700712 1 << 8 | /* ROT_EN */
713 info->downscale_ratio << 2 | /* downscale v ratio */
714 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700715 MSM_ROTATOR_SUB_BLOCK_CFG);
716 iowrite32(0 << 29 | /* frame format 0 = linear */
717 (use_imem ? 0 : 1) << 22 | /* tile size */
718 0 << 19 | /* fetch planes 0=interleaved */
719 0 << 18 | /* unpack align */
720 1 << 17 | /* unpack tight */
721 3 << 13 | /* unpack count 0=1 component */
722 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
723 0 << 8 | /* has alpha */
724 0 << 6 | /* alpha bits 3=8bits */
725 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
726 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
727 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
728 MSM_ROTATOR_SRC_FORMAT);
729 }
730
731 return 0;
732}
733
734static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
735 unsigned int in_paddr,
736 unsigned int out_paddr,
737 unsigned int use_imem,
738 int new_session)
739{
740 int bpp, abits, rbits, gbits, bbits;
741
742 if (info->src.format != info->dst.format)
743 return -EINVAL;
744
745 bpp = get_bpp(info->src.format);
746 if (bpp < 0)
747 return -ENOTTY;
748
749 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
750 iowrite32(out_paddr +
751 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
752 MSM_ROTATOR_OUTP0_ADDR);
753
754 if (new_session) {
755 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
756 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
757 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
758 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700759 1 << 8 | /* ROT_EN */
760 info->downscale_ratio << 2 | /* downscale v ratio */
761 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700762 MSM_ROTATOR_SUB_BLOCK_CFG);
763 switch (info->src.format) {
764 case MDP_RGB_565:
765 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
766 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
767 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
768 MSM_ROTATOR_OUT_PACK_PATTERN1);
769 abits = 0;
770 rbits = COMPONENT_5BITS;
771 gbits = COMPONENT_6BITS;
772 bbits = COMPONENT_5BITS;
773 break;
774
775 case MDP_BGR_565:
776 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
777 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
778 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
779 MSM_ROTATOR_OUT_PACK_PATTERN1);
780 abits = 0;
781 rbits = COMPONENT_5BITS;
782 gbits = COMPONENT_6BITS;
783 bbits = COMPONENT_5BITS;
784 break;
785
786 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700787 case MDP_YCBCR_H1V1:
788 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700789 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
790 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
791 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
792 MSM_ROTATOR_OUT_PACK_PATTERN1);
793 abits = 0;
794 rbits = COMPONENT_8BITS;
795 gbits = COMPONENT_8BITS;
796 bbits = COMPONENT_8BITS;
797 break;
798
799 case MDP_ARGB_8888:
800 case MDP_RGBA_8888:
801 case MDP_XRGB_8888:
802 case MDP_RGBX_8888:
803 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
804 CLR_B, 8),
805 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
806 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
807 CLR_B, 8),
808 MSM_ROTATOR_OUT_PACK_PATTERN1);
809 abits = COMPONENT_8BITS;
810 rbits = COMPONENT_8BITS;
811 gbits = COMPONENT_8BITS;
812 bbits = COMPONENT_8BITS;
813 break;
814
815 case MDP_BGRA_8888:
Pawan Kumar7b5297f2013-05-27 11:54:27 +0530816 case MDP_BGRX_8888:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700817 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
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800859 *p_need = 0;
860
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700861#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700862 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
863 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700864 if (file == NULL) {
865 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700866 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700867 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700868
Naseer Ahmed18018602011-10-25 13:32:58 -0700869 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
870 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700871 if (get_fb_phys_info(start, len, fb_num,
872 ROTATOR_SUBSYSTEM_ID)) {
873 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700874 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700875 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700876 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800877 *p_need = put_needed;
878 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700879 } else {
880 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700881 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700882 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700883 if (ret)
884 fput_light(file, put_needed);
885 return ret;
886 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700887#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700888
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700889 return msm_rotator_iommu_map_buf(fbd->memory_id, domain, start,
890 len, p_ihdl, secure);
Naseer Ahmed18018602011-10-25 13:32:58 -0700891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892}
893
Olav Hauganef95ae32012-05-15 09:50:30 -0700894static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700895 int domain, unsigned int secure)
Naseer Ahmed18018602011-10-25 13:32:58 -0700896{
Naseer Ahmed18018602011-10-25 13:32:58 -0700897#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700898 if (!IS_ERR_OR_NULL(p_ihdl)) {
899 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700900 if (rot_iommu_split_domain) {
901 if (!secure)
902 ion_unmap_iommu(msm_rotator_dev->client,
903 p_ihdl, domain, GEN_POOL);
904 } else {
905 ion_unmap_iommu(msm_rotator_dev->client,
906 p_ihdl, ROTATOR_SRC_DOMAIN, GEN_POOL);
907 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700908
Naseer Ahmed18018602011-10-25 13:32:58 -0700909 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700910 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700911#endif
912}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700913static int msm_rotator_do_rotate(unsigned long arg)
914{
Naseer Ahmed18018602011-10-25 13:32:58 -0700915 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700916 struct msm_rotator_data_info info;
917 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700918 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700919 int use_imem = 0, rc = 0, s;
920 struct file *srcp0_file = NULL, *dstp0_file = NULL;
921 struct file *srcp1_file = NULL, *dstp1_file = NULL;
922 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
923 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800924 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700925 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700926 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700927 struct msm_rotator_img_info *img_info;
928 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700929
930 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
931 return -EFAULT;
932
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700933 mutex_lock(&msm_rotator_dev->rotator_lock);
934 for (s = 0; s < MAX_SESSIONS; s++)
935 if ((msm_rotator_dev->img_info[s] != NULL) &&
936 (info.session_id ==
937 (unsigned int)msm_rotator_dev->img_info[s]
938 ))
939 break;
940
941 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700942 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700943 __func__, s);
944 rc = -EINVAL;
945 goto do_rotate_unlock_mutex;
946 }
947
948 if (msm_rotator_dev->img_info[s]->enable == 0) {
949 dev_dbg(msm_rotator_dev->device,
950 "%s() : Session_id %d not enabled \n",
951 __func__, s);
952 rc = -EINVAL;
953 goto do_rotate_unlock_mutex;
954 }
955
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700956 img_info = msm_rotator_dev->img_info[s];
957 if (msm_rotator_get_plane_sizes(img_info->src.format,
958 img_info->src.width,
959 img_info->src.height,
960 &src_planes)) {
961 pr_err("%s: invalid src format\n", __func__);
962 rc = -EINVAL;
963 goto do_rotate_unlock_mutex;
964 }
965 if (msm_rotator_get_plane_sizes(img_info->dst.format,
966 img_info->dst.width,
967 img_info->dst.height,
968 &dst_planes)) {
969 pr_err("%s: invalid dst format\n", __func__);
970 rc = -EINVAL;
971 goto do_rotate_unlock_mutex;
972 }
973
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700974 rc = get_img(&info.src, ROTATOR_SRC_DOMAIN, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700975 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700976 &srcp0_ihdl, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700977 if (rc) {
978 pr_err("%s: in get_img() failed id=0x%08x\n",
979 DRIVER_NAME, info.src.memory_id);
980 goto do_rotate_unlock_mutex;
981 }
982
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700983 rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700984 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700985 &dstp0_ihdl, img_info->secure);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700986 if (rc) {
987 pr_err("%s: out get_img() failed id=0x%08x\n",
988 DRIVER_NAME, info.dst.memory_id);
989 goto do_rotate_unlock_mutex;
990 }
991
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700992 format = msm_rotator_dev->img_info[s]->src.format;
993 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700994 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
995 (src_planes.num_planes == 2)) {
996 if (checkoffset(info.src.offset,
997 src_planes.plane_size[0],
998 src_len)) {
999 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1000 __func__, src_len, info.src.offset);
1001 rc = -ERANGE;
1002 goto do_rotate_unlock_mutex;
1003 }
1004 if (checkoffset(info.dst.offset,
1005 dst_planes.plane_size[0],
1006 dst_len)) {
1007 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1008 __func__, dst_len, info.dst.offset);
1009 rc = -ERANGE;
1010 goto do_rotate_unlock_mutex;
1011 }
1012
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001013 rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001014 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001015 (unsigned long *)&src_len, &srcp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001016 &srcp1_ihdl, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001018 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001019 DRIVER_NAME, info.src_chroma.memory_id);
1020 goto do_rotate_unlock_mutex;
1021 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001022
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001023 rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001024 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001025 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001026 &dstp1_ihdl, img_info->secure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001027 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001028 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001029 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001030 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001031 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001032
1033 if (checkoffset(info.src_chroma.offset,
1034 src_planes.plane_size[1],
1035 src_len)) {
1036 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1037 __func__, src_len, info.src_chroma.offset);
1038 rc = -ERANGE;
1039 goto do_rotate_unlock_mutex;
1040 }
1041
1042 if (checkoffset(info.dst_chroma.offset,
1043 src_planes.plane_size[1],
1044 dst_len)) {
1045 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1046 __func__, dst_len, info.dst_chroma.offset);
1047 rc = -ERANGE;
1048 goto do_rotate_unlock_mutex;
1049 }
1050
1051 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001052 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001053 } else {
1054 if (checkoffset(info.src.offset,
1055 src_planes.total_size,
1056 src_len)) {
1057 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1058 __func__, src_len, info.src.offset);
1059 rc = -ERANGE;
1060 goto do_rotate_unlock_mutex;
1061 }
1062 if (checkoffset(info.dst.offset,
1063 dst_planes.total_size,
1064 dst_len)) {
1065 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1066 __func__, dst_len, info.dst.offset);
1067 rc = -ERANGE;
1068 goto do_rotate_unlock_mutex;
1069 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001070 }
1071
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001072 in_paddr += info.src.offset;
1073 out_paddr += info.dst.offset;
1074
1075 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1076 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1077 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1078 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1079 if (src_planes.num_planes >= 3)
1080 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1081
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001082 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1083 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1084 enable_rot_clks();
1085 msm_rotator_dev->rot_clk_state = CLK_EN;
1086 }
1087 enable_irq(msm_rotator_dev->irq);
1088
1089#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1090 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1091#else
1092 use_imem = 0;
1093#endif
1094 /*
1095 * workaround for a hardware bug. rotator hardware hangs when we
1096 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1097 * temporary fix use 0x42 for BURST_SIZE when imem used.
1098 */
1099 if (use_imem)
1100 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1101
1102 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1103 << 16) |
1104 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1105 MSM_ROTATOR_SRC_SIZE);
1106 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1107 << 16) |
1108 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1109 MSM_ROTATOR_SRC_XY);
1110 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1111 << 16) |
1112 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1113 MSM_ROTATOR_SRC_IMAGE_SIZE);
1114
1115 switch (format) {
1116 case MDP_RGB_565:
1117 case MDP_BGR_565:
1118 case MDP_RGB_888:
1119 case MDP_ARGB_8888:
1120 case MDP_RGBA_8888:
1121 case MDP_XRGB_8888:
1122 case MDP_BGRA_8888:
1123 case MDP_RGBX_8888:
Pawan Kumar7b5297f2013-05-27 11:54:27 +05301124 case MDP_BGRX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001125 case MDP_YCBCR_H1V1:
1126 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001127 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1128 in_paddr, out_paddr,
1129 use_imem,
1130 msm_rotator_dev->last_session_idx
1131 != s);
1132 break;
1133 case MDP_Y_CBCR_H2V2:
1134 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001135 case MDP_Y_CB_CR_H2V2:
1136 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301137 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001138 case MDP_Y_CRCB_H2V2_TILE:
1139 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001140 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1141 in_paddr, out_paddr, use_imem,
1142 msm_rotator_dev->last_session_idx
1143 != s,
1144 in_chroma_paddr,
1145 out_chroma_paddr,
1146 in_chroma2_paddr);
1147 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001148 case MDP_Y_CBCR_H2V1:
1149 case MDP_Y_CRCB_H2V1:
1150 rc = msm_rotator_ycxcx_h2v1(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 break;
1157 case MDP_YCRYCB_H2V1:
1158 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1159 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301160 msm_rotator_dev->last_session_idx != s,
1161 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001162 break;
1163 default:
1164 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001165 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001166 goto do_rotate_exit;
1167 }
1168
1169 if (rc != 0) {
1170 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001171 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001172 goto do_rotate_exit;
1173 }
1174
1175 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1176
1177 msm_rotator_dev->processing = 1;
1178 iowrite32(0x1, MSM_ROTATOR_START);
1179
1180 wait_event(msm_rotator_dev->wq,
1181 (msm_rotator_dev->processing == 0));
1182 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001183 if ((status & 0x03) != 0x01) {
1184 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1185 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001187 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1189 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1190
1191do_rotate_exit:
1192 disable_irq(msm_rotator_dev->irq);
1193#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1194 msm_rotator_imem_free(ROTATOR_REQUEST);
1195#endif
1196 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001197do_rotate_unlock_mutex:
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001198 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
1199 msm_rotator_dev->img_info[s]->secure);
1200 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1201 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
1202 msm_rotator_dev->img_info[s]->secure);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001203
1204 /* only source may use frame buffer */
1205 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1206 fput_light(srcp0_file, ps0_need);
1207 else
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001208 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001209 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001210 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1211 __func__, rc);
1212 return rc;
1213}
1214
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001215static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1216{
1217 u32 perf_level;
1218
1219 if (is_rgb)
1220 perf_level = 1;
1221 else if (wh <= (640 * 480))
1222 perf_level = 2;
1223 else if (wh <= (736 * 1280))
1224 perf_level = 3;
1225 else
1226 perf_level = 4;
1227
1228#ifdef CONFIG_MSM_BUS_SCALING
1229 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1230 perf_level);
1231#endif
1232
1233}
1234
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001235static int msm_rotator_start(unsigned long arg,
1236 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001237{
1238 struct msm_rotator_img_info info;
1239 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001240 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001242 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001243
1244 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1245 return -EFAULT;
1246
1247 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1248 (info.src.height > MSM_ROTATOR_MAX_H) ||
1249 (info.src.width > MSM_ROTATOR_MAX_W) ||
1250 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1251 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001252 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1253 pr_err("%s: Invalid parameters\n", __func__);
1254 return -EINVAL;
1255 }
1256
1257 if (info.rotations & MDP_ROT_90) {
1258 dst_w = info.src_rect.h >> info.downscale_ratio;
1259 dst_h = info.src_rect.w >> info.downscale_ratio;
1260 } else {
1261 dst_w = info.src_rect.w >> info.downscale_ratio;
1262 dst_h = info.src_rect.h >> info.downscale_ratio;
1263 }
1264
1265 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001266 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1267 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001268 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1269 pr_err("%s: Invalid src or dst rect\n", __func__);
1270 return -ERANGE;
1271 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001272
1273 switch (info.src.format) {
1274 case MDP_RGB_565:
1275 case MDP_BGR_565:
1276 case MDP_RGB_888:
1277 case MDP_ARGB_8888:
1278 case MDP_RGBA_8888:
1279 case MDP_XRGB_8888:
1280 case MDP_RGBX_8888:
1281 case MDP_BGRA_8888:
Pawan Kumar7b5297f2013-05-27 11:54:27 +05301282 case MDP_BGRX_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001283 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301284 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001285 break;
Mayank Goyal5f91c922012-11-07 16:58:09 +05301286 case MDP_Y_CBCR_H2V1:
1287 if (info.rotations & MDP_ROT_90) {
1288 info.dst.format = MDP_Y_CBCR_H1V2;
1289 break;
1290 }
1291 case MDP_Y_CRCB_H2V1:
1292 if (info.rotations & MDP_ROT_90) {
1293 info.dst.format = MDP_Y_CRCB_H1V2;
1294 break;
1295 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296 case MDP_Y_CBCR_H2V2:
1297 case MDP_Y_CRCB_H2V2:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001298 case MDP_YCBCR_H1V1:
1299 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301300 info.dst.format = info.src.format;
1301 break;
1302 case MDP_YCRYCB_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +05301303 if (info.rotations & MDP_ROT_90)
1304 info.dst.format = MDP_Y_CRCB_H1V2;
1305 else
1306 info.dst.format = MDP_Y_CRCB_H2V1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301307 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001308 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301309 case MDP_Y_CBCR_H2V2_TILE:
1310 info.dst.format = MDP_Y_CBCR_H2V2;
1311 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001312 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301313 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301315 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001316 break;
1317 default:
1318 return -EINVAL;
1319 }
1320
1321 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001322
1323 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1324
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001325 for (s = 0; s < MAX_SESSIONS; s++) {
1326 if ((msm_rotator_dev->img_info[s] != NULL) &&
1327 (info.session_id ==
1328 (unsigned int)msm_rotator_dev->img_info[s]
1329 )) {
1330 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001331 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001332
1333 if (msm_rotator_dev->last_session_idx == s)
1334 msm_rotator_dev->last_session_idx =
1335 INVALID_SESSION;
1336 break;
1337 }
1338
1339 if ((msm_rotator_dev->img_info[s] == NULL) &&
1340 (first_free_index ==
1341 INVALID_SESSION))
1342 first_free_index = s;
1343 }
1344
1345 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1346 /* allocate a session id */
1347 msm_rotator_dev->img_info[first_free_index] =
1348 kzalloc(sizeof(struct msm_rotator_img_info),
1349 GFP_KERNEL);
1350 if (!msm_rotator_dev->img_info[first_free_index]) {
1351 printk(KERN_ERR "%s : unable to alloc mem\n",
1352 __func__);
1353 rc = -ENOMEM;
1354 goto rotator_start_exit;
1355 }
1356 info.session_id = (unsigned int)
1357 msm_rotator_dev->img_info[first_free_index];
1358 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001359 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 } else if (s == MAX_SESSIONS) {
1361 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1362 __func__);
1363 rc = -EBUSY;
1364 }
1365
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001366 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1367 rc = -EFAULT;
1368
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001369rotator_start_exit:
1370 mutex_unlock(&msm_rotator_dev->rotator_lock);
1371
1372 return rc;
1373}
1374
1375static int msm_rotator_finish(unsigned long arg)
1376{
1377 int rc = 0;
1378 int s;
1379 unsigned int session_id;
1380
1381 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1382 return -EFAULT;
1383
1384 mutex_lock(&msm_rotator_dev->rotator_lock);
1385 for (s = 0; s < MAX_SESSIONS; s++) {
1386 if ((msm_rotator_dev->img_info[s] != NULL) &&
1387 (session_id ==
1388 (unsigned int)msm_rotator_dev->img_info[s])) {
1389 if (msm_rotator_dev->last_session_idx == s)
1390 msm_rotator_dev->last_session_idx =
1391 INVALID_SESSION;
1392 kfree(msm_rotator_dev->img_info[s]);
1393 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001394 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 break;
1396 }
1397 }
1398
1399 if (s == MAX_SESSIONS)
1400 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001401#ifdef CONFIG_MSM_BUS_SCALING
1402 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1403 0);
1404#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 mutex_unlock(&msm_rotator_dev->rotator_lock);
1406 return rc;
1407}
1408
1409static int
1410msm_rotator_open(struct inode *inode, struct file *filp)
1411{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001412 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 int i;
1414
1415 if (filp->private_data)
1416 return -EBUSY;
1417
1418 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001419 for (i = 0; i < MAX_SESSIONS; i++) {
1420 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001421 break;
1422 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001423
1424 if (i == MAX_SESSIONS) {
1425 mutex_unlock(&msm_rotator_dev->rotator_lock);
1426 return -EBUSY;
1427 }
1428
1429 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1430 if (tmp->pid == current->pid) {
1431 fd_info = tmp;
1432 break;
1433 }
1434 }
1435
1436 if (!fd_info) {
1437 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1438 if (!fd_info) {
1439 mutex_unlock(&msm_rotator_dev->rotator_lock);
1440 pr_err("%s: insufficient memory to alloc resources\n",
1441 __func__);
1442 return -ENOMEM;
1443 }
1444 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1445 fd_info->pid = current->pid;
1446 }
1447 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448 mutex_unlock(&msm_rotator_dev->rotator_lock);
1449
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001450 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001451
1452 return 0;
1453}
1454
1455static int
1456msm_rotator_close(struct inode *inode, struct file *filp)
1457{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001458 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001459 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001461 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1462
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001463 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001464 if (--fd_info->ref_cnt > 0) {
1465 mutex_unlock(&msm_rotator_dev->rotator_lock);
1466 return 0;
1467 }
1468
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001469 for (s = 0; s < MAX_SESSIONS; s++) {
1470 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001471 msm_rotator_dev->fd_info[s] == fd_info) {
1472 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1473 __func__, msm_rotator_dev->img_info[s],
1474 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 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 if (msm_rotator_dev->last_session_idx == s)
1479 msm_rotator_dev->last_session_idx =
1480 INVALID_SESSION;
1481 }
1482 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001483 list_del(&fd_info->list);
1484 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001485 mutex_unlock(&msm_rotator_dev->rotator_lock);
1486
1487 return 0;
1488}
1489
1490static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1491 unsigned long arg)
1492{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001493 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001494
1495 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1496 return -ENOTTY;
1497
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001498 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001499
1500 switch (cmd) {
1501 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001502 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001503 case MSM_ROTATOR_IOCTL_ROTATE:
1504 return msm_rotator_do_rotate(arg);
1505 case MSM_ROTATOR_IOCTL_FINISH:
1506 return msm_rotator_finish(arg);
1507
1508 default:
1509 dev_dbg(msm_rotator_dev->device,
1510 "unexpected IOCTL %d\n", cmd);
1511 return -ENOTTY;
1512 }
1513}
1514
1515static const struct file_operations msm_rotator_fops = {
1516 .owner = THIS_MODULE,
1517 .open = msm_rotator_open,
1518 .release = msm_rotator_close,
1519 .unlocked_ioctl = msm_rotator_ioctl,
1520};
1521
1522static int __devinit msm_rotator_probe(struct platform_device *pdev)
1523{
1524 int rc = 0;
1525 struct resource *res;
1526 struct msm_rotator_platform_data *pdata = NULL;
1527 int i, number_of_clks;
1528 uint32_t ver;
1529
1530 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1531 if (!msm_rotator_dev) {
1532 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1533 __func__);
1534 return -ENOMEM;
1535 }
1536 for (i = 0; i < MAX_SESSIONS; i++)
1537 msm_rotator_dev->img_info[i] = NULL;
1538 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1539
1540 pdata = pdev->dev.platform_data;
1541 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07001542 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001543
1544 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1545 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001546 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001547 msm_rotator_dev->imem_clk_state = CLK_DIS;
1548 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1549 msm_rotator_imem_clk_work_f);
1550 msm_rotator_dev->imem_clk = NULL;
1551 msm_rotator_dev->pdev = pdev;
1552
1553 msm_rotator_dev->core_clk = NULL;
1554 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001555
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001556#ifdef CONFIG_MSM_BUS_SCALING
1557 if (!msm_rotator_dev->bus_client_handle && pdata &&
1558 pdata->bus_scale_table) {
1559 msm_rotator_dev->bus_client_handle =
1560 msm_bus_scale_register_client(
1561 pdata->bus_scale_table);
1562 if (!msm_rotator_dev->bus_client_handle) {
1563 pr_err("%s not able to get bus scale handle\n",
1564 __func__);
1565 }
1566 }
1567#endif
1568
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001569 for (i = 0; i < number_of_clks; i++) {
1570 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1571 msm_rotator_dev->imem_clk =
1572 clk_get(&msm_rotator_dev->pdev->dev,
1573 pdata->rotator_clks[i].clk_name);
1574 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1575 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1576 msm_rotator_dev->imem_clk = NULL;
1577 printk(KERN_ERR "%s: cannot get imem_clk "
1578 "rc=%d\n", DRIVER_NAME, rc);
1579 goto error_imem_clk;
1580 }
1581 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001582 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 pdata->rotator_clks[i].clk_rate);
1584 }
1585 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1586 msm_rotator_dev->pclk =
1587 clk_get(&msm_rotator_dev->pdev->dev,
1588 pdata->rotator_clks[i].clk_name);
1589 if (IS_ERR(msm_rotator_dev->pclk)) {
1590 rc = PTR_ERR(msm_rotator_dev->pclk);
1591 msm_rotator_dev->pclk = NULL;
1592 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1593 DRIVER_NAME, rc);
1594 goto error_pclk;
1595 }
1596
1597 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001598 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001599 pdata->rotator_clks[i].clk_rate);
1600 }
1601
1602 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1603 msm_rotator_dev->core_clk =
1604 clk_get(&msm_rotator_dev->pdev->dev,
1605 pdata->rotator_clks[i].clk_name);
1606 if (IS_ERR(msm_rotator_dev->core_clk)) {
1607 rc = PTR_ERR(msm_rotator_dev->core_clk);
1608 msm_rotator_dev->core_clk = NULL;
1609 printk(KERN_ERR "%s: cannot get core clk "
1610 "rc=%d\n", DRIVER_NAME, rc);
1611 goto error_core_clk;
1612 }
1613
1614 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001615 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001616 pdata->rotator_clks[i].clk_rate);
1617 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001618 }
1619
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001620 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1621 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001622 if (IS_ERR(msm_rotator_dev->regulator))
1623 msm_rotator_dev->regulator = NULL;
1624
1625 msm_rotator_dev->rot_clk_state = CLK_DIS;
1626 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1627 msm_rotator_rot_clk_work_f);
1628
1629 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001630#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1631 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1632#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001633 platform_set_drvdata(pdev, msm_rotator_dev);
1634
1635
1636 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1637 if (!res) {
1638 printk(KERN_ALERT
1639 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1640 rc = -ENODEV;
1641 goto error_get_resource;
1642 }
1643 msm_rotator_dev->io_base = ioremap(res->start,
1644 resource_size(res));
1645
1646#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1647 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001648 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649#endif
1650 enable_rot_clks();
1651 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1652 disable_rot_clks();
1653
1654#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1655 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001656 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001658 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301659 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001660 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001661
Mayank Chopra012a8e72012-04-11 10:41:13 +05301662 rotator_hw_revision = ver;
1663 rotator_hw_revision >>= 16; /* bit 31:16 */
1664 rotator_hw_revision &= 0xff;
1665
1666 pr_info("%s: rotator_hw_revision=%x\n",
1667 __func__, rotator_hw_revision);
1668
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1670 if (msm_rotator_dev->irq < 0) {
1671 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1672 DRIVER_NAME);
1673 rc = -ENODEV;
1674 goto error_get_irq;
1675 }
1676 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1677 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1678 if (rc) {
1679 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1680 goto error_get_irq;
1681 }
1682 /* we enable the IRQ when we need it in the ioctl */
1683 disable_irq(msm_rotator_dev->irq);
1684
1685 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1686 if (rc < 0) {
1687 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1688 __func__, rc);
1689 goto error_get_irq;
1690 }
1691
1692 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1693 if (IS_ERR(msm_rotator_dev->class)) {
1694 rc = PTR_ERR(msm_rotator_dev->class);
1695 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1696 DRIVER_NAME, rc);
1697 goto error_class_create;
1698 }
1699
1700 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1701 msm_rotator_dev->dev_num, NULL,
1702 DRIVER_NAME);
1703 if (IS_ERR(msm_rotator_dev->device)) {
1704 rc = PTR_ERR(msm_rotator_dev->device);
1705 printk(KERN_ERR "%s: device_create failed %d\n",
1706 DRIVER_NAME, rc);
1707 goto error_class_device_create;
1708 }
1709
1710 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1711 rc = cdev_add(&msm_rotator_dev->cdev,
1712 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1713 1);
1714 if (rc < 0) {
1715 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1716 goto error_cdev_add;
1717 }
1718
1719 init_waitqueue_head(&msm_rotator_dev->wq);
1720
1721 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1722 return rc;
1723
1724error_cdev_add:
1725 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1726error_class_device_create:
1727 class_destroy(msm_rotator_dev->class);
1728error_class_create:
1729 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1730error_get_irq:
1731 iounmap(msm_rotator_dev->io_base);
1732error_get_resource:
1733 mutex_destroy(&msm_rotator_dev->rotator_lock);
1734 if (msm_rotator_dev->regulator)
1735 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001736 clk_put(msm_rotator_dev->core_clk);
1737error_core_clk:
1738 clk_put(msm_rotator_dev->pclk);
1739error_pclk:
1740 if (msm_rotator_dev->imem_clk)
1741 clk_put(msm_rotator_dev->imem_clk);
1742error_imem_clk:
1743 mutex_destroy(&msm_rotator_dev->imem_lock);
1744 kfree(msm_rotator_dev);
1745 return rc;
1746}
1747
1748static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1749{
1750 int i;
1751
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001752#ifdef CONFIG_MSM_BUS_SCALING
1753 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1754#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001755 free_irq(msm_rotator_dev->irq, NULL);
1756 mutex_destroy(&msm_rotator_dev->rotator_lock);
1757 cdev_del(&msm_rotator_dev->cdev);
1758 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1759 class_destroy(msm_rotator_dev->class);
1760 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1761 iounmap(msm_rotator_dev->io_base);
1762 if (msm_rotator_dev->imem_clk) {
1763 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001764 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001765 clk_put(msm_rotator_dev->imem_clk);
1766 msm_rotator_dev->imem_clk = NULL;
1767 }
1768 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1769 disable_rot_clks();
1770 clk_put(msm_rotator_dev->core_clk);
1771 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 if (msm_rotator_dev->regulator)
1773 regulator_put(msm_rotator_dev->regulator);
1774 msm_rotator_dev->core_clk = NULL;
1775 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001776 mutex_destroy(&msm_rotator_dev->imem_lock);
1777 for (i = 0; i < MAX_SESSIONS; i++)
1778 if (msm_rotator_dev->img_info[i] != NULL)
1779 kfree(msm_rotator_dev->img_info[i]);
1780 kfree(msm_rotator_dev);
1781 return 0;
1782}
1783
1784#ifdef CONFIG_PM
1785static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1786{
1787 mutex_lock(&msm_rotator_dev->imem_lock);
1788 if (msm_rotator_dev->imem_clk_state == CLK_EN
1789 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001790 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001791 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1792 }
1793 mutex_unlock(&msm_rotator_dev->imem_lock);
1794 mutex_lock(&msm_rotator_dev->rotator_lock);
1795 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1796 disable_rot_clks();
1797 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1798 }
1799 mutex_unlock(&msm_rotator_dev->rotator_lock);
1800 return 0;
1801}
1802
1803static int msm_rotator_resume(struct platform_device *dev)
1804{
1805 mutex_lock(&msm_rotator_dev->imem_lock);
1806 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1807 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001808 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001809 msm_rotator_dev->imem_clk_state = CLK_EN;
1810 }
1811 mutex_unlock(&msm_rotator_dev->imem_lock);
1812 mutex_lock(&msm_rotator_dev->rotator_lock);
1813 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
1814 enable_rot_clks();
1815 msm_rotator_dev->rot_clk_state = CLK_EN;
1816 }
1817 mutex_unlock(&msm_rotator_dev->rotator_lock);
1818 return 0;
1819}
1820#endif
1821
1822static struct platform_driver msm_rotator_platform_driver = {
1823 .probe = msm_rotator_probe,
1824 .remove = __devexit_p(msm_rotator_remove),
1825#ifdef CONFIG_PM
1826 .suspend = msm_rotator_suspend,
1827 .resume = msm_rotator_resume,
1828#endif
1829 .driver = {
1830 .owner = THIS_MODULE,
1831 .name = DRIVER_NAME
1832 }
1833};
1834
1835static int __init msm_rotator_init(void)
1836{
1837 return platform_driver_register(&msm_rotator_platform_driver);
1838}
1839
1840static void __exit msm_rotator_exit(void)
1841{
1842 return platform_driver_unregister(&msm_rotator_platform_driver);
1843}
1844
1845module_init(msm_rotator_init);
1846module_exit(msm_rotator_exit);
1847
1848MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1849MODULE_VERSION("1.0");
1850MODULE_LICENSE("GPL v2");