blob: dd9c8cb626766f6fd3fd94034994523092b52932 [file] [log] [blame]
Ken Zhangfebeabd2012-12-17 10:35:15 -05001/* Copyright (c) 2009-2013, The Linux Foundation. All rights reserved.
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License version 2 and
5 * only version 2 as published by the Free Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 */
13#include <linux/platform_device.h>
14#include <linux/cdev.h>
15#include <linux/list.h>
16#include <linux/module.h>
17#include <linux/fs.h>
18#include <linux/interrupt.h>
19#include <linux/sched.h>
20#include <linux/uaccess.h>
21#include <linux/clk.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070022#include <linux/android_pmem.h>
23#include <linux/msm_rotator.h>
24#include <linux/io.h>
25#include <mach/msm_rotator_imem.h>
26#include <linux/ktime.h>
27#include <linux/workqueue.h>
28#include <linux/file.h>
29#include <linux/major.h>
30#include <linux/regulator/consumer.h>
Mitchel Humpherys9faf7e12012-09-06 10:33:12 -070031#include <linux/msm_ion.h>
Ken Zhanga50db542013-02-20 14:48:06 -050032#include <linux/sync.h>
33#include <linux/sw_sync.h>
34
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -080035#ifdef CONFIG_MSM_BUS_SCALING
36#include <mach/msm_bus.h>
37#include <mach/msm_bus_board.h>
38#endif
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -070039#include <mach/msm_subsystem_map.h>
40#include <mach/iommu_domains.h>
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070041
42#define DRIVER_NAME "msm_rotator"
43
44#define MSM_ROTATOR_BASE (msm_rotator_dev->io_base)
45#define MSM_ROTATOR_INTR_ENABLE (MSM_ROTATOR_BASE+0x0020)
46#define MSM_ROTATOR_INTR_STATUS (MSM_ROTATOR_BASE+0x0024)
47#define MSM_ROTATOR_INTR_CLEAR (MSM_ROTATOR_BASE+0x0028)
48#define MSM_ROTATOR_START (MSM_ROTATOR_BASE+0x0030)
49#define MSM_ROTATOR_MAX_BURST_SIZE (MSM_ROTATOR_BASE+0x0050)
50#define MSM_ROTATOR_HW_VERSION (MSM_ROTATOR_BASE+0x0070)
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -070051#define MSM_ROTATOR_SW_RESET (MSM_ROTATOR_BASE+0x0074)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070052#define MSM_ROTATOR_SRC_SIZE (MSM_ROTATOR_BASE+0x1108)
53#define MSM_ROTATOR_SRCP0_ADDR (MSM_ROTATOR_BASE+0x110c)
54#define MSM_ROTATOR_SRCP1_ADDR (MSM_ROTATOR_BASE+0x1110)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070055#define MSM_ROTATOR_SRCP2_ADDR (MSM_ROTATOR_BASE+0x1114)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070056#define MSM_ROTATOR_SRC_YSTRIDE1 (MSM_ROTATOR_BASE+0x111c)
57#define MSM_ROTATOR_SRC_YSTRIDE2 (MSM_ROTATOR_BASE+0x1120)
58#define MSM_ROTATOR_SRC_FORMAT (MSM_ROTATOR_BASE+0x1124)
59#define MSM_ROTATOR_SRC_UNPACK_PATTERN1 (MSM_ROTATOR_BASE+0x1128)
60#define MSM_ROTATOR_SUB_BLOCK_CFG (MSM_ROTATOR_BASE+0x1138)
61#define MSM_ROTATOR_OUT_PACK_PATTERN1 (MSM_ROTATOR_BASE+0x1154)
62#define MSM_ROTATOR_OUTP0_ADDR (MSM_ROTATOR_BASE+0x1168)
63#define MSM_ROTATOR_OUTP1_ADDR (MSM_ROTATOR_BASE+0x116c)
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -070064#define MSM_ROTATOR_OUTP2_ADDR (MSM_ROTATOR_BASE+0x1170)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070065#define MSM_ROTATOR_OUT_YSTRIDE1 (MSM_ROTATOR_BASE+0x1178)
66#define MSM_ROTATOR_OUT_YSTRIDE2 (MSM_ROTATOR_BASE+0x117c)
67#define MSM_ROTATOR_SRC_XY (MSM_ROTATOR_BASE+0x1200)
68#define MSM_ROTATOR_SRC_IMAGE_SIZE (MSM_ROTATOR_BASE+0x1208)
69
70#define MSM_ROTATOR_MAX_ROT 0x07
71#define MSM_ROTATOR_MAX_H 0x1fff
72#define MSM_ROTATOR_MAX_W 0x1fff
73
74/* from lsb to msb */
75#define GET_PACK_PATTERN(a, x, y, z, bit) \
76 (((a)<<((bit)*3))|((x)<<((bit)*2))|((y)<<(bit))|(z))
77#define CLR_G 0x0
78#define CLR_B 0x1
79#define CLR_R 0x2
80#define CLR_ALPHA 0x3
81
82#define CLR_Y CLR_G
83#define CLR_CB CLR_B
84#define CLR_CR CLR_R
85
86#define ROTATIONS_TO_BITMASK(r) ((((r) & MDP_ROT_90) ? 1 : 0) | \
87 (((r) & MDP_FLIP_LR) ? 2 : 0) | \
88 (((r) & MDP_FLIP_UD) ? 4 : 0))
89
90#define IMEM_NO_OWNER -1;
91
92#define MAX_SESSIONS 16
93#define INVALID_SESSION -1
94#define VERSION_KEY_MASK 0xFFFFFF00
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -070095#define MAX_DOWNSCALE_RATIO 3
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070096
Ken Zhanga50db542013-02-20 14:48:06 -050097#define MAX_TIMELINE_NAME_LEN 16
98#define WAIT_FENCE_FIRST_TIMEOUT MSEC_PER_SEC
99#define WAIT_FENCE_FINAL_TIMEOUT (10 * MSEC_PER_SEC)
100
Mayank Chopra012a8e72012-04-11 10:41:13 +0530101#define ROTATOR_REVISION_V0 0
102#define ROTATOR_REVISION_V1 1
103#define ROTATOR_REVISION_V2 2
104#define ROTATOR_REVISION_NONE 0xffffffff
Mayank Chopra27147a72012-07-17 13:57:22 +0530105#define BASE_ADDR(height, y_stride) ((height % 64) * y_stride)
106#define HW_BASE_ADDR(height, y_stride) (((dstp0_ystride >> 5) << 11) - \
107 ((dst_height & 0x3f) * dstp0_ystride))
Mayank Chopra012a8e72012-04-11 10:41:13 +0530108
109uint32_t rotator_hw_revision;
Olav Hauganef95ae32012-05-15 09:50:30 -0700110static char rot_iommu_split_domain;
Mayank Chopra012a8e72012-04-11 10:41:13 +0530111
112/*
113 * rotator_hw_revision:
114 * 0 == 7x30
115 * 1 == 8x60
116 * 2 == 8960
117 *
118 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700119struct tile_parm {
120 unsigned int width; /* tile's width */
121 unsigned int height; /* tile's height */
122 unsigned int row_tile_w; /* tiles per row's width */
123 unsigned int row_tile_h; /* tiles per row's height */
124};
125
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700126struct msm_rotator_mem_planes {
127 unsigned int num_planes;
128 unsigned int plane_size[4];
129 unsigned int total_size;
130};
131
132#define checkoffset(offset, size, max_size) \
133 ((size) > (max_size) || (offset) > ((max_size) - (size)))
134
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700135struct msm_rotator_fd_info {
136 int pid;
137 int ref_cnt;
138 struct list_head list;
139};
140
Ken Zhanga50db542013-02-20 14:48:06 -0500141struct rot_sync_info {
142 u32 initialized;
143 struct sync_fence *acq_fen;
144 int cur_rel_fen_fd;
145 struct sync_pt *cur_rel_sync_pt;
146 struct sync_fence *cur_rel_fence;
147 struct sync_fence *last_rel_fence;
148 struct sw_sync_timeline *timeline;
149 int timeline_value;
150 struct mutex sync_mutex;
151};
152
Mayank Chopra27147a72012-07-17 13:57:22 +0530153struct msm_rotator_session {
154 struct msm_rotator_img_info img_info;
155 struct msm_rotator_fd_info fd_info;
156 int fast_yuv_enable;
157};
158
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700159struct msm_rotator_dev {
160 void __iomem *io_base;
161 int irq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700162 struct clk *core_clk;
Mayank Chopra27147a72012-07-17 13:57:22 +0530163 struct msm_rotator_session *rot_session[MAX_SESSIONS];
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700164 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700165 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700166 int rot_clk_state;
167 struct regulator *regulator;
168 struct delayed_work rot_clk_work;
169 struct clk *imem_clk;
170 int imem_clk_state;
171 struct delayed_work imem_clk_work;
172 struct platform_device *pdev;
173 struct cdev cdev;
174 struct device *device;
175 struct class *class;
176 dev_t dev_num;
177 int processing;
178 int last_session_idx;
179 struct mutex rotator_lock;
180 struct mutex imem_lock;
181 int imem_owner;
182 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700183 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800184 #ifdef CONFIG_MSM_BUS_SCALING
185 uint32_t bus_client_handle;
186 #endif
Ken Zhangfebeabd2012-12-17 10:35:15 -0500187 u32 sec_mapped;
188 u32 mmu_clk_on;
Ken Zhanga50db542013-02-20 14:48:06 -0500189 struct rot_sync_info sync_info[MAX_SESSIONS];
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190};
191
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700192#define COMPONENT_5BITS 1
193#define COMPONENT_6BITS 2
194#define COMPONENT_8BITS 3
195
196static struct msm_rotator_dev *msm_rotator_dev;
197
198enum {
199 CLK_EN,
200 CLK_DIS,
201 CLK_SUSPEND,
202};
Ken Zhangfebeabd2012-12-17 10:35:15 -0500203struct res_mmu_clk {
204 char *mmu_clk_name;
205 struct clk *mmu_clk;
206};
207
208static struct res_mmu_clk rot_mmu_clks[] = {
209 {"mdp_iommu_clk"}, {"rot_iommu_clk"},
210 {"vcodec_iommu0_clk"}, {"vcodec_iommu1_clk"},
211 {"smmu_iface_clk"}
212};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700213
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700214int msm_rotator_iommu_map_buf(int mem_id, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700215 unsigned long *start, unsigned long *len,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700216 struct ion_handle **pihdl, unsigned int secure)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700217{
218 if (!msm_rotator_dev->client)
219 return -EINVAL;
220
Laura Abbottb14ed962012-01-30 14:18:08 -0800221 *pihdl = ion_import_dma_buf(msm_rotator_dev->client, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700222 if (IS_ERR_OR_NULL(*pihdl)) {
Laura Abbottb14ed962012-01-30 14:18:08 -0800223 pr_err("ion_import_dma_buf() failed\n");
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700224 return PTR_ERR(*pihdl);
225 }
taeyol.kim69400442012-08-03 19:15:10 -0700226 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700227
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700228 if (rot_iommu_split_domain) {
229 if (secure) {
230 if (ion_phys(msm_rotator_dev->client,
231 *pihdl, start, (unsigned *)len)) {
232 pr_err("%s:%d: ion_phys map failed\n",
233 __func__, __LINE__);
234 return -ENOMEM;
235 }
236 } else {
237 if (ion_map_iommu(msm_rotator_dev->client,
238 *pihdl, domain, GEN_POOL,
239 SZ_4K, 0, start, len, 0,
240 ION_IOMMU_UNMAP_DELAYED)) {
241 pr_err("ion_map_iommu() failed\n");
242 return -EINVAL;
243 }
244 }
245 } else {
246 if (ion_map_iommu(msm_rotator_dev->client,
247 *pihdl, ROTATOR_SRC_DOMAIN, GEN_POOL,
248 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
249 pr_err("ion_map_iommu() failed\n");
250 return -EINVAL;
251 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700252 }
253
254 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
255 __func__, mem_id, *start, *len);
256 return 0;
257}
258
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700259int msm_rotator_imem_allocate(int requestor)
260{
261 int rc = 0;
262
263#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
264 switch (requestor) {
265 case ROTATOR_REQUEST:
266 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
267 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
268 rc = 1;
269 } else
270 rc = 0;
271 break;
272 case JPEG_REQUEST:
273 mutex_lock(&msm_rotator_dev->imem_lock);
274 msm_rotator_dev->imem_owner = JPEG_REQUEST;
275 rc = 1;
276 break;
277 default:
278 rc = 0;
279 }
280#else
281 if (requestor == JPEG_REQUEST)
282 rc = 1;
283#endif
284 if (rc == 1) {
285 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
286 if (msm_rotator_dev->imem_clk_state != CLK_EN
287 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700288 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700289 msm_rotator_dev->imem_clk_state = CLK_EN;
290 }
291 }
292
293 return rc;
294}
295EXPORT_SYMBOL(msm_rotator_imem_allocate);
296
297void msm_rotator_imem_free(int requestor)
298{
299#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
300 if (msm_rotator_dev->imem_owner == requestor) {
301 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
302 mutex_unlock(&msm_rotator_dev->imem_lock);
303 }
304#else
305 if (requestor == JPEG_REQUEST)
306 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
307#endif
308}
309EXPORT_SYMBOL(msm_rotator_imem_free);
310
311static void msm_rotator_imem_clk_work_f(struct work_struct *work)
312{
313#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
314 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
315 if (msm_rotator_dev->imem_clk_state == CLK_EN
316 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700317 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700318 msm_rotator_dev->imem_clk_state = CLK_DIS;
319 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
320 msm_rotator_dev->imem_clk_state = CLK_DIS;
321 mutex_unlock(&msm_rotator_dev->imem_lock);
322 }
323#endif
324}
325
326/* enable clocks needed by rotator block */
327static void enable_rot_clks(void)
328{
329 if (msm_rotator_dev->regulator)
330 regulator_enable(msm_rotator_dev->regulator);
331 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700332 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700333 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700334 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700335}
336
337/* disable clocks needed by rotator block */
338static void disable_rot_clks(void)
339{
340 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700341 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700342 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700343 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700344 if (msm_rotator_dev->regulator)
345 regulator_disable(msm_rotator_dev->regulator);
346}
347
348static void msm_rotator_rot_clk_work_f(struct work_struct *work)
349{
350 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
351 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
352 disable_rot_clks();
353 msm_rotator_dev->rot_clk_state = CLK_DIS;
354 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
355 msm_rotator_dev->rot_clk_state = CLK_DIS;
356 mutex_unlock(&msm_rotator_dev->rotator_lock);
357 }
358}
359
360static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
361{
362 if (msm_rotator_dev->processing) {
363 msm_rotator_dev->processing = 0;
364 wake_up(&msm_rotator_dev->wq);
365 } else
366 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
367
368 return IRQ_HANDLED;
369}
370
Ken Zhanga50db542013-02-20 14:48:06 -0500371static void msm_rotator_signal_timeline(u32 session_index)
372{
373 struct rot_sync_info *sync_info;
374 sync_info = &msm_rotator_dev->sync_info[session_index];
375
376 if ((!sync_info->timeline) || (!sync_info->initialized))
377 return;
378
379 mutex_lock(&sync_info->sync_mutex);
380 sw_sync_timeline_inc(sync_info->timeline, 1);
381 sync_info->timeline_value++;
382 sync_info->last_rel_fence = sync_info->cur_rel_fence;
383 sync_info->cur_rel_fence = 0;
384 mutex_unlock(&sync_info->sync_mutex);
385}
386
387static void msm_rotator_release_acq_fence(u32 session_index)
388{
389 struct rot_sync_info *sync_info;
390 sync_info = &msm_rotator_dev->sync_info[session_index];
391
392 if ((!sync_info->timeline) || (!sync_info->initialized))
393 return;
394 mutex_lock(&sync_info->sync_mutex);
395 sync_info->acq_fen = NULL;
396 mutex_unlock(&sync_info->sync_mutex);
397}
398
399static void msm_rotator_release_all_timeline(void)
400{
401 int i;
402 struct rot_sync_info *sync_info;
403 for (i = 0; i < MAX_SESSIONS; i++) {
404 sync_info = &msm_rotator_dev->sync_info[i];
405 if (sync_info->initialized) {
406 msm_rotator_signal_timeline(i);
407 msm_rotator_release_acq_fence(i);
408 }
409 }
410}
411
412static void msm_rotator_wait_for_fence_sub(u32 session_index)
413{
414 struct rot_sync_info *sync_info;
415 int ret;
416 sync_info = &msm_rotator_dev->sync_info[session_index];
417 if (sync_info->acq_fen) {
418 ret = sync_fence_wait(sync_info->acq_fen,
419 WAIT_FENCE_FIRST_TIMEOUT);
420 if (ret == -ETIME) {
421 pr_warn("%s: timeout, wait %ld more ms\n",
422 __func__, WAIT_FENCE_FINAL_TIMEOUT);
423 ret = sync_fence_wait(sync_info->acq_fen,
424 WAIT_FENCE_FINAL_TIMEOUT);
425 }
426 if (ret < 0) {
427 pr_err("%s: sync_fence_wait failed! ret = %x\n",
428 __func__, ret);
429 }
430 sync_fence_put(sync_info->acq_fen);
431 sync_info->acq_fen = NULL;
432 }
433}
434
435static void msm_rotator_wait_for_fence(u32 session_index)
436{
437 struct rot_sync_info *sync_info;
438 sync_info = &msm_rotator_dev->sync_info[session_index];
439 if ((!sync_info->timeline) || (!sync_info->initialized))
440 return;
441
442 mutex_lock(&sync_info->sync_mutex);
443 msm_rotator_wait_for_fence_sub(session_index);
444 mutex_unlock(&sync_info->sync_mutex);
445}
446
447static int msm_rotator_buf_sync(unsigned long arg)
448{
449 struct msm_rotator_buf_sync buf_sync;
450 int ret = 0;
451 struct sync_fence *fence = NULL;
452 struct rot_sync_info *sync_info;
453 u32 s;
454
455 if (copy_from_user(&buf_sync, (void __user *)arg, sizeof(buf_sync)))
456 return -EFAULT;
457
458 for (s = 0; s < MAX_SESSIONS; s++)
459 if ((msm_rotator_dev->rot_session[s] != NULL) &&
460 (buf_sync.session_id ==
461 (unsigned int)msm_rotator_dev->rot_session[s]
462 ))
463 break;
464
465 if (s == MAX_SESSIONS) {
466 pr_err("%s invalid session id %d", __func__,
467 buf_sync.session_id);
468 return -EINVAL;
469 }
470
471 sync_info = &msm_rotator_dev->sync_info[s];
472
473 if ((sync_info->timeline == NULL) ||
474 (sync_info->initialized == false))
475 return -EINVAL;
476
477 mutex_lock(&sync_info->sync_mutex);
478 if (buf_sync.acq_fen_fd >= 0)
479 fence = sync_fence_fdget(buf_sync.acq_fen_fd);
480
481 sync_info->acq_fen = fence;
482
483 if (sync_info->acq_fen &&
484 (buf_sync.flags & MDP_BUF_SYNC_FLAG_WAIT))
485 msm_rotator_wait_for_fence_sub(s);
486
487 sync_info->cur_rel_sync_pt = sw_sync_pt_create(sync_info->timeline,
488 sync_info->timeline_value + 1);
489 if (sync_info->cur_rel_sync_pt == NULL) {
490 pr_err("%s: cannot create sync point", __func__);
491 ret = -ENOMEM;
492 goto buf_sync_err_1;
493 }
494 /* create fence */
495 sync_info->cur_rel_fence = sync_fence_create("msm_rotator-fence",
496 sync_info->cur_rel_sync_pt);
497 if (sync_info->cur_rel_fence == NULL) {
498 sync_pt_free(sync_info->cur_rel_sync_pt);
499 sync_info->cur_rel_sync_pt = NULL;
500 pr_err("%s: cannot create fence", __func__);
501 ret = -ENOMEM;
502 goto buf_sync_err_1;
503 }
504 /* create fd */
505 sync_info->cur_rel_fen_fd = get_unused_fd_flags(0);
506 if (sync_info->cur_rel_fen_fd < 0) {
507 pr_err("%s: get_unused_fd_flags failed", __func__);
508 ret = -EIO;
509 goto buf_sync_err_2;
510 }
511 sync_fence_install(sync_info->cur_rel_fence, sync_info->cur_rel_fen_fd);
512 buf_sync.rel_fen_fd = sync_info->cur_rel_fen_fd;
513
514 ret = copy_to_user((void __user *)arg, &buf_sync, sizeof(buf_sync));
515 mutex_unlock(&sync_info->sync_mutex);
516 return ret;
517buf_sync_err_2:
518 sync_fence_put(sync_info->cur_rel_fence);
519 sync_info->cur_rel_fence = NULL;
520 sync_info->cur_rel_fen_fd = 0;
521buf_sync_err_1:
522 if (sync_info->acq_fen)
523 sync_fence_put(sync_info->acq_fen);
524 sync_info->acq_fen = NULL;
525 mutex_unlock(&sync_info->sync_mutex);
526 return ret;
527}
528
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700529static unsigned int tile_size(unsigned int src_width,
530 unsigned int src_height,
531 const struct tile_parm *tp)
532{
533 unsigned int tile_w, tile_h;
534 unsigned int row_num_w, row_num_h;
535 tile_w = tp->width * tp->row_tile_w;
536 tile_h = tp->height * tp->row_tile_h;
537 row_num_w = (src_width + tile_w - 1) / tile_w;
538 row_num_h = (src_height + tile_h - 1) / tile_h;
539 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
540}
541
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700542static int get_bpp(int format)
543{
544 switch (format) {
545 case MDP_RGB_565:
546 case MDP_BGR_565:
547 return 2;
548
549 case MDP_XRGB_8888:
550 case MDP_ARGB_8888:
551 case MDP_RGBA_8888:
552 case MDP_BGRA_8888:
553 case MDP_RGBX_8888:
554 return 4;
555
556 case MDP_Y_CBCR_H2V2:
557 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700558 case MDP_Y_CB_CR_H2V2:
559 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530560 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700561 case MDP_Y_CRCB_H2V2_TILE:
562 case MDP_Y_CBCR_H2V2_TILE:
563 return 1;
564
565 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700566 case MDP_YCBCR_H1V1:
567 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700568 return 3;
569
570 case MDP_YCRYCB_H2V1:
571 return 2;/* YCrYCb interleave */
572
573 case MDP_Y_CRCB_H2V1:
574 case MDP_Y_CBCR_H2V1:
575 return 1;
576
577 default:
578 return -1;
579 }
580
581}
582
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700583static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
584 struct msm_rotator_mem_planes *p)
585{
586 /*
587 * each row of samsung tile consists of two tiles in height
588 * and two tiles in width which means width should align to
589 * 64 x 2 bytes and height should align to 32 x 2 bytes.
590 * video decoder generate two tiles in width and one tile
591 * in height which ends up height align to 32 X 1 bytes.
592 */
593 const struct tile_parm tile = {64, 32, 2, 1};
594 int i;
595
596 if (p == NULL)
597 return -EINVAL;
598
599 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
600 return -ERANGE;
601
602 memset(p, 0, sizeof(*p));
603
604 switch (format) {
605 case MDP_XRGB_8888:
606 case MDP_ARGB_8888:
607 case MDP_RGBA_8888:
608 case MDP_BGRA_8888:
609 case MDP_RGBX_8888:
610 case MDP_RGB_888:
611 case MDP_RGB_565:
612 case MDP_BGR_565:
613 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700614 case MDP_YCBCR_H1V1:
615 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700616 p->num_planes = 1;
617 p->plane_size[0] = w * h * get_bpp(format);
618 break;
619 case MDP_Y_CRCB_H2V1:
620 case MDP_Y_CBCR_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +0530621 case MDP_Y_CRCB_H1V2:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700622 p->num_planes = 2;
623 p->plane_size[0] = w * h;
624 p->plane_size[1] = w * h;
625 break;
626 case MDP_Y_CBCR_H2V2:
627 case MDP_Y_CRCB_H2V2:
628 p->num_planes = 2;
629 p->plane_size[0] = w * h;
630 p->plane_size[1] = w * h / 2;
631 break;
632 case MDP_Y_CRCB_H2V2_TILE:
633 case MDP_Y_CBCR_H2V2_TILE:
634 p->num_planes = 2;
635 p->plane_size[0] = tile_size(w, h, &tile);
636 p->plane_size[1] = tile_size(w, h/2, &tile);
637 break;
638 case MDP_Y_CB_CR_H2V2:
639 case MDP_Y_CR_CB_H2V2:
640 p->num_planes = 3;
641 p->plane_size[0] = w * h;
642 p->plane_size[1] = (w / 2) * (h / 2);
643 p->plane_size[2] = (w / 2) * (h / 2);
644 break;
645 case MDP_Y_CR_CB_GH2V2:
646 p->num_planes = 3;
647 p->plane_size[0] = ALIGN(w, 16) * h;
648 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
649 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
650 break;
651 default:
652 return -EINVAL;
653 }
654
655 for (i = 0; i < p->num_planes; i++)
656 p->total_size += p->plane_size[i];
657
658 return 0;
659}
660
Mayank Chopra27147a72012-07-17 13:57:22 +0530661/* Checking invalid destination image size on FAST YUV for YUV420PP(NV12) with
662 * HW issue for rotation 90 + U/D filp + with/without flip operation
663 * (rotation 90 + U/D + L/R flip is rotation 270 degree option) and pix_rot
664 * block issue with tile line size is 4.
665 *
666 * Rotator structure is:
667 * if Fetch input image: W x H,
668 * Downscale: W` x H` = W/ScaleHor(2, 4 or 8) x H/ScaleVert(2, 4 or 8)
669 * Rotated output : W`` x H`` = (W` x H`) or (H` x W`) depends on "Rotation 90
670 * degree option"
671 *
672 * Pack: W`` x H``
673 *
674 * Rotator source ROI image width restriction is applied to W x H (case a,
675 * image resolution before downscaling)
676 *
677 * Packer source Image width/ height restriction are applied to W`` x H``
678 * (case c, image resolution after rotation)
679 *
680 * Supertile (64 x 8) and YUV (2 x 2) alignment restriction should be
681 * applied to the W x H (case a). Input image should be at least (2 x 2).
682 *
683 * "Support If packer source image height <= 256, multiple of 8", this
684 * restriction should be applied to the rotated image (W`` x H``)
685 */
686
687uint32_t fast_yuv_invalid_size_checker(unsigned char rot_mode,
688 uint32_t src_width,
689 uint32_t dst_width,
690 uint32_t dst_height,
691 uint32_t dstp0_ystride,
692 uint32_t is_planar420)
693{
694 uint32_t hw_limit;
695
696 hw_limit = is_planar420 ? 512 : 256;
697
698 /* checking image constaints for missing EOT event from pix_rot block */
699 if ((src_width > hw_limit) && ((src_width % (hw_limit / 2)) == 8))
700 return -EINVAL;
701
702 if (rot_mode & MDP_ROT_90) {
703
704 /* if rotation 90 degree on fast yuv
705 * rotator image input width has to be multiple of 8
706 * rotator image input height has to be multiple of 8
707 */
708 if (((dst_width % 8) != 0) || ((dst_height % 8) != 0))
709 return -EINVAL;
710
711 if ((rot_mode & MDP_FLIP_UD) ||
712 (rot_mode & (MDP_FLIP_UD | MDP_FLIP_LR))) {
713
714 /* image constraint checking for wrong address
715 * generation HW issue for Y plane checking
716 */
717 if (((dst_height % 64) != 0) &&
718 ((dst_height / 64) >= 4)) {
719
720 /* compare golden logic for second
721 * tile base address generation in row
722 * with actual HW implementation
723 */
724 if (BASE_ADDR(dst_height, dstp0_ystride) !=
725 HW_BASE_ADDR(dst_height, dstp0_ystride))
726 return -EINVAL;
727 }
728
729 if (is_planar420) {
730 dst_width = dst_width / 2;
731 dstp0_ystride = dstp0_ystride / 2;
732 }
733
734 dst_height = dst_height / 2;
735
736 /* image constraint checking for wrong
737 * address generation HW issue. for
738 * U/V (P) or UV (PP) plane checking
739 */
740 if (((dst_height % 64) != 0) && ((dst_height / 64) >=
741 (hw_limit / 128))) {
742
743 /* compare golden logic for
744 * second tile base address
745 * generation in row with
746 * actual HW implementation
747 */
748 if (BASE_ADDR(dst_height, dstp0_ystride) !=
749 HW_BASE_ADDR(dst_height, dstp0_ystride))
750 return -EINVAL;
751 }
752 }
753 } else {
754 /* if NOT applying rotation 90 degree on fast yuv,
755 * rotator image input width has to be multiple of 8
756 * rotator image input height has to be multiple of 2
757 */
758 if (((dst_width % 8) != 0) || ((dst_height % 2) != 0))
759 return -EINVAL;
760 }
761
762 return 0;
763}
764
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700765static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
766 unsigned int in_paddr,
767 unsigned int out_paddr,
768 unsigned int use_imem,
769 int new_session,
770 unsigned int in_chroma_paddr,
771 unsigned int out_chroma_paddr)
772{
773 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700774
775 if (info->src.format != info->dst.format)
776 return -EINVAL;
777
778 bpp = get_bpp(info->src.format);
779 if (bpp < 0)
780 return -ENOTTY;
781
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700782 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700783 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700784 iowrite32(out_paddr +
785 ((info->dst_y * info->dst.width) + info->dst_x),
786 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700787 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700788 ((info->dst_y * info->dst.width) + info->dst_x),
789 MSM_ROTATOR_OUTP1_ADDR);
790
791 if (new_session) {
792 iowrite32(info->src.width |
793 info->src.width << 16,
794 MSM_ROTATOR_SRC_YSTRIDE1);
795 if (info->rotations & MDP_ROT_90)
796 iowrite32(info->dst.width |
797 info->dst.width*2 << 16,
798 MSM_ROTATOR_OUT_YSTRIDE1);
799 else
800 iowrite32(info->dst.width |
801 info->dst.width << 16,
802 MSM_ROTATOR_OUT_YSTRIDE1);
803 if (info->src.format == MDP_Y_CBCR_H2V1) {
804 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
805 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
806 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
807 MSM_ROTATOR_OUT_PACK_PATTERN1);
808 } else {
809 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
810 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
811 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
812 MSM_ROTATOR_OUT_PACK_PATTERN1);
813 }
814 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
815 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700816 1 << 8 | /* ROT_EN */
817 info->downscale_ratio << 2 | /* downscale v ratio */
818 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700819 MSM_ROTATOR_SUB_BLOCK_CFG);
820 iowrite32(0 << 29 | /* frame format 0 = linear */
821 (use_imem ? 0 : 1) << 22 | /* tile size */
822 2 << 19 | /* fetch planes 2 = pseudo */
823 0 << 18 | /* unpack align */
824 1 << 17 | /* unpack tight */
825 1 << 13 | /* unpack count 0=1 component */
826 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
827 0 << 8 | /* has alpha */
828 0 << 6 | /* alpha bits 3=8bits */
829 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
830 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
831 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
832 MSM_ROTATOR_SRC_FORMAT);
833 }
834
835 return 0;
836}
837
838static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
839 unsigned int in_paddr,
840 unsigned int out_paddr,
841 unsigned int use_imem,
842 int new_session,
843 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700844 unsigned int out_chroma_paddr,
Mayank Chopra27147a72012-07-17 13:57:22 +0530845 unsigned int in_chroma2_paddr,
846 unsigned int out_chroma2_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700847{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700848 uint32_t dst_format;
849 int is_tile = 0;
Mayank Chopra27147a72012-07-17 13:57:22 +0530850 struct msm_rotator_session *rot_ssn =
851 container_of(info, struct msm_rotator_session, img_info);
852 int fast_yuv_en = rot_ssn->fast_yuv_enable;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700853
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700854 switch (info->src.format) {
855 case MDP_Y_CRCB_H2V2_TILE:
856 is_tile = 1;
Mayank Chopra27147a72012-07-17 13:57:22 +0530857 dst_format = MDP_Y_CRCB_H2V2;
858 break;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700859 case MDP_Y_CR_CB_H2V2:
860 case MDP_Y_CR_CB_GH2V2:
Mayank Chopra27147a72012-07-17 13:57:22 +0530861 if (fast_yuv_en) {
862 dst_format = info->src.format;
863 break;
864 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700865 case MDP_Y_CRCB_H2V2:
866 dst_format = MDP_Y_CRCB_H2V2;
867 break;
Mayank Chopra27147a72012-07-17 13:57:22 +0530868 case MDP_Y_CB_CR_H2V2:
869 if (fast_yuv_en) {
870 dst_format = info->src.format;
871 break;
872 }
873 dst_format = MDP_Y_CBCR_H2V2;
874 break;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700875 case MDP_Y_CBCR_H2V2_TILE:
876 is_tile = 1;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700877 case MDP_Y_CBCR_H2V2:
878 dst_format = MDP_Y_CBCR_H2V2;
879 break;
880 default:
881 return -EINVAL;
882 }
883 if (info->dst.format != dst_format)
884 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700885
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800886 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530887 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
888 info->src.format == MDP_Y_CR_CB_GH2V2) &&
889 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800890 swap(in_chroma_paddr, in_chroma2_paddr);
891
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700892 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700893 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
894 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
895
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896 iowrite32(out_paddr +
897 ((info->dst_y * info->dst.width) + info->dst_x),
898 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700899 iowrite32(out_chroma_paddr +
Mayank Chopra27147a72012-07-17 13:57:22 +0530900 (((info->dst_y * info->dst.width)/2) + info->dst_x),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700901 MSM_ROTATOR_OUTP1_ADDR);
Mayank Chopra27147a72012-07-17 13:57:22 +0530902 if (out_chroma2_paddr)
903 iowrite32(out_chroma2_paddr +
904 (((info->dst_y * info->dst.width)/2) + info->dst_x),
905 MSM_ROTATOR_OUTP2_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700906
907 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700908 if (in_chroma2_paddr) {
909 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530910 iowrite32(ALIGN(info->src.width, 16) |
911 ALIGN((info->src.width / 2), 16) << 16,
912 MSM_ROTATOR_SRC_YSTRIDE1);
913 iowrite32(ALIGN((info->src.width / 2), 16),
914 MSM_ROTATOR_SRC_YSTRIDE2);
915 } else {
916 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700917 (info->src.width / 2) << 16,
918 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530919 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700920 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530921 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700922 } else {
923 iowrite32(info->src.width |
924 info->src.width << 16,
925 MSM_ROTATOR_SRC_YSTRIDE1);
926 }
Mayank Chopra27147a72012-07-17 13:57:22 +0530927 if (out_chroma2_paddr) {
928 if (info->dst.format == MDP_Y_CR_CB_GH2V2) {
929 iowrite32(ALIGN(info->dst.width, 16) |
930 ALIGN((info->dst.width / 2), 16) << 16,
931 MSM_ROTATOR_OUT_YSTRIDE1);
932 iowrite32(ALIGN((info->dst.width / 2), 16),
933 MSM_ROTATOR_OUT_YSTRIDE2);
934 } else {
935 iowrite32(info->dst.width |
936 info->dst.width/2 << 16,
937 MSM_ROTATOR_OUT_YSTRIDE1);
938 iowrite32(info->dst.width/2,
939 MSM_ROTATOR_OUT_YSTRIDE2);
940 }
941 } else {
942 iowrite32(info->dst.width |
943 info->dst.width << 16,
944 MSM_ROTATOR_OUT_YSTRIDE1);
945 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700946
Mayank Chopra27147a72012-07-17 13:57:22 +0530947 if (dst_format == MDP_Y_CBCR_H2V2 ||
948 dst_format == MDP_Y_CB_CR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700949 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
950 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
951 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
952 MSM_ROTATOR_OUT_PACK_PATTERN1);
953 } else {
954 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
955 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
956 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
957 MSM_ROTATOR_OUT_PACK_PATTERN1);
958 }
Mayank Chopra27147a72012-07-17 13:57:22 +0530959
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700960 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
961 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700962 1 << 8 | /* ROT_EN */
Mayank Chopra27147a72012-07-17 13:57:22 +0530963 fast_yuv_en << 4 | /*fast YUV*/
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700964 info->downscale_ratio << 2 | /* downscale v ratio */
965 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700966 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700967
968 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700969 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700970 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700971 0 << 18 | /* unpack align */
972 1 << 17 | /* unpack tight */
973 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700974 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700975 0 << 8 | /* has alpha */
976 0 << 6 | /* alpha bits 3=8bits */
977 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
978 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
979 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
980 MSM_ROTATOR_SRC_FORMAT);
981 }
982 return 0;
983}
984
985static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
986 unsigned int in_paddr,
987 unsigned int out_paddr,
988 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +0530989 int new_session,
990 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700991{
992 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +0530993 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700994
Mayank Chopra797bdb72012-03-03 06:29:40 +0530995 if (info->src.format == MDP_YCRYCB_H2V1) {
996 if (info->rotations & MDP_ROT_90)
997 dst_format = MDP_Y_CRCB_H1V2;
998 else
999 dst_format = MDP_Y_CRCB_H2V1;
1000 } else
Mayank Chopra732dcd62012-01-09 20:53:39 +05301001 return -EINVAL;
1002
1003 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001004 return -EINVAL;
1005
1006 bpp = get_bpp(info->src.format);
1007 if (bpp < 0)
1008 return -ENOTTY;
1009
1010 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
1011 iowrite32(out_paddr +
1012 ((info->dst_y * info->dst.width) + info->dst_x),
1013 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +05301014 iowrite32(out_chroma_paddr +
1015 ((info->dst_y * info->dst.width)/2 + info->dst_x),
1016 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017
1018 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +05301019 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001020 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +05301021 if (info->rotations & MDP_ROT_90)
1022 iowrite32(info->dst.width |
1023 (info->dst.width*2) << 16,
1024 MSM_ROTATOR_OUT_YSTRIDE1);
1025 else
1026 iowrite32(info->dst.width |
1027 (info->dst.width) << 16,
1028 MSM_ROTATOR_OUT_YSTRIDE1);
1029
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001030 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
1031 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +05301032 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001033 MSM_ROTATOR_OUT_PACK_PATTERN1);
1034 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
1035 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001036 1 << 8 | /* ROT_EN */
1037 info->downscale_ratio << 2 | /* downscale v ratio */
1038 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001039 MSM_ROTATOR_SUB_BLOCK_CFG);
1040 iowrite32(0 << 29 | /* frame format 0 = linear */
1041 (use_imem ? 0 : 1) << 22 | /* tile size */
1042 0 << 19 | /* fetch planes 0=interleaved */
1043 0 << 18 | /* unpack align */
1044 1 << 17 | /* unpack tight */
1045 3 << 13 | /* unpack count 0=1 component */
1046 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
1047 0 << 8 | /* has alpha */
1048 0 << 6 | /* alpha bits 3=8bits */
1049 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
1050 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
1051 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
1052 MSM_ROTATOR_SRC_FORMAT);
1053 }
1054
1055 return 0;
1056}
1057
1058static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
1059 unsigned int in_paddr,
1060 unsigned int out_paddr,
1061 unsigned int use_imem,
1062 int new_session)
1063{
1064 int bpp, abits, rbits, gbits, bbits;
1065
1066 if (info->src.format != info->dst.format)
1067 return -EINVAL;
1068
1069 bpp = get_bpp(info->src.format);
1070 if (bpp < 0)
1071 return -ENOTTY;
1072
1073 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
1074 iowrite32(out_paddr +
1075 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
1076 MSM_ROTATOR_OUTP0_ADDR);
1077
1078 if (new_session) {
1079 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
1080 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
1081 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
1082 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001083 1 << 8 | /* ROT_EN */
1084 info->downscale_ratio << 2 | /* downscale v ratio */
1085 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001086 MSM_ROTATOR_SUB_BLOCK_CFG);
1087 switch (info->src.format) {
1088 case MDP_RGB_565:
1089 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1090 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1091 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1092 MSM_ROTATOR_OUT_PACK_PATTERN1);
1093 abits = 0;
1094 rbits = COMPONENT_5BITS;
1095 gbits = COMPONENT_6BITS;
1096 bbits = COMPONENT_5BITS;
1097 break;
1098
1099 case MDP_BGR_565:
1100 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
1101 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1102 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
1103 MSM_ROTATOR_OUT_PACK_PATTERN1);
1104 abits = 0;
1105 rbits = COMPONENT_5BITS;
1106 gbits = COMPONENT_6BITS;
1107 bbits = COMPONENT_5BITS;
1108 break;
1109
1110 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001111 case MDP_YCBCR_H1V1:
1112 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001113 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1114 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1115 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1116 MSM_ROTATOR_OUT_PACK_PATTERN1);
1117 abits = 0;
1118 rbits = COMPONENT_8BITS;
1119 gbits = COMPONENT_8BITS;
1120 bbits = COMPONENT_8BITS;
1121 break;
1122
1123 case MDP_ARGB_8888:
1124 case MDP_RGBA_8888:
1125 case MDP_XRGB_8888:
1126 case MDP_RGBX_8888:
1127 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
1128 CLR_B, 8),
1129 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1130 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
1131 CLR_B, 8),
1132 MSM_ROTATOR_OUT_PACK_PATTERN1);
1133 abits = COMPONENT_8BITS;
1134 rbits = COMPONENT_8BITS;
1135 gbits = COMPONENT_8BITS;
1136 bbits = COMPONENT_8BITS;
1137 break;
1138
1139 case MDP_BGRA_8888:
1140 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
1141 CLR_R, 8),
1142 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1143 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
1144 CLR_R, 8),
1145 MSM_ROTATOR_OUT_PACK_PATTERN1);
1146 abits = COMPONENT_8BITS;
1147 rbits = COMPONENT_8BITS;
1148 gbits = COMPONENT_8BITS;
1149 bbits = COMPONENT_8BITS;
1150 break;
1151
1152 default:
1153 return -EINVAL;
1154 }
1155 iowrite32(0 << 29 | /* frame format 0 = linear */
1156 (use_imem ? 0 : 1) << 22 | /* tile size */
1157 0 << 19 | /* fetch planes 0=interleaved */
1158 0 << 18 | /* unpack align */
1159 1 << 17 | /* unpack tight */
1160 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
1161 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
1162 (abits ? 1 : 0) << 8 | /* has alpha */
1163 abits << 6 | /* alpha bits 3=8bits */
1164 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
1165 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
1166 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
1167 MSM_ROTATOR_SRC_FORMAT);
1168 }
1169
1170 return 0;
1171}
1172
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001173static int get_img(struct msmfb_data *fbd, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001174 unsigned long *start, unsigned long *len, struct file **p_file,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001175 int *p_need, struct ion_handle **p_ihdl, unsigned int secure)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001176{
1177 int ret = 0;
1178#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -07001179 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001180 int put_needed, fb_num;
1181#endif
1182#ifdef CONFIG_ANDROID_PMEM
1183 unsigned long vstart;
1184#endif
1185
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001186 *p_need = 0;
1187
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001188#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -07001189 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
1190 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001191 if (file == NULL) {
1192 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -07001193 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001194 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001195
Naseer Ahmed18018602011-10-25 13:32:58 -07001196 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
1197 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001198 if (get_fb_phys_info(start, len, fb_num,
1199 ROTATOR_SUBSYSTEM_ID)) {
1200 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -07001201 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001202 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -07001203 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001204 *p_need = put_needed;
1205 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001206 } else {
1207 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001208 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001209 }
Naseer Ahmed18018602011-10-25 13:32:58 -07001210 if (ret)
1211 fput_light(file, put_needed);
1212 return ret;
1213 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001214#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001215
1216#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001217 return msm_rotator_iommu_map_buf(fbd->memory_id, domain, start,
1218 len, p_ihdl, secure);
Naseer Ahmed18018602011-10-25 13:32:58 -07001219#endif
1220#ifdef CONFIG_ANDROID_PMEM
1221 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
1222 return 0;
1223 else
1224 return -ENOMEM;
1225#endif
1226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001227}
1228
Olav Hauganef95ae32012-05-15 09:50:30 -07001229static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001230 int domain, unsigned int secure)
Naseer Ahmed18018602011-10-25 13:32:58 -07001231{
1232#ifdef CONFIG_ANDROID_PMEM
1233 if (p_file != NULL)
1234 put_pmem_file(p_file);
1235#endif
Olav Hauganef95ae32012-05-15 09:50:30 -07001236
Naseer Ahmed18018602011-10-25 13:32:58 -07001237#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001238 if (!IS_ERR_OR_NULL(p_ihdl)) {
1239 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001240 if (rot_iommu_split_domain) {
1241 if (!secure)
1242 ion_unmap_iommu(msm_rotator_dev->client,
1243 p_ihdl, domain, GEN_POOL);
1244 } else {
1245 ion_unmap_iommu(msm_rotator_dev->client,
1246 p_ihdl, ROTATOR_SRC_DOMAIN, GEN_POOL);
1247 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001248
Naseer Ahmed18018602011-10-25 13:32:58 -07001249 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001250 }
Naseer Ahmed18018602011-10-25 13:32:58 -07001251#endif
1252}
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001253static int msm_rotator_do_rotate(unsigned long arg)
1254{
Naseer Ahmed18018602011-10-25 13:32:58 -07001255 unsigned int status, format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001256 struct msm_rotator_data_info info;
1257 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001258 unsigned long src_len, dst_len;
Naseer Ahmed18018602011-10-25 13:32:58 -07001259 int use_imem = 0, rc = 0, s;
1260 struct file *srcp0_file = NULL, *dstp0_file = NULL;
1261 struct file *srcp1_file = NULL, *dstp1_file = NULL;
1262 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
1263 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001264 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001265 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Mayank Chopra27147a72012-07-17 13:57:22 +05301266 unsigned int in_chroma2_paddr = 0, out_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001267 struct msm_rotator_img_info *img_info;
1268 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001269
1270 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1271 return -EFAULT;
1272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273 mutex_lock(&msm_rotator_dev->rotator_lock);
1274 for (s = 0; s < MAX_SESSIONS; s++)
Mayank Chopra27147a72012-07-17 13:57:22 +05301275 if ((msm_rotator_dev->rot_session[s] != NULL) &&
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001276 (info.session_id ==
Mayank Chopra27147a72012-07-17 13:57:22 +05301277 (unsigned int)msm_rotator_dev->rot_session[s]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001278 ))
1279 break;
1280
1281 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001282 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001283 __func__, s);
1284 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001285 mutex_unlock(&msm_rotator_dev->rotator_lock);
1286 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001287 }
1288
Mayank Chopra27147a72012-07-17 13:57:22 +05301289 img_info = &(msm_rotator_dev->rot_session[s]->img_info);
1290 if (img_info->enable == 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001291 dev_dbg(msm_rotator_dev->device,
Mayank Chopra27147a72012-07-17 13:57:22 +05301292 "%s() : Session_id %d not enabled\n", __func__, s);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001293 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001294 mutex_unlock(&msm_rotator_dev->rotator_lock);
1295 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001296 }
1297
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001298 if (msm_rotator_get_plane_sizes(img_info->src.format,
1299 img_info->src.width,
1300 img_info->src.height,
1301 &src_planes)) {
1302 pr_err("%s: invalid src format\n", __func__);
1303 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001304 mutex_unlock(&msm_rotator_dev->rotator_lock);
1305 return rc;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001306 }
1307 if (msm_rotator_get_plane_sizes(img_info->dst.format,
1308 img_info->dst.width,
1309 img_info->dst.height,
1310 &dst_planes)) {
1311 pr_err("%s: invalid dst format\n", __func__);
1312 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001313 mutex_unlock(&msm_rotator_dev->rotator_lock);
1314 return rc;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001315 }
1316
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001317 rc = get_img(&info.src, ROTATOR_SRC_DOMAIN, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001318 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001319 &srcp0_ihdl, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001320 if (rc) {
1321 pr_err("%s: in get_img() failed id=0x%08x\n",
1322 DRIVER_NAME, info.src.memory_id);
1323 goto do_rotate_unlock_mutex;
1324 }
1325
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001326 rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001327 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001328 &dstp0_ihdl, img_info->secure);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001329 if (rc) {
1330 pr_err("%s: out get_img() failed id=0x%08x\n",
1331 DRIVER_NAME, info.dst.memory_id);
1332 goto do_rotate_unlock_mutex;
1333 }
1334
Mayank Chopra27147a72012-07-17 13:57:22 +05301335 format = img_info->src.format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001336 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001337 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
1338 (src_planes.num_planes == 2)) {
1339 if (checkoffset(info.src.offset,
1340 src_planes.plane_size[0],
1341 src_len)) {
1342 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1343 __func__, src_len, info.src.offset);
1344 rc = -ERANGE;
1345 goto do_rotate_unlock_mutex;
1346 }
1347 if (checkoffset(info.dst.offset,
1348 dst_planes.plane_size[0],
1349 dst_len)) {
1350 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1351 __func__, dst_len, info.dst.offset);
1352 rc = -ERANGE;
1353 goto do_rotate_unlock_mutex;
1354 }
1355
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001356 rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001357 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001358 (unsigned long *)&src_len, &srcp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001359 &srcp1_ihdl, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001360 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001361 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001362 DRIVER_NAME, info.src_chroma.memory_id);
1363 goto do_rotate_unlock_mutex;
1364 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001365
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001366 rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001367 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001368 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001369 &dstp1_ihdl, img_info->secure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001370 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001371 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001372 DRIVER_NAME, info.dst_chroma.memory_id);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001373 goto do_rotate_unlock_mutex;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001374 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001375
1376 if (checkoffset(info.src_chroma.offset,
1377 src_planes.plane_size[1],
1378 src_len)) {
1379 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1380 __func__, src_len, info.src_chroma.offset);
1381 rc = -ERANGE;
1382 goto do_rotate_unlock_mutex;
1383 }
1384
1385 if (checkoffset(info.dst_chroma.offset,
1386 src_planes.plane_size[1],
1387 dst_len)) {
1388 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1389 __func__, dst_len, info.dst_chroma.offset);
1390 rc = -ERANGE;
1391 goto do_rotate_unlock_mutex;
1392 }
1393
1394 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001395 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001396 } else {
1397 if (checkoffset(info.src.offset,
1398 src_planes.total_size,
1399 src_len)) {
1400 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1401 __func__, src_len, info.src.offset);
1402 rc = -ERANGE;
1403 goto do_rotate_unlock_mutex;
1404 }
1405 if (checkoffset(info.dst.offset,
1406 dst_planes.total_size,
1407 dst_len)) {
1408 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1409 __func__, dst_len, info.dst.offset);
1410 rc = -ERANGE;
1411 goto do_rotate_unlock_mutex;
1412 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413 }
1414
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001415 in_paddr += info.src.offset;
1416 out_paddr += info.dst.offset;
1417
1418 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1419 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1420 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1421 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1422 if (src_planes.num_planes >= 3)
1423 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
Mayank Chopra27147a72012-07-17 13:57:22 +05301424 if (dst_planes.num_planes >= 3)
1425 out_chroma2_paddr = out_chroma_paddr + dst_planes.plane_size[1];
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001426
Ken Zhanga50db542013-02-20 14:48:06 -05001427 msm_rotator_wait_for_fence(s);
1428
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001429 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1430 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1431 enable_rot_clks();
1432 msm_rotator_dev->rot_clk_state = CLK_EN;
1433 }
1434 enable_irq(msm_rotator_dev->irq);
1435
1436#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1437 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1438#else
1439 use_imem = 0;
1440#endif
1441 /*
1442 * workaround for a hardware bug. rotator hardware hangs when we
1443 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1444 * temporary fix use 0x42 for BURST_SIZE when imem used.
1445 */
1446 if (use_imem)
1447 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1448
Mayank Chopra27147a72012-07-17 13:57:22 +05301449 iowrite32(((img_info->src_rect.h & 0x1fff)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001450 << 16) |
Mayank Chopra27147a72012-07-17 13:57:22 +05301451 (img_info->src_rect.w & 0x1fff),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001452 MSM_ROTATOR_SRC_SIZE);
Mayank Chopra27147a72012-07-17 13:57:22 +05301453 iowrite32(((img_info->src_rect.y & 0x1fff)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001454 << 16) |
Mayank Chopra27147a72012-07-17 13:57:22 +05301455 (img_info->src_rect.x & 0x1fff),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001456 MSM_ROTATOR_SRC_XY);
Mayank Chopra27147a72012-07-17 13:57:22 +05301457 iowrite32(((img_info->src.height & 0x1fff)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001458 << 16) |
Mayank Chopra27147a72012-07-17 13:57:22 +05301459 (img_info->src.width & 0x1fff),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001460 MSM_ROTATOR_SRC_IMAGE_SIZE);
1461
1462 switch (format) {
1463 case MDP_RGB_565:
1464 case MDP_BGR_565:
1465 case MDP_RGB_888:
1466 case MDP_ARGB_8888:
1467 case MDP_RGBA_8888:
1468 case MDP_XRGB_8888:
1469 case MDP_BGRA_8888:
1470 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001471 case MDP_YCBCR_H1V1:
1472 case MDP_YCRCB_H1V1:
Mayank Chopra27147a72012-07-17 13:57:22 +05301473 rc = msm_rotator_rgb_types(img_info,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001474 in_paddr, out_paddr,
1475 use_imem,
1476 msm_rotator_dev->last_session_idx
1477 != s);
1478 break;
1479 case MDP_Y_CBCR_H2V2:
1480 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001481 case MDP_Y_CB_CR_H2V2:
1482 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301483 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001484 case MDP_Y_CRCB_H2V2_TILE:
1485 case MDP_Y_CBCR_H2V2_TILE:
Mayank Chopra27147a72012-07-17 13:57:22 +05301486 rc = msm_rotator_ycxcx_h2v2(img_info,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001487 in_paddr, out_paddr, use_imem,
1488 msm_rotator_dev->last_session_idx
1489 != s,
1490 in_chroma_paddr,
1491 out_chroma_paddr,
Mayank Chopra27147a72012-07-17 13:57:22 +05301492 in_chroma2_paddr,
1493 out_chroma2_paddr);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001494 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001495 case MDP_Y_CBCR_H2V1:
1496 case MDP_Y_CRCB_H2V1:
Mayank Chopra27147a72012-07-17 13:57:22 +05301497 rc = msm_rotator_ycxcx_h2v1(img_info,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001498 in_paddr, out_paddr, use_imem,
1499 msm_rotator_dev->last_session_idx
1500 != s,
1501 in_chroma_paddr,
1502 out_chroma_paddr);
1503 break;
1504 case MDP_YCRYCB_H2V1:
Mayank Chopra27147a72012-07-17 13:57:22 +05301505 rc = msm_rotator_ycrycb(img_info,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001506 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301507 msm_rotator_dev->last_session_idx != s,
1508 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001509 break;
1510 default:
1511 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001512 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001513 goto do_rotate_exit;
1514 }
1515
1516 if (rc != 0) {
1517 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001518 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001519 goto do_rotate_exit;
1520 }
1521
1522 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1523
1524 msm_rotator_dev->processing = 1;
1525 iowrite32(0x1, MSM_ROTATOR_START);
1526
1527 wait_event(msm_rotator_dev->wq,
1528 (msm_rotator_dev->processing == 0));
1529 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001530 if ((status & 0x03) != 0x01) {
1531 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1532 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001533 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001534 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001535 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1536 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1537
1538do_rotate_exit:
1539 disable_irq(msm_rotator_dev->irq);
1540#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1541 msm_rotator_imem_free(ROTATOR_REQUEST);
1542#endif
1543 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001544do_rotate_unlock_mutex:
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001545 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
Mayank Chopra27147a72012-07-17 13:57:22 +05301546 msm_rotator_dev->rot_session[s]->img_info.secure);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001547 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1548 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
Mayank Chopra27147a72012-07-17 13:57:22 +05301549 msm_rotator_dev->rot_session[s]->img_info.secure);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001550
1551 /* only source may use frame buffer */
1552 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1553 fput_light(srcp0_file, ps0_need);
1554 else
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001555 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
Ken Zhanga50db542013-02-20 14:48:06 -05001556 msm_rotator_signal_timeline(s);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001557 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1559 __func__, rc);
1560 return rc;
1561}
1562
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001563static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1564{
1565 u32 perf_level;
1566
1567 if (is_rgb)
1568 perf_level = 1;
1569 else if (wh <= (640 * 480))
1570 perf_level = 2;
1571 else if (wh <= (736 * 1280))
1572 perf_level = 3;
1573 else
1574 perf_level = 4;
1575
1576#ifdef CONFIG_MSM_BUS_SCALING
1577 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1578 perf_level);
1579#endif
1580
1581}
1582
Ken Zhangfebeabd2012-12-17 10:35:15 -05001583static int rot_enable_iommu_clocks(struct msm_rotator_dev *rot_dev)
1584{
1585 int ret = 0, i;
1586 if (rot_dev->mmu_clk_on)
1587 return 0;
1588 for (i = 0; i < ARRAY_SIZE(rot_mmu_clks); i++) {
1589 rot_mmu_clks[i].mmu_clk = clk_get(&msm_rotator_dev->pdev->dev,
1590 rot_mmu_clks[i].mmu_clk_name);
1591 if (IS_ERR(rot_mmu_clks[i].mmu_clk)) {
1592 pr_err(" %s: Get failed for clk %s", __func__,
1593 rot_mmu_clks[i].mmu_clk_name);
1594 ret = PTR_ERR(rot_mmu_clks[i].mmu_clk);
1595 break;
1596 }
1597 ret = clk_prepare_enable(rot_mmu_clks[i].mmu_clk);
1598 if (ret) {
1599 clk_put(rot_mmu_clks[i].mmu_clk);
1600 rot_mmu_clks[i].mmu_clk = NULL;
1601 }
1602 }
1603 if (ret) {
1604 for (i--; i >= 0; i--) {
1605 clk_disable_unprepare(rot_mmu_clks[i].mmu_clk);
1606 clk_put(rot_mmu_clks[i].mmu_clk);
1607 rot_mmu_clks[i].mmu_clk = NULL;
1608 }
1609 } else {
1610 rot_dev->mmu_clk_on = 1;
1611 }
1612 return ret;
1613}
1614
1615static int rot_disable_iommu_clocks(struct msm_rotator_dev *rot_dev)
1616{
1617 int i;
1618 if (!rot_dev->mmu_clk_on)
1619 return 0;
1620 for (i = 0; i < ARRAY_SIZE(rot_mmu_clks); i++) {
1621 clk_disable_unprepare(rot_mmu_clks[i].mmu_clk);
1622 clk_put(rot_mmu_clks[i].mmu_clk);
1623 rot_mmu_clks[i].mmu_clk = NULL;
1624 }
1625 rot_dev->mmu_clk_on = 0;
1626 return 0;
1627}
1628
1629static int map_sec_resource(struct msm_rotator_dev *rot_dev)
1630{
1631 int ret = 0;
1632 if (rot_dev->sec_mapped)
1633 return 0;
1634
1635 ret = rot_enable_iommu_clocks(rot_dev);
1636 if (ret) {
1637 pr_err("IOMMU clock enabled failed while open");
1638 return ret;
1639 }
1640 ret = msm_ion_secure_heap(ION_HEAP(ION_CP_MM_HEAP_ID));
1641 if (ret)
1642 pr_err("ION heap secure failed heap id %d ret %d\n",
1643 ION_CP_MM_HEAP_ID, ret);
1644 else
1645 rot_dev->sec_mapped = 1;
1646 rot_disable_iommu_clocks(rot_dev);
1647 return ret;
1648}
1649
1650static int unmap_sec_resource(struct msm_rotator_dev *rot_dev)
1651{
1652 int ret = 0;
1653 ret = rot_enable_iommu_clocks(rot_dev);
1654 if (ret) {
1655 pr_err("IOMMU clock enabled failed while close\n");
1656 return ret;
1657 }
1658 msm_ion_unsecure_heap(ION_HEAP(ION_CP_MM_HEAP_ID));
1659 rot_dev->sec_mapped = 0;
1660 rot_disable_iommu_clocks(rot_dev);
1661 return ret;
1662}
1663
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001664static int msm_rotator_start(unsigned long arg,
1665 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666{
1667 struct msm_rotator_img_info info;
Mayank Chopra27147a72012-07-17 13:57:22 +05301668 struct msm_rotator_session *rot_session = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001669 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001670 int s, is_rgb = 0;
Mayank Chopra27147a72012-07-17 13:57:22 +05301671 int first_free_idx = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001672 unsigned int dst_w, dst_h;
Mayank Chopra27147a72012-07-17 13:57:22 +05301673 unsigned int is_planar420 = 0;
1674 int fast_yuv_en = 0;
Ken Zhanga50db542013-02-20 14:48:06 -05001675 struct rot_sync_info *sync_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001676
1677 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1678 return -EFAULT;
1679
1680 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1681 (info.src.height > MSM_ROTATOR_MAX_H) ||
1682 (info.src.width > MSM_ROTATOR_MAX_W) ||
1683 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1684 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001685 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1686 pr_err("%s: Invalid parameters\n", __func__);
1687 return -EINVAL;
1688 }
1689
1690 if (info.rotations & MDP_ROT_90) {
1691 dst_w = info.src_rect.h >> info.downscale_ratio;
1692 dst_h = info.src_rect.w >> info.downscale_ratio;
1693 } else {
1694 dst_w = info.src_rect.w >> info.downscale_ratio;
1695 dst_h = info.src_rect.h >> info.downscale_ratio;
1696 }
1697
1698 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001699 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1700 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001701 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1702 pr_err("%s: Invalid src or dst rect\n", __func__);
1703 return -ERANGE;
1704 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001705
1706 switch (info.src.format) {
Mayank Chopra27147a72012-07-17 13:57:22 +05301707 case MDP_Y_CB_CR_H2V2:
1708 case MDP_Y_CR_CB_H2V2:
1709 case MDP_Y_CR_CB_GH2V2:
1710 is_planar420 = 1;
1711 case MDP_Y_CBCR_H2V2:
1712 case MDP_Y_CRCB_H2V2:
1713 case MDP_Y_CRCB_H2V2_TILE:
1714 case MDP_Y_CBCR_H2V2_TILE:
1715 if (rotator_hw_revision >= ROTATOR_REVISION_V2 &&
1716 !(info.downscale_ratio &&
1717 (info.rotations & MDP_ROT_90)))
1718 fast_yuv_en = !fast_yuv_invalid_size_checker(
1719 info.rotations,
1720 info.src.width,
1721 dst_w,
1722 dst_h,
1723 dst_w,
1724 is_planar420);
1725 break;
1726 default:
1727 fast_yuv_en = 0;
1728 }
1729
1730 switch (info.src.format) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001731 case MDP_RGB_565:
1732 case MDP_BGR_565:
1733 case MDP_RGB_888:
1734 case MDP_ARGB_8888:
1735 case MDP_RGBA_8888:
1736 case MDP_XRGB_8888:
1737 case MDP_RGBX_8888:
1738 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001739 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301740 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001741 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001742 case MDP_Y_CBCR_H2V2:
1743 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301744 case MDP_Y_CBCR_H2V1:
1745 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001746 case MDP_YCBCR_H1V1:
1747 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301748 info.dst.format = info.src.format;
1749 break;
1750 case MDP_YCRYCB_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +05301751 if (info.rotations & MDP_ROT_90)
1752 info.dst.format = MDP_Y_CRCB_H1V2;
1753 else
1754 info.dst.format = MDP_Y_CRCB_H2V1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301755 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001756 case MDP_Y_CB_CR_H2V2:
Mayank Chopra27147a72012-07-17 13:57:22 +05301757 if (fast_yuv_en) {
1758 info.dst.format = info.src.format;
1759 break;
1760 }
Mayank Chopra012a8e72012-04-11 10:41:13 +05301761 case MDP_Y_CBCR_H2V2_TILE:
1762 info.dst.format = MDP_Y_CBCR_H2V2;
1763 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001764 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301765 case MDP_Y_CR_CB_GH2V2:
Mayank Chopra27147a72012-07-17 13:57:22 +05301766 if (fast_yuv_en) {
1767 info.dst.format = info.src.format;
1768 break;
1769 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001770 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301771 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001772 break;
1773 default:
1774 return -EINVAL;
1775 }
1776
1777 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001778
1779 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
1780
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001781 for (s = 0; s < MAX_SESSIONS; s++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05301782 if ((msm_rotator_dev->rot_session[s] != NULL) &&
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001783 (info.session_id ==
Mayank Chopra27147a72012-07-17 13:57:22 +05301784 (unsigned int)msm_rotator_dev->rot_session[s]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001785 )) {
Mayank Chopra27147a72012-07-17 13:57:22 +05301786 rot_session = msm_rotator_dev->rot_session[s];
1787 rot_session->img_info = info;
1788 rot_session->fd_info = *fd_info;
1789 rot_session->fast_yuv_enable = fast_yuv_en;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001790
1791 if (msm_rotator_dev->last_session_idx == s)
1792 msm_rotator_dev->last_session_idx =
1793 INVALID_SESSION;
1794 break;
1795 }
1796
Mayank Chopra27147a72012-07-17 13:57:22 +05301797 if ((msm_rotator_dev->rot_session[s] == NULL) &&
1798 (first_free_idx == INVALID_SESSION))
1799 first_free_idx = s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001800 }
1801
Mayank Chopra27147a72012-07-17 13:57:22 +05301802 if ((s == MAX_SESSIONS) && (first_free_idx != INVALID_SESSION)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001803 /* allocate a session id */
Mayank Chopra27147a72012-07-17 13:57:22 +05301804 msm_rotator_dev->rot_session[first_free_idx] =
1805 kzalloc(sizeof(struct msm_rotator_session),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001806 GFP_KERNEL);
Mayank Chopra27147a72012-07-17 13:57:22 +05301807 if (!msm_rotator_dev->rot_session[first_free_idx]) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001808 printk(KERN_ERR "%s : unable to alloc mem\n",
1809 __func__);
1810 rc = -ENOMEM;
1811 goto rotator_start_exit;
1812 }
1813 info.session_id = (unsigned int)
Mayank Chopra27147a72012-07-17 13:57:22 +05301814 msm_rotator_dev->rot_session[first_free_idx];
1815 rot_session = msm_rotator_dev->rot_session[first_free_idx];
1816
1817 rot_session->img_info = info;
1818 rot_session->fd_info = *fd_info;
1819 rot_session->fast_yuv_enable = fast_yuv_en;
Ken Zhanga50db542013-02-20 14:48:06 -05001820 s = first_free_idx;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001821 } else if (s == MAX_SESSIONS) {
1822 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
1823 __func__);
1824 rc = -EBUSY;
1825 }
1826
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07001827 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
1828 rc = -EFAULT;
Ken Zhangfebeabd2012-12-17 10:35:15 -05001829 if ((rc == 0) && (info.secure))
1830 map_sec_resource(msm_rotator_dev);
Ken Zhanga50db542013-02-20 14:48:06 -05001831
1832 sync_info = &msm_rotator_dev->sync_info[s];
1833 if ((rc == 0) && (sync_info->initialized == false)) {
1834 char timeline_name[MAX_TIMELINE_NAME_LEN];
1835 if (sync_info->timeline == NULL) {
1836 snprintf(timeline_name, sizeof(timeline_name),
1837 "msm_rot_%d", first_free_idx);
1838 sync_info->timeline =
1839 sw_sync_timeline_create(timeline_name);
1840 if (sync_info->timeline == NULL)
1841 pr_err("%s: cannot create %s time line",
1842 __func__, timeline_name);
1843 sync_info->timeline_value = 0;
1844 }
1845 mutex_init(&sync_info->sync_mutex);
1846 sync_info->initialized = true;
1847 }
1848 sync_info->acq_fen = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001849rotator_start_exit:
1850 mutex_unlock(&msm_rotator_dev->rotator_lock);
1851
1852 return rc;
1853}
1854
1855static int msm_rotator_finish(unsigned long arg)
1856{
1857 int rc = 0;
1858 int s;
1859 unsigned int session_id;
1860
1861 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
1862 return -EFAULT;
1863
1864 mutex_lock(&msm_rotator_dev->rotator_lock);
1865 for (s = 0; s < MAX_SESSIONS; s++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05301866 if ((msm_rotator_dev->rot_session[s] != NULL) &&
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001867 (session_id ==
Mayank Chopra27147a72012-07-17 13:57:22 +05301868 (unsigned int)msm_rotator_dev->rot_session[s])) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001869 if (msm_rotator_dev->last_session_idx == s)
1870 msm_rotator_dev->last_session_idx =
1871 INVALID_SESSION;
Ken Zhanga50db542013-02-20 14:48:06 -05001872 msm_rotator_signal_timeline(s);
1873 msm_rotator_release_acq_fence(s);
Mayank Chopra27147a72012-07-17 13:57:22 +05301874 kfree(msm_rotator_dev->rot_session[s]);
1875 msm_rotator_dev->rot_session[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001876 break;
1877 }
1878 }
1879
1880 if (s == MAX_SESSIONS)
1881 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001882#ifdef CONFIG_MSM_BUS_SCALING
1883 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1884 0);
1885#endif
Ken Zhangfebeabd2012-12-17 10:35:15 -05001886 if (msm_rotator_dev->sec_mapped)
1887 unmap_sec_resource(msm_rotator_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001888 mutex_unlock(&msm_rotator_dev->rotator_lock);
1889 return rc;
1890}
1891
1892static int
1893msm_rotator_open(struct inode *inode, struct file *filp)
1894{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001895 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001896 int i;
1897
1898 if (filp->private_data)
1899 return -EBUSY;
1900
1901 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001902 for (i = 0; i < MAX_SESSIONS; i++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05301903 if (msm_rotator_dev->rot_session[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904 break;
1905 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001906
1907 if (i == MAX_SESSIONS) {
1908 mutex_unlock(&msm_rotator_dev->rotator_lock);
1909 return -EBUSY;
1910 }
1911
1912 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
1913 if (tmp->pid == current->pid) {
1914 fd_info = tmp;
1915 break;
1916 }
1917 }
1918
1919 if (!fd_info) {
1920 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
1921 if (!fd_info) {
1922 mutex_unlock(&msm_rotator_dev->rotator_lock);
1923 pr_err("%s: insufficient memory to alloc resources\n",
1924 __func__);
1925 return -ENOMEM;
1926 }
1927 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
1928 fd_info->pid = current->pid;
1929 }
1930 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001931 mutex_unlock(&msm_rotator_dev->rotator_lock);
1932
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001933 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001934
1935 return 0;
1936}
1937
1938static int
1939msm_rotator_close(struct inode *inode, struct file *filp)
1940{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001941 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001942 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001944 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
1945
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001946 mutex_lock(&msm_rotator_dev->rotator_lock);
Ken Zhanga50db542013-02-20 14:48:06 -05001947 msm_rotator_release_all_timeline();
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001948 if (--fd_info->ref_cnt > 0) {
1949 mutex_unlock(&msm_rotator_dev->rotator_lock);
1950 return 0;
1951 }
1952
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001953 for (s = 0; s < MAX_SESSIONS; s++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05301954 if (msm_rotator_dev->rot_session[s] != NULL &&
1955 &(msm_rotator_dev->rot_session[s]->fd_info) == fd_info) {
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001956 pr_debug("%s: freeing rotator session %p (pid %d)\n",
Mayank Chopra27147a72012-07-17 13:57:22 +05301957 __func__, msm_rotator_dev->rot_session[s],
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001958 fd_info->pid);
Mayank Chopra27147a72012-07-17 13:57:22 +05301959 kfree(msm_rotator_dev->rot_session[s]);
1960 msm_rotator_dev->rot_session[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001961 if (msm_rotator_dev->last_session_idx == s)
1962 msm_rotator_dev->last_session_idx =
1963 INVALID_SESSION;
1964 }
1965 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001966 list_del(&fd_info->list);
1967 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001968 mutex_unlock(&msm_rotator_dev->rotator_lock);
1969
1970 return 0;
1971}
1972
1973static long msm_rotator_ioctl(struct file *file, unsigned cmd,
1974 unsigned long arg)
1975{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001976 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001977
1978 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
1979 return -ENOTTY;
1980
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001981 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001982
1983 switch (cmd) {
1984 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001985 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001986 case MSM_ROTATOR_IOCTL_ROTATE:
1987 return msm_rotator_do_rotate(arg);
1988 case MSM_ROTATOR_IOCTL_FINISH:
1989 return msm_rotator_finish(arg);
Ken Zhanga50db542013-02-20 14:48:06 -05001990 case MSM_ROTATOR_IOCTL_BUFFER_SYNC:
1991 return msm_rotator_buf_sync(arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001992
1993 default:
1994 dev_dbg(msm_rotator_dev->device,
1995 "unexpected IOCTL %d\n", cmd);
1996 return -ENOTTY;
1997 }
1998}
1999
2000static const struct file_operations msm_rotator_fops = {
2001 .owner = THIS_MODULE,
2002 .open = msm_rotator_open,
2003 .release = msm_rotator_close,
2004 .unlocked_ioctl = msm_rotator_ioctl,
2005};
2006
2007static int __devinit msm_rotator_probe(struct platform_device *pdev)
2008{
2009 int rc = 0;
2010 struct resource *res;
2011 struct msm_rotator_platform_data *pdata = NULL;
2012 int i, number_of_clks;
2013 uint32_t ver;
2014
2015 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
2016 if (!msm_rotator_dev) {
2017 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
2018 __func__);
2019 return -ENOMEM;
2020 }
2021 for (i = 0; i < MAX_SESSIONS; i++)
Mayank Chopra27147a72012-07-17 13:57:22 +05302022 msm_rotator_dev->rot_session[i] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 msm_rotator_dev->last_session_idx = INVALID_SESSION;
2024
2025 pdata = pdev->dev.platform_data;
2026 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07002027 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028
2029 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
2030 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002031 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002032 msm_rotator_dev->imem_clk_state = CLK_DIS;
2033 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
2034 msm_rotator_imem_clk_work_f);
2035 msm_rotator_dev->imem_clk = NULL;
2036 msm_rotator_dev->pdev = pdev;
2037
2038 msm_rotator_dev->core_clk = NULL;
2039 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002040
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002041#ifdef CONFIG_MSM_BUS_SCALING
2042 if (!msm_rotator_dev->bus_client_handle && pdata &&
2043 pdata->bus_scale_table) {
2044 msm_rotator_dev->bus_client_handle =
2045 msm_bus_scale_register_client(
2046 pdata->bus_scale_table);
2047 if (!msm_rotator_dev->bus_client_handle) {
2048 pr_err("%s not able to get bus scale handle\n",
2049 __func__);
2050 }
2051 }
2052#endif
2053
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002054 for (i = 0; i < number_of_clks; i++) {
2055 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
2056 msm_rotator_dev->imem_clk =
2057 clk_get(&msm_rotator_dev->pdev->dev,
2058 pdata->rotator_clks[i].clk_name);
2059 if (IS_ERR(msm_rotator_dev->imem_clk)) {
2060 rc = PTR_ERR(msm_rotator_dev->imem_clk);
2061 msm_rotator_dev->imem_clk = NULL;
2062 printk(KERN_ERR "%s: cannot get imem_clk "
2063 "rc=%d\n", DRIVER_NAME, rc);
2064 goto error_imem_clk;
2065 }
2066 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08002067 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002068 pdata->rotator_clks[i].clk_rate);
2069 }
2070 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
2071 msm_rotator_dev->pclk =
2072 clk_get(&msm_rotator_dev->pdev->dev,
2073 pdata->rotator_clks[i].clk_name);
2074 if (IS_ERR(msm_rotator_dev->pclk)) {
2075 rc = PTR_ERR(msm_rotator_dev->pclk);
2076 msm_rotator_dev->pclk = NULL;
2077 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
2078 DRIVER_NAME, rc);
2079 goto error_pclk;
2080 }
2081
2082 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08002083 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002084 pdata->rotator_clks[i].clk_rate);
2085 }
2086
2087 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
2088 msm_rotator_dev->core_clk =
2089 clk_get(&msm_rotator_dev->pdev->dev,
2090 pdata->rotator_clks[i].clk_name);
2091 if (IS_ERR(msm_rotator_dev->core_clk)) {
2092 rc = PTR_ERR(msm_rotator_dev->core_clk);
2093 msm_rotator_dev->core_clk = NULL;
2094 printk(KERN_ERR "%s: cannot get core clk "
2095 "rc=%d\n", DRIVER_NAME, rc);
2096 goto error_core_clk;
2097 }
2098
2099 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08002100 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002101 pdata->rotator_clks[i].clk_rate);
2102 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002103 }
2104
Matt Wagantall316f2fc2012-05-03 20:41:42 -07002105 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
2106 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002107 if (IS_ERR(msm_rotator_dev->regulator))
2108 msm_rotator_dev->regulator = NULL;
2109
2110 msm_rotator_dev->rot_clk_state = CLK_DIS;
2111 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
2112 msm_rotator_rot_clk_work_f);
2113
2114 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07002115#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
2116 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
2117#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002118 platform_set_drvdata(pdev, msm_rotator_dev);
2119
2120
2121 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2122 if (!res) {
2123 printk(KERN_ALERT
2124 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
2125 rc = -ENODEV;
2126 goto error_get_resource;
2127 }
2128 msm_rotator_dev->io_base = ioremap(res->start,
2129 resource_size(res));
2130
2131#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
2132 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002133 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002134#endif
2135 enable_rot_clks();
2136 ver = ioread32(MSM_ROTATOR_HW_VERSION);
2137 disable_rot_clks();
2138
2139#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
2140 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002141 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002142#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07002143 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05302144 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07002145 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07002146
Mayank Chopra012a8e72012-04-11 10:41:13 +05302147 rotator_hw_revision = ver;
2148 rotator_hw_revision >>= 16; /* bit 31:16 */
2149 rotator_hw_revision &= 0xff;
2150
2151 pr_info("%s: rotator_hw_revision=%x\n",
2152 __func__, rotator_hw_revision);
2153
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002154 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
2155 if (msm_rotator_dev->irq < 0) {
2156 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
2157 DRIVER_NAME);
2158 rc = -ENODEV;
2159 goto error_get_irq;
2160 }
2161 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
2162 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
2163 if (rc) {
2164 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
2165 goto error_get_irq;
2166 }
2167 /* we enable the IRQ when we need it in the ioctl */
2168 disable_irq(msm_rotator_dev->irq);
2169
2170 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
2171 if (rc < 0) {
2172 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
2173 __func__, rc);
2174 goto error_get_irq;
2175 }
2176
2177 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
2178 if (IS_ERR(msm_rotator_dev->class)) {
2179 rc = PTR_ERR(msm_rotator_dev->class);
2180 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
2181 DRIVER_NAME, rc);
2182 goto error_class_create;
2183 }
2184
2185 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
2186 msm_rotator_dev->dev_num, NULL,
2187 DRIVER_NAME);
2188 if (IS_ERR(msm_rotator_dev->device)) {
2189 rc = PTR_ERR(msm_rotator_dev->device);
2190 printk(KERN_ERR "%s: device_create failed %d\n",
2191 DRIVER_NAME, rc);
2192 goto error_class_device_create;
2193 }
2194
2195 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
2196 rc = cdev_add(&msm_rotator_dev->cdev,
2197 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
2198 1);
2199 if (rc < 0) {
2200 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
2201 goto error_cdev_add;
2202 }
2203
2204 init_waitqueue_head(&msm_rotator_dev->wq);
2205
2206 dev_dbg(msm_rotator_dev->device, "probe successful\n");
2207 return rc;
2208
2209error_cdev_add:
2210 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
2211error_class_device_create:
2212 class_destroy(msm_rotator_dev->class);
2213error_class_create:
2214 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
2215error_get_irq:
2216 iounmap(msm_rotator_dev->io_base);
2217error_get_resource:
2218 mutex_destroy(&msm_rotator_dev->rotator_lock);
2219 if (msm_rotator_dev->regulator)
2220 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002221 clk_put(msm_rotator_dev->core_clk);
2222error_core_clk:
2223 clk_put(msm_rotator_dev->pclk);
2224error_pclk:
2225 if (msm_rotator_dev->imem_clk)
2226 clk_put(msm_rotator_dev->imem_clk);
2227error_imem_clk:
2228 mutex_destroy(&msm_rotator_dev->imem_lock);
2229 kfree(msm_rotator_dev);
2230 return rc;
2231}
2232
2233static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
2234{
2235 int i;
2236
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002237#ifdef CONFIG_MSM_BUS_SCALING
Huaibin Yang5bc13e02013-01-10 17:52:45 -08002238 if (msm_rotator_dev->bus_client_handle) {
2239 msm_bus_scale_unregister_client
2240 (msm_rotator_dev->bus_client_handle);
2241 msm_rotator_dev->bus_client_handle = 0;
2242 }
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002243#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002244 free_irq(msm_rotator_dev->irq, NULL);
2245 mutex_destroy(&msm_rotator_dev->rotator_lock);
2246 cdev_del(&msm_rotator_dev->cdev);
2247 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
2248 class_destroy(msm_rotator_dev->class);
2249 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
2250 iounmap(msm_rotator_dev->io_base);
2251 if (msm_rotator_dev->imem_clk) {
2252 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002253 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002254 clk_put(msm_rotator_dev->imem_clk);
2255 msm_rotator_dev->imem_clk = NULL;
2256 }
2257 if (msm_rotator_dev->rot_clk_state == CLK_EN)
2258 disable_rot_clks();
2259 clk_put(msm_rotator_dev->core_clk);
2260 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002261 if (msm_rotator_dev->regulator)
2262 regulator_put(msm_rotator_dev->regulator);
2263 msm_rotator_dev->core_clk = NULL;
2264 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002265 mutex_destroy(&msm_rotator_dev->imem_lock);
2266 for (i = 0; i < MAX_SESSIONS; i++)
Mayank Chopra27147a72012-07-17 13:57:22 +05302267 if (msm_rotator_dev->rot_session[i] != NULL)
2268 kfree(msm_rotator_dev->rot_session[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002269 kfree(msm_rotator_dev);
2270 return 0;
2271}
2272
2273#ifdef CONFIG_PM
2274static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
2275{
2276 mutex_lock(&msm_rotator_dev->imem_lock);
2277 if (msm_rotator_dev->imem_clk_state == CLK_EN
2278 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002279 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
2281 }
2282 mutex_unlock(&msm_rotator_dev->imem_lock);
2283 mutex_lock(&msm_rotator_dev->rotator_lock);
2284 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
2285 disable_rot_clks();
2286 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
2287 }
Ken Zhanga50db542013-02-20 14:48:06 -05002288 msm_rotator_release_all_timeline();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002289 mutex_unlock(&msm_rotator_dev->rotator_lock);
2290 return 0;
2291}
2292
2293static int msm_rotator_resume(struct platform_device *dev)
2294{
2295 mutex_lock(&msm_rotator_dev->imem_lock);
2296 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
2297 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002298 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002299 msm_rotator_dev->imem_clk_state = CLK_EN;
2300 }
2301 mutex_unlock(&msm_rotator_dev->imem_lock);
2302 mutex_lock(&msm_rotator_dev->rotator_lock);
2303 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
2304 enable_rot_clks();
2305 msm_rotator_dev->rot_clk_state = CLK_EN;
2306 }
2307 mutex_unlock(&msm_rotator_dev->rotator_lock);
2308 return 0;
2309}
2310#endif
2311
2312static struct platform_driver msm_rotator_platform_driver = {
2313 .probe = msm_rotator_probe,
2314 .remove = __devexit_p(msm_rotator_remove),
2315#ifdef CONFIG_PM
2316 .suspend = msm_rotator_suspend,
2317 .resume = msm_rotator_resume,
2318#endif
2319 .driver = {
2320 .owner = THIS_MODULE,
2321 .name = DRIVER_NAME
2322 }
2323};
2324
2325static int __init msm_rotator_init(void)
2326{
2327 return platform_driver_register(&msm_rotator_platform_driver);
2328}
2329
2330static void __exit msm_rotator_exit(void)
2331{
2332 return platform_driver_unregister(&msm_rotator_platform_driver);
2333}
2334
2335module_init(msm_rotator_init);
2336module_exit(msm_rotator_exit);
2337
2338MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
2339MODULE_VERSION("1.0");
2340MODULE_LICENSE("GPL v2");