blob: b0fb9d8d28f98c4e2205ab4a6ee178d401f0b6f2 [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/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/msm_subsystem_map.h>
36#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070037
38#define DRIVER_NAME "msm_rotator"
39
40#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
41#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
42#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
43#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
44#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
45#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
46#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -070047#define MSM_ROTATOR_SW_RESET (MSM_ROTATOR_BASE+0x0074)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070048#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
49#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
50#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070051#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
53#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
54#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
55#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
56#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
57#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
58#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
59#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070060#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070061#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
62#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
63#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
64#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
65
66#define MSM_ROTATOR_MAX_ROT 0x07
67#define MSM_ROTATOR_MAX_H 0x1fff
68#define MSM_ROTATOR_MAX_W 0x1fff
69
70/* from lsb to msb */
71#define GET_PACK_PATTERN(a, x, y, z, bit) \
72 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
73#define CLR_G 0x0
74#define CLR_B 0x1
75#define CLR_R 0x2
76#define CLR_ALPHA 0x3
77
78#define CLR_Y CLR_G
79#define CLR_CB CLR_B
80#define CLR_CR CLR_R
81
82#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
83 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
84 (((r) & MDP_FLIP_UD) ? 4 : 0))
85
86#define IMEM_NO_OWNER -1;
87
88#define MAX_SESSIONS 16
89#define INVALID_SESSION -1
90#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070091#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070092
Mayank Chopra012a8e72012-04-11 10:41:13 +053093#define ROTATOR_REVISION_V0 0
94#define ROTATOR_REVISION_V1 1
95#define ROTATOR_REVISION_V2 2
96#define ROTATOR_REVISION_NONE 0xffffffff
97
98uint32_t rotator_hw_revision;
Olav Hauganef95ae32012-05-15 09:50:30 -070099static char rot_iommu_split_domain;
Mayank Chopra012a8e72012-04-11 10:41:13 +0530100
101/*
102 * rotator_hw_revision:
103 * 0 == 7x30
104 * 1 == 8x60
105 * 2 == 8960
106 *
107 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700108struct tile_parm {
109 unsigned int width; /* tile's width */
110 unsigned int height; /* tile's height */
111 unsigned int row_tile_w; /* tiles per row's width */
112 unsigned int row_tile_h; /* tiles per row's height */
113};
114
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700115struct msm_rotator_mem_planes {
116 unsigned int num_planes;
117 unsigned int plane_size[4];
118 unsigned int total_size;
119};
120
121#define checkoffset(offset, size, max_size) \
122 ((size) > (max_size) || (offset) > ((max_size) - (size)))
123
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700124struct msm_rotator_fd_info {
125 int pid;
126 int ref_cnt;
127 struct list_head list;
128};
129
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700130struct msm_rotator_dev {
131 void __iomem *io_base;
132 int irq;
133 struct msm_rotator_img_info *img_info[MAX_SESSIONS];
134 struct clk *core_clk;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700135 struct msm_rotator_fd_info *fd_info[MAX_SESSIONS];
136 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700137 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700138 int rot_clk_state;
139 struct regulator *regulator;
140 struct delayed_work rot_clk_work;
141 struct clk *imem_clk;
142 int imem_clk_state;
143 struct delayed_work imem_clk_work;
144 struct platform_device *pdev;
145 struct cdev cdev;
146 struct device *device;
147 struct class *class;
148 dev_t dev_num;
149 int processing;
150 int last_session_idx;
151 struct mutex rotator_lock;
152 struct mutex imem_lock;
153 int imem_owner;
154 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700155 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800156 #ifdef CONFIG_MSM_BUS_SCALING
157 uint32_t bus_client_handle;
158 #endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159};
160
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700161#define COMPONENT_5BITS 1
162#define COMPONENT_6BITS 2
163#define COMPONENT_8BITS 3
164
165static struct msm_rotator_dev *msm_rotator_dev;
166
167enum {
168 CLK_EN,
169 CLK_DIS,
170 CLK_SUSPEND,
171};
172
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700173int msm_rotator_iommu_map_buf(int mem_id, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700174 unsigned long *start, unsigned long *len,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700175 struct ion_handle **pihdl, unsigned int secure)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700176{
177 if (!msm_rotator_dev->client)
178 return -EINVAL;
179
Laura Abbottb14ed962012-01-30 14:18:08 -0800180 *pihdl = ion_import_dma_buf(msm_rotator_dev->client, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700181 if (IS_ERR_OR_NULL(*pihdl)) {
Laura Abbottb14ed962012-01-30 14:18:08 -0800182 pr_err("ion_import_dma_buf() failed\n");
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700183 return PTR_ERR(*pihdl);
184 }
Laura Abbottb14ed962012-01-30 14:18:08 -0800185 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl,
186 ion_share_dma_buf(msm_rotator_dev->client, *pihdl));
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700187
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700188 if (rot_iommu_split_domain) {
189 if (secure) {
190 if (ion_phys(msm_rotator_dev->client,
191 *pihdl, start, (unsigned *)len)) {
192 pr_err("%s:%d: ion_phys map failed\n",
193 __func__, __LINE__);
194 return -ENOMEM;
195 }
196 } else {
197 if (ion_map_iommu(msm_rotator_dev->client,
198 *pihdl, domain, GEN_POOL,
199 SZ_4K, 0, start, len, 0,
200 ION_IOMMU_UNMAP_DELAYED)) {
201 pr_err("ion_map_iommu() failed\n");
202 return -EINVAL;
203 }
204 }
205 } else {
206 if (ion_map_iommu(msm_rotator_dev->client,
207 *pihdl, ROTATOR_SRC_DOMAIN, GEN_POOL,
208 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
209 pr_err("ion_map_iommu() failed\n");
210 return -EINVAL;
211 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700212 }
213
214 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
215 __func__, mem_id, *start, *len);
216 return 0;
217}
218
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700219int msm_rotator_imem_allocate(int requestor)
220{
221 int rc = 0;
222
223#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
224 switch (requestor) {
225 case ROTATOR_REQUEST:
226 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
227 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
228 rc = 1;
229 } else
230 rc = 0;
231 break;
232 case JPEG_REQUEST:
233 mutex_lock(&msm_rotator_dev->imem_lock);
234 msm_rotator_dev->imem_owner = JPEG_REQUEST;
235 rc = 1;
236 break;
237 default:
238 rc = 0;
239 }
240#else
241 if (requestor == JPEG_REQUEST)
242 rc = 1;
243#endif
244 if (rc == 1) {
245 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
246 if (msm_rotator_dev->imem_clk_state != CLK_EN
247 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700248 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700249 msm_rotator_dev->imem_clk_state = CLK_EN;
250 }
251 }
252
253 return rc;
254}
255EXPORT_SYMBOL(msm_rotator_imem_allocate);
256
257void msm_rotator_imem_free(int requestor)
258{
259#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
260 if (msm_rotator_dev->imem_owner == requestor) {
261 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
262 mutex_unlock(&msm_rotator_dev->imem_lock);
263 }
264#else
265 if (requestor == JPEG_REQUEST)
266 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
267#endif
268}
269EXPORT_SYMBOL(msm_rotator_imem_free);
270
271static void msm_rotator_imem_clk_work_f(struct work_struct *work)
272{
273#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
274 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
275 if (msm_rotator_dev->imem_clk_state == CLK_EN
276 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700277 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700278 msm_rotator_dev->imem_clk_state = CLK_DIS;
279 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
280 msm_rotator_dev->imem_clk_state = CLK_DIS;
281 mutex_unlock(&msm_rotator_dev->imem_lock);
282 }
283#endif
284}
285
286/* enable clocks needed by rotator block */
287static void enable_rot_clks(void)
288{
289 if (msm_rotator_dev->regulator)
290 regulator_enable(msm_rotator_dev->regulator);
291 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700292 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700293 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700294 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700295}
296
297/* disable clocks needed by rotator block */
298static void disable_rot_clks(void)
299{
300 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700301 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700302 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700303 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700304 if (msm_rotator_dev->regulator)
305 regulator_disable(msm_rotator_dev->regulator);
306}
307
308static void msm_rotator_rot_clk_work_f(struct work_struct *work)
309{
310 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
311 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
312 disable_rot_clks();
313 msm_rotator_dev->rot_clk_state = CLK_DIS;
314 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
315 msm_rotator_dev->rot_clk_state = CLK_DIS;
316 mutex_unlock(&msm_rotator_dev->rotator_lock);
317 }
318}
319
320static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
321{
322 if (msm_rotator_dev->processing) {
323 msm_rotator_dev->processing = 0;
324 wake_up(&msm_rotator_dev->wq);
325 } else
326 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
327
328 return IRQ_HANDLED;
329}
330
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700331static unsigned int tile_size(unsigned int src_width,
332 unsigned int src_height,
333 const struct tile_parm *tp)
334{
335 unsigned int tile_w, tile_h;
336 unsigned int row_num_w, row_num_h;
337 tile_w = tp->width * tp->row_tile_w;
338 tile_h = tp->height * tp->row_tile_h;
339 row_num_w = (src_width + tile_w - 1) / tile_w;
340 row_num_h = (src_height + tile_h - 1) / tile_h;
341 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
342}
343
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344static int get_bpp(int format)
345{
346 switch (format) {
347 case MDP_RGB_565:
348 case MDP_BGR_565:
349 return 2;
350
351 case MDP_XRGB_8888:
352 case MDP_ARGB_8888:
353 case MDP_RGBA_8888:
354 case MDP_BGRA_8888:
355 case MDP_RGBX_8888:
356 return 4;
357
358 case MDP_Y_CBCR_H2V2:
359 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700360 case MDP_Y_CB_CR_H2V2:
361 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530362 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700363 case MDP_Y_CRCB_H2V2_TILE:
364 case MDP_Y_CBCR_H2V2_TILE:
365 return 1;
366
367 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700368 case MDP_YCBCR_H1V1:
369 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 return 3;
371
372 case MDP_YCRYCB_H2V1:
373 return 2;/* YCrYCb interleave */
374
375 case MDP_Y_CRCB_H2V1:
376 case MDP_Y_CBCR_H2V1:
377 return 1;
378
379 default:
380 return -1;
381 }
382
383}
384
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700385static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
386 struct msm_rotator_mem_planes *p)
387{
388 /*
389 * each row of samsung tile consists of two tiles in height
390 * and two tiles in width which means width should align to
391 * 64 x 2 bytes and height should align to 32 x 2 bytes.
392 * video decoder generate two tiles in width and one tile
393 * in height which ends up height align to 32 X 1 bytes.
394 */
395 const struct tile_parm tile = {64, 32, 2, 1};
396 int i;
397
398 if (p == NULL)
399 return -EINVAL;
400
401 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
402 return -ERANGE;
403
404 memset(p, 0, sizeof(*p));
405
406 switch (format) {
407 case MDP_XRGB_8888:
408 case MDP_ARGB_8888:
409 case MDP_RGBA_8888:
410 case MDP_BGRA_8888:
411 case MDP_RGBX_8888:
412 case MDP_RGB_888:
413 case MDP_RGB_565:
414 case MDP_BGR_565:
415 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700416 case MDP_YCBCR_H1V1:
417 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700418 p->num_planes = 1;
419 p->plane_size[0] = w * h * get_bpp(format);
420 break;
421 case MDP_Y_CRCB_H2V1:
422 case MDP_Y_CBCR_H2V1:
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:
816 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
817 CLR_R, 8),
818 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
819 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
820 CLR_R, 8),
821 MSM_ROTATOR_OUT_PACK_PATTERN1);
822 abits = COMPONENT_8BITS;
823 rbits = COMPONENT_8BITS;
824 gbits = COMPONENT_8BITS;
825 bbits = COMPONENT_8BITS;
826 break;
827
828 default:
829 return -EINVAL;
830 }
831 iowrite32(0 << 29 | /* frame format 0 = linear */
832 (use_imem ? 0 : 1) << 22 | /* tile size */
833 0 << 19 | /* fetch planes 0=interleaved */
834 0 << 18 | /* unpack align */
835 1 << 17 | /* unpack tight */
836 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
837 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
838 (abits ? 1 : 0) << 8 | /* has alpha */
839 abits << 6 | /* alpha bits 3=8bits */
840 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
841 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
842 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
843 MSM_ROTATOR_SRC_FORMAT);
844 }
845
846 return 0;
847}
848
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700849static int get_img(struct msmfb_data *fbd, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700850 unsigned long *start, unsigned long *len, struct file **p_file,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700851 int *p_need, struct ion_handle **p_ihdl, unsigned int secure)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700852{
853 int ret = 0;
854#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700855 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700856 int put_needed, fb_num;
857#endif
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800858 *p_need = 0;
859
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700860#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -0700861 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
862 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700863 if (file == NULL) {
864 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700865 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700866 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867
Naseer Ahmed18018602011-10-25 13:32:58 -0700868 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
869 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700870 if (get_fb_phys_info(start, len, fb_num,
871 ROTATOR_SUBSYSTEM_ID)) {
872 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -0700873 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700874 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -0700875 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800876 *p_need = put_needed;
877 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700878 } else {
879 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700880 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700881 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700882 if (ret)
883 fput_light(file, put_needed);
884 return ret;
885 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700886#endif
Naseer Ahmed18018602011-10-25 13:32:58 -0700887
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700888 return msm_rotator_iommu_map_buf(fbd->memory_id, domain, start,
889 len, p_ihdl, secure);
Naseer Ahmed18018602011-10-25 13:32:58 -0700890
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700891}
892
Olav Hauganef95ae32012-05-15 09:50:30 -0700893static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700894 int domain, unsigned int secure)
Naseer Ahmed18018602011-10-25 13:32:58 -0700895{
Naseer Ahmed18018602011-10-25 13:32:58 -0700896#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700897 if (!IS_ERR_OR_NULL(p_ihdl)) {
898 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700899 if (rot_iommu_split_domain) {
900 if (!secure)
901 ion_unmap_iommu(msm_rotator_dev->client,
902 p_ihdl, domain, GEN_POOL);
903 } else {
904 ion_unmap_iommu(msm_rotator_dev->client,
905 p_ihdl, ROTATOR_SRC_DOMAIN, GEN_POOL);
906 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700907
Naseer Ahmed18018602011-10-25 13:32:58 -0700908 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700909 }
Naseer Ahmed18018602011-10-25 13:32:58 -0700910#endif
911}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700912static int msm_rotator_do_rotate(unsigned long arg)
913{
Naseer Ahmed18018602011-10-25 13:32:58 -0700914 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700915 struct msm_rotator_data_info info;
916 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700917 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -0700918 int use_imem = 0, rc = 0, s;
919 struct file *srcp0_file = NULL, *dstp0_file = NULL;
920 struct file *srcp1_file = NULL, *dstp1_file = NULL;
921 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
922 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -0800923 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700924 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700925 unsigned int in_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700926 struct msm_rotator_img_info *img_info;
927 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700928
929 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
930 return -EFAULT;
931
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700932 mutex_lock(&msm_rotator_dev->rotator_lock);
933 for (s = 0; s < MAX_SESSIONS; s++)
934 if ((msm_rotator_dev->img_info[s] != NULL) &&
935 (info.session_id ==
936 (unsigned int)msm_rotator_dev->img_info[s]
937 ))
938 break;
939
940 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -0700941 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 __func__, s);
943 rc = -EINVAL;
944 goto do_rotate_unlock_mutex;
945 }
946
947 if (msm_rotator_dev->img_info[s]->enable == 0) {
948 dev_dbg(msm_rotator_dev->device,
949 "%s() : Session_id %d not enabled \n",
950 __func__, s);
951 rc = -EINVAL;
952 goto do_rotate_unlock_mutex;
953 }
954
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700955 img_info = msm_rotator_dev->img_info[s];
956 if (msm_rotator_get_plane_sizes(img_info->src.format,
957 img_info->src.width,
958 img_info->src.height,
959 &src_planes)) {
960 pr_err("%s: invalid src format\n", __func__);
961 rc = -EINVAL;
962 goto do_rotate_unlock_mutex;
963 }
964 if (msm_rotator_get_plane_sizes(img_info->dst.format,
965 img_info->dst.width,
966 img_info->dst.height,
967 &dst_planes)) {
968 pr_err("%s: invalid dst format\n", __func__);
969 rc = -EINVAL;
970 goto do_rotate_unlock_mutex;
971 }
972
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700973 rc = get_img(&info.src, ROTATOR_SRC_DOMAIN, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700974 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700975 &srcp0_ihdl, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700976 if (rc) {
977 pr_err("%s: in get_img() failed id=0x%08x\n",
978 DRIVER_NAME, info.src.memory_id);
979 goto do_rotate_unlock_mutex;
980 }
981
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700982 rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700983 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700984 &dstp0_ihdl, img_info->secure);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700985 if (rc) {
986 pr_err("%s: out get_img() failed id=0x%08x\n",
987 DRIVER_NAME, info.dst.memory_id);
988 goto do_rotate_unlock_mutex;
989 }
990
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991 format = msm_rotator_dev->img_info[s]->src.format;
992 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700993 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
994 (src_planes.num_planes == 2)) {
995 if (checkoffset(info.src.offset,
996 src_planes.plane_size[0],
997 src_len)) {
998 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
999 __func__, src_len, info.src.offset);
1000 rc = -ERANGE;
1001 goto do_rotate_unlock_mutex;
1002 }
1003 if (checkoffset(info.dst.offset,
1004 dst_planes.plane_size[0],
1005 dst_len)) {
1006 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1007 __func__, dst_len, info.dst.offset);
1008 rc = -ERANGE;
1009 goto do_rotate_unlock_mutex;
1010 }
1011
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001012 rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001013 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001014 (unsigned long *)&src_len, &srcp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001015 &srcp1_ihdl, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001016 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001017 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001018 DRIVER_NAME, info.src_chroma.memory_id);
1019 goto do_rotate_unlock_mutex;
1020 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001022 rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001023 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001024 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001025 &dstp1_ihdl, img_info->secure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001026 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001027 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001028 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001029 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001031
1032 if (checkoffset(info.src_chroma.offset,
1033 src_planes.plane_size[1],
1034 src_len)) {
1035 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1036 __func__, src_len, info.src_chroma.offset);
1037 rc = -ERANGE;
1038 goto do_rotate_unlock_mutex;
1039 }
1040
1041 if (checkoffset(info.dst_chroma.offset,
1042 src_planes.plane_size[1],
1043 dst_len)) {
1044 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1045 __func__, dst_len, info.dst_chroma.offset);
1046 rc = -ERANGE;
1047 goto do_rotate_unlock_mutex;
1048 }
1049
1050 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001051 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001052 } else {
1053 if (checkoffset(info.src.offset,
1054 src_planes.total_size,
1055 src_len)) {
1056 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1057 __func__, src_len, info.src.offset);
1058 rc = -ERANGE;
1059 goto do_rotate_unlock_mutex;
1060 }
1061 if (checkoffset(info.dst.offset,
1062 dst_planes.total_size,
1063 dst_len)) {
1064 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1065 __func__, dst_len, info.dst.offset);
1066 rc = -ERANGE;
1067 goto do_rotate_unlock_mutex;
1068 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001069 }
1070
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001071 in_paddr += info.src.offset;
1072 out_paddr += info.dst.offset;
1073
1074 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1075 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1076 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1077 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1078 if (src_planes.num_planes >= 3)
1079 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
1080
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001081 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1082 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1083 enable_rot_clks();
1084 msm_rotator_dev->rot_clk_state = CLK_EN;
1085 }
1086 enable_irq(msm_rotator_dev->irq);
1087
1088#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1089 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1090#else
1091 use_imem = 0;
1092#endif
1093 /*
1094 * workaround for a hardware bug. rotator hardware hangs when we
1095 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1096 * temporary fix use 0x42 for BURST_SIZE when imem used.
1097 */
1098 if (use_imem)
1099 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1100
1101 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.h & 0x1fff)
1102 << 16) |
1103 (msm_rotator_dev->img_info[s]->src_rect.w & 0x1fff),
1104 MSM_ROTATOR_SRC_SIZE);
1105 iowrite32(((msm_rotator_dev->img_info[s]->src_rect.y & 0x1fff)
1106 << 16) |
1107 (msm_rotator_dev->img_info[s]->src_rect.x & 0x1fff),
1108 MSM_ROTATOR_SRC_XY);
1109 iowrite32(((msm_rotator_dev->img_info[s]->src.height & 0x1fff)
1110 << 16) |
1111 (msm_rotator_dev->img_info[s]->src.width & 0x1fff),
1112 MSM_ROTATOR_SRC_IMAGE_SIZE);
1113
1114 switch (format) {
1115 case MDP_RGB_565:
1116 case MDP_BGR_565:
1117 case MDP_RGB_888:
1118 case MDP_ARGB_8888:
1119 case MDP_RGBA_8888:
1120 case MDP_XRGB_8888:
1121 case MDP_BGRA_8888:
1122 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001123 case MDP_YCBCR_H1V1:
1124 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001125 rc = msm_rotator_rgb_types(msm_rotator_dev->img_info[s],
1126 in_paddr, out_paddr,
1127 use_imem,
1128 msm_rotator_dev->last_session_idx
1129 != s);
1130 break;
1131 case MDP_Y_CBCR_H2V2:
1132 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001133 case MDP_Y_CB_CR_H2V2:
1134 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301135 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001136 case MDP_Y_CRCB_H2V2_TILE:
1137 case MDP_Y_CBCR_H2V2_TILE:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001138 rc = msm_rotator_ycxcx_h2v2(msm_rotator_dev->img_info[s],
1139 in_paddr, out_paddr, use_imem,
1140 msm_rotator_dev->last_session_idx
1141 != s,
1142 in_chroma_paddr,
1143 out_chroma_paddr,
1144 in_chroma2_paddr);
1145 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001146 case MDP_Y_CBCR_H2V1:
1147 case MDP_Y_CRCB_H2V1:
1148 rc = msm_rotator_ycxcx_h2v1(msm_rotator_dev->img_info[s],
1149 in_paddr, out_paddr, use_imem,
1150 msm_rotator_dev->last_session_idx
1151 != s,
1152 in_chroma_paddr,
1153 out_chroma_paddr);
1154 break;
1155 case MDP_YCRYCB_H2V1:
1156 rc = msm_rotator_ycrycb(msm_rotator_dev->img_info[s],
1157 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301158 msm_rotator_dev->last_session_idx != s,
1159 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001160 break;
1161 default:
1162 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001163 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001164 goto do_rotate_exit;
1165 }
1166
1167 if (rc != 0) {
1168 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001169 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001170 goto do_rotate_exit;
1171 }
1172
1173 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1174
1175 msm_rotator_dev->processing = 1;
1176 iowrite32(0x1, MSM_ROTATOR_START);
1177
1178 wait_event(msm_rotator_dev->wq,
1179 (msm_rotator_dev->processing == 0));
1180 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001181 if ((status & 0x03) != 0x01) {
1182 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1183 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001184 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001185 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001186 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1187 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1188
1189do_rotate_exit:
1190 disable_irq(msm_rotator_dev->irq);
1191#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1192 msm_rotator_imem_free(ROTATOR_REQUEST);
1193#endif
1194 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001195do_rotate_unlock_mutex:
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001196 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
1197 msm_rotator_dev->img_info[s]->secure);
1198 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1199 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
1200 msm_rotator_dev->img_info[s]->secure);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001201
1202 /* only source may use frame buffer */
1203 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1204 fput_light(srcp0_file, ps0_need);
1205 else
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001206 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001207 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1209 __func__, rc);
1210 return rc;
1211}
1212
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001213static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1214{
1215 u32 perf_level;
1216
1217 if (is_rgb)
1218 perf_level = 1;
1219 else if (wh <= (640 * 480))
1220 perf_level = 2;
1221 else if (wh <= (736 * 1280))
1222 perf_level = 3;
1223 else
1224 perf_level = 4;
1225
1226#ifdef CONFIG_MSM_BUS_SCALING
1227 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1228 perf_level);
1229#endif
1230
1231}
1232
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001233static int msm_rotator_start(unsigned long arg,
1234 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001235{
1236 struct msm_rotator_img_info info;
1237 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001238 int s, is_rgb = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001239 int first_free_index = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001240 unsigned int dst_w, dst_h;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241
1242 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1243 return -EFAULT;
1244
1245 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1246 (info.src.height > MSM_ROTATOR_MAX_H) ||
1247 (info.src.width > MSM_ROTATOR_MAX_W) ||
1248 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1249 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001250 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1251 pr_err("%s: Invalid parameters\n", __func__);
1252 return -EINVAL;
1253 }
1254
1255 if (info.rotations & MDP_ROT_90) {
1256 dst_w = info.src_rect.h >> info.downscale_ratio;
1257 dst_h = info.src_rect.w >> info.downscale_ratio;
1258 } else {
1259 dst_w = info.src_rect.w >> info.downscale_ratio;
1260 dst_h = info.src_rect.h >> info.downscale_ratio;
1261 }
1262
1263 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001264 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1265 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001266 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1267 pr_err("%s: Invalid src or dst rect\n", __func__);
1268 return -ERANGE;
1269 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001270
1271 switch (info.src.format) {
1272 case MDP_RGB_565:
1273 case MDP_BGR_565:
1274 case MDP_RGB_888:
1275 case MDP_ARGB_8888:
1276 case MDP_RGBA_8888:
1277 case MDP_XRGB_8888:
1278 case MDP_RGBX_8888:
1279 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001280 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301281 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001282 break;
Mayank Goyal5f91c922012-11-07 16:58:09 +05301283 case MDP_Y_CBCR_H2V1:
1284 if (info.rotations & MDP_ROT_90) {
1285 info.dst.format = MDP_Y_CBCR_H1V2;
1286 break;
1287 }
1288 case MDP_Y_CRCB_H2V1:
1289 if (info.rotations & MDP_ROT_90) {
1290 info.dst.format = MDP_Y_CRCB_H1V2;
1291 break;
1292 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 case MDP_Y_CBCR_H2V2:
1294 case MDP_Y_CRCB_H2V2:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001295 case MDP_YCBCR_H1V1:
1296 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301297 info.dst.format = info.src.format;
1298 break;
1299 case MDP_YCRYCB_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +05301300 if (info.rotations & MDP_ROT_90)
1301 info.dst.format = MDP_Y_CRCB_H1V2;
1302 else
1303 info.dst.format = MDP_Y_CRCB_H2V1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301304 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001305 case MDP_Y_CB_CR_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301306 case MDP_Y_CBCR_H2V2_TILE:
1307 info.dst.format = MDP_Y_CBCR_H2V2;
1308 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001309 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301310 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001311 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301312 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001313 break;
1314 default:
1315 return -EINVAL;
1316 }
1317
1318 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001319
1320 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 for (s = 0; s < MAX_SESSIONS; s++) {
1323 if ((msm_rotator_dev->img_info[s] != NULL) &&
1324 (info.session_id ==
1325 (unsigned int)msm_rotator_dev->img_info[s]
1326 )) {
1327 *(msm_rotator_dev->img_info[s]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001328 msm_rotator_dev->fd_info[s] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001329
1330 if (msm_rotator_dev->last_session_idx == s)
1331 msm_rotator_dev->last_session_idx =
1332 INVALID_SESSION;
1333 break;
1334 }
1335
1336 if ((msm_rotator_dev->img_info[s] == NULL) &&
1337 (first_free_index ==
1338 INVALID_SESSION))
1339 first_free_index = s;
1340 }
1341
1342 if ((s == MAX_SESSIONS) && (first_free_index != INVALID_SESSION)) {
1343 /* allocate a session id */
1344 msm_rotator_dev->img_info[first_free_index] =
1345 kzalloc(sizeof(struct msm_rotator_img_info),
1346 GFP_KERNEL);
1347 if (!msm_rotator_dev->img_info[first_free_index]) {
1348 printk(KERN_ERR "%s : unable to alloc mem\n",
1349 __func__);
1350 rc = -ENOMEM;
1351 goto rotator_start_exit;
1352 }
1353 info.session_id = (unsigned int)
1354 msm_rotator_dev->img_info[first_free_index];
1355 *(msm_rotator_dev->img_info[first_free_index]) = info;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001356 msm_rotator_dev->fd_info[first_free_index] = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 } else if (s == MAX_SESSIONS) {
1358 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1359 __func__);
1360 rc = -EBUSY;
1361 }
1362
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001363 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1364 rc = -EFAULT;
1365
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001366rotator_start_exit:
1367 mutex_unlock(&msm_rotator_dev->rotator_lock);
1368
1369 return rc;
1370}
1371
1372static int msm_rotator_finish(unsigned long arg)
1373{
1374 int rc = 0;
1375 int s;
1376 unsigned int session_id;
1377
1378 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1379 return -EFAULT;
1380
1381 mutex_lock(&msm_rotator_dev->rotator_lock);
1382 for (s = 0; s < MAX_SESSIONS; s++) {
1383 if ((msm_rotator_dev->img_info[s] != NULL) &&
1384 (session_id ==
1385 (unsigned int)msm_rotator_dev->img_info[s])) {
1386 if (msm_rotator_dev->last_session_idx == s)
1387 msm_rotator_dev->last_session_idx =
1388 INVALID_SESSION;
1389 kfree(msm_rotator_dev->img_info[s]);
1390 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001391 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001392 break;
1393 }
1394 }
1395
1396 if (s == MAX_SESSIONS)
1397 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001398#ifdef CONFIG_MSM_BUS_SCALING
1399 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1400 0);
1401#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001402 mutex_unlock(&msm_rotator_dev->rotator_lock);
1403 return rc;
1404}
1405
1406static int
1407msm_rotator_open(struct inode *inode, struct file *filp)
1408{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001409 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 int i;
1411
1412 if (filp->private_data)
1413 return -EBUSY;
1414
1415 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001416 for (i = 0; i < MAX_SESSIONS; i++) {
1417 if (msm_rotator_dev->fd_info[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 break;
1419 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001420
1421 if (i == MAX_SESSIONS) {
1422 mutex_unlock(&msm_rotator_dev->rotator_lock);
1423 return -EBUSY;
1424 }
1425
1426 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1427 if (tmp->pid == current->pid) {
1428 fd_info = tmp;
1429 break;
1430 }
1431 }
1432
1433 if (!fd_info) {
1434 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1435 if (!fd_info) {
1436 mutex_unlock(&msm_rotator_dev->rotator_lock);
1437 pr_err("%s: insufficient memory to alloc resources\n",
1438 __func__);
1439 return -ENOMEM;
1440 }
1441 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1442 fd_info->pid = current->pid;
1443 }
1444 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001445 mutex_unlock(&msm_rotator_dev->rotator_lock);
1446
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001447 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001448
1449 return 0;
1450}
1451
1452static int
1453msm_rotator_close(struct inode *inode, struct file *filp)
1454{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001455 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001457
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001458 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1459
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001461 if (--fd_info->ref_cnt > 0) {
1462 mutex_unlock(&msm_rotator_dev->rotator_lock);
1463 return 0;
1464 }
1465
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001466 for (s = 0; s < MAX_SESSIONS; s++) {
1467 if (msm_rotator_dev->img_info[s] != NULL &&
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001468 msm_rotator_dev->fd_info[s] == fd_info) {
1469 pr_debug("%s: freeing rotator session %p (pid %d)\n",
1470 __func__, msm_rotator_dev->img_info[s],
1471 fd_info->pid);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001472 kfree(msm_rotator_dev->img_info[s]);
1473 msm_rotator_dev->img_info[s] = NULL;
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001474 msm_rotator_dev->fd_info[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001475 if (msm_rotator_dev->last_session_idx == s)
1476 msm_rotator_dev->last_session_idx =
1477 INVALID_SESSION;
1478 }
1479 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001480 list_del(&fd_info->list);
1481 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001482 mutex_unlock(&msm_rotator_dev->rotator_lock);
1483
1484 return 0;
1485}
1486
1487static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1488 unsigned long arg)
1489{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001490 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001491
1492 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1493 return -ENOTTY;
1494
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001495 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001496
1497 switch (cmd) {
1498 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001499 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001500 case MSM_ROTATOR_IOCTL_ROTATE:
1501 return msm_rotator_do_rotate(arg);
1502 case MSM_ROTATOR_IOCTL_FINISH:
1503 return msm_rotator_finish(arg);
1504
1505 default:
1506 dev_dbg(msm_rotator_dev->device,
1507 "unexpected IOCTL %d\n", cmd);
1508 return -ENOTTY;
1509 }
1510}
1511
1512static const struct file_operations msm_rotator_fops = {
1513 .owner = THIS_MODULE,
1514 .open = msm_rotator_open,
1515 .release = msm_rotator_close,
1516 .unlocked_ioctl = msm_rotator_ioctl,
1517};
1518
1519static int __devinit msm_rotator_probe(struct platform_device *pdev)
1520{
1521 int rc = 0;
1522 struct resource *res;
1523 struct msm_rotator_platform_data *pdata = NULL;
1524 int i, number_of_clks;
1525 uint32_t ver;
1526
1527 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
1528 if (!msm_rotator_dev) {
1529 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
1530 __func__);
1531 return -ENOMEM;
1532 }
1533 for (i = 0; i < MAX_SESSIONS; i++)
1534 msm_rotator_dev->img_info[i] = NULL;
1535 msm_rotator_dev->last_session_idx = INVALID_SESSION;
1536
1537 pdata = pdev->dev.platform_data;
1538 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07001539 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001540
1541 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
1542 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001543 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001544 msm_rotator_dev->imem_clk_state = CLK_DIS;
1545 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
1546 msm_rotator_imem_clk_work_f);
1547 msm_rotator_dev->imem_clk = NULL;
1548 msm_rotator_dev->pdev = pdev;
1549
1550 msm_rotator_dev->core_clk = NULL;
1551 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001552
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001553#ifdef CONFIG_MSM_BUS_SCALING
1554 if (!msm_rotator_dev->bus_client_handle && pdata &&
1555 pdata->bus_scale_table) {
1556 msm_rotator_dev->bus_client_handle =
1557 msm_bus_scale_register_client(
1558 pdata->bus_scale_table);
1559 if (!msm_rotator_dev->bus_client_handle) {
1560 pr_err("%s not able to get bus scale handle\n",
1561 __func__);
1562 }
1563 }
1564#endif
1565
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001566 for (i = 0; i < number_of_clks; i++) {
1567 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
1568 msm_rotator_dev->imem_clk =
1569 clk_get(&msm_rotator_dev->pdev->dev,
1570 pdata->rotator_clks[i].clk_name);
1571 if (IS_ERR(msm_rotator_dev->imem_clk)) {
1572 rc = PTR_ERR(msm_rotator_dev->imem_clk);
1573 msm_rotator_dev->imem_clk = NULL;
1574 printk(KERN_ERR "%s: cannot get imem_clk "
1575 "rc=%d\n", DRIVER_NAME, rc);
1576 goto error_imem_clk;
1577 }
1578 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001579 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001580 pdata->rotator_clks[i].clk_rate);
1581 }
1582 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
1583 msm_rotator_dev->pclk =
1584 clk_get(&msm_rotator_dev->pdev->dev,
1585 pdata->rotator_clks[i].clk_name);
1586 if (IS_ERR(msm_rotator_dev->pclk)) {
1587 rc = PTR_ERR(msm_rotator_dev->pclk);
1588 msm_rotator_dev->pclk = NULL;
1589 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
1590 DRIVER_NAME, rc);
1591 goto error_pclk;
1592 }
1593
1594 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001595 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001596 pdata->rotator_clks[i].clk_rate);
1597 }
1598
1599 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
1600 msm_rotator_dev->core_clk =
1601 clk_get(&msm_rotator_dev->pdev->dev,
1602 pdata->rotator_clks[i].clk_name);
1603 if (IS_ERR(msm_rotator_dev->core_clk)) {
1604 rc = PTR_ERR(msm_rotator_dev->core_clk);
1605 msm_rotator_dev->core_clk = NULL;
1606 printk(KERN_ERR "%s: cannot get core clk "
1607 "rc=%d\n", DRIVER_NAME, rc);
1608 goto error_core_clk;
1609 }
1610
1611 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08001612 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 pdata->rotator_clks[i].clk_rate);
1614 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001615 }
1616
Matt Wagantall316f2fc2012-05-03 20:41:42 -07001617 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
1618 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001619 if (IS_ERR(msm_rotator_dev->regulator))
1620 msm_rotator_dev->regulator = NULL;
1621
1622 msm_rotator_dev->rot_clk_state = CLK_DIS;
1623 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
1624 msm_rotator_rot_clk_work_f);
1625
1626 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07001627#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
1628 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
1629#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001630 platform_set_drvdata(pdev, msm_rotator_dev);
1631
1632
1633 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1634 if (!res) {
1635 printk(KERN_ALERT
1636 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
1637 rc = -ENODEV;
1638 goto error_get_resource;
1639 }
1640 msm_rotator_dev->io_base = ioremap(res->start,
1641 resource_size(res));
1642
1643#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1644 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001645 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001646#endif
1647 enable_rot_clks();
1648 ver = ioread32(MSM_ROTATOR_HW_VERSION);
1649 disable_rot_clks();
1650
1651#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1652 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001653 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001654#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001655 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05301656 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001657 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07001658
Mayank Chopra012a8e72012-04-11 10:41:13 +05301659 rotator_hw_revision = ver;
1660 rotator_hw_revision >>= 16; /* bit 31:16 */
1661 rotator_hw_revision &= 0xff;
1662
1663 pr_info("%s: rotator_hw_revision=%x\n",
1664 __func__, rotator_hw_revision);
1665
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
1667 if (msm_rotator_dev->irq < 0) {
1668 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
1669 DRIVER_NAME);
1670 rc = -ENODEV;
1671 goto error_get_irq;
1672 }
1673 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
1674 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
1675 if (rc) {
1676 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
1677 goto error_get_irq;
1678 }
1679 /* we enable the IRQ when we need it in the ioctl */
1680 disable_irq(msm_rotator_dev->irq);
1681
1682 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
1683 if (rc < 0) {
1684 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
1685 __func__, rc);
1686 goto error_get_irq;
1687 }
1688
1689 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
1690 if (IS_ERR(msm_rotator_dev->class)) {
1691 rc = PTR_ERR(msm_rotator_dev->class);
1692 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
1693 DRIVER_NAME, rc);
1694 goto error_class_create;
1695 }
1696
1697 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
1698 msm_rotator_dev->dev_num, NULL,
1699 DRIVER_NAME);
1700 if (IS_ERR(msm_rotator_dev->device)) {
1701 rc = PTR_ERR(msm_rotator_dev->device);
1702 printk(KERN_ERR "%s: device_create failed %d\n",
1703 DRIVER_NAME, rc);
1704 goto error_class_device_create;
1705 }
1706
1707 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
1708 rc = cdev_add(&msm_rotator_dev->cdev,
1709 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
1710 1);
1711 if (rc < 0) {
1712 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
1713 goto error_cdev_add;
1714 }
1715
1716 init_waitqueue_head(&msm_rotator_dev->wq);
1717
1718 dev_dbg(msm_rotator_dev->device, "probe successful\n");
1719 return rc;
1720
1721error_cdev_add:
1722 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1723error_class_device_create:
1724 class_destroy(msm_rotator_dev->class);
1725error_class_create:
1726 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1727error_get_irq:
1728 iounmap(msm_rotator_dev->io_base);
1729error_get_resource:
1730 mutex_destroy(&msm_rotator_dev->rotator_lock);
1731 if (msm_rotator_dev->regulator)
1732 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001733 clk_put(msm_rotator_dev->core_clk);
1734error_core_clk:
1735 clk_put(msm_rotator_dev->pclk);
1736error_pclk:
1737 if (msm_rotator_dev->imem_clk)
1738 clk_put(msm_rotator_dev->imem_clk);
1739error_imem_clk:
1740 mutex_destroy(&msm_rotator_dev->imem_lock);
1741 kfree(msm_rotator_dev);
1742 return rc;
1743}
1744
1745static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
1746{
1747 int i;
1748
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001749#ifdef CONFIG_MSM_BUS_SCALING
1750 msm_bus_scale_unregister_client(msm_rotator_dev->bus_client_handle);
1751#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001752 free_irq(msm_rotator_dev->irq, NULL);
1753 mutex_destroy(&msm_rotator_dev->rotator_lock);
1754 cdev_del(&msm_rotator_dev->cdev);
1755 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
1756 class_destroy(msm_rotator_dev->class);
1757 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
1758 iounmap(msm_rotator_dev->io_base);
1759 if (msm_rotator_dev->imem_clk) {
1760 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001761 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001762 clk_put(msm_rotator_dev->imem_clk);
1763 msm_rotator_dev->imem_clk = NULL;
1764 }
1765 if (msm_rotator_dev->rot_clk_state == CLK_EN)
1766 disable_rot_clks();
1767 clk_put(msm_rotator_dev->core_clk);
1768 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001769 if (msm_rotator_dev->regulator)
1770 regulator_put(msm_rotator_dev->regulator);
1771 msm_rotator_dev->core_clk = NULL;
1772 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001773 mutex_destroy(&msm_rotator_dev->imem_lock);
1774 for (i = 0; i < MAX_SESSIONS; i++)
1775 if (msm_rotator_dev->img_info[i] != NULL)
1776 kfree(msm_rotator_dev->img_info[i]);
1777 kfree(msm_rotator_dev);
1778 return 0;
1779}
1780
1781#ifdef CONFIG_PM
1782static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
1783{
1784 mutex_lock(&msm_rotator_dev->imem_lock);
1785 if (msm_rotator_dev->imem_clk_state == CLK_EN
1786 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001787 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001788 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
1789 }
1790 mutex_unlock(&msm_rotator_dev->imem_lock);
1791 mutex_lock(&msm_rotator_dev->rotator_lock);
1792 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
1793 disable_rot_clks();
1794 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
1795 }
1796 mutex_unlock(&msm_rotator_dev->rotator_lock);
1797 return 0;
1798}
1799
1800static int msm_rotator_resume(struct platform_device *dev)
1801{
1802 mutex_lock(&msm_rotator_dev->imem_lock);
1803 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
1804 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07001805 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 msm_rotator_dev->imem_clk_state = CLK_EN;
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_SUSPEND) {
1811 enable_rot_clks();
1812 msm_rotator_dev->rot_clk_state = CLK_EN;
1813 }
1814 mutex_unlock(&msm_rotator_dev->rotator_lock);
1815 return 0;
1816}
1817#endif
1818
1819static struct platform_driver msm_rotator_platform_driver = {
1820 .probe = msm_rotator_probe,
1821 .remove = __devexit_p(msm_rotator_remove),
1822#ifdef CONFIG_PM
1823 .suspend = msm_rotator_suspend,
1824 .resume = msm_rotator_resume,
1825#endif
1826 .driver = {
1827 .owner = THIS_MODULE,
1828 .name = DRIVER_NAME
1829 }
1830};
1831
1832static int __init msm_rotator_init(void)
1833{
1834 return platform_driver_register(&msm_rotator_platform_driver);
1835}
1836
1837static void __exit msm_rotator_exit(void)
1838{
1839 return platform_driver_unregister(&msm_rotator_platform_driver);
1840}
1841
1842module_init(msm_rotator_init);
1843module_exit(msm_rotator_exit);
1844
1845MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
1846MODULE_VERSION("1.0");
1847MODULE_LICENSE("GPL v2");