diff options
Diffstat (limited to 'drivers/video/msm/mdp.c')
-rw-r--r-- | drivers/video/msm/mdp.c | 538 |
1 files changed, 538 insertions, 0 deletions
diff --git a/drivers/video/msm/mdp.c b/drivers/video/msm/mdp.c new file mode 100644 index 000000000000..99636a2b20f2 --- /dev/null +++ b/drivers/video/msm/mdp.c | |||
@@ -0,0 +1,538 @@ | |||
1 | /* drivers/video/msm_fb/mdp.c | ||
2 | * | ||
3 | * MSM MDP Interface (used by framebuffer core) | ||
4 | * | ||
5 | * Copyright (C) 2007 QUALCOMM Incorporated | ||
6 | * Copyright (C) 2007 Google Incorporated | ||
7 | * | ||
8 | * This software is licensed under the terms of the GNU General Public | ||
9 | * License version 2, as published by the Free Software Foundation, and | ||
10 | * may be copied, distributed, and modified under those terms. | ||
11 | * | ||
12 | * This program is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | * GNU General Public License for more details. | ||
16 | */ | ||
17 | |||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/fb.h> | ||
20 | #include <linux/msm_mdp.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/wait.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/file.h> | ||
25 | #ifdef CONFIG_ANDROID_PMEM | ||
26 | #include <linux/android_pmem.h> | ||
27 | #endif | ||
28 | #include <linux/major.h> | ||
29 | |||
30 | #include <mach/msm_iomap.h> | ||
31 | #include <mach/msm_fb.h> | ||
32 | #include <linux/platform_device.h> | ||
33 | |||
34 | #include "mdp_hw.h" | ||
35 | |||
36 | struct class *mdp_class; | ||
37 | |||
38 | #define MDP_CMD_DEBUG_ACCESS_BASE (0x10000) | ||
39 | |||
40 | static uint16_t mdp_default_ccs[] = { | ||
41 | 0x254, 0x000, 0x331, 0x254, 0xF38, 0xE61, 0x254, 0x409, 0x000, | ||
42 | 0x010, 0x080, 0x080 | ||
43 | }; | ||
44 | |||
45 | static DECLARE_WAIT_QUEUE_HEAD(mdp_dma2_waitqueue); | ||
46 | static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue); | ||
47 | static struct msmfb_callback *dma_callback; | ||
48 | static struct clk *clk; | ||
49 | static unsigned int mdp_irq_mask; | ||
50 | static DEFINE_SPINLOCK(mdp_lock); | ||
51 | DEFINE_MUTEX(mdp_mutex); | ||
52 | |||
53 | static int enable_mdp_irq(struct mdp_info *mdp, uint32_t mask) | ||
54 | { | ||
55 | unsigned long irq_flags; | ||
56 | int ret = 0; | ||
57 | |||
58 | BUG_ON(!mask); | ||
59 | |||
60 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
61 | /* if the mask bits are already set return an error, this interrupt | ||
62 | * is already enabled */ | ||
63 | if (mdp_irq_mask & mask) { | ||
64 | printk(KERN_ERR "mdp irq already on already on %x %x\n", | ||
65 | mdp_irq_mask, mask); | ||
66 | ret = -1; | ||
67 | } | ||
68 | /* if the mdp irq is not already enabled enable it */ | ||
69 | if (!mdp_irq_mask) { | ||
70 | if (clk) | ||
71 | clk_enable(clk); | ||
72 | enable_irq(mdp->irq); | ||
73 | } | ||
74 | |||
75 | /* update the irq mask to reflect the fact that the interrupt is | ||
76 | * enabled */ | ||
77 | mdp_irq_mask |= mask; | ||
78 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | static int locked_disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) | ||
83 | { | ||
84 | /* this interrupt is already disabled! */ | ||
85 | if (!(mdp_irq_mask & mask)) { | ||
86 | printk(KERN_ERR "mdp irq already off %x %x\n", | ||
87 | mdp_irq_mask, mask); | ||
88 | return -1; | ||
89 | } | ||
90 | /* update the irq mask to reflect the fact that the interrupt is | ||
91 | * disabled */ | ||
92 | mdp_irq_mask &= ~(mask); | ||
93 | /* if no one is waiting on the interrupt, disable it */ | ||
94 | if (!mdp_irq_mask) { | ||
95 | disable_irq(mdp->irq); | ||
96 | if (clk) | ||
97 | clk_disable(clk); | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) | ||
103 | { | ||
104 | unsigned long irq_flags; | ||
105 | int ret; | ||
106 | |||
107 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
108 | ret = locked_disable_mdp_irq(mdp, mask); | ||
109 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static irqreturn_t mdp_isr(int irq, void *data) | ||
114 | { | ||
115 | uint32_t status; | ||
116 | unsigned long irq_flags; | ||
117 | struct mdp_info *mdp = data; | ||
118 | |||
119 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
120 | |||
121 | status = mdp_readl(mdp, MDP_INTR_STATUS); | ||
122 | mdp_writel(mdp, status, MDP_INTR_CLEAR); | ||
123 | |||
124 | status &= mdp_irq_mask; | ||
125 | if (status & DL0_DMA2_TERM_DONE) { | ||
126 | if (dma_callback) { | ||
127 | dma_callback->func(dma_callback); | ||
128 | dma_callback = NULL; | ||
129 | } | ||
130 | wake_up(&mdp_dma2_waitqueue); | ||
131 | } | ||
132 | |||
133 | if (status & DL0_ROI_DONE) | ||
134 | wake_up(&mdp_ppp_waitqueue); | ||
135 | |||
136 | if (status) | ||
137 | locked_disable_mdp_irq(mdp, status); | ||
138 | |||
139 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
140 | return IRQ_HANDLED; | ||
141 | } | ||
142 | |||
143 | static uint32_t mdp_check_mask(uint32_t mask) | ||
144 | { | ||
145 | uint32_t ret; | ||
146 | unsigned long irq_flags; | ||
147 | |||
148 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
149 | ret = mdp_irq_mask & mask; | ||
150 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq) | ||
155 | { | ||
156 | int ret = 0; | ||
157 | unsigned long irq_flags; | ||
158 | |||
159 | wait_event_timeout(*wq, !mdp_check_mask(mask), HZ); | ||
160 | |||
161 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
162 | if (mdp_irq_mask & mask) { | ||
163 | locked_disable_mdp_irq(mdp, mask); | ||
164 | printk(KERN_WARNING "timeout waiting for mdp to complete %x\n", | ||
165 | mask); | ||
166 | ret = -ETIMEDOUT; | ||
167 | } | ||
168 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | void mdp_dma_wait(struct mdp_device *mdp_dev) | ||
174 | { | ||
175 | #define MDP_MAX_TIMEOUTS 20 | ||
176 | static int timeout_count; | ||
177 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
178 | |||
179 | if (mdp_wait(mdp, DL0_DMA2_TERM_DONE, &mdp_dma2_waitqueue) == -ETIMEDOUT) | ||
180 | timeout_count++; | ||
181 | else | ||
182 | timeout_count = 0; | ||
183 | |||
184 | if (timeout_count > MDP_MAX_TIMEOUTS) { | ||
185 | printk(KERN_ERR "mdp: dma failed %d times, somethings wrong!\n", | ||
186 | MDP_MAX_TIMEOUTS); | ||
187 | BUG(); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static int mdp_ppp_wait(struct mdp_info *mdp) | ||
192 | { | ||
193 | return mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue); | ||
194 | } | ||
195 | |||
196 | void mdp_dma_to_mddi(struct mdp_info *mdp, uint32_t addr, uint32_t stride, | ||
197 | uint32_t width, uint32_t height, uint32_t x, uint32_t y, | ||
198 | struct msmfb_callback *callback) | ||
199 | { | ||
200 | uint32_t dma2_cfg; | ||
201 | uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */ | ||
202 | |||
203 | if (enable_mdp_irq(mdp, DL0_DMA2_TERM_DONE)) { | ||
204 | printk(KERN_ERR "mdp_dma_to_mddi: busy\n"); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | dma_callback = callback; | ||
209 | |||
210 | dma2_cfg = DMA_PACK_TIGHT | | ||
211 | DMA_PACK_ALIGN_LSB | | ||
212 | DMA_PACK_PATTERN_RGB | | ||
213 | DMA_OUT_SEL_AHB | | ||
214 | DMA_IBUF_NONCONTIGUOUS; | ||
215 | |||
216 | dma2_cfg |= DMA_IBUF_FORMAT_RGB565; | ||
217 | |||
218 | dma2_cfg |= DMA_OUT_SEL_MDDI; | ||
219 | |||
220 | dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; | ||
221 | |||
222 | dma2_cfg |= DMA_DITHER_EN; | ||
223 | |||
224 | /* setup size, address, and stride */ | ||
225 | mdp_writel(mdp, (height << 16) | (width), | ||
226 | MDP_CMD_DEBUG_ACCESS_BASE + 0x0184); | ||
227 | mdp_writel(mdp, addr, MDP_CMD_DEBUG_ACCESS_BASE + 0x0188); | ||
228 | mdp_writel(mdp, stride, MDP_CMD_DEBUG_ACCESS_BASE + 0x018C); | ||
229 | |||
230 | /* 666 18BPP */ | ||
231 | dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; | ||
232 | |||
233 | /* set y & x offset and MDDI transaction parameters */ | ||
234 | mdp_writel(mdp, (y << 16) | (x), MDP_CMD_DEBUG_ACCESS_BASE + 0x0194); | ||
235 | mdp_writel(mdp, ld_param, MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0); | ||
236 | mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM, | ||
237 | MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4); | ||
238 | |||
239 | mdp_writel(mdp, dma2_cfg, MDP_CMD_DEBUG_ACCESS_BASE + 0x0180); | ||
240 | |||
241 | /* start DMA2 */ | ||
242 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0044); | ||
243 | } | ||
244 | |||
245 | void mdp_dma(struct mdp_device *mdp_dev, uint32_t addr, uint32_t stride, | ||
246 | uint32_t width, uint32_t height, uint32_t x, uint32_t y, | ||
247 | struct msmfb_callback *callback, int interface) | ||
248 | { | ||
249 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
250 | |||
251 | if (interface == MSM_MDDI_PMDH_INTERFACE) { | ||
252 | mdp_dma_to_mddi(mdp, addr, stride, width, height, x, y, | ||
253 | callback); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | int get_img(struct mdp_img *img, struct fb_info *info, | ||
258 | unsigned long *start, unsigned long *len, | ||
259 | struct file **filep) | ||
260 | { | ||
261 | int put_needed, ret = 0; | ||
262 | struct file *file; | ||
263 | unsigned long vstart; | ||
264 | |||
265 | #ifdef CONFIG_ANDROID_PMEM | ||
266 | if (!get_pmem_file(img->memory_id, start, &vstart, len, filep)) | ||
267 | return 0; | ||
268 | #endif | ||
269 | |||
270 | file = fget_light(img->memory_id, &put_needed); | ||
271 | if (file == NULL) | ||
272 | return -1; | ||
273 | |||
274 | if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { | ||
275 | *start = info->fix.smem_start; | ||
276 | *len = info->fix.smem_len; | ||
277 | } else | ||
278 | ret = -1; | ||
279 | fput_light(file, put_needed); | ||
280 | |||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | void put_img(struct file *src_file, struct file *dst_file) | ||
285 | { | ||
286 | #ifdef CONFIG_ANDROID_PMEM | ||
287 | if (src_file) | ||
288 | put_pmem_file(src_file); | ||
289 | if (dst_file) | ||
290 | put_pmem_file(dst_file); | ||
291 | #endif | ||
292 | } | ||
293 | |||
294 | int mdp_blit(struct mdp_device *mdp_dev, struct fb_info *fb, | ||
295 | struct mdp_blit_req *req) | ||
296 | { | ||
297 | int ret; | ||
298 | unsigned long src_start = 0, src_len = 0, dst_start = 0, dst_len = 0; | ||
299 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
300 | struct file *src_file = 0, *dst_file = 0; | ||
301 | |||
302 | /* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */ | ||
303 | if (unlikely(req->src_rect.h == 0 || | ||
304 | req->src_rect.w == 0)) { | ||
305 | printk(KERN_ERR "mpd_ppp: src img of zero size!\n"); | ||
306 | return -EINVAL; | ||
307 | } | ||
308 | if (unlikely(req->dst_rect.h == 0 || | ||
309 | req->dst_rect.w == 0)) | ||
310 | return -EINVAL; | ||
311 | |||
312 | /* do this first so that if this fails, the caller can always | ||
313 | * safely call put_img */ | ||
314 | if (unlikely(get_img(&req->src, fb, &src_start, &src_len, &src_file))) { | ||
315 | printk(KERN_ERR "mpd_ppp: could not retrieve src image from " | ||
316 | "memory\n"); | ||
317 | return -EINVAL; | ||
318 | } | ||
319 | |||
320 | if (unlikely(get_img(&req->dst, fb, &dst_start, &dst_len, &dst_file))) { | ||
321 | printk(KERN_ERR "mpd_ppp: could not retrieve dst image from " | ||
322 | "memory\n"); | ||
323 | #ifdef CONFIG_ANDROID_PMEM | ||
324 | put_pmem_file(src_file); | ||
325 | #endif | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | mutex_lock(&mdp_mutex); | ||
329 | |||
330 | /* transp_masking unimplemented */ | ||
331 | req->transp_mask = MDP_TRANSP_NOP; | ||
332 | if (unlikely((req->transp_mask != MDP_TRANSP_NOP || | ||
333 | req->alpha != MDP_ALPHA_NOP || | ||
334 | HAS_ALPHA(req->src.format)) && | ||
335 | (req->flags & MDP_ROT_90 && | ||
336 | req->dst_rect.w <= 16 && req->dst_rect.h >= 16))) { | ||
337 | int i; | ||
338 | unsigned int tiles = req->dst_rect.h / 16; | ||
339 | unsigned int remainder = req->dst_rect.h % 16; | ||
340 | req->src_rect.w = 16*req->src_rect.w / req->dst_rect.h; | ||
341 | req->dst_rect.h = 16; | ||
342 | for (i = 0; i < tiles; i++) { | ||
343 | enable_mdp_irq(mdp, DL0_ROI_DONE); | ||
344 | ret = mdp_ppp_blit(mdp, req, src_file, src_start, | ||
345 | src_len, dst_file, dst_start, | ||
346 | dst_len); | ||
347 | if (ret) | ||
348 | goto err_bad_blit; | ||
349 | ret = mdp_ppp_wait(mdp); | ||
350 | if (ret) | ||
351 | goto err_wait_failed; | ||
352 | req->dst_rect.y += 16; | ||
353 | req->src_rect.x += req->src_rect.w; | ||
354 | } | ||
355 | if (!remainder) | ||
356 | goto end; | ||
357 | req->src_rect.w = remainder*req->src_rect.w / req->dst_rect.h; | ||
358 | req->dst_rect.h = remainder; | ||
359 | } | ||
360 | enable_mdp_irq(mdp, DL0_ROI_DONE); | ||
361 | ret = mdp_ppp_blit(mdp, req, src_file, src_start, src_len, dst_file, | ||
362 | dst_start, | ||
363 | dst_len); | ||
364 | if (ret) | ||
365 | goto err_bad_blit; | ||
366 | ret = mdp_ppp_wait(mdp); | ||
367 | if (ret) | ||
368 | goto err_wait_failed; | ||
369 | end: | ||
370 | put_img(src_file, dst_file); | ||
371 | mutex_unlock(&mdp_mutex); | ||
372 | return 0; | ||
373 | err_bad_blit: | ||
374 | disable_mdp_irq(mdp, DL0_ROI_DONE); | ||
375 | err_wait_failed: | ||
376 | put_img(src_file, dst_file); | ||
377 | mutex_unlock(&mdp_mutex); | ||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | void mdp_set_grp_disp(struct mdp_device *mdp_dev, unsigned disp_id) | ||
382 | { | ||
383 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
384 | |||
385 | disp_id &= 0xf; | ||
386 | mdp_writel(mdp, disp_id, MDP_FULL_BYPASS_WORD43); | ||
387 | } | ||
388 | |||
389 | int register_mdp_client(struct class_interface *cint) | ||
390 | { | ||
391 | if (!mdp_class) { | ||
392 | pr_err("mdp: no mdp_class when registering mdp client\n"); | ||
393 | return -ENODEV; | ||
394 | } | ||
395 | cint->class = mdp_class; | ||
396 | return class_interface_register(cint); | ||
397 | } | ||
398 | |||
399 | #include "mdp_csc_table.h" | ||
400 | #include "mdp_scale_tables.h" | ||
401 | |||
402 | int mdp_probe(struct platform_device *pdev) | ||
403 | { | ||
404 | struct resource *resource; | ||
405 | int ret; | ||
406 | int n; | ||
407 | struct mdp_info *mdp; | ||
408 | |||
409 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
410 | if (!resource) { | ||
411 | pr_err("mdp: can not get mdp mem resource!\n"); | ||
412 | return -ENOMEM; | ||
413 | } | ||
414 | |||
415 | mdp = kzalloc(sizeof(struct mdp_info), GFP_KERNEL); | ||
416 | if (!mdp) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | mdp->irq = platform_get_irq(pdev, 0); | ||
420 | if (mdp->irq < 0) { | ||
421 | pr_err("mdp: can not get mdp irq\n"); | ||
422 | ret = mdp->irq; | ||
423 | goto error_get_irq; | ||
424 | } | ||
425 | |||
426 | mdp->base = ioremap(resource->start, | ||
427 | resource->end - resource->start); | ||
428 | if (mdp->base == 0) { | ||
429 | printk(KERN_ERR "msmfb: cannot allocate mdp regs!\n"); | ||
430 | ret = -ENOMEM; | ||
431 | goto error_ioremap; | ||
432 | } | ||
433 | |||
434 | mdp->mdp_dev.dma = mdp_dma; | ||
435 | mdp->mdp_dev.dma_wait = mdp_dma_wait; | ||
436 | mdp->mdp_dev.blit = mdp_blit; | ||
437 | mdp->mdp_dev.set_grp_disp = mdp_set_grp_disp; | ||
438 | |||
439 | clk = clk_get(&pdev->dev, "mdp_clk"); | ||
440 | if (IS_ERR(clk)) { | ||
441 | printk(KERN_INFO "mdp: failed to get mdp clk"); | ||
442 | return PTR_ERR(clk); | ||
443 | } | ||
444 | |||
445 | ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp); | ||
446 | if (ret) | ||
447 | goto error_request_irq; | ||
448 | disable_irq(mdp->irq); | ||
449 | mdp_irq_mask = 0; | ||
450 | |||
451 | /* debug interface write access */ | ||
452 | mdp_writel(mdp, 1, 0x60); | ||
453 | |||
454 | mdp_writel(mdp, MDP_ANY_INTR_MASK, MDP_INTR_ENABLE); | ||
455 | mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE); | ||
456 | |||
457 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8); | ||
458 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc); | ||
459 | |||
460 | for (n = 0; n < ARRAY_SIZE(csc_table); n++) | ||
461 | mdp_writel(mdp, csc_table[n].val, csc_table[n].reg); | ||
462 | |||
463 | /* clear up unused fg/main registers */ | ||
464 | /* comp.plane 2&3 ystride */ | ||
465 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120); | ||
466 | |||
467 | /* unpacked pattern */ | ||
468 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c); | ||
469 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130); | ||
470 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134); | ||
471 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158); | ||
472 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c); | ||
473 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160); | ||
474 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170); | ||
475 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174); | ||
476 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c); | ||
477 | |||
478 | /* comp.plane 2 & 3 */ | ||
479 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114); | ||
480 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118); | ||
481 | |||
482 | /* clear unused bg registers */ | ||
483 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8); | ||
484 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0); | ||
485 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc); | ||
486 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0); | ||
487 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4); | ||
488 | |||
489 | for (n = 0; n < ARRAY_SIZE(mdp_upscale_table); n++) | ||
490 | mdp_writel(mdp, mdp_upscale_table[n].val, | ||
491 | mdp_upscale_table[n].reg); | ||
492 | |||
493 | for (n = 0; n < 9; n++) | ||
494 | mdp_writel(mdp, mdp_default_ccs[n], 0x40440 + 4 * n); | ||
495 | mdp_writel(mdp, mdp_default_ccs[9], 0x40500 + 4 * 0); | ||
496 | mdp_writel(mdp, mdp_default_ccs[10], 0x40500 + 4 * 0); | ||
497 | mdp_writel(mdp, mdp_default_ccs[11], 0x40500 + 4 * 0); | ||
498 | |||
499 | /* register mdp device */ | ||
500 | mdp->mdp_dev.dev.parent = &pdev->dev; | ||
501 | mdp->mdp_dev.dev.class = mdp_class; | ||
502 | snprintf(mdp->mdp_dev.dev.bus_id, BUS_ID_SIZE, "mdp%d", pdev->id); | ||
503 | |||
504 | /* if you can remove the platform device you'd have to implement | ||
505 | * this: | ||
506 | mdp_dev.release = mdp_class; */ | ||
507 | |||
508 | ret = device_register(&mdp->mdp_dev.dev); | ||
509 | if (ret) | ||
510 | goto error_device_register; | ||
511 | return 0; | ||
512 | |||
513 | error_device_register: | ||
514 | free_irq(mdp->irq, mdp); | ||
515 | error_request_irq: | ||
516 | iounmap(mdp->base); | ||
517 | error_get_irq: | ||
518 | error_ioremap: | ||
519 | kfree(mdp); | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | static struct platform_driver msm_mdp_driver = { | ||
524 | .probe = mdp_probe, | ||
525 | .driver = {.name = "msm_mdp"}, | ||
526 | }; | ||
527 | |||
528 | static int __init mdp_init(void) | ||
529 | { | ||
530 | mdp_class = class_create(THIS_MODULE, "msm_mdp"); | ||
531 | if (IS_ERR(mdp_class)) { | ||
532 | printk(KERN_ERR "Error creating mdp class\n"); | ||
533 | return PTR_ERR(mdp_class); | ||
534 | } | ||
535 | return platform_driver_register(&msm_mdp_driver); | ||
536 | } | ||
537 | |||
538 | subsys_initcall(mdp_init); | ||