blob: 20e716efb213407a8fa6781e8747f3b220669276 [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
Ken Zhang93b9f9a2013-04-08 18:56:58 -040096#define MAX_COMMIT_QUEUE 4
97#define WAIT_ROT_TIMEOUT 1000
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -070098
Ken Zhanga50db542013-02-20 14:48:06 -050099#define MAX_TIMELINE_NAME_LEN 16
100#define WAIT_FENCE_FIRST_TIMEOUT MSEC_PER_SEC
101#define WAIT_FENCE_FINAL_TIMEOUT (10 * MSEC_PER_SEC)
102
Mayank Chopra012a8e72012-04-11 10:41:13 +0530103#define ROTATOR_REVISION_V0 0
104#define ROTATOR_REVISION_V1 1
105#define ROTATOR_REVISION_V2 2
106#define ROTATOR_REVISION_NONE 0xffffffff
Mayank Chopra27147a72012-07-17 13:57:22 +0530107#define BASE_ADDR(height, y_stride) ((height % 64) * y_stride)
108#define HW_BASE_ADDR(height, y_stride) (((dstp0_ystride >> 5) << 11) - \
109 ((dst_height & 0x3f) * dstp0_ystride))
Mayank Chopra012a8e72012-04-11 10:41:13 +0530110
111uint32_t rotator_hw_revision;
Olav Hauganef95ae32012-05-15 09:50:30 -0700112static char rot_iommu_split_domain;
Mayank Chopra012a8e72012-04-11 10:41:13 +0530113
114/*
115 * rotator_hw_revision:
116 * 0 == 7x30
117 * 1 == 8x60
118 * 2 == 8960
119 *
120 */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700121struct tile_parm {
122 unsigned int width; /* tile's width */
123 unsigned int height; /* tile's height */
124 unsigned int row_tile_w; /* tiles per row's width */
125 unsigned int row_tile_h; /* tiles per row's height */
126};
127
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700128struct msm_rotator_mem_planes {
129 unsigned int num_planes;
130 unsigned int plane_size[4];
131 unsigned int total_size;
132};
133
134#define checkoffset(offset, size, max_size) \
135 ((size) > (max_size) || (offset) > ((max_size) - (size)))
136
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700137struct msm_rotator_fd_info {
138 int pid;
139 int ref_cnt;
140 struct list_head list;
141};
142
Ken Zhanga50db542013-02-20 14:48:06 -0500143struct rot_sync_info {
144 u32 initialized;
145 struct sync_fence *acq_fen;
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400146 struct sync_fence *rel_fen;
147 int rel_fen_fd;
Ken Zhanga50db542013-02-20 14:48:06 -0500148 struct sw_sync_timeline *timeline;
149 int timeline_value;
150 struct mutex sync_mutex;
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400151 atomic_t queue_buf_cnt;
Ken Zhanga50db542013-02-20 14:48:06 -0500152};
153
Mayank Chopra27147a72012-07-17 13:57:22 +0530154struct msm_rotator_session {
155 struct msm_rotator_img_info img_info;
156 struct msm_rotator_fd_info fd_info;
157 int fast_yuv_enable;
158};
159
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400160struct msm_rotator_commit_info {
161 struct msm_rotator_data_info data_info;
162 struct msm_rotator_img_info img_info;
163 unsigned int format;
164 unsigned int in_paddr;
165 unsigned int out_paddr;
166 unsigned int in_chroma_paddr;
167 unsigned int out_chroma_paddr;
168 unsigned int in_chroma2_paddr;
169 unsigned int out_chroma2_paddr;
170 struct file *srcp0_file;
171 struct file *srcp1_file;
172 struct file *dstp0_file;
173 struct file *dstp1_file;
174 struct ion_handle *srcp0_ihdl;
175 struct ion_handle *srcp1_ihdl;
176 struct ion_handle *dstp0_ihdl;
177 struct ion_handle *dstp1_ihdl;
178 int ps0_need;
179 int session_index;
180 struct sync_fence *acq_fen;
181 int fast_yuv_en;
182};
183
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700184struct msm_rotator_dev {
185 void __iomem *io_base;
186 int irq;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700187 struct clk *core_clk;
Mayank Chopra27147a72012-07-17 13:57:22 +0530188 struct msm_rotator_session *rot_session[MAX_SESSIONS];
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -0700189 struct list_head fd_list;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700190 struct clk *pclk;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700191 int rot_clk_state;
192 struct regulator *regulator;
193 struct delayed_work rot_clk_work;
194 struct clk *imem_clk;
195 int imem_clk_state;
196 struct delayed_work imem_clk_work;
197 struct platform_device *pdev;
198 struct cdev cdev;
199 struct device *device;
200 struct class *class;
201 dev_t dev_num;
202 int processing;
203 int last_session_idx;
204 struct mutex rotator_lock;
205 struct mutex imem_lock;
206 int imem_owner;
207 wait_queue_head_t wq;
Naseer Ahmed18018602011-10-25 13:32:58 -0700208 struct ion_client *client;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -0800209 #ifdef CONFIG_MSM_BUS_SCALING
210 uint32_t bus_client_handle;
211 #endif
Ken Zhangfebeabd2012-12-17 10:35:15 -0500212 u32 sec_mapped;
213 u32 mmu_clk_on;
Ken Zhanga50db542013-02-20 14:48:06 -0500214 struct rot_sync_info sync_info[MAX_SESSIONS];
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400215 /* non blocking */
216 struct mutex commit_mutex;
217 struct mutex commit_wq_mutex;
218 struct completion commit_comp;
219 u32 commit_running;
220 struct work_struct commit_work;
221 struct msm_rotator_commit_info commit_info[MAX_COMMIT_QUEUE];
222 atomic_t commit_q_r;
223 atomic_t commit_q_w;
224 atomic_t commit_q_cnt;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700225};
226
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700227#define COMPONENT_5BITS 1
228#define COMPONENT_6BITS 2
229#define COMPONENT_8BITS 3
230
231static struct msm_rotator_dev *msm_rotator_dev;
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400232#define mrd msm_rotator_dev
233static void rot_wait_for_commit_queue(u32 is_all);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700234
235enum {
236 CLK_EN,
237 CLK_DIS,
238 CLK_SUSPEND,
239};
Ken Zhangfebeabd2012-12-17 10:35:15 -0500240struct res_mmu_clk {
241 char *mmu_clk_name;
242 struct clk *mmu_clk;
243};
244
245static struct res_mmu_clk rot_mmu_clks[] = {
246 {"mdp_iommu_clk"}, {"rot_iommu_clk"},
247 {"vcodec_iommu0_clk"}, {"vcodec_iommu1_clk"},
248 {"smmu_iface_clk"}
249};
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700250
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700251int msm_rotator_iommu_map_buf(int mem_id, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700252 unsigned long *start, unsigned long *len,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700253 struct ion_handle **pihdl, unsigned int secure)
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700254{
255 if (!msm_rotator_dev->client)
256 return -EINVAL;
257
Laura Abbottb14ed962012-01-30 14:18:08 -0800258 *pihdl = ion_import_dma_buf(msm_rotator_dev->client, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700259 if (IS_ERR_OR_NULL(*pihdl)) {
Laura Abbottb14ed962012-01-30 14:18:08 -0800260 pr_err("ion_import_dma_buf() failed\n");
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700261 return PTR_ERR(*pihdl);
262 }
taeyol.kim69400442012-08-03 19:15:10 -0700263 pr_debug("%s(): ion_hdl %p, ion_fd %d\n", __func__, *pihdl, mem_id);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700264
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -0700265 if (rot_iommu_split_domain) {
266 if (secure) {
267 if (ion_phys(msm_rotator_dev->client,
268 *pihdl, start, (unsigned *)len)) {
269 pr_err("%s:%d: ion_phys map failed\n",
270 __func__, __LINE__);
271 return -ENOMEM;
272 }
273 } else {
274 if (ion_map_iommu(msm_rotator_dev->client,
275 *pihdl, domain, GEN_POOL,
276 SZ_4K, 0, start, len, 0,
277 ION_IOMMU_UNMAP_DELAYED)) {
278 pr_err("ion_map_iommu() failed\n");
279 return -EINVAL;
280 }
281 }
282 } else {
283 if (ion_map_iommu(msm_rotator_dev->client,
284 *pihdl, ROTATOR_SRC_DOMAIN, GEN_POOL,
285 SZ_4K, 0, start, len, 0, ION_IOMMU_UNMAP_DELAYED)) {
286 pr_err("ion_map_iommu() failed\n");
287 return -EINVAL;
288 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -0700289 }
290
291 pr_debug("%s(): mem_id %d, start 0x%lx, len 0x%lx\n",
292 __func__, mem_id, *start, *len);
293 return 0;
294}
295
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700296int msm_rotator_imem_allocate(int requestor)
297{
298 int rc = 0;
299
300#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
301 switch (requestor) {
302 case ROTATOR_REQUEST:
303 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
304 msm_rotator_dev->imem_owner = ROTATOR_REQUEST;
305 rc = 1;
306 } else
307 rc = 0;
308 break;
309 case JPEG_REQUEST:
310 mutex_lock(&msm_rotator_dev->imem_lock);
311 msm_rotator_dev->imem_owner = JPEG_REQUEST;
312 rc = 1;
313 break;
314 default:
315 rc = 0;
316 }
317#else
318 if (requestor == JPEG_REQUEST)
319 rc = 1;
320#endif
321 if (rc == 1) {
322 cancel_delayed_work(&msm_rotator_dev->imem_clk_work);
323 if (msm_rotator_dev->imem_clk_state != CLK_EN
324 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700325 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700326 msm_rotator_dev->imem_clk_state = CLK_EN;
327 }
328 }
329
330 return rc;
331}
332EXPORT_SYMBOL(msm_rotator_imem_allocate);
333
334void msm_rotator_imem_free(int requestor)
335{
336#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
337 if (msm_rotator_dev->imem_owner == requestor) {
338 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
339 mutex_unlock(&msm_rotator_dev->imem_lock);
340 }
341#else
342 if (requestor == JPEG_REQUEST)
343 schedule_delayed_work(&msm_rotator_dev->imem_clk_work, HZ);
344#endif
345}
346EXPORT_SYMBOL(msm_rotator_imem_free);
347
348static void msm_rotator_imem_clk_work_f(struct work_struct *work)
349{
350#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
351 if (mutex_trylock(&msm_rotator_dev->imem_lock)) {
352 if (msm_rotator_dev->imem_clk_state == CLK_EN
353 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700354 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700355 msm_rotator_dev->imem_clk_state = CLK_DIS;
356 } else if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND)
357 msm_rotator_dev->imem_clk_state = CLK_DIS;
358 mutex_unlock(&msm_rotator_dev->imem_lock);
359 }
360#endif
361}
362
363/* enable clocks needed by rotator block */
364static void enable_rot_clks(void)
365{
366 if (msm_rotator_dev->regulator)
367 regulator_enable(msm_rotator_dev->regulator);
368 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700369 clk_prepare_enable(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700370 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700371 clk_prepare_enable(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700372}
373
374/* disable clocks needed by rotator block */
375static void disable_rot_clks(void)
376{
377 if (msm_rotator_dev->core_clk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700378 clk_disable_unprepare(msm_rotator_dev->core_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700379 if (msm_rotator_dev->pclk != NULL)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -0700380 clk_disable_unprepare(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700381 if (msm_rotator_dev->regulator)
382 regulator_disable(msm_rotator_dev->regulator);
383}
384
385static void msm_rotator_rot_clk_work_f(struct work_struct *work)
386{
387 if (mutex_trylock(&msm_rotator_dev->rotator_lock)) {
388 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
389 disable_rot_clks();
390 msm_rotator_dev->rot_clk_state = CLK_DIS;
391 } else if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND)
392 msm_rotator_dev->rot_clk_state = CLK_DIS;
393 mutex_unlock(&msm_rotator_dev->rotator_lock);
394 }
395}
396
397static irqreturn_t msm_rotator_isr(int irq, void *dev_id)
398{
399 if (msm_rotator_dev->processing) {
400 msm_rotator_dev->processing = 0;
401 wake_up(&msm_rotator_dev->wq);
402 } else
403 printk(KERN_WARNING "%s: unexpected interrupt\n", DRIVER_NAME);
404
405 return IRQ_HANDLED;
406}
407
Ken Zhanga50db542013-02-20 14:48:06 -0500408static void msm_rotator_signal_timeline(u32 session_index)
409{
410 struct rot_sync_info *sync_info;
411 sync_info = &msm_rotator_dev->sync_info[session_index];
412
413 if ((!sync_info->timeline) || (!sync_info->initialized))
414 return;
415
416 mutex_lock(&sync_info->sync_mutex);
417 sw_sync_timeline_inc(sync_info->timeline, 1);
418 sync_info->timeline_value++;
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400419 mutex_unlock(&sync_info->sync_mutex);
420}
421
422static void msm_rotator_signal_timeline_done(u32 session_index)
423{
424 struct rot_sync_info *sync_info;
425 sync_info = &msm_rotator_dev->sync_info[session_index];
426
427 if ((sync_info->timeline == NULL) ||
428 (sync_info->initialized == false))
429 return;
430 mutex_lock(&sync_info->sync_mutex);
431 sw_sync_timeline_inc(sync_info->timeline, 1);
432 sync_info->timeline_value++;
433 if (atomic_read(&sync_info->queue_buf_cnt) <= 0)
434 pr_err("%s queue_buf_cnt=%d", __func__,
435 atomic_read(&sync_info->queue_buf_cnt));
436 else
437 atomic_dec(&sync_info->queue_buf_cnt);
Ken Zhanga50db542013-02-20 14:48:06 -0500438 mutex_unlock(&sync_info->sync_mutex);
439}
440
441static void msm_rotator_release_acq_fence(u32 session_index)
442{
443 struct rot_sync_info *sync_info;
444 sync_info = &msm_rotator_dev->sync_info[session_index];
445
446 if ((!sync_info->timeline) || (!sync_info->initialized))
447 return;
448 mutex_lock(&sync_info->sync_mutex);
449 sync_info->acq_fen = NULL;
450 mutex_unlock(&sync_info->sync_mutex);
451}
452
453static void msm_rotator_release_all_timeline(void)
454{
455 int i;
456 struct rot_sync_info *sync_info;
457 for (i = 0; i < MAX_SESSIONS; i++) {
458 sync_info = &msm_rotator_dev->sync_info[i];
459 if (sync_info->initialized) {
460 msm_rotator_signal_timeline(i);
461 msm_rotator_release_acq_fence(i);
462 }
463 }
464}
465
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400466static void msm_rotator_wait_for_fence(struct sync_fence *acq_fen)
Ken Zhanga50db542013-02-20 14:48:06 -0500467{
Ken Zhanga50db542013-02-20 14:48:06 -0500468 int ret;
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400469 if (acq_fen) {
470 ret = sync_fence_wait(acq_fen,
Ken Zhanga50db542013-02-20 14:48:06 -0500471 WAIT_FENCE_FIRST_TIMEOUT);
472 if (ret == -ETIME) {
473 pr_warn("%s: timeout, wait %ld more ms\n",
474 __func__, WAIT_FENCE_FINAL_TIMEOUT);
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400475 ret = sync_fence_wait(acq_fen,
Ken Zhanga50db542013-02-20 14:48:06 -0500476 WAIT_FENCE_FINAL_TIMEOUT);
477 }
478 if (ret < 0) {
479 pr_err("%s: sync_fence_wait failed! ret = %x\n",
480 __func__, ret);
481 }
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400482 sync_fence_put(acq_fen);
Ken Zhanga50db542013-02-20 14:48:06 -0500483 }
484}
485
Ken Zhanga50db542013-02-20 14:48:06 -0500486static int msm_rotator_buf_sync(unsigned long arg)
487{
488 struct msm_rotator_buf_sync buf_sync;
489 int ret = 0;
490 struct sync_fence *fence = NULL;
491 struct rot_sync_info *sync_info;
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400492 struct sync_pt *rel_sync_pt;
493 struct sync_fence *rel_fence;
494 int rel_fen_fd;
Ken Zhanga50db542013-02-20 14:48:06 -0500495 u32 s;
496
497 if (copy_from_user(&buf_sync, (void __user *)arg, sizeof(buf_sync)))
498 return -EFAULT;
499
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400500 rot_wait_for_commit_queue(false);
Ken Zhanga50db542013-02-20 14:48:06 -0500501 for (s = 0; s < MAX_SESSIONS; s++)
502 if ((msm_rotator_dev->rot_session[s] != NULL) &&
503 (buf_sync.session_id ==
504 (unsigned int)msm_rotator_dev->rot_session[s]
505 ))
506 break;
507
508 if (s == MAX_SESSIONS) {
509 pr_err("%s invalid session id %d", __func__,
510 buf_sync.session_id);
511 return -EINVAL;
512 }
513
514 sync_info = &msm_rotator_dev->sync_info[s];
515
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400516 if (sync_info->acq_fen)
517 pr_err("%s previous acq_fen will be overwritten", __func__);
518
Ken Zhanga50db542013-02-20 14:48:06 -0500519 if ((sync_info->timeline == NULL) ||
520 (sync_info->initialized == false))
521 return -EINVAL;
522
523 mutex_lock(&sync_info->sync_mutex);
524 if (buf_sync.acq_fen_fd >= 0)
525 fence = sync_fence_fdget(buf_sync.acq_fen_fd);
526
527 sync_info->acq_fen = fence;
528
529 if (sync_info->acq_fen &&
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400530 (buf_sync.flags & MDP_BUF_SYNC_FLAG_WAIT)) {
531 msm_rotator_wait_for_fence(sync_info->acq_fen);
532 sync_info->acq_fen = NULL;
533 }
Ken Zhanga50db542013-02-20 14:48:06 -0500534
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400535 rel_sync_pt = sw_sync_pt_create(sync_info->timeline,
536 sync_info->timeline_value +
537 atomic_read(&sync_info->queue_buf_cnt) + 1);
538 if (rel_sync_pt == NULL) {
Ken Zhanga50db542013-02-20 14:48:06 -0500539 pr_err("%s: cannot create sync point", __func__);
540 ret = -ENOMEM;
541 goto buf_sync_err_1;
542 }
543 /* create fence */
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400544 rel_fence = sync_fence_create("msm_rotator-fence",
545 rel_sync_pt);
546 if (rel_fence == NULL) {
547 sync_pt_free(rel_sync_pt);
Ken Zhanga50db542013-02-20 14:48:06 -0500548 pr_err("%s: cannot create fence", __func__);
549 ret = -ENOMEM;
550 goto buf_sync_err_1;
551 }
552 /* create fd */
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400553 rel_fen_fd = get_unused_fd_flags(0);
554 if (rel_fen_fd < 0) {
Ken Zhanga50db542013-02-20 14:48:06 -0500555 pr_err("%s: get_unused_fd_flags failed", __func__);
556 ret = -EIO;
557 goto buf_sync_err_2;
558 }
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400559 sync_fence_install(rel_fence, rel_fen_fd);
560 buf_sync.rel_fen_fd = rel_fen_fd;
561 sync_info->rel_fen = rel_fence;
562 sync_info->rel_fen_fd = rel_fen_fd;
Ken Zhanga50db542013-02-20 14:48:06 -0500563
564 ret = copy_to_user((void __user *)arg, &buf_sync, sizeof(buf_sync));
565 mutex_unlock(&sync_info->sync_mutex);
566 return ret;
567buf_sync_err_2:
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400568 sync_fence_put(rel_fence);
Ken Zhanga50db542013-02-20 14:48:06 -0500569buf_sync_err_1:
570 if (sync_info->acq_fen)
571 sync_fence_put(sync_info->acq_fen);
572 sync_info->acq_fen = NULL;
573 mutex_unlock(&sync_info->sync_mutex);
574 return ret;
575}
576
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700577static unsigned int tile_size(unsigned int src_width,
578 unsigned int src_height,
579 const struct tile_parm *tp)
580{
581 unsigned int tile_w, tile_h;
582 unsigned int row_num_w, row_num_h;
583 tile_w = tp->width * tp->row_tile_w;
584 tile_h = tp->height * tp->row_tile_h;
585 row_num_w = (src_width + tile_w - 1) / tile_w;
586 row_num_h = (src_height + tile_h - 1) / tile_h;
587 return ((row_num_w * row_num_h * tile_w * tile_h) + 8191) & ~8191;
588}
589
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700590static int get_bpp(int format)
591{
592 switch (format) {
593 case MDP_RGB_565:
594 case MDP_BGR_565:
595 return 2;
596
597 case MDP_XRGB_8888:
598 case MDP_ARGB_8888:
599 case MDP_RGBA_8888:
600 case MDP_BGRA_8888:
601 case MDP_RGBX_8888:
602 return 4;
603
604 case MDP_Y_CBCR_H2V2:
605 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700606 case MDP_Y_CB_CR_H2V2:
607 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530608 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700609 case MDP_Y_CRCB_H2V2_TILE:
610 case MDP_Y_CBCR_H2V2_TILE:
611 return 1;
612
613 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -0700614 case MDP_YCBCR_H1V1:
615 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700616 return 3;
617
618 case MDP_YCRYCB_H2V1:
619 return 2;/* YCrYCb interleave */
620
621 case MDP_Y_CRCB_H2V1:
622 case MDP_Y_CBCR_H2V1:
623 return 1;
624
625 default:
626 return -1;
627 }
628
629}
630
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700631static int msm_rotator_get_plane_sizes(uint32_t format, uint32_t w, uint32_t h,
632 struct msm_rotator_mem_planes *p)
633{
634 /*
635 * each row of samsung tile consists of two tiles in height
636 * and two tiles in width which means width should align to
637 * 64 x 2 bytes and height should align to 32 x 2 bytes.
638 * video decoder generate two tiles in width and one tile
639 * in height which ends up height align to 32 X 1 bytes.
640 */
641 const struct tile_parm tile = {64, 32, 2, 1};
642 int i;
643
644 if (p == NULL)
645 return -EINVAL;
646
647 if ((w > MSM_ROTATOR_MAX_W) || (h > MSM_ROTATOR_MAX_H))
648 return -ERANGE;
649
650 memset(p, 0, sizeof(*p));
651
652 switch (format) {
653 case MDP_XRGB_8888:
654 case MDP_ARGB_8888:
655 case MDP_RGBA_8888:
656 case MDP_BGRA_8888:
657 case MDP_RGBX_8888:
658 case MDP_RGB_888:
659 case MDP_RGB_565:
660 case MDP_BGR_565:
661 case MDP_YCRYCB_H2V1:
Kyong Hwa Baeebf19192012-05-09 16:31:05 -0700662 case MDP_YCBCR_H1V1:
663 case MDP_YCRCB_H1V1:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700664 p->num_planes = 1;
665 p->plane_size[0] = w * h * get_bpp(format);
666 break;
667 case MDP_Y_CRCB_H2V1:
668 case MDP_Y_CBCR_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +0530669 case MDP_Y_CRCB_H1V2:
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700670 p->num_planes = 2;
671 p->plane_size[0] = w * h;
672 p->plane_size[1] = w * h;
673 break;
674 case MDP_Y_CBCR_H2V2:
675 case MDP_Y_CRCB_H2V2:
676 p->num_planes = 2;
677 p->plane_size[0] = w * h;
678 p->plane_size[1] = w * h / 2;
679 break;
680 case MDP_Y_CRCB_H2V2_TILE:
681 case MDP_Y_CBCR_H2V2_TILE:
682 p->num_planes = 2;
683 p->plane_size[0] = tile_size(w, h, &tile);
684 p->plane_size[1] = tile_size(w, h/2, &tile);
685 break;
686 case MDP_Y_CB_CR_H2V2:
687 case MDP_Y_CR_CB_H2V2:
688 p->num_planes = 3;
689 p->plane_size[0] = w * h;
690 p->plane_size[1] = (w / 2) * (h / 2);
691 p->plane_size[2] = (w / 2) * (h / 2);
692 break;
693 case MDP_Y_CR_CB_GH2V2:
694 p->num_planes = 3;
695 p->plane_size[0] = ALIGN(w, 16) * h;
696 p->plane_size[1] = ALIGN(w / 2, 16) * (h / 2);
697 p->plane_size[2] = ALIGN(w / 2, 16) * (h / 2);
698 break;
699 default:
700 return -EINVAL;
701 }
702
703 for (i = 0; i < p->num_planes; i++)
704 p->total_size += p->plane_size[i];
705
706 return 0;
707}
708
Mayank Chopra27147a72012-07-17 13:57:22 +0530709/* Checking invalid destination image size on FAST YUV for YUV420PP(NV12) with
710 * HW issue for rotation 90 + U/D filp + with/without flip operation
711 * (rotation 90 + U/D + L/R flip is rotation 270 degree option) and pix_rot
712 * block issue with tile line size is 4.
713 *
714 * Rotator structure is:
715 * if Fetch input image: W x H,
716 * Downscale: W` x H` = W/ScaleHor(2, 4 or 8) x H/ScaleVert(2, 4 or 8)
717 * Rotated output : W`` x H`` = (W` x H`) or (H` x W`) depends on "Rotation 90
718 * degree option"
719 *
720 * Pack: W`` x H``
721 *
722 * Rotator source ROI image width restriction is applied to W x H (case a,
723 * image resolution before downscaling)
724 *
725 * Packer source Image width/ height restriction are applied to W`` x H``
726 * (case c, image resolution after rotation)
727 *
728 * Supertile (64 x 8) and YUV (2 x 2) alignment restriction should be
729 * applied to the W x H (case a). Input image should be at least (2 x 2).
730 *
731 * "Support If packer source image height <= 256, multiple of 8", this
732 * restriction should be applied to the rotated image (W`` x H``)
733 */
734
735uint32_t fast_yuv_invalid_size_checker(unsigned char rot_mode,
736 uint32_t src_width,
737 uint32_t dst_width,
738 uint32_t dst_height,
739 uint32_t dstp0_ystride,
740 uint32_t is_planar420)
741{
742 uint32_t hw_limit;
743
744 hw_limit = is_planar420 ? 512 : 256;
745
746 /* checking image constaints for missing EOT event from pix_rot block */
747 if ((src_width > hw_limit) && ((src_width % (hw_limit / 2)) == 8))
748 return -EINVAL;
749
750 if (rot_mode & MDP_ROT_90) {
751
752 /* if rotation 90 degree on fast yuv
753 * rotator image input width has to be multiple of 8
754 * rotator image input height has to be multiple of 8
755 */
756 if (((dst_width % 8) != 0) || ((dst_height % 8) != 0))
757 return -EINVAL;
758
759 if ((rot_mode & MDP_FLIP_UD) ||
760 (rot_mode & (MDP_FLIP_UD | MDP_FLIP_LR))) {
761
762 /* image constraint checking for wrong address
763 * generation HW issue for Y plane checking
764 */
765 if (((dst_height % 64) != 0) &&
766 ((dst_height / 64) >= 4)) {
767
768 /* compare golden logic for second
769 * tile base address generation in row
770 * with actual HW implementation
771 */
772 if (BASE_ADDR(dst_height, dstp0_ystride) !=
773 HW_BASE_ADDR(dst_height, dstp0_ystride))
774 return -EINVAL;
775 }
776
777 if (is_planar420) {
778 dst_width = dst_width / 2;
779 dstp0_ystride = dstp0_ystride / 2;
780 }
781
782 dst_height = dst_height / 2;
783
784 /* image constraint checking for wrong
785 * address generation HW issue. for
786 * U/V (P) or UV (PP) plane checking
787 */
788 if (((dst_height % 64) != 0) && ((dst_height / 64) >=
789 (hw_limit / 128))) {
790
791 /* compare golden logic for
792 * second tile base address
793 * generation in row with
794 * actual HW implementation
795 */
796 if (BASE_ADDR(dst_height, dstp0_ystride) !=
797 HW_BASE_ADDR(dst_height, dstp0_ystride))
798 return -EINVAL;
799 }
800 }
801 } else {
802 /* if NOT applying rotation 90 degree on fast yuv,
803 * rotator image input width has to be multiple of 8
804 * rotator image input height has to be multiple of 2
805 */
806 if (((dst_width % 8) != 0) || ((dst_height % 2) != 0))
807 return -EINVAL;
808 }
809
810 return 0;
811}
812
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700813static int msm_rotator_ycxcx_h2v1(struct msm_rotator_img_info *info,
814 unsigned int in_paddr,
815 unsigned int out_paddr,
816 unsigned int use_imem,
817 int new_session,
818 unsigned int in_chroma_paddr,
819 unsigned int out_chroma_paddr)
820{
821 int bpp;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700822
823 if (info->src.format != info->dst.format)
824 return -EINVAL;
825
826 bpp = get_bpp(info->src.format);
827 if (bpp < 0)
828 return -ENOTTY;
829
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700830 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700831 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700832 iowrite32(out_paddr +
833 ((info->dst_y * info->dst.width) + info->dst_x),
834 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700835 iowrite32(out_chroma_paddr +
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700836 ((info->dst_y * info->dst.width) + info->dst_x),
837 MSM_ROTATOR_OUTP1_ADDR);
838
839 if (new_session) {
840 iowrite32(info->src.width |
841 info->src.width << 16,
842 MSM_ROTATOR_SRC_YSTRIDE1);
843 if (info->rotations & MDP_ROT_90)
844 iowrite32(info->dst.width |
845 info->dst.width*2 << 16,
846 MSM_ROTATOR_OUT_YSTRIDE1);
847 else
848 iowrite32(info->dst.width |
849 info->dst.width << 16,
850 MSM_ROTATOR_OUT_YSTRIDE1);
851 if (info->src.format == MDP_Y_CBCR_H2V1) {
852 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
853 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
854 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
855 MSM_ROTATOR_OUT_PACK_PATTERN1);
856 } else {
857 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
858 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
859 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
860 MSM_ROTATOR_OUT_PACK_PATTERN1);
861 }
862 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
863 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -0700864 1 << 8 | /* ROT_EN */
865 info->downscale_ratio << 2 | /* downscale v ratio */
866 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700867 MSM_ROTATOR_SUB_BLOCK_CFG);
868 iowrite32(0 << 29 | /* frame format 0 = linear */
869 (use_imem ? 0 : 1) << 22 | /* tile size */
870 2 << 19 | /* fetch planes 2 = pseudo */
871 0 << 18 | /* unpack align */
872 1 << 17 | /* unpack tight */
873 1 << 13 | /* unpack count 0=1 component */
874 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
875 0 << 8 | /* has alpha */
876 0 << 6 | /* alpha bits 3=8bits */
877 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
878 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
879 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
880 MSM_ROTATOR_SRC_FORMAT);
881 }
882
883 return 0;
884}
885
886static int msm_rotator_ycxcx_h2v2(struct msm_rotator_img_info *info,
887 unsigned int in_paddr,
888 unsigned int out_paddr,
889 unsigned int use_imem,
890 int new_session,
891 unsigned int in_chroma_paddr,
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700892 unsigned int out_chroma_paddr,
Mayank Chopra27147a72012-07-17 13:57:22 +0530893 unsigned int in_chroma2_paddr,
Ken Zhang93b9f9a2013-04-08 18:56:58 -0400894 unsigned int out_chroma2_paddr,
895 int fast_yuv_en)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700896{
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700897 uint32_t dst_format;
898 int is_tile = 0;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700899
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700900 switch (info->src.format) {
901 case MDP_Y_CRCB_H2V2_TILE:
902 is_tile = 1;
Mayank Chopra27147a72012-07-17 13:57:22 +0530903 dst_format = MDP_Y_CRCB_H2V2;
904 break;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700905 case MDP_Y_CR_CB_H2V2:
906 case MDP_Y_CR_CB_GH2V2:
Mayank Chopra27147a72012-07-17 13:57:22 +0530907 if (fast_yuv_en) {
908 dst_format = info->src.format;
909 break;
910 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700911 case MDP_Y_CRCB_H2V2:
912 dst_format = MDP_Y_CRCB_H2V2;
913 break;
Mayank Chopra27147a72012-07-17 13:57:22 +0530914 case MDP_Y_CB_CR_H2V2:
915 if (fast_yuv_en) {
916 dst_format = info->src.format;
917 break;
918 }
919 dst_format = MDP_Y_CBCR_H2V2;
920 break;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700921 case MDP_Y_CBCR_H2V2_TILE:
922 is_tile = 1;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700923 case MDP_Y_CBCR_H2V2:
924 dst_format = MDP_Y_CBCR_H2V2;
925 break;
926 default:
927 return -EINVAL;
928 }
929 if (info->dst.format != dst_format)
930 return -EINVAL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700931
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800932 /* rotator expects YCbCr for planar input format */
Mayank Chopra012a8e72012-04-11 10:41:13 +0530933 if ((info->src.format == MDP_Y_CR_CB_H2V2 ||
934 info->src.format == MDP_Y_CR_CB_GH2V2) &&
935 rotator_hw_revision < ROTATOR_REVISION_V2)
Adrian Salido-Moreno19caf152012-01-03 18:46:25 -0800936 swap(in_chroma_paddr, in_chroma2_paddr);
937
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700938 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700939 iowrite32(in_chroma_paddr, MSM_ROTATOR_SRCP1_ADDR);
940 iowrite32(in_chroma2_paddr, MSM_ROTATOR_SRCP2_ADDR);
941
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700942 iowrite32(out_paddr +
943 ((info->dst_y * info->dst.width) + info->dst_x),
944 MSM_ROTATOR_OUTP0_ADDR);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700945 iowrite32(out_chroma_paddr +
Mayank Chopra27147a72012-07-17 13:57:22 +0530946 (((info->dst_y * info->dst.width)/2) + info->dst_x),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700947 MSM_ROTATOR_OUTP1_ADDR);
Mayank Chopra27147a72012-07-17 13:57:22 +0530948 if (out_chroma2_paddr)
949 iowrite32(out_chroma2_paddr +
950 (((info->dst_y * info->dst.width)/2) + info->dst_x),
951 MSM_ROTATOR_OUTP2_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700952
953 if (new_session) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -0700954 if (in_chroma2_paddr) {
955 if (info->src.format == MDP_Y_CR_CB_GH2V2) {
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530956 iowrite32(ALIGN(info->src.width, 16) |
957 ALIGN((info->src.width / 2), 16) << 16,
958 MSM_ROTATOR_SRC_YSTRIDE1);
959 iowrite32(ALIGN((info->src.width / 2), 16),
960 MSM_ROTATOR_SRC_YSTRIDE2);
961 } else {
962 iowrite32(info->src.width |
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700963 (info->src.width / 2) << 16,
964 MSM_ROTATOR_SRC_YSTRIDE1);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530965 iowrite32((info->src.width / 2),
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700966 MSM_ROTATOR_SRC_YSTRIDE2);
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +0530967 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700968 } else {
969 iowrite32(info->src.width |
970 info->src.width << 16,
971 MSM_ROTATOR_SRC_YSTRIDE1);
972 }
Mayank Chopra27147a72012-07-17 13:57:22 +0530973 if (out_chroma2_paddr) {
974 if (info->dst.format == MDP_Y_CR_CB_GH2V2) {
975 iowrite32(ALIGN(info->dst.width, 16) |
976 ALIGN((info->dst.width / 2), 16) << 16,
977 MSM_ROTATOR_OUT_YSTRIDE1);
978 iowrite32(ALIGN((info->dst.width / 2), 16),
979 MSM_ROTATOR_OUT_YSTRIDE2);
980 } else {
981 iowrite32(info->dst.width |
982 info->dst.width/2 << 16,
983 MSM_ROTATOR_OUT_YSTRIDE1);
984 iowrite32(info->dst.width/2,
985 MSM_ROTATOR_OUT_YSTRIDE2);
986 }
987 } else {
988 iowrite32(info->dst.width |
989 info->dst.width << 16,
990 MSM_ROTATOR_OUT_YSTRIDE1);
991 }
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -0700992
Mayank Chopra27147a72012-07-17 13:57:22 +0530993 if (dst_format == MDP_Y_CBCR_H2V2 ||
994 dst_format == MDP_Y_CB_CR_H2V2) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -0700995 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
996 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
997 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8),
998 MSM_ROTATOR_OUT_PACK_PATTERN1);
999 } else {
1000 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
1001 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1002 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
1003 MSM_ROTATOR_OUT_PACK_PATTERN1);
1004 }
Mayank Chopra27147a72012-07-17 13:57:22 +05301005
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001006 iowrite32((3 << 18) | /* chroma sampling 3=4:2:0 */
1007 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001008 1 << 8 | /* ROT_EN */
Mayank Chopra27147a72012-07-17 13:57:22 +05301009 fast_yuv_en << 4 | /*fast YUV*/
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001010 info->downscale_ratio << 2 | /* downscale v ratio */
1011 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001012 MSM_ROTATOR_SUB_BLOCK_CFG);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001013
1014 iowrite32((is_tile ? 2 : 0) << 29 | /* frame format */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001015 (use_imem ? 0 : 1) << 22 | /* tile size */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001016 (in_chroma2_paddr ? 1 : 2) << 19 | /* fetch planes */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001017 0 << 18 | /* unpack align */
1018 1 << 17 | /* unpack tight */
1019 1 << 13 | /* unpack count 0=1 component */
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001020 0 << 9 | /* src Bpp 0=1 byte ... */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001021 0 << 8 | /* has alpha */
1022 0 << 6 | /* alpha bits 3=8bits */
1023 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
1024 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
1025 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
1026 MSM_ROTATOR_SRC_FORMAT);
1027 }
1028 return 0;
1029}
1030
1031static int msm_rotator_ycrycb(struct msm_rotator_img_info *info,
1032 unsigned int in_paddr,
1033 unsigned int out_paddr,
1034 unsigned int use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301035 int new_session,
1036 unsigned int out_chroma_paddr)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001037{
1038 int bpp;
Mayank Chopra732dcd62012-01-09 20:53:39 +05301039 uint32_t dst_format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001040
Mayank Chopra797bdb72012-03-03 06:29:40 +05301041 if (info->src.format == MDP_YCRYCB_H2V1) {
1042 if (info->rotations & MDP_ROT_90)
1043 dst_format = MDP_Y_CRCB_H1V2;
1044 else
1045 dst_format = MDP_Y_CRCB_H2V1;
1046 } else
Mayank Chopra732dcd62012-01-09 20:53:39 +05301047 return -EINVAL;
1048
1049 if (info->dst.format != dst_format)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001050 return -EINVAL;
1051
1052 bpp = get_bpp(info->src.format);
1053 if (bpp < 0)
1054 return -ENOTTY;
1055
1056 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
1057 iowrite32(out_paddr +
1058 ((info->dst_y * info->dst.width) + info->dst_x),
1059 MSM_ROTATOR_OUTP0_ADDR);
Mayank Chopra732dcd62012-01-09 20:53:39 +05301060 iowrite32(out_chroma_paddr +
1061 ((info->dst_y * info->dst.width)/2 + info->dst_x),
1062 MSM_ROTATOR_OUTP1_ADDR);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001063
1064 if (new_session) {
Mayank Chopra732dcd62012-01-09 20:53:39 +05301065 iowrite32(info->src.width * bpp,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001066 MSM_ROTATOR_SRC_YSTRIDE1);
Mayank Chopra732dcd62012-01-09 20:53:39 +05301067 if (info->rotations & MDP_ROT_90)
1068 iowrite32(info->dst.width |
1069 (info->dst.width*2) << 16,
1070 MSM_ROTATOR_OUT_YSTRIDE1);
1071 else
1072 iowrite32(info->dst.width |
1073 (info->dst.width) << 16,
1074 MSM_ROTATOR_OUT_YSTRIDE1);
1075
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001076 iowrite32(GET_PACK_PATTERN(CLR_Y, CLR_CR, CLR_Y, CLR_CB, 8),
1077 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
Mayank Chopra732dcd62012-01-09 20:53:39 +05301078 iowrite32(GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001079 MSM_ROTATOR_OUT_PACK_PATTERN1);
1080 iowrite32((1 << 18) | /* chroma sampling 1=H2V1 */
1081 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001082 1 << 8 | /* ROT_EN */
1083 info->downscale_ratio << 2 | /* downscale v ratio */
1084 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001085 MSM_ROTATOR_SUB_BLOCK_CFG);
1086 iowrite32(0 << 29 | /* frame format 0 = linear */
1087 (use_imem ? 0 : 1) << 22 | /* tile size */
1088 0 << 19 | /* fetch planes 0=interleaved */
1089 0 << 18 | /* unpack align */
1090 1 << 17 | /* unpack tight */
1091 3 << 13 | /* unpack count 0=1 component */
1092 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
1093 0 << 8 | /* has alpha */
1094 0 << 6 | /* alpha bits 3=8bits */
1095 3 << 4 | /* R/Cr bits 1=5 2=6 3=8 */
1096 3 << 2 | /* B/Cb bits 1=5 2=6 3=8 */
1097 3 << 0, /* G/Y bits 1=5 2=6 3=8 */
1098 MSM_ROTATOR_SRC_FORMAT);
1099 }
1100
1101 return 0;
1102}
1103
1104static int msm_rotator_rgb_types(struct msm_rotator_img_info *info,
1105 unsigned int in_paddr,
1106 unsigned int out_paddr,
1107 unsigned int use_imem,
1108 int new_session)
1109{
1110 int bpp, abits, rbits, gbits, bbits;
1111
1112 if (info->src.format != info->dst.format)
1113 return -EINVAL;
1114
1115 bpp = get_bpp(info->src.format);
1116 if (bpp < 0)
1117 return -ENOTTY;
1118
1119 iowrite32(in_paddr, MSM_ROTATOR_SRCP0_ADDR);
1120 iowrite32(out_paddr +
1121 ((info->dst_y * info->dst.width) + info->dst_x) * bpp,
1122 MSM_ROTATOR_OUTP0_ADDR);
1123
1124 if (new_session) {
1125 iowrite32(info->src.width * bpp, MSM_ROTATOR_SRC_YSTRIDE1);
1126 iowrite32(info->dst.width * bpp, MSM_ROTATOR_OUT_YSTRIDE1);
1127 iowrite32((0 << 18) | /* chroma sampling 0=rgb */
1128 (ROTATIONS_TO_BITMASK(info->rotations) << 9) |
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001129 1 << 8 | /* ROT_EN */
1130 info->downscale_ratio << 2 | /* downscale v ratio */
1131 info->downscale_ratio, /* downscale h ratio */
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001132 MSM_ROTATOR_SUB_BLOCK_CFG);
1133 switch (info->src.format) {
1134 case MDP_RGB_565:
1135 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1136 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1137 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1138 MSM_ROTATOR_OUT_PACK_PATTERN1);
1139 abits = 0;
1140 rbits = COMPONENT_5BITS;
1141 gbits = COMPONENT_6BITS;
1142 bbits = COMPONENT_5BITS;
1143 break;
1144
1145 case MDP_BGR_565:
1146 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
1147 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1148 iowrite32(GET_PACK_PATTERN(0, CLR_B, CLR_G, CLR_R, 8),
1149 MSM_ROTATOR_OUT_PACK_PATTERN1);
1150 abits = 0;
1151 rbits = COMPONENT_5BITS;
1152 gbits = COMPONENT_6BITS;
1153 bbits = COMPONENT_5BITS;
1154 break;
1155
1156 case MDP_RGB_888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001157 case MDP_YCBCR_H1V1:
1158 case MDP_YCRCB_H1V1:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001159 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1160 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1161 iowrite32(GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8),
1162 MSM_ROTATOR_OUT_PACK_PATTERN1);
1163 abits = 0;
1164 rbits = COMPONENT_8BITS;
1165 gbits = COMPONENT_8BITS;
1166 bbits = COMPONENT_8BITS;
1167 break;
1168
1169 case MDP_ARGB_8888:
1170 case MDP_RGBA_8888:
1171 case MDP_XRGB_8888:
1172 case MDP_RGBX_8888:
1173 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
1174 CLR_B, 8),
1175 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1176 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G,
1177 CLR_B, 8),
1178 MSM_ROTATOR_OUT_PACK_PATTERN1);
1179 abits = COMPONENT_8BITS;
1180 rbits = COMPONENT_8BITS;
1181 gbits = COMPONENT_8BITS;
1182 bbits = COMPONENT_8BITS;
1183 break;
1184
1185 case MDP_BGRA_8888:
1186 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
1187 CLR_R, 8),
1188 MSM_ROTATOR_SRC_UNPACK_PATTERN1);
1189 iowrite32(GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G,
1190 CLR_R, 8),
1191 MSM_ROTATOR_OUT_PACK_PATTERN1);
1192 abits = COMPONENT_8BITS;
1193 rbits = COMPONENT_8BITS;
1194 gbits = COMPONENT_8BITS;
1195 bbits = COMPONENT_8BITS;
1196 break;
1197
1198 default:
1199 return -EINVAL;
1200 }
1201 iowrite32(0 << 29 | /* frame format 0 = linear */
1202 (use_imem ? 0 : 1) << 22 | /* tile size */
1203 0 << 19 | /* fetch planes 0=interleaved */
1204 0 << 18 | /* unpack align */
1205 1 << 17 | /* unpack tight */
1206 (abits ? 3 : 2) << 13 | /* unpack count 0=1 comp */
1207 (bpp-1) << 9 | /* src Bpp 0=1 byte ... */
1208 (abits ? 1 : 0) << 8 | /* has alpha */
1209 abits << 6 | /* alpha bits 3=8bits */
1210 rbits << 4 | /* R/Cr bits 1=5 2=6 3=8 */
1211 bbits << 2 | /* B/Cb bits 1=5 2=6 3=8 */
1212 gbits << 0, /* G/Y bits 1=5 2=6 3=8 */
1213 MSM_ROTATOR_SRC_FORMAT);
1214 }
1215
1216 return 0;
1217}
1218
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001219static int get_img(struct msmfb_data *fbd, int domain,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001220 unsigned long *start, unsigned long *len, struct file **p_file,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001221 int *p_need, struct ion_handle **p_ihdl, unsigned int secure)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001222{
1223 int ret = 0;
1224#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -07001225 struct file *file = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001226 int put_needed, fb_num;
1227#endif
1228#ifdef CONFIG_ANDROID_PMEM
1229 unsigned long vstart;
1230#endif
1231
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001232 *p_need = 0;
1233
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001234#ifdef CONFIG_FB
Naseer Ahmed18018602011-10-25 13:32:58 -07001235 if (fbd->flags & MDP_MEMORY_ID_TYPE_FB) {
1236 file = fget_light(fbd->memory_id, &put_needed);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001237 if (file == NULL) {
1238 pr_err("fget_light returned NULL\n");
Naseer Ahmed18018602011-10-25 13:32:58 -07001239 return -EINVAL;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001240 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001241
Naseer Ahmed18018602011-10-25 13:32:58 -07001242 if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) {
1243 fb_num = MINOR(file->f_dentry->d_inode->i_rdev);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001244 if (get_fb_phys_info(start, len, fb_num,
1245 ROTATOR_SUBSYSTEM_ID)) {
1246 pr_err("get_fb_phys_info() failed\n");
Naseer Ahmed18018602011-10-25 13:32:58 -07001247 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001248 } else {
Naseer Ahmed18018602011-10-25 13:32:58 -07001249 *p_file = file;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001250 *p_need = put_needed;
1251 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001252 } else {
1253 pr_err("invalid FB_MAJOR failed\n");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001254 ret = -1;
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001255 }
Naseer Ahmed18018602011-10-25 13:32:58 -07001256 if (ret)
1257 fput_light(file, put_needed);
1258 return ret;
1259 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001260#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07001261
1262#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001263 return msm_rotator_iommu_map_buf(fbd->memory_id, domain, start,
1264 len, p_ihdl, secure);
Naseer Ahmed18018602011-10-25 13:32:58 -07001265#endif
1266#ifdef CONFIG_ANDROID_PMEM
1267 if (!get_pmem_file(fbd->memory_id, start, &vstart, len, p_file))
1268 return 0;
1269 else
1270 return -ENOMEM;
1271#endif
1272
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001273}
1274
Olav Hauganef95ae32012-05-15 09:50:30 -07001275static void put_img(struct file *p_file, struct ion_handle *p_ihdl,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001276 int domain, unsigned int secure)
Naseer Ahmed18018602011-10-25 13:32:58 -07001277{
1278#ifdef CONFIG_ANDROID_PMEM
1279 if (p_file != NULL)
1280 put_pmem_file(p_file);
1281#endif
Olav Hauganef95ae32012-05-15 09:50:30 -07001282
Naseer Ahmed18018602011-10-25 13:32:58 -07001283#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001284 if (!IS_ERR_OR_NULL(p_ihdl)) {
1285 pr_debug("%s(): p_ihdl %p\n", __func__, p_ihdl);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001286 if (rot_iommu_split_domain) {
1287 if (!secure)
1288 ion_unmap_iommu(msm_rotator_dev->client,
1289 p_ihdl, domain, GEN_POOL);
1290 } else {
1291 ion_unmap_iommu(msm_rotator_dev->client,
1292 p_ihdl, ROTATOR_SRC_DOMAIN, GEN_POOL);
1293 }
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001294
Naseer Ahmed18018602011-10-25 13:32:58 -07001295 ion_free(msm_rotator_dev->client, p_ihdl);
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001296 }
Naseer Ahmed18018602011-10-25 13:32:58 -07001297#endif
1298}
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001299
1300static int msm_rotator_rotate_prepare(
1301 struct msm_rotator_data_info *data_info,
1302 struct msm_rotator_commit_info *commit_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001303{
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001304 unsigned int format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001305 struct msm_rotator_data_info info;
1306 unsigned int in_paddr, out_paddr;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001307 unsigned long src_len, dst_len;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001308 int rc = 0, s;
Naseer Ahmed18018602011-10-25 13:32:58 -07001309 struct file *srcp0_file = NULL, *dstp0_file = NULL;
1310 struct file *srcp1_file = NULL, *dstp1_file = NULL;
1311 struct ion_handle *srcp0_ihdl = NULL, *dstp0_ihdl = NULL;
1312 struct ion_handle *srcp1_ihdl = NULL, *dstp1_ihdl = NULL;
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001313 int ps0_need, p_need;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001314 unsigned int in_chroma_paddr = 0, out_chroma_paddr = 0;
Mayank Chopra27147a72012-07-17 13:57:22 +05301315 unsigned int in_chroma2_paddr = 0, out_chroma2_paddr = 0;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001316 struct msm_rotator_img_info *img_info;
1317 struct msm_rotator_mem_planes src_planes, dst_planes;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001318
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001319 mutex_lock(&msm_rotator_dev->rotator_lock);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001320 info = *data_info;
1321
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001322 for (s = 0; s < MAX_SESSIONS; s++)
Mayank Chopra27147a72012-07-17 13:57:22 +05301323 if ((msm_rotator_dev->rot_session[s] != NULL) &&
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001324 (info.session_id ==
Mayank Chopra27147a72012-07-17 13:57:22 +05301325 (unsigned int)msm_rotator_dev->rot_session[s]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001326 ))
1327 break;
1328
1329 if (s == MAX_SESSIONS) {
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001330 pr_err("%s() : Attempt to use invalid session_id %d\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001331 __func__, s);
1332 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001333 mutex_unlock(&msm_rotator_dev->rotator_lock);
1334 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001335 }
1336
Mayank Chopra27147a72012-07-17 13:57:22 +05301337 img_info = &(msm_rotator_dev->rot_session[s]->img_info);
1338 if (img_info->enable == 0) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001339 dev_dbg(msm_rotator_dev->device,
Mayank Chopra27147a72012-07-17 13:57:22 +05301340 "%s() : Session_id %d not enabled\n", __func__, s);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001341 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001342 mutex_unlock(&msm_rotator_dev->rotator_lock);
1343 return rc;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001344 }
1345
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001346 if (msm_rotator_get_plane_sizes(img_info->src.format,
1347 img_info->src.width,
1348 img_info->src.height,
1349 &src_planes)) {
1350 pr_err("%s: invalid src format\n", __func__);
1351 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001352 mutex_unlock(&msm_rotator_dev->rotator_lock);
1353 return rc;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001354 }
1355 if (msm_rotator_get_plane_sizes(img_info->dst.format,
1356 img_info->dst.width,
1357 img_info->dst.height,
1358 &dst_planes)) {
1359 pr_err("%s: invalid dst format\n", __func__);
1360 rc = -EINVAL;
Kuogee Hsiehb98fad42013-03-27 17:41:49 -07001361 mutex_unlock(&msm_rotator_dev->rotator_lock);
1362 return rc;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001363 }
1364
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001365 rc = get_img(&info.src, ROTATOR_SRC_DOMAIN, (unsigned long *)&in_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001366 (unsigned long *)&src_len, &srcp0_file, &ps0_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001367 &srcp0_ihdl, 0);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001368 if (rc) {
1369 pr_err("%s: in get_img() failed id=0x%08x\n",
1370 DRIVER_NAME, info.src.memory_id);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001371 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001372 }
1373
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001374 rc = get_img(&info.dst, ROTATOR_DST_DOMAIN, (unsigned long *)&out_paddr,
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07001375 (unsigned long *)&dst_len, &dstp0_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001376 &dstp0_ihdl, img_info->secure);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001377 if (rc) {
1378 pr_err("%s: out get_img() failed id=0x%08x\n",
1379 DRIVER_NAME, info.dst.memory_id);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001380 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001381 }
1382
Mayank Chopra27147a72012-07-17 13:57:22 +05301383 format = img_info->src.format;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001384 if (((info.version_key & VERSION_KEY_MASK) == 0xA5B4C300) &&
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001385 ((info.version_key & ~VERSION_KEY_MASK) > 0) &&
1386 (src_planes.num_planes == 2)) {
1387 if (checkoffset(info.src.offset,
1388 src_planes.plane_size[0],
1389 src_len)) {
1390 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1391 __func__, src_len, info.src.offset);
1392 rc = -ERANGE;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001393 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001394 }
1395 if (checkoffset(info.dst.offset,
1396 dst_planes.plane_size[0],
1397 dst_len)) {
1398 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1399 __func__, dst_len, info.dst.offset);
1400 rc = -ERANGE;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001401 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001402 }
1403
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001404 rc = get_img(&info.src_chroma, ROTATOR_SRC_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001405 (unsigned long *)&in_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001406 (unsigned long *)&src_len, &srcp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001407 &srcp1_ihdl, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001408 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001409 pr_err("%s: in chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001410 DRIVER_NAME, info.src_chroma.memory_id);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001411 goto rotate_prepare_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001412 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001413
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001414 rc = get_img(&info.dst_chroma, ROTATOR_DST_DOMAIN,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001415 (unsigned long *)&out_chroma_paddr,
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001416 (unsigned long *)&dst_len, &dstp1_file, &p_need,
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001417 &dstp1_ihdl, img_info->secure);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001418 if (rc) {
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001419 pr_err("%s: out chroma get_img() failed id=0x%08x\n",
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001420 DRIVER_NAME, info.dst_chroma.memory_id);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001421 goto rotate_prepare_error;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001422 }
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001423
1424 if (checkoffset(info.src_chroma.offset,
1425 src_planes.plane_size[1],
1426 src_len)) {
1427 pr_err("%s: invalid chr src buf len=%lu offset=%x\n",
1428 __func__, src_len, info.src_chroma.offset);
1429 rc = -ERANGE;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001430 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001431 }
1432
1433 if (checkoffset(info.dst_chroma.offset,
1434 src_planes.plane_size[1],
1435 dst_len)) {
1436 pr_err("%s: invalid chr dst buf len=%lu offset=%x\n",
1437 __func__, dst_len, info.dst_chroma.offset);
1438 rc = -ERANGE;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001439 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001440 }
1441
1442 in_chroma_paddr += info.src_chroma.offset;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001443 out_chroma_paddr += info.dst_chroma.offset;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001444 } else {
1445 if (checkoffset(info.src.offset,
1446 src_planes.total_size,
1447 src_len)) {
1448 pr_err("%s: invalid src buffer (len=%lu offset=%x)\n",
1449 __func__, src_len, info.src.offset);
1450 rc = -ERANGE;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001451 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001452 }
1453 if (checkoffset(info.dst.offset,
1454 dst_planes.total_size,
1455 dst_len)) {
1456 pr_err("%s: invalid dst buffer (len=%lu offset=%x)\n",
1457 __func__, dst_len, info.dst.offset);
1458 rc = -ERANGE;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001459 goto rotate_prepare_error;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001460 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001461 }
1462
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001463 in_paddr += info.src.offset;
1464 out_paddr += info.dst.offset;
1465
1466 if (!in_chroma_paddr && src_planes.num_planes >= 2)
1467 in_chroma_paddr = in_paddr + src_planes.plane_size[0];
1468 if (!out_chroma_paddr && dst_planes.num_planes >= 2)
1469 out_chroma_paddr = out_paddr + dst_planes.plane_size[0];
1470 if (src_planes.num_planes >= 3)
1471 in_chroma2_paddr = in_chroma_paddr + src_planes.plane_size[1];
Mayank Chopra27147a72012-07-17 13:57:22 +05301472 if (dst_planes.num_planes >= 3)
1473 out_chroma2_paddr = out_chroma_paddr + dst_planes.plane_size[1];
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001474
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001475 commit_info->data_info = info;
1476 commit_info->img_info = *img_info;
1477 commit_info->format = format;
1478 commit_info->in_paddr = in_paddr;
1479 commit_info->out_paddr = out_paddr;
1480 commit_info->in_chroma_paddr = in_chroma_paddr;
1481 commit_info->out_chroma_paddr = out_chroma_paddr;
1482 commit_info->in_chroma2_paddr = in_chroma2_paddr;
1483 commit_info->out_chroma2_paddr = out_chroma2_paddr;
1484 commit_info->srcp0_file = srcp0_file;
1485 commit_info->srcp1_file = srcp1_file;
1486 commit_info->srcp0_ihdl = srcp0_ihdl;
1487 commit_info->srcp1_ihdl = srcp1_ihdl;
1488 commit_info->dstp0_file = dstp0_file;
1489 commit_info->dstp0_ihdl = dstp0_ihdl;
1490 commit_info->dstp1_file = dstp1_file;
1491 commit_info->dstp1_ihdl = dstp1_ihdl;
1492 commit_info->ps0_need = ps0_need;
1493 commit_info->session_index = s;
1494 commit_info->acq_fen = msm_rotator_dev->sync_info[s].acq_fen;
1495 commit_info->fast_yuv_en = mrd->rot_session[s]->fast_yuv_enable;
1496 mutex_unlock(&msm_rotator_dev->rotator_lock);
1497 return 0;
1498
1499rotate_prepare_error:
1500 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
1501 msm_rotator_dev->rot_session[s]->img_info.secure);
1502 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1503 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
1504 msm_rotator_dev->rot_session[s]->img_info.secure);
1505
1506 /* only source may use frame buffer */
1507 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1508 fput_light(srcp0_file, ps0_need);
1509 else
1510 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
1511 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1512 __func__, rc);
1513 mutex_unlock(&msm_rotator_dev->rotator_lock);
1514 return rc;
1515}
1516
1517static int msm_rotator_do_rotate_sub(
1518 struct msm_rotator_commit_info *commit_info)
1519{
1520 unsigned int status, format;
1521 struct msm_rotator_data_info info;
1522 unsigned int in_paddr, out_paddr;
1523 int use_imem = 0, rc = 0;
1524 struct file *srcp0_file, *dstp0_file;
1525 struct file *srcp1_file, *dstp1_file;
1526 struct ion_handle *srcp0_ihdl, *dstp0_ihdl;
1527 struct ion_handle *srcp1_ihdl, *dstp1_ihdl;
1528 int s, ps0_need;
1529 unsigned int in_chroma_paddr, out_chroma_paddr;
1530 unsigned int in_chroma2_paddr, out_chroma2_paddr;
1531 struct msm_rotator_img_info *img_info;
1532
1533 mutex_lock(&msm_rotator_dev->rotator_lock);
1534
1535 info = commit_info->data_info;
1536 img_info = &commit_info->img_info;
1537 format = commit_info->format;
1538 in_paddr = commit_info->in_paddr;
1539 out_paddr = commit_info->out_paddr;
1540 in_chroma_paddr = commit_info->in_chroma_paddr;
1541 out_chroma_paddr = commit_info->out_chroma_paddr;
1542 in_chroma2_paddr = commit_info->in_chroma2_paddr;
1543 out_chroma2_paddr = commit_info->out_chroma2_paddr;
1544 srcp0_file = commit_info->srcp0_file;
1545 srcp1_file = commit_info->srcp1_file;
1546 srcp0_ihdl = commit_info->srcp0_ihdl;
1547 srcp1_ihdl = commit_info->srcp1_ihdl;
1548 dstp0_file = commit_info->dstp0_file;
1549 dstp0_ihdl = commit_info->dstp0_ihdl;
1550 dstp1_file = commit_info->dstp1_file;
1551 dstp1_ihdl = commit_info->dstp1_ihdl;
1552 ps0_need = commit_info->ps0_need;
1553 s = commit_info->session_index;
1554
1555 msm_rotator_wait_for_fence(commit_info->acq_fen);
1556 commit_info->acq_fen = NULL;
Ken Zhanga50db542013-02-20 14:48:06 -05001557
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001558 cancel_delayed_work(&msm_rotator_dev->rot_clk_work);
1559 if (msm_rotator_dev->rot_clk_state != CLK_EN) {
1560 enable_rot_clks();
1561 msm_rotator_dev->rot_clk_state = CLK_EN;
1562 }
1563 enable_irq(msm_rotator_dev->irq);
1564
1565#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1566 use_imem = msm_rotator_imem_allocate(ROTATOR_REQUEST);
1567#else
1568 use_imem = 0;
1569#endif
1570 /*
1571 * workaround for a hardware bug. rotator hardware hangs when we
1572 * use write burst beat size 16 on 128X128 tile fetch mode. As a
1573 * temporary fix use 0x42 for BURST_SIZE when imem used.
1574 */
1575 if (use_imem)
1576 iowrite32(0x42, MSM_ROTATOR_MAX_BURST_SIZE);
1577
Mayank Chopra27147a72012-07-17 13:57:22 +05301578 iowrite32(((img_info->src_rect.h & 0x1fff)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001579 << 16) |
Mayank Chopra27147a72012-07-17 13:57:22 +05301580 (img_info->src_rect.w & 0x1fff),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001581 MSM_ROTATOR_SRC_SIZE);
Mayank Chopra27147a72012-07-17 13:57:22 +05301582 iowrite32(((img_info->src_rect.y & 0x1fff)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001583 << 16) |
Mayank Chopra27147a72012-07-17 13:57:22 +05301584 (img_info->src_rect.x & 0x1fff),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001585 MSM_ROTATOR_SRC_XY);
Mayank Chopra27147a72012-07-17 13:57:22 +05301586 iowrite32(((img_info->src.height & 0x1fff)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001587 << 16) |
Mayank Chopra27147a72012-07-17 13:57:22 +05301588 (img_info->src.width & 0x1fff),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001589 MSM_ROTATOR_SRC_IMAGE_SIZE);
1590
1591 switch (format) {
1592 case MDP_RGB_565:
1593 case MDP_BGR_565:
1594 case MDP_RGB_888:
1595 case MDP_ARGB_8888:
1596 case MDP_RGBA_8888:
1597 case MDP_XRGB_8888:
1598 case MDP_BGRA_8888:
1599 case MDP_RGBX_8888:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001600 case MDP_YCBCR_H1V1:
1601 case MDP_YCRCB_H1V1:
Mayank Chopra27147a72012-07-17 13:57:22 +05301602 rc = msm_rotator_rgb_types(img_info,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001603 in_paddr, out_paddr,
1604 use_imem,
1605 msm_rotator_dev->last_session_idx
1606 != s);
1607 break;
1608 case MDP_Y_CBCR_H2V2:
1609 case MDP_Y_CRCB_H2V2:
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001610 case MDP_Y_CB_CR_H2V2:
1611 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05301612 case MDP_Y_CR_CB_GH2V2:
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001613 case MDP_Y_CRCB_H2V2_TILE:
1614 case MDP_Y_CBCR_H2V2_TILE:
Mayank Chopra27147a72012-07-17 13:57:22 +05301615 rc = msm_rotator_ycxcx_h2v2(img_info,
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001616 in_paddr, out_paddr, use_imem,
1617 msm_rotator_dev->last_session_idx
1618 != s,
1619 in_chroma_paddr,
1620 out_chroma_paddr,
Mayank Chopra27147a72012-07-17 13:57:22 +05301621 in_chroma2_paddr,
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001622 out_chroma2_paddr,
1623 commit_info->fast_yuv_en);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001624 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001625 case MDP_Y_CBCR_H2V1:
1626 case MDP_Y_CRCB_H2V1:
Mayank Chopra27147a72012-07-17 13:57:22 +05301627 rc = msm_rotator_ycxcx_h2v1(img_info,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001628 in_paddr, out_paddr, use_imem,
1629 msm_rotator_dev->last_session_idx
1630 != s,
1631 in_chroma_paddr,
1632 out_chroma_paddr);
1633 break;
1634 case MDP_YCRYCB_H2V1:
Mayank Chopra27147a72012-07-17 13:57:22 +05301635 rc = msm_rotator_ycrycb(img_info,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001636 in_paddr, out_paddr, use_imem,
Mayank Chopra732dcd62012-01-09 20:53:39 +05301637 msm_rotator_dev->last_session_idx != s,
1638 out_chroma_paddr);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001639 break;
1640 default:
1641 rc = -EINVAL;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001642 pr_err("%s(): Unsupported format %u\n", __func__, format);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001643 goto do_rotate_exit;
1644 }
1645
1646 if (rc != 0) {
1647 msm_rotator_dev->last_session_idx = INVALID_SESSION;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001648 pr_err("%s(): Invalid session error\n", __func__);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001649 goto do_rotate_exit;
1650 }
1651
1652 iowrite32(3, MSM_ROTATOR_INTR_ENABLE);
1653
1654 msm_rotator_dev->processing = 1;
1655 iowrite32(0x1, MSM_ROTATOR_START);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001656 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001657 wait_event(msm_rotator_dev->wq,
1658 (msm_rotator_dev->processing == 0));
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001659 mutex_lock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001660 status = (unsigned char)ioread32(MSM_ROTATOR_INTR_STATUS);
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001661 if ((status & 0x03) != 0x01) {
1662 pr_err("%s(): AXI Bus Error, issuing SW_RESET\n", __func__);
1663 iowrite32(0x1, MSM_ROTATOR_SW_RESET);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001664 rc = -EFAULT;
Ravishangar Kalyanam30cf3eb2012-04-13 18:10:26 -07001665 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001666 iowrite32(0, MSM_ROTATOR_INTR_ENABLE);
1667 iowrite32(3, MSM_ROTATOR_INTR_CLEAR);
1668
1669do_rotate_exit:
1670 disable_irq(msm_rotator_dev->irq);
1671#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
1672 msm_rotator_imem_free(ROTATOR_REQUEST);
1673#endif
1674 schedule_delayed_work(&msm_rotator_dev->rot_clk_work, HZ);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001675 put_img(dstp1_file, dstp1_ihdl, ROTATOR_DST_DOMAIN,
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001676 img_info->secure);
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001677 put_img(srcp1_file, srcp1_ihdl, ROTATOR_SRC_DOMAIN, 0);
1678 put_img(dstp0_file, dstp0_ihdl, ROTATOR_DST_DOMAIN,
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001679 img_info->secure);
Kuogee Hsiehbeaa9352012-02-24 16:59:26 -08001680
1681 /* only source may use frame buffer */
1682 if (info.src.flags & MDP_MEMORY_ID_TYPE_FB)
1683 fput_light(srcp0_file, ps0_need);
1684 else
Ravishangar Kalyanam1eca3522012-05-31 18:02:24 -07001685 put_img(srcp0_file, srcp0_ihdl, ROTATOR_SRC_DOMAIN, 0);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001686 msm_rotator_signal_timeline_done(s);
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001687 mutex_unlock(&msm_rotator_dev->rotator_lock);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001688 dev_dbg(msm_rotator_dev->device, "%s() returning rc = %d\n",
1689 __func__, rc);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001690
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001691 return rc;
1692}
1693
Ken Zhang93b9f9a2013-04-08 18:56:58 -04001694static void rot_wait_for_commit_queue(u32 is_all)
1695{
1696 int ret = 0;
1697 u32 loop_cnt = 0;
1698
1699 while (1) {
1700 mutex_lock(&mrd->commit_mutex);
1701 if (is_all && (atomic_read(&mrd->commit_q_cnt) == 0))
1702 break;
1703 if ((!is_all) &&
1704 (atomic_read(&mrd->commit_q_cnt) < MAX_COMMIT_QUEUE))
1705 break;
1706 INIT_COMPLETION(mrd->commit_comp);
1707 mutex_unlock(&mrd->commit_mutex);
1708 ret = wait_for_completion_interruptible_timeout(
1709 &mrd->commit_comp,
1710 msecs_to_jiffies(WAIT_ROT_TIMEOUT));
1711 if ((ret <= 0) ||
1712 (atomic_read(&mrd->commit_q_cnt) >= MAX_COMMIT_QUEUE) ||
1713 (loop_cnt > MAX_COMMIT_QUEUE)) {
1714 pr_err("%s wait for commit queue failed ret=%d pointers:%d %d",
1715 __func__, ret, atomic_read(&mrd->commit_q_r),
1716 atomic_read(&mrd->commit_q_w));
1717 mutex_lock(&mrd->commit_mutex);
1718 ret = -ETIME;
1719 break;
1720 } else {
1721 ret = 0;
1722 }
1723 loop_cnt++;
1724 };
1725 if (is_all || ret) {
1726 atomic_set(&mrd->commit_q_r, 0);
1727 atomic_set(&mrd->commit_q_cnt, 0);
1728 atomic_set(&mrd->commit_q_w, 0);
1729 }
1730 mutex_unlock(&mrd->commit_mutex);
1731}
1732
1733static int msm_rotator_do_rotate(unsigned long arg)
1734{
1735 struct msm_rotator_data_info info;
1736 struct rot_sync_info *sync_info;
1737 int session_index, ret;
1738 int commit_q_w;
1739
1740 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1741 return -EFAULT;
1742
1743 rot_wait_for_commit_queue(false);
1744 mutex_lock(&mrd->commit_mutex);
1745 commit_q_w = atomic_read(&mrd->commit_q_w);
1746 ret = msm_rotator_rotate_prepare(&info,
1747 &mrd->commit_info[commit_q_w]);
1748 if (ret) {
1749 mutex_unlock(&mrd->commit_mutex);
1750 return ret;
1751 }
1752
1753 session_index = mrd->commit_info[commit_q_w].session_index;
1754 sync_info = &msm_rotator_dev->sync_info[session_index];
1755 mutex_lock(&sync_info->sync_mutex);
1756 atomic_inc(&sync_info->queue_buf_cnt);
1757 sync_info->acq_fen = NULL;
1758 mutex_unlock(&sync_info->sync_mutex);
1759
1760 if (atomic_inc_return(&mrd->commit_q_w) >= MAX_COMMIT_QUEUE)
1761 atomic_set(&mrd->commit_q_w, 0);
1762 atomic_inc(&mrd->commit_q_cnt);
1763
1764 schedule_work(&mrd->commit_work);
1765 mutex_unlock(&mrd->commit_mutex);
1766
1767 if (info.wait_for_finish)
1768 rot_wait_for_commit_queue(true);
1769
1770 return 0;
1771}
1772
1773static void rot_commit_wq_handler(struct work_struct *work)
1774{
1775 mutex_lock(&mrd->commit_wq_mutex);
1776 mutex_lock(&mrd->commit_mutex);
1777 while (atomic_read(&mrd->commit_q_cnt) > 0) {
1778 mrd->commit_running = true;
1779 mutex_unlock(&mrd->commit_mutex);
1780 msm_rotator_do_rotate_sub(
1781 &mrd->commit_info[atomic_read(&mrd->commit_q_r)]);
1782 mutex_lock(&mrd->commit_mutex);
1783 if (atomic_read(&mrd->commit_q_cnt) > 0) {
1784 atomic_dec(&mrd->commit_q_cnt);
1785 if (atomic_inc_return(&mrd->commit_q_r) >=
1786 MAX_COMMIT_QUEUE)
1787 atomic_set(&mrd->commit_q_r, 0);
1788 }
1789 complete_all(&mrd->commit_comp);
1790 }
1791 mrd->commit_running = false;
1792 if (atomic_read(&mrd->commit_q_r) != atomic_read(&mrd->commit_q_w))
1793 pr_err("%s invalid state: r=%d w=%d cnt=%d", __func__,
1794 atomic_read(&mrd->commit_q_r),
1795 atomic_read(&mrd->commit_q_w),
1796 atomic_read(&mrd->commit_q_cnt));
1797 mutex_unlock(&mrd->commit_mutex);
1798 mutex_unlock(&mrd->commit_wq_mutex);
1799}
1800
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001801static void msm_rotator_set_perf_level(u32 wh, u32 is_rgb)
1802{
1803 u32 perf_level;
1804
1805 if (is_rgb)
1806 perf_level = 1;
1807 else if (wh <= (640 * 480))
1808 perf_level = 2;
1809 else if (wh <= (736 * 1280))
1810 perf_level = 3;
1811 else
1812 perf_level = 4;
1813
1814#ifdef CONFIG_MSM_BUS_SCALING
1815 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
1816 perf_level);
1817#endif
1818
1819}
1820
Ken Zhangfebeabd2012-12-17 10:35:15 -05001821static int rot_enable_iommu_clocks(struct msm_rotator_dev *rot_dev)
1822{
1823 int ret = 0, i;
1824 if (rot_dev->mmu_clk_on)
1825 return 0;
1826 for (i = 0; i < ARRAY_SIZE(rot_mmu_clks); i++) {
1827 rot_mmu_clks[i].mmu_clk = clk_get(&msm_rotator_dev->pdev->dev,
1828 rot_mmu_clks[i].mmu_clk_name);
1829 if (IS_ERR(rot_mmu_clks[i].mmu_clk)) {
1830 pr_err(" %s: Get failed for clk %s", __func__,
1831 rot_mmu_clks[i].mmu_clk_name);
1832 ret = PTR_ERR(rot_mmu_clks[i].mmu_clk);
1833 break;
1834 }
1835 ret = clk_prepare_enable(rot_mmu_clks[i].mmu_clk);
1836 if (ret) {
1837 clk_put(rot_mmu_clks[i].mmu_clk);
1838 rot_mmu_clks[i].mmu_clk = NULL;
1839 }
1840 }
1841 if (ret) {
1842 for (i--; i >= 0; i--) {
1843 clk_disable_unprepare(rot_mmu_clks[i].mmu_clk);
1844 clk_put(rot_mmu_clks[i].mmu_clk);
1845 rot_mmu_clks[i].mmu_clk = NULL;
1846 }
1847 } else {
1848 rot_dev->mmu_clk_on = 1;
1849 }
1850 return ret;
1851}
1852
1853static int rot_disable_iommu_clocks(struct msm_rotator_dev *rot_dev)
1854{
1855 int i;
1856 if (!rot_dev->mmu_clk_on)
1857 return 0;
1858 for (i = 0; i < ARRAY_SIZE(rot_mmu_clks); i++) {
1859 clk_disable_unprepare(rot_mmu_clks[i].mmu_clk);
1860 clk_put(rot_mmu_clks[i].mmu_clk);
1861 rot_mmu_clks[i].mmu_clk = NULL;
1862 }
1863 rot_dev->mmu_clk_on = 0;
1864 return 0;
1865}
1866
1867static int map_sec_resource(struct msm_rotator_dev *rot_dev)
1868{
1869 int ret = 0;
1870 if (rot_dev->sec_mapped)
1871 return 0;
1872
1873 ret = rot_enable_iommu_clocks(rot_dev);
1874 if (ret) {
1875 pr_err("IOMMU clock enabled failed while open");
1876 return ret;
1877 }
1878 ret = msm_ion_secure_heap(ION_HEAP(ION_CP_MM_HEAP_ID));
1879 if (ret)
1880 pr_err("ION heap secure failed heap id %d ret %d\n",
1881 ION_CP_MM_HEAP_ID, ret);
1882 else
1883 rot_dev->sec_mapped = 1;
1884 rot_disable_iommu_clocks(rot_dev);
1885 return ret;
1886}
1887
1888static int unmap_sec_resource(struct msm_rotator_dev *rot_dev)
1889{
1890 int ret = 0;
1891 ret = rot_enable_iommu_clocks(rot_dev);
1892 if (ret) {
1893 pr_err("IOMMU clock enabled failed while close\n");
1894 return ret;
1895 }
1896 msm_ion_unsecure_heap(ION_HEAP(ION_CP_MM_HEAP_ID));
1897 rot_dev->sec_mapped = 0;
1898 rot_disable_iommu_clocks(rot_dev);
1899 return ret;
1900}
1901
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07001902static int msm_rotator_start(unsigned long arg,
1903 struct msm_rotator_fd_info *fd_info)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001904{
1905 struct msm_rotator_img_info info;
Mayank Chopra27147a72012-07-17 13:57:22 +05301906 struct msm_rotator_session *rot_session = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001907 int rc = 0;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001908 int s, is_rgb = 0;
Mayank Chopra27147a72012-07-17 13:57:22 +05301909 int first_free_idx = INVALID_SESSION;
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001910 unsigned int dst_w, dst_h;
Mayank Chopra27147a72012-07-17 13:57:22 +05301911 unsigned int is_planar420 = 0;
1912 int fast_yuv_en = 0;
Ken Zhanga50db542013-02-20 14:48:06 -05001913 struct rot_sync_info *sync_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001914
1915 if (copy_from_user(&info, (void __user *)arg, sizeof(info)))
1916 return -EFAULT;
1917
1918 if ((info.rotations > MSM_ROTATOR_MAX_ROT) ||
1919 (info.src.height > MSM_ROTATOR_MAX_H) ||
1920 (info.src.width > MSM_ROTATOR_MAX_W) ||
1921 (info.dst.height > MSM_ROTATOR_MAX_H) ||
1922 (info.dst.width > MSM_ROTATOR_MAX_W) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001923 (info.downscale_ratio > MAX_DOWNSCALE_RATIO)) {
1924 pr_err("%s: Invalid parameters\n", __func__);
1925 return -EINVAL;
1926 }
1927
1928 if (info.rotations & MDP_ROT_90) {
1929 dst_w = info.src_rect.h >> info.downscale_ratio;
1930 dst_h = info.src_rect.w >> info.downscale_ratio;
1931 } else {
1932 dst_w = info.src_rect.w >> info.downscale_ratio;
1933 dst_h = info.src_rect.h >> info.downscale_ratio;
1934 }
1935
1936 if (checkoffset(info.src_rect.x, info.src_rect.w, info.src.width) ||
Adrian Salido-Moreno88411862011-09-20 18:54:03 -07001937 checkoffset(info.src_rect.y, info.src_rect.h, info.src.height) ||
1938 checkoffset(info.dst_x, dst_w, info.dst.width) ||
Adrian Salido-Moreno67273e52011-10-21 19:04:18 -07001939 checkoffset(info.dst_y, dst_h, info.dst.height)) {
1940 pr_err("%s: Invalid src or dst rect\n", __func__);
1941 return -ERANGE;
1942 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001943
1944 switch (info.src.format) {
Mayank Chopra27147a72012-07-17 13:57:22 +05301945 case MDP_Y_CB_CR_H2V2:
1946 case MDP_Y_CR_CB_H2V2:
1947 case MDP_Y_CR_CB_GH2V2:
1948 is_planar420 = 1;
1949 case MDP_Y_CBCR_H2V2:
1950 case MDP_Y_CRCB_H2V2:
1951 case MDP_Y_CRCB_H2V2_TILE:
1952 case MDP_Y_CBCR_H2V2_TILE:
1953 if (rotator_hw_revision >= ROTATOR_REVISION_V2 &&
1954 !(info.downscale_ratio &&
1955 (info.rotations & MDP_ROT_90)))
1956 fast_yuv_en = !fast_yuv_invalid_size_checker(
1957 info.rotations,
1958 info.src.width,
1959 dst_w,
1960 dst_h,
1961 dst_w,
1962 is_planar420);
1963 break;
1964 default:
1965 fast_yuv_en = 0;
1966 }
1967
1968 switch (info.src.format) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001969 case MDP_RGB_565:
1970 case MDP_BGR_565:
1971 case MDP_RGB_888:
1972 case MDP_ARGB_8888:
1973 case MDP_RGBA_8888:
1974 case MDP_XRGB_8888:
1975 case MDP_RGBX_8888:
1976 case MDP_BGRA_8888:
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001977 is_rgb = 1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301978 info.dst.format = info.src.format;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08001979 break;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07001980 case MDP_Y_CBCR_H2V2:
1981 case MDP_Y_CRCB_H2V2:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301982 case MDP_Y_CBCR_H2V1:
1983 case MDP_Y_CRCB_H2V1:
Adrian Salido-Morenoeeb06c72011-08-15 10:41:35 -07001984 case MDP_YCBCR_H1V1:
1985 case MDP_YCRCB_H1V1:
Mayank Chopra012a8e72012-04-11 10:41:13 +05301986 info.dst.format = info.src.format;
1987 break;
1988 case MDP_YCRYCB_H2V1:
Mayank Chopra797bdb72012-03-03 06:29:40 +05301989 if (info.rotations & MDP_ROT_90)
1990 info.dst.format = MDP_Y_CRCB_H1V2;
1991 else
1992 info.dst.format = MDP_Y_CRCB_H2V1;
Mayank Chopra012a8e72012-04-11 10:41:13 +05301993 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07001994 case MDP_Y_CB_CR_H2V2:
Mayank Chopra27147a72012-07-17 13:57:22 +05301995 if (fast_yuv_en) {
1996 info.dst.format = info.src.format;
1997 break;
1998 }
Mayank Chopra012a8e72012-04-11 10:41:13 +05301999 case MDP_Y_CBCR_H2V2_TILE:
2000 info.dst.format = MDP_Y_CBCR_H2V2;
2001 break;
Adrian Salido-Moreno0644f342011-07-08 12:05:01 -07002002 case MDP_Y_CR_CB_H2V2:
Pradeep Jilagam9b4a6be2011-10-03 17:19:20 +05302003 case MDP_Y_CR_CB_GH2V2:
Mayank Chopra27147a72012-07-17 13:57:22 +05302004 if (fast_yuv_en) {
2005 info.dst.format = info.src.format;
2006 break;
2007 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002008 case MDP_Y_CRCB_H2V2_TILE:
Mayank Chopra012a8e72012-04-11 10:41:13 +05302009 info.dst.format = MDP_Y_CRCB_H2V2;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002010 break;
2011 default:
2012 return -EINVAL;
2013 }
2014
2015 mutex_lock(&msm_rotator_dev->rotator_lock);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002016
2017 msm_rotator_set_perf_level((info.src.width*info.src.height), is_rgb);
2018
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002019 for (s = 0; s < MAX_SESSIONS; s++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05302020 if ((msm_rotator_dev->rot_session[s] != NULL) &&
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002021 (info.session_id ==
Mayank Chopra27147a72012-07-17 13:57:22 +05302022 (unsigned int)msm_rotator_dev->rot_session[s]
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002023 )) {
Mayank Chopra27147a72012-07-17 13:57:22 +05302024 rot_session = msm_rotator_dev->rot_session[s];
2025 rot_session->img_info = info;
2026 rot_session->fd_info = *fd_info;
2027 rot_session->fast_yuv_enable = fast_yuv_en;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002028
2029 if (msm_rotator_dev->last_session_idx == s)
2030 msm_rotator_dev->last_session_idx =
2031 INVALID_SESSION;
2032 break;
2033 }
2034
Mayank Chopra27147a72012-07-17 13:57:22 +05302035 if ((msm_rotator_dev->rot_session[s] == NULL) &&
2036 (first_free_idx == INVALID_SESSION))
2037 first_free_idx = s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002038 }
2039
Mayank Chopra27147a72012-07-17 13:57:22 +05302040 if ((s == MAX_SESSIONS) && (first_free_idx != INVALID_SESSION)) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002041 /* allocate a session id */
Mayank Chopra27147a72012-07-17 13:57:22 +05302042 msm_rotator_dev->rot_session[first_free_idx] =
2043 kzalloc(sizeof(struct msm_rotator_session),
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002044 GFP_KERNEL);
Mayank Chopra27147a72012-07-17 13:57:22 +05302045 if (!msm_rotator_dev->rot_session[first_free_idx]) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002046 printk(KERN_ERR "%s : unable to alloc mem\n",
2047 __func__);
2048 rc = -ENOMEM;
2049 goto rotator_start_exit;
2050 }
2051 info.session_id = (unsigned int)
Mayank Chopra27147a72012-07-17 13:57:22 +05302052 msm_rotator_dev->rot_session[first_free_idx];
2053 rot_session = msm_rotator_dev->rot_session[first_free_idx];
2054
2055 rot_session->img_info = info;
2056 rot_session->fd_info = *fd_info;
2057 rot_session->fast_yuv_enable = fast_yuv_en;
Ken Zhanga50db542013-02-20 14:48:06 -05002058 s = first_free_idx;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002059 } else if (s == MAX_SESSIONS) {
2060 dev_dbg(msm_rotator_dev->device, "%s: all sessions in use\n",
2061 __func__);
2062 rc = -EBUSY;
2063 }
2064
Adrian Salido-Morenoc5639952012-04-20 19:07:58 -07002065 if (rc == 0 && copy_to_user((void __user *)arg, &info, sizeof(info)))
2066 rc = -EFAULT;
Ken Zhangfebeabd2012-12-17 10:35:15 -05002067 if ((rc == 0) && (info.secure))
2068 map_sec_resource(msm_rotator_dev);
Ken Zhanga50db542013-02-20 14:48:06 -05002069
2070 sync_info = &msm_rotator_dev->sync_info[s];
2071 if ((rc == 0) && (sync_info->initialized == false)) {
2072 char timeline_name[MAX_TIMELINE_NAME_LEN];
2073 if (sync_info->timeline == NULL) {
2074 snprintf(timeline_name, sizeof(timeline_name),
2075 "msm_rot_%d", first_free_idx);
2076 sync_info->timeline =
2077 sw_sync_timeline_create(timeline_name);
2078 if (sync_info->timeline == NULL)
2079 pr_err("%s: cannot create %s time line",
2080 __func__, timeline_name);
2081 sync_info->timeline_value = 0;
2082 }
2083 mutex_init(&sync_info->sync_mutex);
2084 sync_info->initialized = true;
2085 }
2086 sync_info->acq_fen = NULL;
Ken Zhang93b9f9a2013-04-08 18:56:58 -04002087 atomic_set(&sync_info->queue_buf_cnt, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002088rotator_start_exit:
2089 mutex_unlock(&msm_rotator_dev->rotator_lock);
2090
2091 return rc;
2092}
2093
2094static int msm_rotator_finish(unsigned long arg)
2095{
2096 int rc = 0;
2097 int s;
2098 unsigned int session_id;
2099
2100 if (copy_from_user(&session_id, (void __user *)arg, sizeof(s)))
2101 return -EFAULT;
2102
2103 mutex_lock(&msm_rotator_dev->rotator_lock);
2104 for (s = 0; s < MAX_SESSIONS; s++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05302105 if ((msm_rotator_dev->rot_session[s] != NULL) &&
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002106 (session_id ==
Mayank Chopra27147a72012-07-17 13:57:22 +05302107 (unsigned int)msm_rotator_dev->rot_session[s])) {
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002108 if (msm_rotator_dev->last_session_idx == s)
2109 msm_rotator_dev->last_session_idx =
2110 INVALID_SESSION;
Ken Zhanga50db542013-02-20 14:48:06 -05002111 msm_rotator_signal_timeline(s);
2112 msm_rotator_release_acq_fence(s);
Mayank Chopra27147a72012-07-17 13:57:22 +05302113 kfree(msm_rotator_dev->rot_session[s]);
2114 msm_rotator_dev->rot_session[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002115 break;
2116 }
2117 }
2118
2119 if (s == MAX_SESSIONS)
2120 rc = -EINVAL;
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002121#ifdef CONFIG_MSM_BUS_SCALING
2122 msm_bus_scale_client_update_request(msm_rotator_dev->bus_client_handle,
2123 0);
2124#endif
Ken Zhangfebeabd2012-12-17 10:35:15 -05002125 if (msm_rotator_dev->sec_mapped)
2126 unmap_sec_resource(msm_rotator_dev);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002127 mutex_unlock(&msm_rotator_dev->rotator_lock);
2128 return rc;
2129}
2130
2131static int
2132msm_rotator_open(struct inode *inode, struct file *filp)
2133{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002134 struct msm_rotator_fd_info *tmp, *fd_info = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002135 int i;
2136
2137 if (filp->private_data)
2138 return -EBUSY;
2139
2140 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002141 for (i = 0; i < MAX_SESSIONS; i++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05302142 if (msm_rotator_dev->rot_session[i] == NULL)
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002143 break;
2144 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002145
2146 if (i == MAX_SESSIONS) {
2147 mutex_unlock(&msm_rotator_dev->rotator_lock);
2148 return -EBUSY;
2149 }
2150
2151 list_for_each_entry(tmp, &msm_rotator_dev->fd_list, list) {
2152 if (tmp->pid == current->pid) {
2153 fd_info = tmp;
2154 break;
2155 }
2156 }
2157
2158 if (!fd_info) {
2159 fd_info = kzalloc(sizeof(*fd_info), GFP_KERNEL);
2160 if (!fd_info) {
2161 mutex_unlock(&msm_rotator_dev->rotator_lock);
2162 pr_err("%s: insufficient memory to alloc resources\n",
2163 __func__);
2164 return -ENOMEM;
2165 }
2166 list_add(&fd_info->list, &msm_rotator_dev->fd_list);
2167 fd_info->pid = current->pid;
2168 }
2169 fd_info->ref_cnt++;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002170 mutex_unlock(&msm_rotator_dev->rotator_lock);
2171
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002172 filp->private_data = fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002173
2174 return 0;
2175}
2176
2177static int
2178msm_rotator_close(struct inode *inode, struct file *filp)
2179{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002180 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002181 int s;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002182
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002183 fd_info = (struct msm_rotator_fd_info *)filp->private_data;
2184
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002185 mutex_lock(&msm_rotator_dev->rotator_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002186 if (--fd_info->ref_cnt > 0) {
2187 mutex_unlock(&msm_rotator_dev->rotator_lock);
2188 return 0;
2189 }
2190
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002191 for (s = 0; s < MAX_SESSIONS; s++) {
Mayank Chopra27147a72012-07-17 13:57:22 +05302192 if (msm_rotator_dev->rot_session[s] != NULL &&
2193 &(msm_rotator_dev->rot_session[s]->fd_info) == fd_info) {
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002194 pr_debug("%s: freeing rotator session %p (pid %d)\n",
Mayank Chopra27147a72012-07-17 13:57:22 +05302195 __func__, msm_rotator_dev->rot_session[s],
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002196 fd_info->pid);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04002197 rot_wait_for_commit_queue(true);
2198 msm_rotator_signal_timeline(s);
Mayank Chopra27147a72012-07-17 13:57:22 +05302199 kfree(msm_rotator_dev->rot_session[s]);
2200 msm_rotator_dev->rot_session[s] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002201 if (msm_rotator_dev->last_session_idx == s)
2202 msm_rotator_dev->last_session_idx =
2203 INVALID_SESSION;
2204 }
2205 }
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002206 list_del(&fd_info->list);
2207 kfree(fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002208 mutex_unlock(&msm_rotator_dev->rotator_lock);
2209
2210 return 0;
2211}
2212
2213static long msm_rotator_ioctl(struct file *file, unsigned cmd,
2214 unsigned long arg)
2215{
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002216 struct msm_rotator_fd_info *fd_info;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002217
2218 if (_IOC_TYPE(cmd) != MSM_ROTATOR_IOCTL_MAGIC)
2219 return -ENOTTY;
2220
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002221 fd_info = (struct msm_rotator_fd_info *)file->private_data;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002222
2223 switch (cmd) {
2224 case MSM_ROTATOR_IOCTL_START:
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002225 return msm_rotator_start(arg, fd_info);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002226 case MSM_ROTATOR_IOCTL_ROTATE:
2227 return msm_rotator_do_rotate(arg);
2228 case MSM_ROTATOR_IOCTL_FINISH:
2229 return msm_rotator_finish(arg);
Ken Zhanga50db542013-02-20 14:48:06 -05002230 case MSM_ROTATOR_IOCTL_BUFFER_SYNC:
2231 return msm_rotator_buf_sync(arg);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002232
2233 default:
2234 dev_dbg(msm_rotator_dev->device,
2235 "unexpected IOCTL %d\n", cmd);
2236 return -ENOTTY;
2237 }
2238}
2239
2240static const struct file_operations msm_rotator_fops = {
2241 .owner = THIS_MODULE,
2242 .open = msm_rotator_open,
2243 .release = msm_rotator_close,
2244 .unlocked_ioctl = msm_rotator_ioctl,
2245};
2246
2247static int __devinit msm_rotator_probe(struct platform_device *pdev)
2248{
2249 int rc = 0;
2250 struct resource *res;
2251 struct msm_rotator_platform_data *pdata = NULL;
2252 int i, number_of_clks;
2253 uint32_t ver;
2254
2255 msm_rotator_dev = kzalloc(sizeof(struct msm_rotator_dev), GFP_KERNEL);
2256 if (!msm_rotator_dev) {
2257 printk(KERN_ERR "%s Unable to allocate memory for struct\n",
2258 __func__);
2259 return -ENOMEM;
2260 }
2261 for (i = 0; i < MAX_SESSIONS; i++)
Mayank Chopra27147a72012-07-17 13:57:22 +05302262 msm_rotator_dev->rot_session[i] = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002263 msm_rotator_dev->last_session_idx = INVALID_SESSION;
2264
2265 pdata = pdev->dev.platform_data;
2266 number_of_clks = pdata->number_of_clocks;
Olav Hauganef95ae32012-05-15 09:50:30 -07002267 rot_iommu_split_domain = pdata->rot_iommu_split_domain;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002268
2269 msm_rotator_dev->imem_owner = IMEM_NO_OWNER;
2270 mutex_init(&msm_rotator_dev->imem_lock);
Adrian Salido-Moreno5737db12012-04-02 15:22:08 -07002271 INIT_LIST_HEAD(&msm_rotator_dev->fd_list);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002272 msm_rotator_dev->imem_clk_state = CLK_DIS;
2273 INIT_DELAYED_WORK(&msm_rotator_dev->imem_clk_work,
2274 msm_rotator_imem_clk_work_f);
2275 msm_rotator_dev->imem_clk = NULL;
2276 msm_rotator_dev->pdev = pdev;
2277
2278 msm_rotator_dev->core_clk = NULL;
2279 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002280
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002281#ifdef CONFIG_MSM_BUS_SCALING
2282 if (!msm_rotator_dev->bus_client_handle && pdata &&
2283 pdata->bus_scale_table) {
2284 msm_rotator_dev->bus_client_handle =
2285 msm_bus_scale_register_client(
2286 pdata->bus_scale_table);
2287 if (!msm_rotator_dev->bus_client_handle) {
2288 pr_err("%s not able to get bus scale handle\n",
2289 __func__);
2290 }
2291 }
2292#endif
2293
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002294 for (i = 0; i < number_of_clks; i++) {
2295 if (pdata->rotator_clks[i].clk_type == ROTATOR_IMEM_CLK) {
2296 msm_rotator_dev->imem_clk =
2297 clk_get(&msm_rotator_dev->pdev->dev,
2298 pdata->rotator_clks[i].clk_name);
2299 if (IS_ERR(msm_rotator_dev->imem_clk)) {
2300 rc = PTR_ERR(msm_rotator_dev->imem_clk);
2301 msm_rotator_dev->imem_clk = NULL;
2302 printk(KERN_ERR "%s: cannot get imem_clk "
2303 "rc=%d\n", DRIVER_NAME, rc);
2304 goto error_imem_clk;
2305 }
2306 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08002307 clk_set_rate(msm_rotator_dev->imem_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002308 pdata->rotator_clks[i].clk_rate);
2309 }
2310 if (pdata->rotator_clks[i].clk_type == ROTATOR_PCLK) {
2311 msm_rotator_dev->pclk =
2312 clk_get(&msm_rotator_dev->pdev->dev,
2313 pdata->rotator_clks[i].clk_name);
2314 if (IS_ERR(msm_rotator_dev->pclk)) {
2315 rc = PTR_ERR(msm_rotator_dev->pclk);
2316 msm_rotator_dev->pclk = NULL;
2317 printk(KERN_ERR "%s: cannot get pclk rc=%d\n",
2318 DRIVER_NAME, rc);
2319 goto error_pclk;
2320 }
2321
2322 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08002323 clk_set_rate(msm_rotator_dev->pclk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002324 pdata->rotator_clks[i].clk_rate);
2325 }
2326
2327 if (pdata->rotator_clks[i].clk_type == ROTATOR_CORE_CLK) {
2328 msm_rotator_dev->core_clk =
2329 clk_get(&msm_rotator_dev->pdev->dev,
2330 pdata->rotator_clks[i].clk_name);
2331 if (IS_ERR(msm_rotator_dev->core_clk)) {
2332 rc = PTR_ERR(msm_rotator_dev->core_clk);
2333 msm_rotator_dev->core_clk = NULL;
2334 printk(KERN_ERR "%s: cannot get core clk "
2335 "rc=%d\n", DRIVER_NAME, rc);
2336 goto error_core_clk;
2337 }
2338
2339 if (pdata->rotator_clks[i].clk_rate)
Matt Wagantall754f2472011-11-08 15:44:00 -08002340 clk_set_rate(msm_rotator_dev->core_clk,
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002341 pdata->rotator_clks[i].clk_rate);
2342 }
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002343 }
2344
Matt Wagantall316f2fc2012-05-03 20:41:42 -07002345 msm_rotator_dev->regulator = regulator_get(&msm_rotator_dev->pdev->dev,
2346 "vdd");
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002347 if (IS_ERR(msm_rotator_dev->regulator))
2348 msm_rotator_dev->regulator = NULL;
2349
2350 msm_rotator_dev->rot_clk_state = CLK_DIS;
2351 INIT_DELAYED_WORK(&msm_rotator_dev->rot_clk_work,
2352 msm_rotator_rot_clk_work_f);
2353
2354 mutex_init(&msm_rotator_dev->rotator_lock);
Naseer Ahmed18018602011-10-25 13:32:58 -07002355#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
2356 msm_rotator_dev->client = msm_ion_client_create(-1, pdev->name);
2357#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002358 platform_set_drvdata(pdev, msm_rotator_dev);
2359
2360
2361 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
2362 if (!res) {
2363 printk(KERN_ALERT
2364 "%s: could not get IORESOURCE_MEM\n", DRIVER_NAME);
2365 rc = -ENODEV;
2366 goto error_get_resource;
2367 }
2368 msm_rotator_dev->io_base = ioremap(res->start,
2369 resource_size(res));
2370
2371#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
2372 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002373 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002374#endif
2375 enable_rot_clks();
2376 ver = ioread32(MSM_ROTATOR_HW_VERSION);
2377 disable_rot_clks();
2378
2379#ifdef CONFIG_MSM_ROTATOR_USE_IMEM
2380 if (msm_rotator_dev->imem_clk)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002381 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002382#endif
Naseer Ahmed18018602011-10-25 13:32:58 -07002383 if (ver != pdata->hardware_version_number)
Mayank Chopra012a8e72012-04-11 10:41:13 +05302384 pr_debug("%s: invalid HW version ver 0x%x\n",
Ravishangar Kalyanam6bc448a2012-03-14 11:31:52 -07002385 DRIVER_NAME, ver);
Naseer Ahmed18018602011-10-25 13:32:58 -07002386
Mayank Chopra012a8e72012-04-11 10:41:13 +05302387 rotator_hw_revision = ver;
2388 rotator_hw_revision >>= 16; /* bit 31:16 */
2389 rotator_hw_revision &= 0xff;
2390
2391 pr_info("%s: rotator_hw_revision=%x\n",
2392 __func__, rotator_hw_revision);
2393
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002394 msm_rotator_dev->irq = platform_get_irq(pdev, 0);
2395 if (msm_rotator_dev->irq < 0) {
2396 printk(KERN_ALERT "%s: could not get IORESOURCE_IRQ\n",
2397 DRIVER_NAME);
2398 rc = -ENODEV;
2399 goto error_get_irq;
2400 }
2401 rc = request_irq(msm_rotator_dev->irq, msm_rotator_isr,
2402 IRQF_TRIGGER_RISING, DRIVER_NAME, NULL);
2403 if (rc) {
2404 printk(KERN_ERR "%s: request_irq() failed\n", DRIVER_NAME);
2405 goto error_get_irq;
2406 }
2407 /* we enable the IRQ when we need it in the ioctl */
2408 disable_irq(msm_rotator_dev->irq);
2409
2410 rc = alloc_chrdev_region(&msm_rotator_dev->dev_num, 0, 1, DRIVER_NAME);
2411 if (rc < 0) {
2412 printk(KERN_ERR "%s: alloc_chrdev_region Failed rc = %d\n",
2413 __func__, rc);
2414 goto error_get_irq;
2415 }
2416
2417 msm_rotator_dev->class = class_create(THIS_MODULE, DRIVER_NAME);
2418 if (IS_ERR(msm_rotator_dev->class)) {
2419 rc = PTR_ERR(msm_rotator_dev->class);
2420 printk(KERN_ERR "%s: couldn't create class rc = %d\n",
2421 DRIVER_NAME, rc);
2422 goto error_class_create;
2423 }
2424
2425 msm_rotator_dev->device = device_create(msm_rotator_dev->class, NULL,
2426 msm_rotator_dev->dev_num, NULL,
2427 DRIVER_NAME);
2428 if (IS_ERR(msm_rotator_dev->device)) {
2429 rc = PTR_ERR(msm_rotator_dev->device);
2430 printk(KERN_ERR "%s: device_create failed %d\n",
2431 DRIVER_NAME, rc);
2432 goto error_class_device_create;
2433 }
2434
2435 cdev_init(&msm_rotator_dev->cdev, &msm_rotator_fops);
2436 rc = cdev_add(&msm_rotator_dev->cdev,
2437 MKDEV(MAJOR(msm_rotator_dev->dev_num), 0),
2438 1);
2439 if (rc < 0) {
2440 printk(KERN_ERR "%s: cdev_add failed %d\n", __func__, rc);
2441 goto error_cdev_add;
2442 }
2443
2444 init_waitqueue_head(&msm_rotator_dev->wq);
Ken Zhang93b9f9a2013-04-08 18:56:58 -04002445 INIT_WORK(&msm_rotator_dev->commit_work, rot_commit_wq_handler);
2446 init_completion(&msm_rotator_dev->commit_comp);
2447 mutex_init(&msm_rotator_dev->commit_mutex);
2448 mutex_init(&msm_rotator_dev->commit_wq_mutex);
2449 atomic_set(&msm_rotator_dev->commit_q_w, 0);
2450 atomic_set(&msm_rotator_dev->commit_q_r, 0);
2451 atomic_set(&msm_rotator_dev->commit_q_cnt, 0);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002452
2453 dev_dbg(msm_rotator_dev->device, "probe successful\n");
2454 return rc;
2455
2456error_cdev_add:
2457 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
2458error_class_device_create:
2459 class_destroy(msm_rotator_dev->class);
2460error_class_create:
2461 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
2462error_get_irq:
2463 iounmap(msm_rotator_dev->io_base);
2464error_get_resource:
2465 mutex_destroy(&msm_rotator_dev->rotator_lock);
2466 if (msm_rotator_dev->regulator)
2467 regulator_put(msm_rotator_dev->regulator);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002468 clk_put(msm_rotator_dev->core_clk);
2469error_core_clk:
2470 clk_put(msm_rotator_dev->pclk);
2471error_pclk:
2472 if (msm_rotator_dev->imem_clk)
2473 clk_put(msm_rotator_dev->imem_clk);
2474error_imem_clk:
2475 mutex_destroy(&msm_rotator_dev->imem_lock);
2476 kfree(msm_rotator_dev);
2477 return rc;
2478}
2479
2480static int __devexit msm_rotator_remove(struct platform_device *plat_dev)
2481{
2482 int i;
2483
Ken Zhang93b9f9a2013-04-08 18:56:58 -04002484 rot_wait_for_commit_queue(true);
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002485#ifdef CONFIG_MSM_BUS_SCALING
Huaibin Yang5bc13e02013-01-10 17:52:45 -08002486 if (msm_rotator_dev->bus_client_handle) {
2487 msm_bus_scale_unregister_client
2488 (msm_rotator_dev->bus_client_handle);
2489 msm_rotator_dev->bus_client_handle = 0;
2490 }
Nagamalleswararao Ganjie1a9f872011-11-06 23:13:32 -08002491#endif
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002492 free_irq(msm_rotator_dev->irq, NULL);
2493 mutex_destroy(&msm_rotator_dev->rotator_lock);
2494 cdev_del(&msm_rotator_dev->cdev);
2495 device_destroy(msm_rotator_dev->class, msm_rotator_dev->dev_num);
2496 class_destroy(msm_rotator_dev->class);
2497 unregister_chrdev_region(msm_rotator_dev->dev_num, 1);
2498 iounmap(msm_rotator_dev->io_base);
2499 if (msm_rotator_dev->imem_clk) {
2500 if (msm_rotator_dev->imem_clk_state == CLK_EN)
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002501 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002502 clk_put(msm_rotator_dev->imem_clk);
2503 msm_rotator_dev->imem_clk = NULL;
2504 }
2505 if (msm_rotator_dev->rot_clk_state == CLK_EN)
2506 disable_rot_clks();
2507 clk_put(msm_rotator_dev->core_clk);
2508 clk_put(msm_rotator_dev->pclk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002509 if (msm_rotator_dev->regulator)
2510 regulator_put(msm_rotator_dev->regulator);
2511 msm_rotator_dev->core_clk = NULL;
2512 msm_rotator_dev->pclk = NULL;
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002513 mutex_destroy(&msm_rotator_dev->imem_lock);
2514 for (i = 0; i < MAX_SESSIONS; i++)
Mayank Chopra27147a72012-07-17 13:57:22 +05302515 if (msm_rotator_dev->rot_session[i] != NULL)
2516 kfree(msm_rotator_dev->rot_session[i]);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002517 kfree(msm_rotator_dev);
2518 return 0;
2519}
2520
2521#ifdef CONFIG_PM
2522static int msm_rotator_suspend(struct platform_device *dev, pm_message_t state)
2523{
Ken Zhang93b9f9a2013-04-08 18:56:58 -04002524 rot_wait_for_commit_queue(true);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002525 mutex_lock(&msm_rotator_dev->imem_lock);
2526 if (msm_rotator_dev->imem_clk_state == CLK_EN
2527 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002528 clk_disable_unprepare(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002529 msm_rotator_dev->imem_clk_state = CLK_SUSPEND;
2530 }
2531 mutex_unlock(&msm_rotator_dev->imem_lock);
2532 mutex_lock(&msm_rotator_dev->rotator_lock);
2533 if (msm_rotator_dev->rot_clk_state == CLK_EN) {
2534 disable_rot_clks();
2535 msm_rotator_dev->rot_clk_state = CLK_SUSPEND;
2536 }
Ken Zhanga50db542013-02-20 14:48:06 -05002537 msm_rotator_release_all_timeline();
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002538 mutex_unlock(&msm_rotator_dev->rotator_lock);
2539 return 0;
2540}
2541
2542static int msm_rotator_resume(struct platform_device *dev)
2543{
2544 mutex_lock(&msm_rotator_dev->imem_lock);
2545 if (msm_rotator_dev->imem_clk_state == CLK_SUSPEND
2546 && msm_rotator_dev->imem_clk) {
Ravishangar Kalyanamd16485d2012-03-21 16:51:26 -07002547 clk_prepare_enable(msm_rotator_dev->imem_clk);
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07002548 msm_rotator_dev->imem_clk_state = CLK_EN;
2549 }
2550 mutex_unlock(&msm_rotator_dev->imem_lock);
2551 mutex_lock(&msm_rotator_dev->rotator_lock);
2552 if (msm_rotator_dev->rot_clk_state == CLK_SUSPEND) {
2553 enable_rot_clks();
2554 msm_rotator_dev->rot_clk_state = CLK_EN;
2555 }
2556 mutex_unlock(&msm_rotator_dev->rotator_lock);
2557 return 0;
2558}
2559#endif
2560
2561static struct platform_driver msm_rotator_platform_driver = {
2562 .probe = msm_rotator_probe,
2563 .remove = __devexit_p(msm_rotator_remove),
2564#ifdef CONFIG_PM
2565 .suspend = msm_rotator_suspend,
2566 .resume = msm_rotator_resume,
2567#endif
2568 .driver = {
2569 .owner = THIS_MODULE,
2570 .name = DRIVER_NAME
2571 }
2572};
2573
2574static int __init msm_rotator_init(void)
2575{
2576 return platform_driver_register(&msm_rotator_platform_driver);
2577}
2578
2579static void __exit msm_rotator_exit(void)
2580{
2581 return platform_driver_unregister(&msm_rotator_platform_driver);
2582}
2583
2584module_init(msm_rotator_init);
2585module_exit(msm_rotator_exit);
2586
2587MODULE_DESCRIPTION("MSM Offline Image Rotator driver");
2588MODULE_VERSION("1.0");
2589MODULE_LICENSE("GPL v2");