aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPavel Machek <pavel@ucw.cz>2009-09-22 19:47:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:50 -0400
commitd480ace08d5b59133575e672a0bd1c97b0f8400f (patch)
tree3e2e0edd582d7f511544ad87a6095c6227d280aa
parent689620100172e24fdf0981e9978a9559e8769258 (diff)
fbdev: framebuffer support for HTC Dream
Add a framebuffer driver for Qualcomm MSM/QSD SoCs, tested on HTC Dream smartphone (aka T-Mobile G1, aka ADP1). Brian said: I did the original quick and dirty version for bringup. Rebecca took over and (re)wrote the bulk of the driver, getting things stable for production ship of Dream and Sapphire, and Dima is currently adding support for later Qualcomm chipsets (QSD8x50, etc). Signed-off-by: Pavel Machek <pavel@ucw.cz> Cc: Brian Swetland <swetland@google.com> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Cc: Rebecca Schultz Zavin <rebecca@android.com> Cc: Dima Zavin <dima@android.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--drivers/video/Kconfig8
-rw-r--r--drivers/video/Makefile1
-rw-r--r--drivers/video/msm/Makefile19
-rw-r--r--drivers/video/msm/mddi.c828
-rw-r--r--drivers/video/msm/mddi_client_dummy.c97
-rw-r--r--drivers/video/msm/mddi_client_nt35399.c255
-rw-r--r--drivers/video/msm/mddi_client_toshiba.c283
-rw-r--r--drivers/video/msm/mddi_hw.h305
-rw-r--r--drivers/video/msm/mdp.c538
-rw-r--r--drivers/video/msm/mdp_csc_table.h582
-rw-r--r--drivers/video/msm/mdp_hw.h621
-rw-r--r--drivers/video/msm/mdp_ppp.c750
-rw-r--r--drivers/video/msm/mdp_scale_tables.c766
-rw-r--r--drivers/video/msm/mdp_scale_tables.h38
-rw-r--r--drivers/video/msm/msm_fb.c636
15 files changed, 5727 insertions, 0 deletions
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 11af4cb8924e..05184a1c3e97 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -2124,6 +2124,14 @@ config FB_PRE_INIT_FB
2124 Select this option if display contents should be inherited as set by 2124 Select this option if display contents should be inherited as set by
2125 the bootloader. 2125 the bootloader.
2126 2126
2127config FB_MSM
2128 tristate
2129 depends on FB && ARCH_MSM
2130 select FB_CFB_FILLRECT
2131 select FB_CFB_COPYAREA
2132 select FB_CFB_IMAGEBLIT
2133 default y
2134
2127config FB_MX3 2135config FB_MX3
2128 tristate "MX3 Framebuffer support" 2136 tristate "MX3 Framebuffer support"
2129 depends on FB && MX3_IPU 2137 depends on FB && MX3_IPU
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 01a819f47371..f4b6c150bd06 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -126,6 +126,7 @@ obj-$(CONFIG_FB_OMAP) += omap/
126obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o 126obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o
127obj-$(CONFIG_FB_CARMINE) += carminefb.o 127obj-$(CONFIG_FB_CARMINE) += carminefb.o
128obj-$(CONFIG_FB_MB862XX) += mb862xx/ 128obj-$(CONFIG_FB_MB862XX) += mb862xx/
129obj-$(CONFIG_FB_MSM) += msm/
129 130
130# Platform or fallback drivers go here 131# Platform or fallback drivers go here
131obj-$(CONFIG_FB_UVESA) += uvesafb.o 132obj-$(CONFIG_FB_UVESA) += uvesafb.o
diff --git a/drivers/video/msm/Makefile b/drivers/video/msm/Makefile
new file mode 100644
index 000000000000..802d6ae523fb
--- /dev/null
+++ b/drivers/video/msm/Makefile
@@ -0,0 +1,19 @@
1
2# core framebuffer
3#
4obj-y := msm_fb.o
5
6# MDP DMA/PPP engine
7#
8obj-y += mdp.o mdp_scale_tables.o mdp_ppp.o
9
10# MDDI interface
11#
12obj-y += mddi.o
13
14# MDDI client/panel drivers
15#
16obj-y += mddi_client_dummy.o
17obj-y += mddi_client_toshiba.o
18obj-y += mddi_client_nt35399.o
19
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
new file mode 100644
index 000000000000..f2de5a1acd6d
--- /dev/null
+++ b/drivers/video/msm/mddi.c
@@ -0,0 +1,828 @@
1/*
2 * MSM MDDI Transport
3 *
4 * Copyright (C) 2007 Google Incorporated
5 * Copyright (C) 2007 QUALCOMM Incorporated
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/dma-mapping.h>
21#include <linux/interrupt.h>
22#include <linux/platform_device.h>
23#include <linux/delay.h>
24#include <linux/spinlock.h>
25#include <linux/clk.h>
26#include <linux/io.h>
27#include <mach/msm_iomap.h>
28#include <mach/irqs.h>
29#include <mach/board.h>
30#include <linux/delay.h>
31
32#include <mach/msm_fb.h>
33#include "mddi_hw.h"
34
35#define FLAG_DISABLE_HIBERNATION 0x0001
36#define FLAG_HAVE_CAPS 0x0002
37#define FLAG_HAS_VSYNC_IRQ 0x0004
38#define FLAG_HAVE_STATUS 0x0008
39
40#define CMD_GET_CLIENT_CAP 0x0601
41#define CMD_GET_CLIENT_STATUS 0x0602
42
43union mddi_rev {
44 unsigned char raw[MDDI_REV_BUFFER_SIZE];
45 struct mddi_rev_packet hdr;
46 struct mddi_client_status status;
47 struct mddi_client_caps caps;
48 struct mddi_register_access reg;
49};
50
51struct reg_read_info {
52 struct completion done;
53 uint32_t reg;
54 uint32_t status;
55 uint32_t result;
56};
57
58struct mddi_info {
59 uint16_t flags;
60 uint16_t version;
61 char __iomem *base;
62 int irq;
63 struct clk *clk;
64 struct msm_mddi_client_data client_data;
65
66 /* buffer for rev encap packets */
67 void *rev_data;
68 dma_addr_t rev_addr;
69 struct mddi_llentry *reg_write_data;
70 dma_addr_t reg_write_addr;
71 struct mddi_llentry *reg_read_data;
72 dma_addr_t reg_read_addr;
73 size_t rev_data_curr;
74
75 spinlock_t int_lock;
76 uint32_t int_enable;
77 uint32_t got_int;
78 wait_queue_head_t int_wait;
79
80 struct mutex reg_write_lock;
81 struct mutex reg_read_lock;
82 struct reg_read_info *reg_read;
83
84 struct mddi_client_caps caps;
85 struct mddi_client_status status;
86
87 void (*power_client)(struct msm_mddi_client_data *, int);
88
89 /* client device published to bind us to the
90 * appropriate mddi_client driver
91 */
92 char client_name[20];
93
94 struct platform_device client_pdev;
95};
96
97static void mddi_init_rev_encap(struct mddi_info *mddi);
98
99#define mddi_readl(r) readl(mddi->base + (MDDI_##r))
100#define mddi_writel(v, r) writel((v), mddi->base + (MDDI_##r))
101
102void mddi_activate_link(struct msm_mddi_client_data *cdata)
103{
104 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
105 client_data);
106
107 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
108}
109
110static void mddi_handle_link_list_done(struct mddi_info *mddi)
111{
112}
113
114static void mddi_reset_rev_encap_ptr(struct mddi_info *mddi)
115{
116 printk(KERN_INFO "mddi: resetting rev ptr\n");
117 mddi->rev_data_curr = 0;
118 mddi_writel(mddi->rev_addr, REV_PTR);
119 mddi_writel(mddi->rev_addr, REV_PTR);
120 mddi_writel(MDDI_CMD_FORCE_NEW_REV_PTR, CMD);
121}
122
123static void mddi_handle_rev_data(struct mddi_info *mddi, union mddi_rev *rev)
124{
125 int i;
126 struct reg_read_info *ri;
127
128 if ((rev->hdr.length <= MDDI_REV_BUFFER_SIZE - 2) &&
129 (rev->hdr.length >= sizeof(struct mddi_rev_packet) - 2)) {
130
131 switch (rev->hdr.type) {
132 case TYPE_CLIENT_CAPS:
133 memcpy(&mddi->caps, &rev->caps,
134 sizeof(struct mddi_client_caps));
135 mddi->flags |= FLAG_HAVE_CAPS;
136 wake_up(&mddi->int_wait);
137 break;
138 case TYPE_CLIENT_STATUS:
139 memcpy(&mddi->status, &rev->status,
140 sizeof(struct mddi_client_status));
141 mddi->flags |= FLAG_HAVE_STATUS;
142 wake_up(&mddi->int_wait);
143 break;
144 case TYPE_REGISTER_ACCESS:
145 ri = mddi->reg_read;
146 if (ri == 0) {
147 printk(KERN_INFO "rev: got reg %x = %x without "
148 " pending read\n",
149 rev->reg.register_address,
150 rev->reg.register_data_list);
151 break;
152 }
153 if (ri->reg != rev->reg.register_address) {
154 printk(KERN_INFO "rev: got reg %x = %x for "
155 "wrong register, expected "
156 "%x\n",
157 rev->reg.register_address,
158 rev->reg.register_data_list, ri->reg);
159 break;
160 }
161 mddi->reg_read = NULL;
162 ri->status = 0;
163 ri->result = rev->reg.register_data_list;
164 complete(&ri->done);
165 break;
166 default:
167 printk(KERN_INFO "rev: unknown reverse packet: "
168 "len=%04x type=%04x CURR_REV_PTR=%x\n",
169 rev->hdr.length, rev->hdr.type,
170 mddi_readl(CURR_REV_PTR));
171 for (i = 0; i < rev->hdr.length + 2; i++) {
172 if ((i % 16) == 0)
173 printk(KERN_INFO "\n");
174 printk(KERN_INFO " %02x", rev->raw[i]);
175 }
176 printk(KERN_INFO "\n");
177 mddi_reset_rev_encap_ptr(mddi);
178 }
179 } else {
180 printk(KERN_INFO "bad rev length, %d, CURR_REV_PTR %x\n",
181 rev->hdr.length, mddi_readl(CURR_REV_PTR));
182 mddi_reset_rev_encap_ptr(mddi);
183 }
184}
185
186static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask);
187
188static void mddi_handle_rev_data_avail(struct mddi_info *mddi)
189{
190 union mddi_rev *rev = mddi->rev_data;
191 uint32_t rev_data_count;
192 uint32_t rev_crc_err_count;
193 int i;
194 struct reg_read_info *ri;
195 size_t prev_offset;
196 uint16_t length;
197
198 union mddi_rev *crev = mddi->rev_data + mddi->rev_data_curr;
199
200 /* clear the interrupt */
201 mddi_writel(MDDI_INT_REV_DATA_AVAIL, INT);
202 rev_data_count = mddi_readl(REV_PKT_CNT);
203 rev_crc_err_count = mddi_readl(REV_CRC_ERR);
204 if (rev_data_count > 1)
205 printk(KERN_INFO "rev_data_count %d\n", rev_data_count);
206
207 if (rev_crc_err_count) {
208 printk(KERN_INFO "rev_crc_err_count %d, INT %x\n",
209 rev_crc_err_count, mddi_readl(INT));
210 ri = mddi->reg_read;
211 if (ri == 0) {
212 printk(KERN_INFO "rev: got crc error without pending "
213 "read\n");
214 } else {
215 mddi->reg_read = NULL;
216 ri->status = -EIO;
217 ri->result = -1;
218 complete(&ri->done);
219 }
220 }
221
222 if (rev_data_count == 0)
223 return;
224
225 prev_offset = mddi->rev_data_curr;
226
227 length = *((uint8_t *)mddi->rev_data + mddi->rev_data_curr);
228 mddi->rev_data_curr++;
229 if (mddi->rev_data_curr == MDDI_REV_BUFFER_SIZE)
230 mddi->rev_data_curr = 0;
231 length += *((uint8_t *)mddi->rev_data + mddi->rev_data_curr) << 8;
232 mddi->rev_data_curr += 1 + length;
233 if (mddi->rev_data_curr >= MDDI_REV_BUFFER_SIZE)
234 mddi->rev_data_curr =
235 mddi->rev_data_curr % MDDI_REV_BUFFER_SIZE;
236
237 if (length > MDDI_REV_BUFFER_SIZE - 2) {
238 printk(KERN_INFO "mddi: rev data length greater than buffer"
239 "size\n");
240 mddi_reset_rev_encap_ptr(mddi);
241 return;
242 }
243
244 if (prev_offset + 2 + length >= MDDI_REV_BUFFER_SIZE) {
245 union mddi_rev tmprev;
246 size_t rem = MDDI_REV_BUFFER_SIZE - prev_offset;
247 memcpy(&tmprev.raw[0], mddi->rev_data + prev_offset, rem);
248 memcpy(&tmprev.raw[rem], mddi->rev_data, 2 + length - rem);
249 mddi_handle_rev_data(mddi, &tmprev);
250 } else {
251 mddi_handle_rev_data(mddi, crev);
252 }
253
254 if (prev_offset < MDDI_REV_BUFFER_SIZE / 2 &&
255 mddi->rev_data_curr >= MDDI_REV_BUFFER_SIZE / 2) {
256 mddi_writel(mddi->rev_addr, REV_PTR);
257 }
258}
259
260static irqreturn_t mddi_isr(int irq, void *data)
261{
262 struct msm_mddi_client_data *cdata = data;
263 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
264 client_data);
265 uint32_t active, status;
266
267 spin_lock(&mddi->int_lock);
268
269 active = mddi_readl(INT);
270 status = mddi_readl(STAT);
271
272 mddi_writel(active, INT);
273
274 /* ignore any interrupts we have disabled */
275 active &= mddi->int_enable;
276
277 mddi->got_int |= active;
278 wake_up(&mddi->int_wait);
279
280 if (active & MDDI_INT_PRI_LINK_LIST_DONE) {
281 mddi->int_enable &= (~MDDI_INT_PRI_LINK_LIST_DONE);
282 mddi_handle_link_list_done(mddi);
283 }
284 if (active & MDDI_INT_REV_DATA_AVAIL)
285 mddi_handle_rev_data_avail(mddi);
286
287 if (active & ~MDDI_INT_NEED_CLEAR)
288 mddi->int_enable &= ~(active & ~MDDI_INT_NEED_CLEAR);
289
290 if (active & MDDI_INT_LINK_ACTIVE) {
291 mddi->int_enable &= (~MDDI_INT_LINK_ACTIVE);
292 mddi->int_enable |= MDDI_INT_IN_HIBERNATION;
293 }
294
295 if (active & MDDI_INT_IN_HIBERNATION) {
296 mddi->int_enable &= (~MDDI_INT_IN_HIBERNATION);
297 mddi->int_enable |= MDDI_INT_LINK_ACTIVE;
298 }
299
300 mddi_writel(mddi->int_enable, INTEN);
301 spin_unlock(&mddi->int_lock);
302
303 return IRQ_HANDLED;
304}
305
306static long mddi_wait_interrupt_timeout(struct mddi_info *mddi,
307 uint32_t intmask, int timeout)
308{
309 unsigned long irq_flags;
310
311 spin_lock_irqsave(&mddi->int_lock, irq_flags);
312 mddi->got_int &= ~intmask;
313 mddi->int_enable |= intmask;
314 mddi_writel(mddi->int_enable, INTEN);
315 spin_unlock_irqrestore(&mddi->int_lock, irq_flags);
316 return wait_event_timeout(mddi->int_wait, mddi->got_int & intmask,
317 timeout);
318}
319
320static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask)
321{
322 if (mddi_wait_interrupt_timeout(mddi, intmask, HZ/10) == 0)
323 printk(KERN_INFO KERN_ERR "mddi_wait_interrupt %d, timeout "
324 "waiting for %x, INT = %x, STAT = %x gotint = %x\n",
325 current->pid, intmask, mddi_readl(INT), mddi_readl(STAT),
326 mddi->got_int);
327}
328
329static void mddi_init_rev_encap(struct mddi_info *mddi)
330{
331 memset(mddi->rev_data, 0xee, MDDI_REV_BUFFER_SIZE);
332 mddi_writel(mddi->rev_addr, REV_PTR);
333 mddi_writel(MDDI_CMD_FORCE_NEW_REV_PTR, CMD);
334 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
335}
336
337void mddi_set_auto_hibernate(struct msm_mddi_client_data *cdata, int on)
338{
339 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
340 client_data);
341 mddi_writel(MDDI_CMD_POWERDOWN, CMD);
342 mddi_wait_interrupt(mddi, MDDI_INT_IN_HIBERNATION);
343 mddi_writel(MDDI_CMD_HIBERNATE | !!on, CMD);
344 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
345}
346
347
348static uint16_t mddi_init_registers(struct mddi_info *mddi)
349{
350 mddi_writel(0x0001, VERSION);
351 mddi_writel(MDDI_HOST_BYTES_PER_SUBFRAME, BPS);
352 mddi_writel(0x0003, SPM); /* subframes per media */
353 mddi_writel(0x0005, TA1_LEN);
354 mddi_writel(MDDI_HOST_TA2_LEN, TA2_LEN);
355 mddi_writel(0x0096, DRIVE_HI);
356 /* 0x32 normal, 0x50 for Toshiba display */
357 mddi_writel(0x0050, DRIVE_LO);
358 mddi_writel(0x003C, DISP_WAKE); /* wakeup counter */
359 mddi_writel(MDDI_HOST_REV_RATE_DIV, REV_RATE_DIV);
360
361 mddi_writel(MDDI_REV_BUFFER_SIZE, REV_SIZE);
362 mddi_writel(MDDI_MAX_REV_PKT_SIZE, REV_ENCAP_SZ);
363
364 /* disable periodic rev encap */
365 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP, CMD);
366 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
367
368 if (mddi_readl(PAD_CTL) == 0) {
369 /* If we are turning on band gap, need to wait 5us before
370 * turning on the rest of the PAD */
371 mddi_writel(0x08000, PAD_CTL);
372 udelay(5);
373 }
374
375 /* Recommendation from PAD hw team */
376 mddi_writel(0xa850f, PAD_CTL);
377
378
379 /* Need an even number for counts */
380 mddi_writel(0x60006, DRIVER_START_CNT);
381
382 mddi_set_auto_hibernate(&mddi->client_data, 0);
383
384 mddi_writel(MDDI_CMD_DISP_IGNORE, CMD);
385 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
386
387 mddi_init_rev_encap(mddi);
388 return mddi_readl(CORE_VER) & 0xffff;
389}
390
391static void mddi_suspend(struct msm_mddi_client_data *cdata)
392{
393 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
394 client_data);
395 /* turn off the client */
396 if (mddi->power_client)
397 mddi->power_client(&mddi->client_data, 0);
398 /* turn off the link */
399 mddi_writel(MDDI_CMD_RESET, CMD);
400 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
401 /* turn off the clock */
402 clk_disable(mddi->clk);
403}
404
405static void mddi_resume(struct msm_mddi_client_data *cdata)
406{
407 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
408 client_data);
409 mddi_set_auto_hibernate(&mddi->client_data, 0);
410 /* turn on the client */
411 if (mddi->power_client)
412 mddi->power_client(&mddi->client_data, 1);
413 /* turn on the clock */
414 clk_enable(mddi->clk);
415 /* set up the local registers */
416 mddi->rev_data_curr = 0;
417 mddi_init_registers(mddi);
418 mddi_writel(mddi->int_enable, INTEN);
419 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
420 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
421 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
422 mddi_set_auto_hibernate(&mddi->client_data, 1);
423}
424
425static int __init mddi_get_client_caps(struct mddi_info *mddi)
426{
427 int i, j;
428
429 /* clear any stale interrupts */
430 mddi_writel(0xffffffff, INT);
431
432 mddi->int_enable = MDDI_INT_LINK_ACTIVE |
433 MDDI_INT_IN_HIBERNATION |
434 MDDI_INT_PRI_LINK_LIST_DONE |
435 MDDI_INT_REV_DATA_AVAIL |
436 MDDI_INT_REV_OVERFLOW |
437 MDDI_INT_REV_OVERWRITE |
438 MDDI_INT_RTD_FAILURE;
439 mddi_writel(mddi->int_enable, INTEN);
440
441 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
442 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
443
444 for (j = 0; j < 3; j++) {
445 /* the toshiba vga panel does not respond to get
446 * caps unless you SEND_RTD, but the first SEND_RTD
447 * will fail...
448 */
449 for (i = 0; i < 4; i++) {
450 uint32_t stat;
451
452 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
453 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
454 stat = mddi_readl(STAT);
455 printk(KERN_INFO "mddi cmd send rtd: int %x, stat %x, "
456 "rtd val %x\n", mddi_readl(INT), stat,
457 mddi_readl(RTD_VAL));
458 if ((stat & MDDI_STAT_RTD_MEAS_FAIL) == 0)
459 break;
460 msleep(1);
461 }
462
463 mddi_writel(CMD_GET_CLIENT_CAP, CMD);
464 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
465 wait_event_timeout(mddi->int_wait, mddi->flags & FLAG_HAVE_CAPS,
466 HZ / 100);
467
468 if (mddi->flags & FLAG_HAVE_CAPS)
469 break;
470 printk(KERN_INFO KERN_ERR "mddi_init, timeout waiting for "
471 "caps\n");
472 }
473 return mddi->flags & FLAG_HAVE_CAPS;
474}
475
476/* link must be active when this is called */
477int mddi_check_status(struct mddi_info *mddi)
478{
479 int ret = -1, retry = 3;
480 mutex_lock(&mddi->reg_read_lock);
481 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD);
482 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
483
484 do {
485 mddi->flags &= ~FLAG_HAVE_STATUS;
486 mddi_writel(CMD_GET_CLIENT_STATUS, CMD);
487 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
488 wait_event_timeout(mddi->int_wait,
489 mddi->flags & FLAG_HAVE_STATUS,
490 HZ / 100);
491
492 if (mddi->flags & FLAG_HAVE_STATUS) {
493 if (mddi->status.crc_error_count)
494 printk(KERN_INFO "mddi status: crc_error "
495 "count: %d\n",
496 mddi->status.crc_error_count);
497 else
498 ret = 0;
499 break;
500 } else
501 printk(KERN_INFO "mddi status: failed to get client "
502 "status\n");
503 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
504 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
505 } while (--retry);
506
507 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD);
508 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
509 mutex_unlock(&mddi->reg_read_lock);
510 return ret;
511}
512
513
514void mddi_remote_write(struct msm_mddi_client_data *cdata, uint32_t val,
515 uint32_t reg)
516{
517 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
518 client_data);
519 struct mddi_llentry *ll;
520 struct mddi_register_access *ra;
521
522 mutex_lock(&mddi->reg_write_lock);
523
524 ll = mddi->reg_write_data;
525
526 ra = &(ll->u.r);
527 ra->length = 14 + 4;
528 ra->type = TYPE_REGISTER_ACCESS;
529 ra->client_id = 0;
530 ra->read_write_info = MDDI_WRITE | 1;
531 ra->crc16 = 0;
532
533 ra->register_address = reg;
534 ra->register_data_list = val;
535
536 ll->flags = 1;
537 ll->header_count = 14;
538 ll->data_count = 4;
539 ll->data = mddi->reg_write_addr + offsetof(struct mddi_llentry,
540 u.r.register_data_list);
541 ll->next = 0;
542 ll->reserved = 0;
543
544 mddi_writel(mddi->reg_write_addr, PRI_PTR);
545
546 mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE);
547 mutex_unlock(&mddi->reg_write_lock);
548}
549
550uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg)
551{
552 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
553 client_data);
554 struct mddi_llentry *ll;
555 struct mddi_register_access *ra;
556 struct reg_read_info ri;
557 unsigned s;
558 int retry_count = 2;
559 unsigned long irq_flags;
560
561 mutex_lock(&mddi->reg_read_lock);
562
563 ll = mddi->reg_read_data;
564
565 ra = &(ll->u.r);
566 ra->length = 14;
567 ra->type = TYPE_REGISTER_ACCESS;
568 ra->client_id = 0;
569 ra->read_write_info = MDDI_READ | 1;
570 ra->crc16 = 0;
571
572 ra->register_address = reg;
573
574 ll->flags = 0x11;
575 ll->header_count = 14;
576 ll->data_count = 0;
577 ll->data = 0;
578 ll->next = 0;
579 ll->reserved = 0;
580
581 s = mddi_readl(STAT);
582
583 ri.reg = reg;
584 ri.status = -1;
585
586 do {
587 init_completion(&ri.done);
588 mddi->reg_read = &ri;
589 mddi_writel(mddi->reg_read_addr, PRI_PTR);
590
591 mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE);
592
593 /* Enable Periodic Reverse Encapsulation. */
594 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD);
595 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
596 if (wait_for_completion_timeout(&ri.done, HZ/10) == 0 &&
597 !ri.done.done) {
598 printk(KERN_INFO "mddi_remote_read(%x) timeout "
599 "(%d %d %d)\n",
600 reg, ri.status, ri.result, ri.done.done);
601 spin_lock_irqsave(&mddi->int_lock, irq_flags);
602 mddi->reg_read = NULL;
603 spin_unlock_irqrestore(&mddi->int_lock, irq_flags);
604 ri.status = -1;
605 ri.result = -1;
606 }
607 if (ri.status == 0)
608 break;
609
610 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
611 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
612 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
613 printk(KERN_INFO "mddi_remote_read: failed, sent "
614 "MDDI_CMD_SEND_RTD: int %x, stat %x, rtd val %x "
615 "curr_rev_ptr %x\n", mddi_readl(INT), mddi_readl(STAT),
616 mddi_readl(RTD_VAL), mddi_readl(CURR_REV_PTR));
617 } while (retry_count-- > 0);
618 /* Disable Periodic Reverse Encapsulation. */
619 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD);
620 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
621 mddi->reg_read = NULL;
622 mutex_unlock(&mddi->reg_read_lock);
623 return ri.result;
624}
625
626static struct mddi_info mddi_info[2];
627
628static int __init mddi_clk_setup(struct platform_device *pdev,
629 struct mddi_info *mddi,
630 unsigned long clk_rate)
631{
632 int ret;
633
634 /* set up the clocks */
635 mddi->clk = clk_get(&pdev->dev, "mddi_clk");
636 if (IS_ERR(mddi->clk)) {
637 printk(KERN_INFO "mddi: failed to get clock\n");
638 return PTR_ERR(mddi->clk);
639 }
640 ret = clk_enable(mddi->clk);
641 if (ret)
642 goto fail;
643 ret = clk_set_rate(mddi->clk, clk_rate);
644 if (ret)
645 goto fail;
646 return 0;
647
648fail:
649 clk_put(mddi->clk);
650 return ret;
651}
652
653static int __init mddi_rev_data_setup(struct mddi_info *mddi)
654{
655 void *dma;
656 dma_addr_t dma_addr;
657
658 /* set up dma buffer */
659 dma = dma_alloc_coherent(NULL, 0x1000, &dma_addr, GFP_KERNEL);
660 if (dma == 0)
661 return -ENOMEM;
662 mddi->rev_data = dma;
663 mddi->rev_data_curr = 0;
664 mddi->rev_addr = dma_addr;
665 mddi->reg_write_data = dma + MDDI_REV_BUFFER_SIZE;
666 mddi->reg_write_addr = dma_addr + MDDI_REV_BUFFER_SIZE;
667 mddi->reg_read_data = mddi->reg_write_data + 1;
668 mddi->reg_read_addr = mddi->reg_write_addr +
669 sizeof(*mddi->reg_write_data);
670 return 0;
671}
672
673static int __init mddi_probe(struct platform_device *pdev)
674{
675 struct msm_mddi_platform_data *pdata = pdev->dev.platform_data;
676 struct mddi_info *mddi = &mddi_info[pdev->id];
677 struct resource *resource;
678 int ret, i;
679
680 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
681 if (!resource) {
682 printk(KERN_ERR "mddi: no associated mem resource!\n");
683 return -ENOMEM;
684 }
685 mddi->base = ioremap(resource->start, resource->end - resource->start);
686 if (!mddi->base) {
687 printk(KERN_ERR "mddi: failed to remap base!\n");
688 ret = -EINVAL;
689 goto error_ioremap;
690 }
691 resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
692 if (!resource) {
693 printk(KERN_ERR "mddi: no associated irq resource!\n");
694 ret = -EINVAL;
695 goto error_get_irq_resource;
696 }
697 mddi->irq = resource->start;
698 printk(KERN_INFO "mddi: init() base=0x%p irq=%d\n", mddi->base,
699 mddi->irq);
700 mddi->power_client = pdata->power_client;
701
702 mutex_init(&mddi->reg_write_lock);
703 mutex_init(&mddi->reg_read_lock);
704 spin_lock_init(&mddi->int_lock);
705 init_waitqueue_head(&mddi->int_wait);
706
707 ret = mddi_clk_setup(pdev, mddi, pdata->clk_rate);
708 if (ret) {
709 printk(KERN_ERR "mddi: failed to setup clock!\n");
710 goto error_clk_setup;
711 }
712
713 ret = mddi_rev_data_setup(mddi);
714 if (ret) {
715 printk(KERN_ERR "mddi: failed to setup rev data!\n");
716 goto error_rev_data;
717 }
718
719 mddi->int_enable = 0;
720 mddi_writel(mddi->int_enable, INTEN);
721 ret = request_irq(mddi->irq, mddi_isr, IRQF_DISABLED, "mddi",
722 &mddi->client_data);
723 if (ret) {
724 printk(KERN_ERR "mddi: failed to request enable irq!\n");
725 goto error_request_irq;
726 }
727
728 /* turn on the mddi client bridge chip */
729 if (mddi->power_client)
730 mddi->power_client(&mddi->client_data, 1);
731
732 /* initialize the mddi registers */
733 mddi_set_auto_hibernate(&mddi->client_data, 0);
734 mddi_writel(MDDI_CMD_RESET, CMD);
735 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
736 mddi->version = mddi_init_registers(mddi);
737 if (mddi->version < 0x20) {
738 printk(KERN_ERR "mddi: unsupported version 0x%x\n",
739 mddi->version);
740 ret = -ENODEV;
741 goto error_mddi_version;
742 }
743
744 /* read the capabilities off the client */
745 if (!mddi_get_client_caps(mddi)) {
746 printk(KERN_INFO "mddi: no client found\n");
747 /* power down the panel */
748 mddi_writel(MDDI_CMD_POWERDOWN, CMD);
749 printk(KERN_INFO "mddi powerdown: stat %x\n", mddi_readl(STAT));
750 msleep(100);
751 printk(KERN_INFO "mddi powerdown: stat %x\n", mddi_readl(STAT));
752 return 0;
753 }
754 mddi_set_auto_hibernate(&mddi->client_data, 1);
755
756 if (mddi->caps.Mfr_Name == 0 && mddi->caps.Product_Code == 0)
757 pdata->fixup(&mddi->caps.Mfr_Name, &mddi->caps.Product_Code);
758
759 mddi->client_pdev.id = 0;
760 for (i = 0; i < pdata->num_clients; i++) {
761 if (pdata->client_platform_data[i].product_id ==
762 (mddi->caps.Mfr_Name << 16 | mddi->caps.Product_Code)) {
763 mddi->client_data.private_client_data =
764 pdata->client_platform_data[i].client_data;
765 mddi->client_pdev.name =
766 pdata->client_platform_data[i].name;
767 mddi->client_pdev.id =
768 pdata->client_platform_data[i].id;
769 /* XXX: possibly set clock */
770 break;
771 }
772 }
773
774 if (i >= pdata->num_clients)
775 mddi->client_pdev.name = "mddi_c_dummy";
776 printk(KERN_INFO "mddi: registering panel %s\n",
777 mddi->client_pdev.name);
778
779 mddi->client_data.suspend = mddi_suspend;
780 mddi->client_data.resume = mddi_resume;
781 mddi->client_data.activate_link = mddi_activate_link;
782 mddi->client_data.remote_write = mddi_remote_write;
783 mddi->client_data.remote_read = mddi_remote_read;
784 mddi->client_data.auto_hibernate = mddi_set_auto_hibernate;
785 mddi->client_data.fb_resource = pdata->fb_resource;
786 if (pdev->id == 0)
787 mddi->client_data.interface_type = MSM_MDDI_PMDH_INTERFACE;
788 else if (pdev->id == 1)
789 mddi->client_data.interface_type = MSM_MDDI_EMDH_INTERFACE;
790 else {
791 printk(KERN_ERR "mddi: can not determine interface %d!\n",
792 pdev->id);
793 ret = -EINVAL;
794 goto error_mddi_interface;
795 }
796
797 mddi->client_pdev.dev.platform_data = &mddi->client_data;
798 printk(KERN_INFO "mddi: publish: %s\n", mddi->client_name);
799 platform_device_register(&mddi->client_pdev);
800 return 0;
801
802error_mddi_interface:
803error_mddi_version:
804 free_irq(mddi->irq, 0);
805error_request_irq:
806 dma_free_coherent(NULL, 0x1000, mddi->rev_data, mddi->rev_addr);
807error_rev_data:
808error_clk_setup:
809error_get_irq_resource:
810 iounmap(mddi->base);
811error_ioremap:
812
813 printk(KERN_INFO "mddi: mddi_init() failed (%d)\n", ret);
814 return ret;
815}
816
817
818static struct platform_driver mddi_driver = {
819 .probe = mddi_probe,
820 .driver = { .name = "msm_mddi" },
821};
822
823static int __init _mddi_init(void)
824{
825 return platform_driver_register(&mddi_driver);
826}
827
828module_init(_mddi_init);
diff --git a/drivers/video/msm/mddi_client_dummy.c b/drivers/video/msm/mddi_client_dummy.c
new file mode 100644
index 000000000000..ebbae87885b6
--- /dev/null
+++ b/drivers/video/msm/mddi_client_dummy.c
@@ -0,0 +1,97 @@
1/* drivers/video/msm_fb/mddi_client_dummy.c
2 *
3 * Support for "dummy" mddi client devices which require no
4 * special initialization code.
5 *
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/module.h>
19#include <linux/kernel.h>
20#include <linux/platform_device.h>
21
22#include <mach/msm_fb.h>
23
24struct panel_info {
25 struct platform_device pdev;
26 struct msm_panel_data panel_data;
27};
28
29static int mddi_dummy_suspend(struct msm_panel_data *panel_data)
30{
31 return 0;
32}
33
34static int mddi_dummy_resume(struct msm_panel_data *panel_data)
35{
36 return 0;
37}
38
39static int mddi_dummy_blank(struct msm_panel_data *panel_data)
40{
41 return 0;
42}
43
44static int mddi_dummy_unblank(struct msm_panel_data *panel_data)
45{
46 return 0;
47}
48
49static int mddi_dummy_probe(struct platform_device *pdev)
50{
51 struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
52 struct panel_info *panel =
53 kzalloc(sizeof(struct panel_info), GFP_KERNEL);
54 int ret;
55 if (!panel)
56 return -ENOMEM;
57 platform_set_drvdata(pdev, panel);
58 panel->panel_data.suspend = mddi_dummy_suspend;
59 panel->panel_data.resume = mddi_dummy_resume;
60 panel->panel_data.blank = mddi_dummy_blank;
61 panel->panel_data.unblank = mddi_dummy_unblank;
62 panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES;
63 panel->pdev.name = "msm_panel";
64 panel->pdev.id = pdev->id;
65 platform_device_add_resources(&panel->pdev,
66 client_data->fb_resource, 1);
67 panel->panel_data.fb_data = client_data->private_client_data;
68 panel->pdev.dev.platform_data = &panel->panel_data;
69 ret = platform_device_register(&panel->pdev);
70 if (ret) {
71 kfree(panel);
72 return ret;
73 }
74 return 0;
75}
76
77static int mddi_dummy_remove(struct platform_device *pdev)
78{
79 struct panel_info *panel = platform_get_drvdata(pdev);
80 kfree(panel);
81 return 0;
82}
83
84static struct platform_driver mddi_client_dummy = {
85 .probe = mddi_dummy_probe,
86 .remove = mddi_dummy_remove,
87 .driver = { .name = "mddi_c_dummy" },
88};
89
90static int __init mddi_client_dummy_init(void)
91{
92 platform_driver_register(&mddi_client_dummy);
93 return 0;
94}
95
96module_init(mddi_client_dummy_init);
97
diff --git a/drivers/video/msm/mddi_client_nt35399.c b/drivers/video/msm/mddi_client_nt35399.c
new file mode 100644
index 000000000000..9c78050ac799
--- /dev/null
+++ b/drivers/video/msm/mddi_client_nt35399.c
@@ -0,0 +1,255 @@
1/* drivers/video/msm_fb/mddi_client_nt35399.c
2 *
3 * Support for Novatek NT35399 MDDI client of Sapphire
4 *
5 * Copyright (C) 2008 HTC Incorporated
6 * Author: Solomon Chiu (solomon_chiu@htc.com)
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/module.h>
19#include <linux/kernel.h>
20#include <linux/platform_device.h>
21#include <linux/interrupt.h>
22#include <linux/gpio.h>
23#include <mach/msm_fb.h>
24
25static DECLARE_WAIT_QUEUE_HEAD(nt35399_vsync_wait);
26
27struct panel_info {
28 struct msm_mddi_client_data *client_data;
29 struct platform_device pdev;
30 struct msm_panel_data panel_data;
31 struct msmfb_callback *fb_callback;
32 struct work_struct panel_work;
33 struct workqueue_struct *fb_wq;
34 int nt35399_got_int;
35};
36
37static void
38nt35399_request_vsync(struct msm_panel_data *panel_data,
39 struct msmfb_callback *callback)
40{
41 struct panel_info *panel = container_of(panel_data, struct panel_info,
42 panel_data);
43 struct msm_mddi_client_data *client_data = panel->client_data;
44
45 panel->fb_callback = callback;
46 if (panel->nt35399_got_int) {
47 panel->nt35399_got_int = 0;
48 client_data->activate_link(client_data); /* clears interrupt */
49 }
50}
51
52static void nt35399_wait_vsync(struct msm_panel_data *panel_data)
53{
54 struct panel_info *panel = container_of(panel_data, struct panel_info,
55 panel_data);
56 struct msm_mddi_client_data *client_data = panel->client_data;
57
58 if (panel->nt35399_got_int) {
59 panel->nt35399_got_int = 0;
60 client_data->activate_link(client_data); /* clears interrupt */
61 }
62
63 if (wait_event_timeout(nt35399_vsync_wait, panel->nt35399_got_int,
64 HZ/2) == 0)
65 printk(KERN_ERR "timeout waiting for VSYNC\n");
66
67 panel->nt35399_got_int = 0;
68 /* interrupt clears when screen dma starts */
69}
70
71static int nt35399_suspend(struct msm_panel_data *panel_data)
72{
73 struct panel_info *panel = container_of(panel_data, struct panel_info,
74 panel_data);
75 struct msm_mddi_client_data *client_data = panel->client_data;
76
77 struct msm_mddi_bridge_platform_data *bridge_data =
78 client_data->private_client_data;
79 int ret;
80
81 ret = bridge_data->uninit(bridge_data, client_data);
82 if (ret) {
83 printk(KERN_INFO "mddi nt35399 client: non zero return from "
84 "uninit\n");
85 return ret;
86 }
87 client_data->suspend(client_data);
88 return 0;
89}
90
91static int nt35399_resume(struct msm_panel_data *panel_data)
92{
93 struct panel_info *panel = container_of(panel_data, struct panel_info,
94 panel_data);
95 struct msm_mddi_client_data *client_data = panel->client_data;
96
97 struct msm_mddi_bridge_platform_data *bridge_data =
98 client_data->private_client_data;
99 int ret;
100
101 client_data->resume(client_data);
102 ret = bridge_data->init(bridge_data, client_data);
103 if (ret)
104 return ret;
105 return 0;
106}
107
108static int nt35399_blank(struct msm_panel_data *panel_data)
109{
110 struct panel_info *panel = container_of(panel_data, struct panel_info,
111 panel_data);
112 struct msm_mddi_client_data *client_data = panel->client_data;
113 struct msm_mddi_bridge_platform_data *bridge_data =
114 client_data->private_client_data;
115
116 return bridge_data->blank(bridge_data, client_data);
117}
118
119static int nt35399_unblank(struct msm_panel_data *panel_data)
120{
121 struct panel_info *panel = container_of(panel_data, struct panel_info,
122 panel_data);
123 struct msm_mddi_client_data *client_data = panel->client_data;
124 struct msm_mddi_bridge_platform_data *bridge_data =
125 client_data->private_client_data;
126
127 return bridge_data->unblank(bridge_data, client_data);
128}
129
130irqreturn_t nt35399_vsync_interrupt(int irq, void *data)
131{
132 struct panel_info *panel = data;
133
134 panel->nt35399_got_int = 1;
135
136 if (panel->fb_callback) {
137 panel->fb_callback->func(panel->fb_callback);
138 panel->fb_callback = NULL;
139 }
140
141 wake_up(&nt35399_vsync_wait);
142
143 return IRQ_HANDLED;
144}
145
146static int setup_vsync(struct panel_info *panel, int init)
147{
148 int ret;
149 int gpio = 97;
150 unsigned int irq;
151
152 if (!init) {
153 ret = 0;
154 goto uninit;
155 }
156 ret = gpio_request(gpio, "vsync");
157 if (ret)
158 goto err_request_gpio_failed;
159
160 ret = gpio_direction_input(gpio);
161 if (ret)
162 goto err_gpio_direction_input_failed;
163
164 ret = irq = gpio_to_irq(gpio);
165 if (ret < 0)
166 goto err_get_irq_num_failed;
167
168 ret = request_irq(irq, nt35399_vsync_interrupt, IRQF_TRIGGER_RISING,
169 "vsync", panel);
170 if (ret)
171 goto err_request_irq_failed;
172
173 printk(KERN_INFO "vsync on gpio %d now %d\n",
174 gpio, gpio_get_value(gpio));
175 return 0;
176
177uninit:
178 free_irq(gpio_to_irq(gpio), panel->client_data);
179err_request_irq_failed:
180err_get_irq_num_failed:
181err_gpio_direction_input_failed:
182 gpio_free(gpio);
183err_request_gpio_failed:
184 return ret;
185}
186
187static int mddi_nt35399_probe(struct platform_device *pdev)
188{
189 struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
190 struct msm_mddi_bridge_platform_data *bridge_data =
191 client_data->private_client_data;
192
193 int ret;
194
195 struct panel_info *panel = kzalloc(sizeof(struct panel_info),
196 GFP_KERNEL);
197
198 printk(KERN_DEBUG "%s: enter.\n", __func__);
199
200 if (!panel)
201 return -ENOMEM;
202 platform_set_drvdata(pdev, panel);
203
204 ret = setup_vsync(panel, 1);
205 if (ret) {
206 dev_err(&pdev->dev, "mddi_nt35399_setup_vsync failed\n");
207 return ret;
208 }
209
210 panel->client_data = client_data;
211 panel->panel_data.suspend = nt35399_suspend;
212 panel->panel_data.resume = nt35399_resume;
213 panel->panel_data.wait_vsync = nt35399_wait_vsync;
214 panel->panel_data.request_vsync = nt35399_request_vsync;
215 panel->panel_data.blank = nt35399_blank;
216 panel->panel_data.unblank = nt35399_unblank;
217 panel->panel_data.fb_data = &bridge_data->fb_data;
218 panel->panel_data.caps = 0;
219
220 panel->pdev.name = "msm_panel";
221 panel->pdev.id = pdev->id;
222 panel->pdev.resource = client_data->fb_resource;
223 panel->pdev.num_resources = 1;
224 panel->pdev.dev.platform_data = &panel->panel_data;
225
226 if (bridge_data->init)
227 bridge_data->init(bridge_data, client_data);
228
229 platform_device_register(&panel->pdev);
230
231 return 0;
232}
233
234static int mddi_nt35399_remove(struct platform_device *pdev)
235{
236 struct panel_info *panel = platform_get_drvdata(pdev);
237
238 setup_vsync(panel, 0);
239 kfree(panel);
240 return 0;
241}
242
243static struct platform_driver mddi_client_0bda_8a47 = {
244 .probe = mddi_nt35399_probe,
245 .remove = mddi_nt35399_remove,
246 .driver = { .name = "mddi_c_0bda_8a47" },
247};
248
249static int __init mddi_client_nt35399_init(void)
250{
251 return platform_driver_register(&mddi_client_0bda_8a47);
252}
253
254module_init(mddi_client_nt35399_init);
255
diff --git a/drivers/video/msm/mddi_client_toshiba.c b/drivers/video/msm/mddi_client_toshiba.c
new file mode 100644
index 000000000000..80d0f5fdf0b1
--- /dev/null
+++ b/drivers/video/msm/mddi_client_toshiba.c
@@ -0,0 +1,283 @@
1/* drivers/video/msm_fb/mddi_client_toshiba.c
2 *
3 * Support for Toshiba TC358720XBG mddi client devices which require no
4 * special initialization code.
5 *
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/module.h>
19#include <linux/kernel.h>
20#include <linux/platform_device.h>
21#include <linux/interrupt.h>
22#include <linux/gpio.h>
23#include <mach/msm_fb.h>
24
25
26#define LCD_CONTROL_BLOCK_BASE 0x110000
27#define CMN (LCD_CONTROL_BLOCK_BASE|0x10)
28#define INTFLG (LCD_CONTROL_BLOCK_BASE|0x18)
29#define HCYCLE (LCD_CONTROL_BLOCK_BASE|0x34)
30#define HDE_START (LCD_CONTROL_BLOCK_BASE|0x3C)
31#define VPOS (LCD_CONTROL_BLOCK_BASE|0xC0)
32#define MPLFBUF (LCD_CONTROL_BLOCK_BASE|0x20)
33#define WAKEUP (LCD_CONTROL_BLOCK_BASE|0x54)
34#define WSYN_DLY (LCD_CONTROL_BLOCK_BASE|0x58)
35#define REGENB (LCD_CONTROL_BLOCK_BASE|0x5C)
36
37#define BASE5 0x150000
38#define BASE6 0x160000
39#define BASE7 0x170000
40
41#define GPIOIEV (BASE5 + 0x10)
42#define GPIOIE (BASE5 + 0x14)
43#define GPIORIS (BASE5 + 0x18)
44#define GPIOMIS (BASE5 + 0x1C)
45#define GPIOIC (BASE5 + 0x20)
46
47#define INTMASK (BASE6 + 0x0C)
48#define INTMASK_VWAKEOUT (1U << 0)
49#define INTMASK_VWAKEOUT_ACTIVE_LOW (1U << 8)
50#define GPIOSEL (BASE7 + 0x00)
51#define GPIOSEL_VWAKEINT (1U << 0)
52
53static DECLARE_WAIT_QUEUE_HEAD(toshiba_vsync_wait);
54
55struct panel_info {
56 struct msm_mddi_client_data *client_data;
57 struct platform_device pdev;
58 struct msm_panel_data panel_data;
59 struct msmfb_callback *toshiba_callback;
60 int toshiba_got_int;
61};
62
63
64static void toshiba_request_vsync(struct msm_panel_data *panel_data,
65 struct msmfb_callback *callback)
66{
67 struct panel_info *panel = container_of(panel_data, struct panel_info,
68 panel_data);
69 struct msm_mddi_client_data *client_data = panel->client_data;
70
71 panel->toshiba_callback = callback;
72 if (panel->toshiba_got_int) {
73 panel->toshiba_got_int = 0;
74 client_data->activate_link(client_data);
75 }
76}
77
78static void toshiba_clear_vsync(struct msm_panel_data *panel_data)
79{
80 struct panel_info *panel = container_of(panel_data, struct panel_info,
81 panel_data);
82 struct msm_mddi_client_data *client_data = panel->client_data;
83
84 client_data->activate_link(client_data);
85}
86
87static void toshiba_wait_vsync(struct msm_panel_data *panel_data)
88{
89 struct panel_info *panel = container_of(panel_data, struct panel_info,
90 panel_data);
91 struct msm_mddi_client_data *client_data = panel->client_data;
92
93 if (panel->toshiba_got_int) {
94 panel->toshiba_got_int = 0;
95 client_data->activate_link(client_data); /* clears interrupt */
96 }
97 if (wait_event_timeout(toshiba_vsync_wait, panel->toshiba_got_int,
98 HZ/2) == 0)
99 printk(KERN_ERR "timeout waiting for VSYNC\n");
100 panel->toshiba_got_int = 0;
101 /* interrupt clears when screen dma starts */
102}
103
104static int toshiba_suspend(struct msm_panel_data *panel_data)
105{
106 struct panel_info *panel = container_of(panel_data, struct panel_info,
107 panel_data);
108 struct msm_mddi_client_data *client_data = panel->client_data;
109
110 struct msm_mddi_bridge_platform_data *bridge_data =
111 client_data->private_client_data;
112 int ret;
113
114 ret = bridge_data->uninit(bridge_data, client_data);
115 if (ret) {
116 printk(KERN_INFO "mddi toshiba client: non zero return from "
117 "uninit\n");
118 return ret;
119 }
120 client_data->suspend(client_data);
121 return 0;
122}
123
124static int toshiba_resume(struct msm_panel_data *panel_data)
125{
126 struct panel_info *panel = container_of(panel_data, struct panel_info,
127 panel_data);
128 struct msm_mddi_client_data *client_data = panel->client_data;
129
130 struct msm_mddi_bridge_platform_data *bridge_data =
131 client_data->private_client_data;
132 int ret;
133
134 client_data->resume(client_data);
135 ret = bridge_data->init(bridge_data, client_data);
136 if (ret)
137 return ret;
138 return 0;
139}
140
141static int toshiba_blank(struct msm_panel_data *panel_data)
142{
143 struct panel_info *panel = container_of(panel_data, struct panel_info,
144 panel_data);
145 struct msm_mddi_client_data *client_data = panel->client_data;
146 struct msm_mddi_bridge_platform_data *bridge_data =
147 client_data->private_client_data;
148
149 return bridge_data->blank(bridge_data, client_data);
150}
151
152static int toshiba_unblank(struct msm_panel_data *panel_data)
153{
154 struct panel_info *panel = container_of(panel_data, struct panel_info,
155 panel_data);
156 struct msm_mddi_client_data *client_data = panel->client_data;
157 struct msm_mddi_bridge_platform_data *bridge_data =
158 client_data->private_client_data;
159
160 return bridge_data->unblank(bridge_data, client_data);
161}
162
163irqreturn_t toshiba_vsync_interrupt(int irq, void *data)
164{
165 struct panel_info *panel = data;
166
167 panel->toshiba_got_int = 1;
168 if (panel->toshiba_callback) {
169 panel->toshiba_callback->func(panel->toshiba_callback);
170 panel->toshiba_callback = 0;
171 }
172 wake_up(&toshiba_vsync_wait);
173 return IRQ_HANDLED;
174}
175
176static int setup_vsync(struct panel_info *panel,
177 int init)
178{
179 int ret;
180 int gpio = 97;
181 unsigned int irq;
182
183 if (!init) {
184 ret = 0;
185 goto uninit;
186 }
187 ret = gpio_request(gpio, "vsync");
188 if (ret)
189 goto err_request_gpio_failed;
190
191 ret = gpio_direction_input(gpio);
192 if (ret)
193 goto err_gpio_direction_input_failed;
194
195 ret = irq = gpio_to_irq(gpio);
196 if (ret < 0)
197 goto err_get_irq_num_failed;
198
199 ret = request_irq(irq, toshiba_vsync_interrupt, IRQF_TRIGGER_RISING,
200 "vsync", panel);
201 if (ret)
202 goto err_request_irq_failed;
203 printk(KERN_INFO "vsync on gpio %d now %d\n",
204 gpio, gpio_get_value(gpio));
205 return 0;
206
207uninit:
208 free_irq(gpio_to_irq(gpio), panel);
209err_request_irq_failed:
210err_get_irq_num_failed:
211err_gpio_direction_input_failed:
212 gpio_free(gpio);
213err_request_gpio_failed:
214 return ret;
215}
216
217static int mddi_toshiba_probe(struct platform_device *pdev)
218{
219 int ret;
220 struct msm_mddi_client_data *client_data = pdev->dev.platform_data;
221 struct msm_mddi_bridge_platform_data *bridge_data =
222 client_data->private_client_data;
223 struct panel_info *panel =
224 kzalloc(sizeof(struct panel_info), GFP_KERNEL);
225 if (!panel)
226 return -ENOMEM;
227 platform_set_drvdata(pdev, panel);
228
229 /* mddi_remote_write(mddi, 0, WAKEUP); */
230 client_data->remote_write(client_data, GPIOSEL_VWAKEINT, GPIOSEL);
231 client_data->remote_write(client_data, INTMASK_VWAKEOUT, INTMASK);
232
233 ret = setup_vsync(panel, 1);
234 if (ret) {
235 dev_err(&pdev->dev, "mddi_bridge_setup_vsync failed\n");
236 return ret;
237 }
238
239 panel->client_data = client_data;
240 panel->panel_data.suspend = toshiba_suspend;
241 panel->panel_data.resume = toshiba_resume;
242 panel->panel_data.wait_vsync = toshiba_wait_vsync;
243 panel->panel_data.request_vsync = toshiba_request_vsync;
244 panel->panel_data.clear_vsync = toshiba_clear_vsync;
245 panel->panel_data.blank = toshiba_blank;
246 panel->panel_data.unblank = toshiba_unblank;
247 panel->panel_data.fb_data = &bridge_data->fb_data;
248 panel->panel_data.caps = MSMFB_CAP_PARTIAL_UPDATES;
249
250 panel->pdev.name = "msm_panel";
251 panel->pdev.id = pdev->id;
252 panel->pdev.resource = client_data->fb_resource;
253 panel->pdev.num_resources = 1;
254 panel->pdev.dev.platform_data = &panel->panel_data;
255 bridge_data->init(bridge_data, client_data);
256 platform_device_register(&panel->pdev);
257
258 return 0;
259}
260
261static int mddi_toshiba_remove(struct platform_device *pdev)
262{
263 struct panel_info *panel = platform_get_drvdata(pdev);
264
265 setup_vsync(panel, 0);
266 kfree(panel);
267 return 0;
268}
269
270static struct platform_driver mddi_client_d263_0000 = {
271 .probe = mddi_toshiba_probe,
272 .remove = mddi_toshiba_remove,
273 .driver = { .name = "mddi_c_d263_0000" },
274};
275
276static int __init mddi_client_toshiba_init(void)
277{
278 platform_driver_register(&mddi_client_d263_0000);
279 return 0;
280}
281
282module_init(mddi_client_toshiba_init);
283
diff --git a/drivers/video/msm/mddi_hw.h b/drivers/video/msm/mddi_hw.h
new file mode 100644
index 000000000000..45cc01fc1e7f
--- /dev/null
+++ b/drivers/video/msm/mddi_hw.h
@@ -0,0 +1,305 @@
1/* drivers/video/msm_fb/mddi_hw.h
2 *
3 * MSM MDDI Hardware Registers and Structures
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#ifndef _MDDI_HW_H_
19#define _MDDI_HW_H_
20
21#include <linux/types.h>
22
23#define MDDI_CMD 0x0000
24#define MDDI_VERSION 0x0004
25#define MDDI_PRI_PTR 0x0008
26#define MDDI_SEC_PTR 0x000c
27#define MDDI_BPS 0x0010
28#define MDDI_SPM 0x0014
29#define MDDI_INT 0x0018
30#define MDDI_INTEN 0x001c
31#define MDDI_REV_PTR 0x0020
32#define MDDI_REV_SIZE 0x0024
33#define MDDI_STAT 0x0028
34#define MDDI_REV_RATE_DIV 0x002c
35#define MDDI_REV_CRC_ERR 0x0030
36#define MDDI_TA1_LEN 0x0034
37#define MDDI_TA2_LEN 0x0038
38#define MDDI_TEST_BUS 0x003c
39#define MDDI_TEST 0x0040
40#define MDDI_REV_PKT_CNT 0x0044
41#define MDDI_DRIVE_HI 0x0048
42#define MDDI_DRIVE_LO 0x004c
43#define MDDI_DISP_WAKE 0x0050
44#define MDDI_REV_ENCAP_SZ 0x0054
45#define MDDI_RTD_VAL 0x0058
46#define MDDI_PAD_CTL 0x0068
47#define MDDI_DRIVER_START_CNT 0x006c
48#define MDDI_NEXT_PRI_PTR 0x0070
49#define MDDI_NEXT_SEC_PTR 0x0074
50#define MDDI_MISR_CTL 0x0078
51#define MDDI_MISR_DATA 0x007c
52#define MDDI_SF_CNT 0x0080
53#define MDDI_MF_CNT 0x0084
54#define MDDI_CURR_REV_PTR 0x0088
55#define MDDI_CORE_VER 0x008c
56
57#define MDDI_INT_PRI_PTR_READ 0x0001
58#define MDDI_INT_SEC_PTR_READ 0x0002
59#define MDDI_INT_REV_DATA_AVAIL 0x0004
60#define MDDI_INT_DISP_REQ 0x0008
61#define MDDI_INT_PRI_UNDERFLOW 0x0010
62#define MDDI_INT_SEC_UNDERFLOW 0x0020
63#define MDDI_INT_REV_OVERFLOW 0x0040
64#define MDDI_INT_CRC_ERROR 0x0080
65#define MDDI_INT_MDDI_IN 0x0100
66#define MDDI_INT_PRI_OVERWRITE 0x0200
67#define MDDI_INT_SEC_OVERWRITE 0x0400
68#define MDDI_INT_REV_OVERWRITE 0x0800
69#define MDDI_INT_DMA_FAILURE 0x1000
70#define MDDI_INT_LINK_ACTIVE 0x2000
71#define MDDI_INT_IN_HIBERNATION 0x4000
72#define MDDI_INT_PRI_LINK_LIST_DONE 0x8000
73#define MDDI_INT_SEC_LINK_LIST_DONE 0x10000
74#define MDDI_INT_NO_CMD_PKTS_PEND 0x20000
75#define MDDI_INT_RTD_FAILURE 0x40000
76#define MDDI_INT_REV_PKT_RECEIVED 0x80000
77#define MDDI_INT_REV_PKTS_AVAIL 0x100000
78
79#define MDDI_INT_NEED_CLEAR ( \
80 MDDI_INT_REV_DATA_AVAIL | \
81 MDDI_INT_PRI_UNDERFLOW | \
82 MDDI_INT_SEC_UNDERFLOW | \
83 MDDI_INT_REV_OVERFLOW | \
84 MDDI_INT_CRC_ERROR | \
85 MDDI_INT_REV_PKT_RECEIVED)
86
87
88#define MDDI_STAT_LINK_ACTIVE 0x0001
89#define MDDI_STAT_NEW_REV_PTR 0x0002
90#define MDDI_STAT_NEW_PRI_PTR 0x0004
91#define MDDI_STAT_NEW_SEC_PTR 0x0008
92#define MDDI_STAT_IN_HIBERNATION 0x0010
93#define MDDI_STAT_PRI_LINK_LIST_DONE 0x0020
94#define MDDI_STAT_SEC_LINK_LIST_DONE 0x0040
95#define MDDI_STAT_PENDING_TIMING_PKT 0x0080
96#define MDDI_STAT_PENDING_REV_ENCAP 0x0100
97#define MDDI_STAT_PENDING_POWERDOWN 0x0200
98#define MDDI_STAT_RTD_MEAS_FAIL 0x0800
99#define MDDI_STAT_CLIENT_WAKEUP_REQ 0x1000
100
101
102#define MDDI_CMD_POWERDOWN 0x0100
103#define MDDI_CMD_POWERUP 0x0200
104#define MDDI_CMD_HIBERNATE 0x0300
105#define MDDI_CMD_RESET 0x0400
106#define MDDI_CMD_DISP_IGNORE 0x0501
107#define MDDI_CMD_DISP_LISTEN 0x0500
108#define MDDI_CMD_SEND_REV_ENCAP 0x0600
109#define MDDI_CMD_GET_CLIENT_CAP 0x0601
110#define MDDI_CMD_GET_CLIENT_STATUS 0x0602
111#define MDDI_CMD_SEND_RTD 0x0700
112#define MDDI_CMD_LINK_ACTIVE 0x0900
113#define MDDI_CMD_PERIODIC_REV_ENCAP 0x0A00
114#define MDDI_CMD_FORCE_NEW_REV_PTR 0x0C00
115
116
117
118#define MDDI_VIDEO_REV_PKT_SIZE 0x40
119#define MDDI_CLIENT_CAPABILITY_REV_PKT_SIZE 0x60
120#define MDDI_MAX_REV_PKT_SIZE 0x60
121
122/* #define MDDI_REV_BUFFER_SIZE 128 */
123#define MDDI_REV_BUFFER_SIZE (MDDI_MAX_REV_PKT_SIZE * 4)
124
125/* MDP sends 256 pixel packets, so lower value hibernates more without
126 * significantly increasing latency of waiting for next subframe */
127#define MDDI_HOST_BYTES_PER_SUBFRAME 0x3C00
128#define MDDI_HOST_TA2_LEN 0x000c
129#define MDDI_HOST_REV_RATE_DIV 0x0002
130
131
132struct __attribute__((packed)) mddi_rev_packet {
133 uint16_t length;
134 uint16_t type;
135 uint16_t client_id;
136};
137
138struct __attribute__((packed)) mddi_client_status {
139 uint16_t length;
140 uint16_t type;
141 uint16_t client_id;
142 uint16_t reverse_link_request; /* bytes needed in rev encap message */
143 uint8_t crc_error_count;
144 uint8_t capability_change;
145 uint16_t graphics_busy_flags;
146 uint16_t crc16;
147};
148
149struct __attribute__((packed)) mddi_client_caps {
150 uint16_t length; /* length, exclusive of this field */
151 uint16_t type; /* 66 */
152 uint16_t client_id;
153
154 uint16_t Protocol_Version;
155 uint16_t Minimum_Protocol_Version;
156 uint16_t Data_Rate_Capability;
157 uint8_t Interface_Type_Capability;
158 uint8_t Number_of_Alt_Displays;
159 uint16_t PostCal_Data_Rate;
160 uint16_t Bitmap_Width;
161 uint16_t Bitmap_Height;
162 uint16_t Display_Window_Width;
163 uint16_t Display_Window_Height;
164 uint32_t Color_Map_Size;
165 uint16_t Color_Map_RGB_Width;
166 uint16_t RGB_Capability;
167 uint8_t Monochrome_Capability;
168 uint8_t Reserved_1;
169 uint16_t Y_Cb_Cr_Capability;
170 uint16_t Bayer_Capability;
171 uint16_t Alpha_Cursor_Image_Planes;
172 uint32_t Client_Feature_Capability_Indicators;
173 uint8_t Maximum_Video_Frame_Rate_Capability;
174 uint8_t Minimum_Video_Frame_Rate_Capability;
175 uint16_t Minimum_Sub_frame_Rate;
176 uint16_t Audio_Buffer_Depth;
177 uint16_t Audio_Channel_Capability;
178 uint16_t Audio_Sample_Rate_Capability;
179 uint8_t Audio_Sample_Resolution;
180 uint8_t Mic_Audio_Sample_Resolution;
181 uint16_t Mic_Sample_Rate_Capability;
182 uint8_t Keyboard_Data_Format;
183 uint8_t pointing_device_data_format;
184 uint16_t content_protection_type;
185 uint16_t Mfr_Name;
186 uint16_t Product_Code;
187 uint16_t Reserved_3;
188 uint32_t Serial_Number;
189 uint8_t Week_of_Manufacture;
190 uint8_t Year_of_Manufacture;
191
192 uint16_t crc16;
193} mddi_client_capability_type;
194
195
196struct __attribute__((packed)) mddi_video_stream {
197 uint16_t length;
198 uint16_t type; /* 16 */
199 uint16_t client_id; /* 0 */
200
201 uint16_t video_data_format_descriptor;
202/* format of each pixel in the Pixel Data in the present stream in the
203 * present packet.
204 * If bits [15:13] = 000 monochrome
205 * If bits [15:13] = 001 color pixels (palette).
206 * If bits [15:13] = 010 color pixels in raw RGB
207 * If bits [15:13] = 011 data in 4:2:2 Y Cb Cr format
208 * If bits [15:13] = 100 Bayer pixels
209 */
210
211 uint16_t pixel_data_attributes;
212/* interpreted as follows:
213 * Bits [1:0] = 11 pixel data is displayed to both eyes
214 * Bits [1:0] = 10 pixel data is routed to the left eye only.
215 * Bits [1:0] = 01 pixel data is routed to the right eye only.
216 * Bits [1:0] = 00 pixel data is routed to the alternate display.
217 * Bit 2 is 0 Pixel Data is in the standard progressive format.
218 * Bit 2 is 1 Pixel Data is in interlace format.
219 * Bit 3 is 0 Pixel Data is in the standard progressive format.
220 * Bit 3 is 1 Pixel Data is in alternate pixel format.
221 * Bit 4 is 0 Pixel Data is to or from the display frame buffer.
222 * Bit 4 is 1 Pixel Data is to or from the camera.
223 * Bit 5 is 0 pixel data contains the next consecutive row of pixels.
224 * Bit 5 is 1 X Left Edge, Y Top Edge, X Right Edge, Y Bottom Edge,
225 * X Start, and Y Start parameters are not defined and
226 * shall be ignored by the client.
227 * Bits [7:6] = 01 Pixel data is written to the offline image buffer.
228 * Bits [7:6] = 00 Pixel data is written to the buffer to refresh display.
229 * Bits [7:6] = 11 Pixel data is written to all image buffers.
230 * Bits [7:6] = 10 Invalid. Reserved for future use.
231 * Bits 8 through 11 alternate display number.
232 * Bits 12 through 14 are reserved for future use and shall be set to zero.
233 * Bit 15 is 1 the row of pixels is the last row of pixels in a frame.
234 */
235
236 uint16_t x_left_edge;
237 uint16_t y_top_edge;
238 /* X,Y coordinate of the top left edge of the screen window */
239
240 uint16_t x_right_edge;
241 uint16_t y_bottom_edge;
242 /* X,Y coordinate of the bottom right edge of the window being
243 * updated. */
244
245 uint16_t x_start;
246 uint16_t y_start;
247 /* (X Start, Y Start) is the first pixel in the Pixel Data field
248 * below. */
249
250 uint16_t pixel_count;
251 /* number of pixels in the Pixel Data field below. */
252
253 uint16_t parameter_CRC;
254 /* 16-bit CRC of all bytes from the Packet Length to the Pixel Count. */
255
256 uint16_t reserved;
257 /* 16-bit variable to make structure align on 4 byte boundary */
258};
259
260#define TYPE_VIDEO_STREAM 16
261#define TYPE_CLIENT_CAPS 66
262#define TYPE_REGISTER_ACCESS 146
263#define TYPE_CLIENT_STATUS 70
264
265struct __attribute__((packed)) mddi_register_access {
266 uint16_t length;
267 uint16_t type; /* 146 */
268 uint16_t client_id;
269
270 uint16_t read_write_info;
271 /* Bits 13:0 a 14-bit unsigned integer that specifies the number of
272 * 32-bit Register Data List items to be transferred in the
273 * Register Data List field.
274 * Bits[15:14] = 00 Write to register(s);
275 * Bits[15:14] = 10 Read from register(s);
276 * Bits[15:14] = 11 Response to a Read.
277 * Bits[15:14] = 01 this value is reserved for future use. */
278#define MDDI_WRITE (0 << 14)
279#define MDDI_READ (2 << 14)
280#define MDDI_READ_RESP (3 << 14)
281
282 uint32_t register_address;
283 /* the register address that is to be written to or read from. */
284
285 uint16_t crc16;
286
287 uint32_t register_data_list;
288 /* list of 4-byte register data values for/from client registers */
289};
290
291struct __attribute__((packed)) mddi_llentry {
292 uint16_t flags;
293 uint16_t header_count;
294 uint16_t data_count;
295 dma_addr_t data; /* 32 bit */
296 struct mddi_llentry *next;
297 uint16_t reserved;
298 union {
299 struct mddi_video_stream v;
300 struct mddi_register_access r;
301 uint32_t _[12];
302 } u;
303};
304
305#endif
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
36struct class *mdp_class;
37
38#define MDP_CMD_DEBUG_ACCESS_BASE (0x10000)
39
40static uint16_t mdp_default_ccs[] = {
41 0x254, 0x000, 0x331, 0x254, 0xF38, 0xE61, 0x254, 0x409, 0x000,
42 0x010, 0x080, 0x080
43};
44
45static DECLARE_WAIT_QUEUE_HEAD(mdp_dma2_waitqueue);
46static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue);
47static struct msmfb_callback *dma_callback;
48static struct clk *clk;
49static unsigned int mdp_irq_mask;
50static DEFINE_SPINLOCK(mdp_lock);
51DEFINE_MUTEX(mdp_mutex);
52
53static 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
82static 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
102static 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
113static 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
143static 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
154static 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
173void 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
191static int mdp_ppp_wait(struct mdp_info *mdp)
192{
193 return mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue);
194}
195
196void 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
245void 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
257int 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
284void 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
294int 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;
369end:
370 put_img(src_file, dst_file);
371 mutex_unlock(&mdp_mutex);
372 return 0;
373err_bad_blit:
374 disable_mdp_irq(mdp, DL0_ROI_DONE);
375err_wait_failed:
376 put_img(src_file, dst_file);
377 mutex_unlock(&mdp_mutex);
378 return ret;
379}
380
381void 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
389int 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
402int 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
513error_device_register:
514 free_irq(mdp->irq, mdp);
515error_request_irq:
516 iounmap(mdp->base);
517error_get_irq:
518error_ioremap:
519 kfree(mdp);
520 return ret;
521}
522
523static struct platform_driver msm_mdp_driver = {
524 .probe = mdp_probe,
525 .driver = {.name = "msm_mdp"},
526};
527
528static 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
538subsys_initcall(mdp_init);
diff --git a/drivers/video/msm/mdp_csc_table.h b/drivers/video/msm/mdp_csc_table.h
new file mode 100644
index 000000000000..d1cde30ead52
--- /dev/null
+++ b/drivers/video/msm/mdp_csc_table.h
@@ -0,0 +1,582 @@
1/* drivers/video/msm_fb/mdp_csc_table.h
2 *
3 * Copyright (C) 2007 QUALCOMM Incorporated
4 * Copyright (C) 2007 Google Incorporated
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16static struct {
17 uint32_t reg;
18 uint32_t val;
19} csc_table[] = {
20 { 0x40400, 0x83 },
21 { 0x40404, 0x102 },
22 { 0x40408, 0x32 },
23 { 0x4040c, 0xffffffb5 },
24 { 0x40410, 0xffffff6c },
25 { 0x40414, 0xe1 },
26 { 0x40418, 0xe1 },
27 { 0x4041c, 0xffffff45 },
28 { 0x40420, 0xffffffdc },
29 { 0x40440, 0x254 },
30 { 0x40444, 0x0 },
31 { 0x40448, 0x331 },
32 { 0x4044c, 0x254 },
33 { 0x40450, 0xffffff38 },
34 { 0x40454, 0xfffffe61 },
35 { 0x40458, 0x254 },
36 { 0x4045c, 0x409 },
37 { 0x40460, 0x0 },
38 { 0x40480, 0x5d },
39 { 0x40484, 0x13a },
40 { 0x40488, 0x20 },
41 { 0x4048c, 0xffffffcd },
42 { 0x40490, 0xffffff54 },
43 { 0x40494, 0xe1 },
44 { 0x40498, 0xe1 },
45 { 0x4049c, 0xffffff35 },
46 { 0x404a0, 0xffffffec },
47 { 0x404c0, 0x254 },
48 { 0x404c4, 0x0 },
49 { 0x404c8, 0x396 },
50 { 0x404cc, 0x254 },
51 { 0x404d0, 0xffffff94 },
52 { 0x404d4, 0xfffffef0 },
53 { 0x404d8, 0x254 },
54 { 0x404dc, 0x43a },
55 { 0x404e0, 0x0 },
56 { 0x40500, 0x10 },
57 { 0x40504, 0x80 },
58 { 0x40508, 0x80 },
59 { 0x40540, 0x10 },
60 { 0x40544, 0x80 },
61 { 0x40548, 0x80 },
62 { 0x40580, 0x10 },
63 { 0x40584, 0xeb },
64 { 0x40588, 0x10 },
65 { 0x4058c, 0xf0 },
66 { 0x405c0, 0x10 },
67 { 0x405c4, 0xeb },
68 { 0x405c8, 0x10 },
69 { 0x405cc, 0xf0 },
70 { 0x40800, 0x0 },
71 { 0x40804, 0x151515 },
72 { 0x40808, 0x1d1d1d },
73 { 0x4080c, 0x232323 },
74 { 0x40810, 0x272727 },
75 { 0x40814, 0x2b2b2b },
76 { 0x40818, 0x2f2f2f },
77 { 0x4081c, 0x333333 },
78 { 0x40820, 0x363636 },
79 { 0x40824, 0x393939 },
80 { 0x40828, 0x3b3b3b },
81 { 0x4082c, 0x3e3e3e },
82 { 0x40830, 0x404040 },
83 { 0x40834, 0x434343 },
84 { 0x40838, 0x454545 },
85 { 0x4083c, 0x474747 },
86 { 0x40840, 0x494949 },
87 { 0x40844, 0x4b4b4b },
88 { 0x40848, 0x4d4d4d },
89 { 0x4084c, 0x4f4f4f },
90 { 0x40850, 0x515151 },
91 { 0x40854, 0x535353 },
92 { 0x40858, 0x555555 },
93 { 0x4085c, 0x565656 },
94 { 0x40860, 0x585858 },
95 { 0x40864, 0x5a5a5a },
96 { 0x40868, 0x5b5b5b },
97 { 0x4086c, 0x5d5d5d },
98 { 0x40870, 0x5e5e5e },
99 { 0x40874, 0x606060 },
100 { 0x40878, 0x616161 },
101 { 0x4087c, 0x636363 },
102 { 0x40880, 0x646464 },
103 { 0x40884, 0x666666 },
104 { 0x40888, 0x676767 },
105 { 0x4088c, 0x686868 },
106 { 0x40890, 0x6a6a6a },
107 { 0x40894, 0x6b6b6b },
108 { 0x40898, 0x6c6c6c },
109 { 0x4089c, 0x6e6e6e },
110 { 0x408a0, 0x6f6f6f },
111 { 0x408a4, 0x707070 },
112 { 0x408a8, 0x717171 },
113 { 0x408ac, 0x727272 },
114 { 0x408b0, 0x747474 },
115 { 0x408b4, 0x757575 },
116 { 0x408b8, 0x767676 },
117 { 0x408bc, 0x777777 },
118 { 0x408c0, 0x787878 },
119 { 0x408c4, 0x797979 },
120 { 0x408c8, 0x7a7a7a },
121 { 0x408cc, 0x7c7c7c },
122 { 0x408d0, 0x7d7d7d },
123 { 0x408d4, 0x7e7e7e },
124 { 0x408d8, 0x7f7f7f },
125 { 0x408dc, 0x808080 },
126 { 0x408e0, 0x818181 },
127 { 0x408e4, 0x828282 },
128 { 0x408e8, 0x838383 },
129 { 0x408ec, 0x848484 },
130 { 0x408f0, 0x858585 },
131 { 0x408f4, 0x868686 },
132 { 0x408f8, 0x878787 },
133 { 0x408fc, 0x888888 },
134 { 0x40900, 0x898989 },
135 { 0x40904, 0x8a8a8a },
136 { 0x40908, 0x8b8b8b },
137 { 0x4090c, 0x8c8c8c },
138 { 0x40910, 0x8d8d8d },
139 { 0x40914, 0x8e8e8e },
140 { 0x40918, 0x8f8f8f },
141 { 0x4091c, 0x8f8f8f },
142 { 0x40920, 0x909090 },
143 { 0x40924, 0x919191 },
144 { 0x40928, 0x929292 },
145 { 0x4092c, 0x939393 },
146 { 0x40930, 0x949494 },
147 { 0x40934, 0x959595 },
148 { 0x40938, 0x969696 },
149 { 0x4093c, 0x969696 },
150 { 0x40940, 0x979797 },
151 { 0x40944, 0x989898 },
152 { 0x40948, 0x999999 },
153 { 0x4094c, 0x9a9a9a },
154 { 0x40950, 0x9b9b9b },
155 { 0x40954, 0x9c9c9c },
156 { 0x40958, 0x9c9c9c },
157 { 0x4095c, 0x9d9d9d },
158 { 0x40960, 0x9e9e9e },
159 { 0x40964, 0x9f9f9f },
160 { 0x40968, 0xa0a0a0 },
161 { 0x4096c, 0xa0a0a0 },
162 { 0x40970, 0xa1a1a1 },
163 { 0x40974, 0xa2a2a2 },
164 { 0x40978, 0xa3a3a3 },
165 { 0x4097c, 0xa4a4a4 },
166 { 0x40980, 0xa4a4a4 },
167 { 0x40984, 0xa5a5a5 },
168 { 0x40988, 0xa6a6a6 },
169 { 0x4098c, 0xa7a7a7 },
170 { 0x40990, 0xa7a7a7 },
171 { 0x40994, 0xa8a8a8 },
172 { 0x40998, 0xa9a9a9 },
173 { 0x4099c, 0xaaaaaa },
174 { 0x409a0, 0xaaaaaa },
175 { 0x409a4, 0xababab },
176 { 0x409a8, 0xacacac },
177 { 0x409ac, 0xadadad },
178 { 0x409b0, 0xadadad },
179 { 0x409b4, 0xaeaeae },
180 { 0x409b8, 0xafafaf },
181 { 0x409bc, 0xafafaf },
182 { 0x409c0, 0xb0b0b0 },
183 { 0x409c4, 0xb1b1b1 },
184 { 0x409c8, 0xb2b2b2 },
185 { 0x409cc, 0xb2b2b2 },
186 { 0x409d0, 0xb3b3b3 },
187 { 0x409d4, 0xb4b4b4 },
188 { 0x409d8, 0xb4b4b4 },
189 { 0x409dc, 0xb5b5b5 },
190 { 0x409e0, 0xb6b6b6 },
191 { 0x409e4, 0xb6b6b6 },
192 { 0x409e8, 0xb7b7b7 },
193 { 0x409ec, 0xb8b8b8 },
194 { 0x409f0, 0xb8b8b8 },
195 { 0x409f4, 0xb9b9b9 },
196 { 0x409f8, 0xbababa },
197 { 0x409fc, 0xbababa },
198 { 0x40a00, 0xbbbbbb },
199 { 0x40a04, 0xbcbcbc },
200 { 0x40a08, 0xbcbcbc },
201 { 0x40a0c, 0xbdbdbd },
202 { 0x40a10, 0xbebebe },
203 { 0x40a14, 0xbebebe },
204 { 0x40a18, 0xbfbfbf },
205 { 0x40a1c, 0xc0c0c0 },
206 { 0x40a20, 0xc0c0c0 },
207 { 0x40a24, 0xc1c1c1 },
208 { 0x40a28, 0xc1c1c1 },
209 { 0x40a2c, 0xc2c2c2 },
210 { 0x40a30, 0xc3c3c3 },
211 { 0x40a34, 0xc3c3c3 },
212 { 0x40a38, 0xc4c4c4 },
213 { 0x40a3c, 0xc5c5c5 },
214 { 0x40a40, 0xc5c5c5 },
215 { 0x40a44, 0xc6c6c6 },
216 { 0x40a48, 0xc6c6c6 },
217 { 0x40a4c, 0xc7c7c7 },
218 { 0x40a50, 0xc8c8c8 },
219 { 0x40a54, 0xc8c8c8 },
220 { 0x40a58, 0xc9c9c9 },
221 { 0x40a5c, 0xc9c9c9 },
222 { 0x40a60, 0xcacaca },
223 { 0x40a64, 0xcbcbcb },
224 { 0x40a68, 0xcbcbcb },
225 { 0x40a6c, 0xcccccc },
226 { 0x40a70, 0xcccccc },
227 { 0x40a74, 0xcdcdcd },
228 { 0x40a78, 0xcecece },
229 { 0x40a7c, 0xcecece },
230 { 0x40a80, 0xcfcfcf },
231 { 0x40a84, 0xcfcfcf },
232 { 0x40a88, 0xd0d0d0 },
233 { 0x40a8c, 0xd0d0d0 },
234 { 0x40a90, 0xd1d1d1 },
235 { 0x40a94, 0xd2d2d2 },
236 { 0x40a98, 0xd2d2d2 },
237 { 0x40a9c, 0xd3d3d3 },
238 { 0x40aa0, 0xd3d3d3 },
239 { 0x40aa4, 0xd4d4d4 },
240 { 0x40aa8, 0xd4d4d4 },
241 { 0x40aac, 0xd5d5d5 },
242 { 0x40ab0, 0xd6d6d6 },
243 { 0x40ab4, 0xd6d6d6 },
244 { 0x40ab8, 0xd7d7d7 },
245 { 0x40abc, 0xd7d7d7 },
246 { 0x40ac0, 0xd8d8d8 },
247 { 0x40ac4, 0xd8d8d8 },
248 { 0x40ac8, 0xd9d9d9 },
249 { 0x40acc, 0xd9d9d9 },
250 { 0x40ad0, 0xdadada },
251 { 0x40ad4, 0xdbdbdb },
252 { 0x40ad8, 0xdbdbdb },
253 { 0x40adc, 0xdcdcdc },
254 { 0x40ae0, 0xdcdcdc },
255 { 0x40ae4, 0xdddddd },
256 { 0x40ae8, 0xdddddd },
257 { 0x40aec, 0xdedede },
258 { 0x40af0, 0xdedede },
259 { 0x40af4, 0xdfdfdf },
260 { 0x40af8, 0xdfdfdf },
261 { 0x40afc, 0xe0e0e0 },
262 { 0x40b00, 0xe0e0e0 },
263 { 0x40b04, 0xe1e1e1 },
264 { 0x40b08, 0xe1e1e1 },
265 { 0x40b0c, 0xe2e2e2 },
266 { 0x40b10, 0xe3e3e3 },
267 { 0x40b14, 0xe3e3e3 },
268 { 0x40b18, 0xe4e4e4 },
269 { 0x40b1c, 0xe4e4e4 },
270 { 0x40b20, 0xe5e5e5 },
271 { 0x40b24, 0xe5e5e5 },
272 { 0x40b28, 0xe6e6e6 },
273 { 0x40b2c, 0xe6e6e6 },
274 { 0x40b30, 0xe7e7e7 },
275 { 0x40b34, 0xe7e7e7 },
276 { 0x40b38, 0xe8e8e8 },
277 { 0x40b3c, 0xe8e8e8 },
278 { 0x40b40, 0xe9e9e9 },
279 { 0x40b44, 0xe9e9e9 },
280 { 0x40b48, 0xeaeaea },
281 { 0x40b4c, 0xeaeaea },
282 { 0x40b50, 0xebebeb },
283 { 0x40b54, 0xebebeb },
284 { 0x40b58, 0xececec },
285 { 0x40b5c, 0xececec },
286 { 0x40b60, 0xededed },
287 { 0x40b64, 0xededed },
288 { 0x40b68, 0xeeeeee },
289 { 0x40b6c, 0xeeeeee },
290 { 0x40b70, 0xefefef },
291 { 0x40b74, 0xefefef },
292 { 0x40b78, 0xf0f0f0 },
293 { 0x40b7c, 0xf0f0f0 },
294 { 0x40b80, 0xf1f1f1 },
295 { 0x40b84, 0xf1f1f1 },
296 { 0x40b88, 0xf2f2f2 },
297 { 0x40b8c, 0xf2f2f2 },
298 { 0x40b90, 0xf2f2f2 },
299 { 0x40b94, 0xf3f3f3 },
300 { 0x40b98, 0xf3f3f3 },
301 { 0x40b9c, 0xf4f4f4 },
302 { 0x40ba0, 0xf4f4f4 },
303 { 0x40ba4, 0xf5f5f5 },
304 { 0x40ba8, 0xf5f5f5 },
305 { 0x40bac, 0xf6f6f6 },
306 { 0x40bb0, 0xf6f6f6 },
307 { 0x40bb4, 0xf7f7f7 },
308 { 0x40bb8, 0xf7f7f7 },
309 { 0x40bbc, 0xf8f8f8 },
310 { 0x40bc0, 0xf8f8f8 },
311 { 0x40bc4, 0xf9f9f9 },
312 { 0x40bc8, 0xf9f9f9 },
313 { 0x40bcc, 0xfafafa },
314 { 0x40bd0, 0xfafafa },
315 { 0x40bd4, 0xfafafa },
316 { 0x40bd8, 0xfbfbfb },
317 { 0x40bdc, 0xfbfbfb },
318 { 0x40be0, 0xfcfcfc },
319 { 0x40be4, 0xfcfcfc },
320 { 0x40be8, 0xfdfdfd },
321 { 0x40bec, 0xfdfdfd },
322 { 0x40bf0, 0xfefefe },
323 { 0x40bf4, 0xfefefe },
324 { 0x40bf8, 0xffffff },
325 { 0x40bfc, 0xffffff },
326 { 0x40c00, 0x0 },
327 { 0x40c04, 0x0 },
328 { 0x40c08, 0x0 },
329 { 0x40c0c, 0x0 },
330 { 0x40c10, 0x0 },
331 { 0x40c14, 0x0 },
332 { 0x40c18, 0x0 },
333 { 0x40c1c, 0x0 },
334 { 0x40c20, 0x0 },
335 { 0x40c24, 0x0 },
336 { 0x40c28, 0x0 },
337 { 0x40c2c, 0x0 },
338 { 0x40c30, 0x0 },
339 { 0x40c34, 0x0 },
340 { 0x40c38, 0x0 },
341 { 0x40c3c, 0x0 },
342 { 0x40c40, 0x10101 },
343 { 0x40c44, 0x10101 },
344 { 0x40c48, 0x10101 },
345 { 0x40c4c, 0x10101 },
346 { 0x40c50, 0x10101 },
347 { 0x40c54, 0x10101 },
348 { 0x40c58, 0x10101 },
349 { 0x40c5c, 0x10101 },
350 { 0x40c60, 0x10101 },
351 { 0x40c64, 0x10101 },
352 { 0x40c68, 0x20202 },
353 { 0x40c6c, 0x20202 },
354 { 0x40c70, 0x20202 },
355 { 0x40c74, 0x20202 },
356 { 0x40c78, 0x20202 },
357 { 0x40c7c, 0x20202 },
358 { 0x40c80, 0x30303 },
359 { 0x40c84, 0x30303 },
360 { 0x40c88, 0x30303 },
361 { 0x40c8c, 0x30303 },
362 { 0x40c90, 0x30303 },
363 { 0x40c94, 0x40404 },
364 { 0x40c98, 0x40404 },
365 { 0x40c9c, 0x40404 },
366 { 0x40ca0, 0x40404 },
367 { 0x40ca4, 0x40404 },
368 { 0x40ca8, 0x50505 },
369 { 0x40cac, 0x50505 },
370 { 0x40cb0, 0x50505 },
371 { 0x40cb4, 0x50505 },
372 { 0x40cb8, 0x60606 },
373 { 0x40cbc, 0x60606 },
374 { 0x40cc0, 0x60606 },
375 { 0x40cc4, 0x70707 },
376 { 0x40cc8, 0x70707 },
377 { 0x40ccc, 0x70707 },
378 { 0x40cd0, 0x70707 },
379 { 0x40cd4, 0x80808 },
380 { 0x40cd8, 0x80808 },
381 { 0x40cdc, 0x80808 },
382 { 0x40ce0, 0x90909 },
383 { 0x40ce4, 0x90909 },
384 { 0x40ce8, 0xa0a0a },
385 { 0x40cec, 0xa0a0a },
386 { 0x40cf0, 0xa0a0a },
387 { 0x40cf4, 0xb0b0b },
388 { 0x40cf8, 0xb0b0b },
389 { 0x40cfc, 0xb0b0b },
390 { 0x40d00, 0xc0c0c },
391 { 0x40d04, 0xc0c0c },
392 { 0x40d08, 0xd0d0d },
393 { 0x40d0c, 0xd0d0d },
394 { 0x40d10, 0xe0e0e },
395 { 0x40d14, 0xe0e0e },
396 { 0x40d18, 0xe0e0e },
397 { 0x40d1c, 0xf0f0f },
398 { 0x40d20, 0xf0f0f },
399 { 0x40d24, 0x101010 },
400 { 0x40d28, 0x101010 },
401 { 0x40d2c, 0x111111 },
402 { 0x40d30, 0x111111 },
403 { 0x40d34, 0x121212 },
404 { 0x40d38, 0x121212 },
405 { 0x40d3c, 0x131313 },
406 { 0x40d40, 0x131313 },
407 { 0x40d44, 0x141414 },
408 { 0x40d48, 0x151515 },
409 { 0x40d4c, 0x151515 },
410 { 0x40d50, 0x161616 },
411 { 0x40d54, 0x161616 },
412 { 0x40d58, 0x171717 },
413 { 0x40d5c, 0x171717 },
414 { 0x40d60, 0x181818 },
415 { 0x40d64, 0x191919 },
416 { 0x40d68, 0x191919 },
417 { 0x40d6c, 0x1a1a1a },
418 { 0x40d70, 0x1b1b1b },
419 { 0x40d74, 0x1b1b1b },
420 { 0x40d78, 0x1c1c1c },
421 { 0x40d7c, 0x1c1c1c },
422 { 0x40d80, 0x1d1d1d },
423 { 0x40d84, 0x1e1e1e },
424 { 0x40d88, 0x1f1f1f },
425 { 0x40d8c, 0x1f1f1f },
426 { 0x40d90, 0x202020 },
427 { 0x40d94, 0x212121 },
428 { 0x40d98, 0x212121 },
429 { 0x40d9c, 0x222222 },
430 { 0x40da0, 0x232323 },
431 { 0x40da4, 0x242424 },
432 { 0x40da8, 0x242424 },
433 { 0x40dac, 0x252525 },
434 { 0x40db0, 0x262626 },
435 { 0x40db4, 0x272727 },
436 { 0x40db8, 0x272727 },
437 { 0x40dbc, 0x282828 },
438 { 0x40dc0, 0x292929 },
439 { 0x40dc4, 0x2a2a2a },
440 { 0x40dc8, 0x2b2b2b },
441 { 0x40dcc, 0x2c2c2c },
442 { 0x40dd0, 0x2c2c2c },
443 { 0x40dd4, 0x2d2d2d },
444 { 0x40dd8, 0x2e2e2e },
445 { 0x40ddc, 0x2f2f2f },
446 { 0x40de0, 0x303030 },
447 { 0x40de4, 0x313131 },
448 { 0x40de8, 0x323232 },
449 { 0x40dec, 0x333333 },
450 { 0x40df0, 0x333333 },
451 { 0x40df4, 0x343434 },
452 { 0x40df8, 0x353535 },
453 { 0x40dfc, 0x363636 },
454 { 0x40e00, 0x373737 },
455 { 0x40e04, 0x383838 },
456 { 0x40e08, 0x393939 },
457 { 0x40e0c, 0x3a3a3a },
458 { 0x40e10, 0x3b3b3b },
459 { 0x40e14, 0x3c3c3c },
460 { 0x40e18, 0x3d3d3d },
461 { 0x40e1c, 0x3e3e3e },
462 { 0x40e20, 0x3f3f3f },
463 { 0x40e24, 0x404040 },
464 { 0x40e28, 0x414141 },
465 { 0x40e2c, 0x424242 },
466 { 0x40e30, 0x434343 },
467 { 0x40e34, 0x444444 },
468 { 0x40e38, 0x464646 },
469 { 0x40e3c, 0x474747 },
470 { 0x40e40, 0x484848 },
471 { 0x40e44, 0x494949 },
472 { 0x40e48, 0x4a4a4a },
473 { 0x40e4c, 0x4b4b4b },
474 { 0x40e50, 0x4c4c4c },
475 { 0x40e54, 0x4d4d4d },
476 { 0x40e58, 0x4f4f4f },
477 { 0x40e5c, 0x505050 },
478 { 0x40e60, 0x515151 },
479 { 0x40e64, 0x525252 },
480 { 0x40e68, 0x535353 },
481 { 0x40e6c, 0x545454 },
482 { 0x40e70, 0x565656 },
483 { 0x40e74, 0x575757 },
484 { 0x40e78, 0x585858 },
485 { 0x40e7c, 0x595959 },
486 { 0x40e80, 0x5b5b5b },
487 { 0x40e84, 0x5c5c5c },
488 { 0x40e88, 0x5d5d5d },
489 { 0x40e8c, 0x5e5e5e },
490 { 0x40e90, 0x606060 },
491 { 0x40e94, 0x616161 },
492 { 0x40e98, 0x626262 },
493 { 0x40e9c, 0x646464 },
494 { 0x40ea0, 0x656565 },
495 { 0x40ea4, 0x666666 },
496 { 0x40ea8, 0x686868 },
497 { 0x40eac, 0x696969 },
498 { 0x40eb0, 0x6a6a6a },
499 { 0x40eb4, 0x6c6c6c },
500 { 0x40eb8, 0x6d6d6d },
501 { 0x40ebc, 0x6f6f6f },
502 { 0x40ec0, 0x707070 },
503 { 0x40ec4, 0x717171 },
504 { 0x40ec8, 0x737373 },
505 { 0x40ecc, 0x747474 },
506 { 0x40ed0, 0x767676 },
507 { 0x40ed4, 0x777777 },
508 { 0x40ed8, 0x797979 },
509 { 0x40edc, 0x7a7a7a },
510 { 0x40ee0, 0x7c7c7c },
511 { 0x40ee4, 0x7d7d7d },
512 { 0x40ee8, 0x7f7f7f },
513 { 0x40eec, 0x808080 },
514 { 0x40ef0, 0x828282 },
515 { 0x40ef4, 0x838383 },
516 { 0x40ef8, 0x858585 },
517 { 0x40efc, 0x868686 },
518 { 0x40f00, 0x888888 },
519 { 0x40f04, 0x898989 },
520 { 0x40f08, 0x8b8b8b },
521 { 0x40f0c, 0x8d8d8d },
522 { 0x40f10, 0x8e8e8e },
523 { 0x40f14, 0x909090 },
524 { 0x40f18, 0x919191 },
525 { 0x40f1c, 0x939393 },
526 { 0x40f20, 0x959595 },
527 { 0x40f24, 0x969696 },
528 { 0x40f28, 0x989898 },
529 { 0x40f2c, 0x9a9a9a },
530 { 0x40f30, 0x9b9b9b },
531 { 0x40f34, 0x9d9d9d },
532 { 0x40f38, 0x9f9f9f },
533 { 0x40f3c, 0xa1a1a1 },
534 { 0x40f40, 0xa2a2a2 },
535 { 0x40f44, 0xa4a4a4 },
536 { 0x40f48, 0xa6a6a6 },
537 { 0x40f4c, 0xa7a7a7 },
538 { 0x40f50, 0xa9a9a9 },
539 { 0x40f54, 0xababab },
540 { 0x40f58, 0xadadad },
541 { 0x40f5c, 0xafafaf },
542 { 0x40f60, 0xb0b0b0 },
543 { 0x40f64, 0xb2b2b2 },
544 { 0x40f68, 0xb4b4b4 },
545 { 0x40f6c, 0xb6b6b6 },
546 { 0x40f70, 0xb8b8b8 },
547 { 0x40f74, 0xbababa },
548 { 0x40f78, 0xbbbbbb },
549 { 0x40f7c, 0xbdbdbd },
550 { 0x40f80, 0xbfbfbf },
551 { 0x40f84, 0xc1c1c1 },
552 { 0x40f88, 0xc3c3c3 },
553 { 0x40f8c, 0xc5c5c5 },
554 { 0x40f90, 0xc7c7c7 },
555 { 0x40f94, 0xc9c9c9 },
556 { 0x40f98, 0xcbcbcb },
557 { 0x40f9c, 0xcdcdcd },
558 { 0x40fa0, 0xcfcfcf },
559 { 0x40fa4, 0xd1d1d1 },
560 { 0x40fa8, 0xd3d3d3 },
561 { 0x40fac, 0xd5d5d5 },
562 { 0x40fb0, 0xd7d7d7 },
563 { 0x40fb4, 0xd9d9d9 },
564 { 0x40fb8, 0xdbdbdb },
565 { 0x40fbc, 0xdddddd },
566 { 0x40fc0, 0xdfdfdf },
567 { 0x40fc4, 0xe1e1e1 },
568 { 0x40fc8, 0xe3e3e3 },
569 { 0x40fcc, 0xe5e5e5 },
570 { 0x40fd0, 0xe7e7e7 },
571 { 0x40fd4, 0xe9e9e9 },
572 { 0x40fd8, 0xebebeb },
573 { 0x40fdc, 0xeeeeee },
574 { 0x40fe0, 0xf0f0f0 },
575 { 0x40fe4, 0xf2f2f2 },
576 { 0x40fe8, 0xf4f4f4 },
577 { 0x40fec, 0xf6f6f6 },
578 { 0x40ff0, 0xf8f8f8 },
579 { 0x40ff4, 0xfbfbfb },
580 { 0x40ff8, 0xfdfdfd },
581 { 0x40ffc, 0xffffff },
582};
diff --git a/drivers/video/msm/mdp_hw.h b/drivers/video/msm/mdp_hw.h
new file mode 100644
index 000000000000..4e3deb4e592b
--- /dev/null
+++ b/drivers/video/msm/mdp_hw.h
@@ -0,0 +1,621 @@
1/* drivers/video/msm_fb/mdp_hw.h
2 *
3 * Copyright (C) 2007 QUALCOMM Incorporated
4 * Copyright (C) 2007 Google Incorporated
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15#ifndef _MDP_HW_H_
16#define _MDP_HW_H_
17
18#include <mach/msm_iomap.h>
19#include <mach/msm_fb.h>
20
21struct mdp_info {
22 struct mdp_device mdp_dev;
23 char * __iomem base;
24 int irq;
25};
26struct mdp_blit_req;
27struct mdp_device;
28int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
29 struct file *src_file, unsigned long src_start,
30 unsigned long src_len, struct file *dst_file,
31 unsigned long dst_start, unsigned long dst_len);
32#define mdp_writel(mdp, value, offset) writel(value, mdp->base + offset)
33#define mdp_readl(mdp, offset) readl(mdp->base + offset)
34
35#define MDP_SYNC_CONFIG_0 (0x00000)
36#define MDP_SYNC_CONFIG_1 (0x00004)
37#define MDP_SYNC_CONFIG_2 (0x00008)
38#define MDP_SYNC_STATUS_0 (0x0000c)
39#define MDP_SYNC_STATUS_1 (0x00010)
40#define MDP_SYNC_STATUS_2 (0x00014)
41#define MDP_SYNC_THRESH_0 (0x00018)
42#define MDP_SYNC_THRESH_1 (0x0001c)
43#define MDP_INTR_ENABLE (0x00020)
44#define MDP_INTR_STATUS (0x00024)
45#define MDP_INTR_CLEAR (0x00028)
46#define MDP_DISPLAY0_START (0x00030)
47#define MDP_DISPLAY1_START (0x00034)
48#define MDP_DISPLAY_STATUS (0x00038)
49#define MDP_EBI2_LCD0 (0x0003c)
50#define MDP_EBI2_LCD1 (0x00040)
51#define MDP_DISPLAY0_ADDR (0x00054)
52#define MDP_DISPLAY1_ADDR (0x00058)
53#define MDP_EBI2_PORTMAP_MODE (0x0005c)
54#define MDP_MODE (0x00060)
55#define MDP_TV_OUT_STATUS (0x00064)
56#define MDP_HW_VERSION (0x00070)
57#define MDP_SW_RESET (0x00074)
58#define MDP_AXI_ERROR_MASTER_STOP (0x00078)
59#define MDP_SEL_CLK_OR_HCLK_TEST_BUS (0x0007c)
60#define MDP_PRIMARY_VSYNC_OUT_CTRL (0x00080)
61#define MDP_SECONDARY_VSYNC_OUT_CTRL (0x00084)
62#define MDP_EXTERNAL_VSYNC_OUT_CTRL (0x00088)
63#define MDP_VSYNC_CTRL (0x0008c)
64#define MDP_CGC_EN (0x00100)
65#define MDP_CMD_STATUS (0x10008)
66#define MDP_PROFILE_EN (0x10010)
67#define MDP_PROFILE_COUNT (0x10014)
68#define MDP_DMA_START (0x10044)
69#define MDP_FULL_BYPASS_WORD0 (0x10100)
70#define MDP_FULL_BYPASS_WORD1 (0x10104)
71#define MDP_COMMAND_CONFIG (0x10104)
72#define MDP_FULL_BYPASS_WORD2 (0x10108)
73#define MDP_FULL_BYPASS_WORD3 (0x1010c)
74#define MDP_FULL_BYPASS_WORD4 (0x10110)
75#define MDP_FULL_BYPASS_WORD6 (0x10118)
76#define MDP_FULL_BYPASS_WORD7 (0x1011c)
77#define MDP_FULL_BYPASS_WORD8 (0x10120)
78#define MDP_FULL_BYPASS_WORD9 (0x10124)
79#define MDP_PPP_SOURCE_CONFIG (0x10124)
80#define MDP_FULL_BYPASS_WORD10 (0x10128)
81#define MDP_FULL_BYPASS_WORD11 (0x1012c)
82#define MDP_FULL_BYPASS_WORD12 (0x10130)
83#define MDP_FULL_BYPASS_WORD13 (0x10134)
84#define MDP_FULL_BYPASS_WORD14 (0x10138)
85#define MDP_PPP_OPERATION_CONFIG (0x10138)
86#define MDP_FULL_BYPASS_WORD15 (0x1013c)
87#define MDP_FULL_BYPASS_WORD16 (0x10140)
88#define MDP_FULL_BYPASS_WORD17 (0x10144)
89#define MDP_FULL_BYPASS_WORD18 (0x10148)
90#define MDP_FULL_BYPASS_WORD19 (0x1014c)
91#define MDP_FULL_BYPASS_WORD20 (0x10150)
92#define MDP_PPP_DESTINATION_CONFIG (0x10150)
93#define MDP_FULL_BYPASS_WORD21 (0x10154)
94#define MDP_FULL_BYPASS_WORD22 (0x10158)
95#define MDP_FULL_BYPASS_WORD23 (0x1015c)
96#define MDP_FULL_BYPASS_WORD24 (0x10160)
97#define MDP_FULL_BYPASS_WORD25 (0x10164)
98#define MDP_FULL_BYPASS_WORD26 (0x10168)
99#define MDP_FULL_BYPASS_WORD27 (0x1016c)
100#define MDP_FULL_BYPASS_WORD29 (0x10174)
101#define MDP_FULL_BYPASS_WORD30 (0x10178)
102#define MDP_FULL_BYPASS_WORD31 (0x1017c)
103#define MDP_FULL_BYPASS_WORD32 (0x10180)
104#define MDP_DMA_CONFIG (0x10180)
105#define MDP_FULL_BYPASS_WORD33 (0x10184)
106#define MDP_FULL_BYPASS_WORD34 (0x10188)
107#define MDP_FULL_BYPASS_WORD35 (0x1018c)
108#define MDP_FULL_BYPASS_WORD37 (0x10194)
109#define MDP_FULL_BYPASS_WORD39 (0x1019c)
110#define MDP_FULL_BYPASS_WORD40 (0x101a0)
111#define MDP_FULL_BYPASS_WORD41 (0x101a4)
112#define MDP_FULL_BYPASS_WORD43 (0x101ac)
113#define MDP_FULL_BYPASS_WORD46 (0x101b8)
114#define MDP_FULL_BYPASS_WORD47 (0x101bc)
115#define MDP_FULL_BYPASS_WORD48 (0x101c0)
116#define MDP_FULL_BYPASS_WORD49 (0x101c4)
117#define MDP_FULL_BYPASS_WORD50 (0x101c8)
118#define MDP_FULL_BYPASS_WORD51 (0x101cc)
119#define MDP_FULL_BYPASS_WORD52 (0x101d0)
120#define MDP_FULL_BYPASS_WORD53 (0x101d4)
121#define MDP_FULL_BYPASS_WORD54 (0x101d8)
122#define MDP_FULL_BYPASS_WORD55 (0x101dc)
123#define MDP_FULL_BYPASS_WORD56 (0x101e0)
124#define MDP_FULL_BYPASS_WORD57 (0x101e4)
125#define MDP_FULL_BYPASS_WORD58 (0x101e8)
126#define MDP_FULL_BYPASS_WORD59 (0x101ec)
127#define MDP_FULL_BYPASS_WORD60 (0x101f0)
128#define MDP_VSYNC_THRESHOLD (0x101f0)
129#define MDP_FULL_BYPASS_WORD61 (0x101f4)
130#define MDP_FULL_BYPASS_WORD62 (0x101f8)
131#define MDP_FULL_BYPASS_WORD63 (0x101fc)
132#define MDP_TFETCH_TEST_MODE (0x20004)
133#define MDP_TFETCH_STATUS (0x20008)
134#define MDP_TFETCH_TILE_COUNT (0x20010)
135#define MDP_TFETCH_FETCH_COUNT (0x20014)
136#define MDP_TFETCH_CONSTANT_COLOR (0x20040)
137#define MDP_CSC_BYPASS (0x40004)
138#define MDP_SCALE_COEFF_LSB (0x5fffc)
139#define MDP_TV_OUT_CTL (0xc0000)
140#define MDP_TV_OUT_FIR_COEFF (0xc0004)
141#define MDP_TV_OUT_BUF_ADDR (0xc0008)
142#define MDP_TV_OUT_CC_DATA (0xc000c)
143#define MDP_TV_OUT_SOBEL (0xc0010)
144#define MDP_TV_OUT_Y_CLAMP (0xc0018)
145#define MDP_TV_OUT_CB_CLAMP (0xc001c)
146#define MDP_TV_OUT_CR_CLAMP (0xc0020)
147#define MDP_TEST_MODE_CLK (0xd0000)
148#define MDP_TEST_MISR_RESET_CLK (0xd0004)
149#define MDP_TEST_EXPORT_MISR_CLK (0xd0008)
150#define MDP_TEST_MISR_CURR_VAL_CLK (0xd000c)
151#define MDP_TEST_MODE_HCLK (0xd0100)
152#define MDP_TEST_MISR_RESET_HCLK (0xd0104)
153#define MDP_TEST_EXPORT_MISR_HCLK (0xd0108)
154#define MDP_TEST_MISR_CURR_VAL_HCLK (0xd010c)
155#define MDP_TEST_MODE_DCLK (0xd0200)
156#define MDP_TEST_MISR_RESET_DCLK (0xd0204)
157#define MDP_TEST_EXPORT_MISR_DCLK (0xd0208)
158#define MDP_TEST_MISR_CURR_VAL_DCLK (0xd020c)
159#define MDP_TEST_CAPTURED_DCLK (0xd0210)
160#define MDP_TEST_MISR_CAPT_VAL_DCLK (0xd0214)
161#define MDP_LCDC_CTL (0xe0000)
162#define MDP_LCDC_HSYNC_CTL (0xe0004)
163#define MDP_LCDC_VSYNC_CTL (0xe0008)
164#define MDP_LCDC_ACTIVE_HCTL (0xe000c)
165#define MDP_LCDC_ACTIVE_VCTL (0xe0010)
166#define MDP_LCDC_BORDER_CLR (0xe0014)
167#define MDP_LCDC_H_BLANK (0xe0018)
168#define MDP_LCDC_V_BLANK (0xe001c)
169#define MDP_LCDC_UNDERFLOW_CLR (0xe0020)
170#define MDP_LCDC_HSYNC_SKEW (0xe0024)
171#define MDP_LCDC_TEST_CTL (0xe0028)
172#define MDP_LCDC_LINE_IRQ (0xe002c)
173#define MDP_LCDC_CTL_POLARITY (0xe0030)
174#define MDP_LCDC_DMA_CONFIG (0xe1000)
175#define MDP_LCDC_DMA_SIZE (0xe1004)
176#define MDP_LCDC_DMA_IBUF_ADDR (0xe1008)
177#define MDP_LCDC_DMA_IBUF_Y_STRIDE (0xe100c)
178
179
180#define MDP_DMA2_TERM 0x1
181#define MDP_DMA3_TERM 0x2
182#define MDP_PPP_TERM 0x3
183
184/* MDP_INTR_ENABLE */
185#define DL0_ROI_DONE (1<<0)
186#define DL1_ROI_DONE (1<<1)
187#define DL0_DMA2_TERM_DONE (1<<2)
188#define DL1_DMA2_TERM_DONE (1<<3)
189#define DL0_PPP_TERM_DONE (1<<4)
190#define DL1_PPP_TERM_DONE (1<<5)
191#define TV_OUT_DMA3_DONE (1<<6)
192#define TV_ENC_UNDERRUN (1<<7)
193#define DL0_FETCH_DONE (1<<11)
194#define DL1_FETCH_DONE (1<<12)
195
196#define MDP_PPP_BUSY_STATUS (DL0_ROI_DONE| \
197 DL1_ROI_DONE| \
198 DL0_PPP_TERM_DONE| \
199 DL1_PPP_TERM_DONE)
200
201#define MDP_ANY_INTR_MASK (DL0_ROI_DONE| \
202 DL1_ROI_DONE| \
203 DL0_DMA2_TERM_DONE| \
204 DL1_DMA2_TERM_DONE| \
205 DL0_PPP_TERM_DONE| \
206 DL1_PPP_TERM_DONE| \
207 DL0_FETCH_DONE| \
208 DL1_FETCH_DONE| \
209 TV_ENC_UNDERRUN)
210
211#define MDP_TOP_LUMA 16
212#define MDP_TOP_CHROMA 0
213#define MDP_BOTTOM_LUMA 19
214#define MDP_BOTTOM_CHROMA 3
215#define MDP_LEFT_LUMA 22
216#define MDP_LEFT_CHROMA 6
217#define MDP_RIGHT_LUMA 25
218#define MDP_RIGHT_CHROMA 9
219
220#define CLR_G 0x0
221#define CLR_B 0x1
222#define CLR_R 0x2
223#define CLR_ALPHA 0x3
224
225#define CLR_Y CLR_G
226#define CLR_CB CLR_B
227#define CLR_CR CLR_R
228
229/* from lsb to msb */
230#define MDP_GET_PACK_PATTERN(a, x, y, z, bit) \
231 (((a)<<(bit*3))|((x)<<(bit*2))|((y)<<bit)|(z))
232
233/* MDP_SYNC_CONFIG_0/1/2 */
234#define MDP_SYNCFG_HGT_LOC 22
235#define MDP_SYNCFG_VSYNC_EXT_EN (1<<21)
236#define MDP_SYNCFG_VSYNC_INT_EN (1<<20)
237
238/* MDP_SYNC_THRESH_0 */
239#define MDP_PRIM_BELOW_LOC 0
240#define MDP_PRIM_ABOVE_LOC 8
241
242/* MDP_{PRIMARY,SECONDARY,EXTERNAL}_VSYNC_OUT_CRL */
243#define VSYNC_PULSE_EN (1<<31)
244#define VSYNC_PULSE_INV (1<<30)
245
246/* MDP_VSYNC_CTRL */
247#define DISP0_VSYNC_MAP_VSYNC0 0
248#define DISP0_VSYNC_MAP_VSYNC1 (1<<0)
249#define DISP0_VSYNC_MAP_VSYNC2 ((1<<0)|(1<<1))
250
251#define DISP1_VSYNC_MAP_VSYNC0 0
252#define DISP1_VSYNC_MAP_VSYNC1 (1<<2)
253#define DISP1_VSYNC_MAP_VSYNC2 ((1<<2)|(1<<3))
254
255#define PRIMARY_LCD_SYNC_EN (1<<4)
256#define PRIMARY_LCD_SYNC_DISABLE 0
257
258#define SECONDARY_LCD_SYNC_EN (1<<5)
259#define SECONDARY_LCD_SYNC_DISABLE 0
260
261#define EXTERNAL_LCD_SYNC_EN (1<<6)
262#define EXTERNAL_LCD_SYNC_DISABLE 0
263
264/* MDP_VSYNC_THRESHOLD / MDP_FULL_BYPASS_WORD60 */
265#define VSYNC_THRESHOLD_ABOVE_LOC 0
266#define VSYNC_THRESHOLD_BELOW_LOC 16
267#define VSYNC_ANTI_TEAR_EN (1<<31)
268
269/* MDP_COMMAND_CONFIG / MDP_FULL_BYPASS_WORD1 */
270#define MDP_CMD_DBGBUS_EN (1<<0)
271
272/* MDP_PPP_SOURCE_CONFIG / MDP_FULL_BYPASS_WORD9&53 */
273#define PPP_SRC_C0G_8BIT ((1<<1)|(1<<0))
274#define PPP_SRC_C1B_8BIT ((1<<3)|(1<<2))
275#define PPP_SRC_C2R_8BIT ((1<<5)|(1<<4))
276#define PPP_SRC_C3A_8BIT ((1<<7)|(1<<6))
277
278#define PPP_SRC_C0G_6BIT (1<<1)
279#define PPP_SRC_C1B_6BIT (1<<3)
280#define PPP_SRC_C2R_6BIT (1<<5)
281
282#define PPP_SRC_C0G_5BIT (1<<0)
283#define PPP_SRC_C1B_5BIT (1<<2)
284#define PPP_SRC_C2R_5BIT (1<<4)
285
286#define PPP_SRC_C3ALPHA_EN (1<<8)
287
288#define PPP_SRC_BPP_1BYTES 0
289#define PPP_SRC_BPP_2BYTES (1<<9)
290#define PPP_SRC_BPP_3BYTES (1<<10)
291#define PPP_SRC_BPP_4BYTES ((1<<10)|(1<<9))
292
293#define PPP_SRC_BPP_ROI_ODD_X (1<<11)
294#define PPP_SRC_BPP_ROI_ODD_Y (1<<12)
295#define PPP_SRC_INTERLVD_2COMPONENTS (1<<13)
296#define PPP_SRC_INTERLVD_3COMPONENTS (1<<14)
297#define PPP_SRC_INTERLVD_4COMPONENTS ((1<<14)|(1<<13))
298
299
300/* RGB666 unpack format
301** TIGHT means R6+G6+B6 together
302** LOOSE means R6+2 +G6+2+ B6+2 (with MSB)
303** or 2+R6 +2+G6 +2+B6 (with LSB)
304*/
305#define PPP_SRC_PACK_TIGHT (1<<17)
306#define PPP_SRC_PACK_LOOSE 0
307#define PPP_SRC_PACK_ALIGN_LSB 0
308#define PPP_SRC_PACK_ALIGN_MSB (1<<18)
309
310#define PPP_SRC_PLANE_INTERLVD 0
311#define PPP_SRC_PLANE_PSEUDOPLNR (1<<20)
312
313#define PPP_SRC_WMV9_MODE (1<<21)
314
315/* MDP_PPP_OPERATION_CONFIG / MDP_FULL_BYPASS_WORD14 */
316#define PPP_OP_SCALE_X_ON (1<<0)
317#define PPP_OP_SCALE_Y_ON (1<<1)
318
319#define PPP_OP_CONVERT_RGB2YCBCR 0
320#define PPP_OP_CONVERT_YCBCR2RGB (1<<2)
321#define PPP_OP_CONVERT_ON (1<<3)
322
323#define PPP_OP_CONVERT_MATRIX_PRIMARY 0
324#define PPP_OP_CONVERT_MATRIX_SECONDARY (1<<4)
325
326#define PPP_OP_LUT_C0_ON (1<<5)
327#define PPP_OP_LUT_C1_ON (1<<6)
328#define PPP_OP_LUT_C2_ON (1<<7)
329
330/* rotate or blend enable */
331#define PPP_OP_ROT_ON (1<<8)
332
333#define PPP_OP_ROT_90 (1<<9)
334#define PPP_OP_FLIP_LR (1<<10)
335#define PPP_OP_FLIP_UD (1<<11)
336
337#define PPP_OP_BLEND_ON (1<<12)
338
339#define PPP_OP_BLEND_SRCPIXEL_ALPHA 0
340#define PPP_OP_BLEND_DSTPIXEL_ALPHA (1<<13)
341#define PPP_OP_BLEND_CONSTANT_ALPHA (1<<14)
342#define PPP_OP_BLEND_SRCPIXEL_TRANSP ((1<<13)|(1<<14))
343
344#define PPP_OP_BLEND_ALPHA_BLEND_NORMAL 0
345#define PPP_OP_BLEND_ALPHA_BLEND_REVERSE (1<<15)
346
347#define PPP_OP_DITHER_EN (1<<16)
348
349#define PPP_OP_COLOR_SPACE_RGB 0
350#define PPP_OP_COLOR_SPACE_YCBCR (1<<17)
351
352#define PPP_OP_SRC_CHROMA_RGB 0
353#define PPP_OP_SRC_CHROMA_H2V1 (1<<18)
354#define PPP_OP_SRC_CHROMA_H1V2 (1<<19)
355#define PPP_OP_SRC_CHROMA_420 ((1<<18)|(1<<19))
356#define PPP_OP_SRC_CHROMA_COSITE 0
357#define PPP_OP_SRC_CHROMA_OFFSITE (1<<20)
358
359#define PPP_OP_DST_CHROMA_RGB 0
360#define PPP_OP_DST_CHROMA_H2V1 (1<<21)
361#define PPP_OP_DST_CHROMA_H1V2 (1<<22)
362#define PPP_OP_DST_CHROMA_420 ((1<<21)|(1<<22))
363#define PPP_OP_DST_CHROMA_COSITE 0
364#define PPP_OP_DST_CHROMA_OFFSITE (1<<23)
365
366#define PPP_BLEND_ALPHA_TRANSP (1<<24)
367
368#define PPP_OP_BG_CHROMA_RGB 0
369#define PPP_OP_BG_CHROMA_H2V1 (1<<25)
370#define PPP_OP_BG_CHROMA_H1V2 (1<<26)
371#define PPP_OP_BG_CHROMA_420 ((1<<25)|(1<<26))
372#define PPP_OP_BG_CHROMA_SITE_COSITE 0
373#define PPP_OP_BG_CHROMA_SITE_OFFSITE (1<<27)
374
375/* MDP_PPP_DESTINATION_CONFIG / MDP_FULL_BYPASS_WORD20 */
376#define PPP_DST_C0G_8BIT ((1<<0)|(1<<1))
377#define PPP_DST_C1B_8BIT ((1<<3)|(1<<2))
378#define PPP_DST_C2R_8BIT ((1<<5)|(1<<4))
379#define PPP_DST_C3A_8BIT ((1<<7)|(1<<6))
380
381#define PPP_DST_C0G_6BIT (1<<1)
382#define PPP_DST_C1B_6BIT (1<<3)
383#define PPP_DST_C2R_6BIT (1<<5)
384
385#define PPP_DST_C0G_5BIT (1<<0)
386#define PPP_DST_C1B_5BIT (1<<2)
387#define PPP_DST_C2R_5BIT (1<<4)
388
389#define PPP_DST_C3A_8BIT ((1<<7)|(1<<6))
390#define PPP_DST_C3ALPHA_EN (1<<8)
391
392#define PPP_DST_INTERLVD_2COMPONENTS (1<<9)
393#define PPP_DST_INTERLVD_3COMPONENTS (1<<10)
394#define PPP_DST_INTERLVD_4COMPONENTS ((1<<10)|(1<<9))
395#define PPP_DST_INTERLVD_6COMPONENTS ((1<<11)|(1<<9))
396
397#define PPP_DST_PACK_LOOSE 0
398#define PPP_DST_PACK_TIGHT (1<<13)
399#define PPP_DST_PACK_ALIGN_LSB 0
400#define PPP_DST_PACK_ALIGN_MSB (1<<14)
401
402#define PPP_DST_OUT_SEL_AXI 0
403#define PPP_DST_OUT_SEL_MDDI (1<<15)
404
405#define PPP_DST_BPP_2BYTES (1<<16)
406#define PPP_DST_BPP_3BYTES (1<<17)
407#define PPP_DST_BPP_4BYTES ((1<<17)|(1<<16))
408
409#define PPP_DST_PLANE_INTERLVD 0
410#define PPP_DST_PLANE_PLANAR (1<<18)
411#define PPP_DST_PLANE_PSEUDOPLNR (1<<19)
412
413#define PPP_DST_TO_TV (1<<20)
414
415#define PPP_DST_MDDI_PRIMARY 0
416#define PPP_DST_MDDI_SECONDARY (1<<21)
417#define PPP_DST_MDDI_EXTERNAL (1<<22)
418
419/* image configurations by image type */
420#define PPP_CFG_MDP_RGB_565(dir) (PPP_##dir##_C2R_5BIT | \
421 PPP_##dir##_C0G_6BIT | \
422 PPP_##dir##_C1B_5BIT | \
423 PPP_##dir##_BPP_2BYTES | \
424 PPP_##dir##_INTERLVD_3COMPONENTS | \
425 PPP_##dir##_PACK_TIGHT | \
426 PPP_##dir##_PACK_ALIGN_LSB | \
427 PPP_##dir##_PLANE_INTERLVD)
428
429#define PPP_CFG_MDP_RGB_888(dir) (PPP_##dir##_C2R_8BIT | \
430 PPP_##dir##_C0G_8BIT | \
431 PPP_##dir##_C1B_8BIT | \
432 PPP_##dir##_BPP_3BYTES | \
433 PPP_##dir##_INTERLVD_3COMPONENTS | \
434 PPP_##dir##_PACK_TIGHT | \
435 PPP_##dir##_PACK_ALIGN_LSB | \
436 PPP_##dir##_PLANE_INTERLVD)
437
438#define PPP_CFG_MDP_ARGB_8888(dir) (PPP_##dir##_C2R_8BIT | \
439 PPP_##dir##_C0G_8BIT | \
440 PPP_##dir##_C1B_8BIT | \
441 PPP_##dir##_C3A_8BIT | \
442 PPP_##dir##_C3ALPHA_EN | \
443 PPP_##dir##_BPP_4BYTES | \
444 PPP_##dir##_INTERLVD_4COMPONENTS | \
445 PPP_##dir##_PACK_TIGHT | \
446 PPP_##dir##_PACK_ALIGN_LSB | \
447 PPP_##dir##_PLANE_INTERLVD)
448
449#define PPP_CFG_MDP_XRGB_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
450#define PPP_CFG_MDP_RGBA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
451#define PPP_CFG_MDP_BGRA_8888(dir) PPP_CFG_MDP_ARGB_8888(dir)
452
453#define PPP_CFG_MDP_Y_CBCR_H2V2(dir) (PPP_##dir##_C2R_8BIT | \
454 PPP_##dir##_C0G_8BIT | \
455 PPP_##dir##_C1B_8BIT | \
456 PPP_##dir##_C3A_8BIT | \
457 PPP_##dir##_BPP_2BYTES | \
458 PPP_##dir##_INTERLVD_2COMPONENTS | \
459 PPP_##dir##_PACK_TIGHT | \
460 PPP_##dir##_PACK_ALIGN_LSB | \
461 PPP_##dir##_PLANE_PSEUDOPLNR)
462
463#define PPP_CFG_MDP_Y_CRCB_H2V2(dir) PPP_CFG_MDP_Y_CBCR_H2V2(dir)
464
465#define PPP_CFG_MDP_YCRYCB_H2V1(dir) (PPP_##dir##_C2R_8BIT | \
466 PPP_##dir##_C0G_8BIT | \
467 PPP_##dir##_C1B_8BIT | \
468 PPP_##dir##_C3A_8BIT | \
469 PPP_##dir##_BPP_2BYTES | \
470 PPP_##dir##_INTERLVD_4COMPONENTS | \
471 PPP_##dir##_PACK_TIGHT | \
472 PPP_##dir##_PACK_ALIGN_LSB |\
473 PPP_##dir##_PLANE_INTERLVD)
474
475#define PPP_CFG_MDP_Y_CBCR_H2V1(dir) (PPP_##dir##_C2R_8BIT | \
476 PPP_##dir##_C0G_8BIT | \
477 PPP_##dir##_C1B_8BIT | \
478 PPP_##dir##_C3A_8BIT | \
479 PPP_##dir##_BPP_2BYTES | \
480 PPP_##dir##_INTERLVD_2COMPONENTS | \
481 PPP_##dir##_PACK_TIGHT | \
482 PPP_##dir##_PACK_ALIGN_LSB | \
483 PPP_##dir##_PLANE_PSEUDOPLNR)
484
485#define PPP_CFG_MDP_Y_CRCB_H2V1(dir) PPP_CFG_MDP_Y_CBCR_H2V1(dir)
486
487#define PPP_PACK_PATTERN_MDP_RGB_565 \
488 MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 8)
489#define PPP_PACK_PATTERN_MDP_RGB_888 PPP_PACK_PATTERN_MDP_RGB_565
490#define PPP_PACK_PATTERN_MDP_XRGB_8888 \
491 MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8)
492#define PPP_PACK_PATTERN_MDP_ARGB_8888 PPP_PACK_PATTERN_MDP_XRGB_8888
493#define PPP_PACK_PATTERN_MDP_RGBA_8888 \
494 MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_B, CLR_G, CLR_R, 8)
495#define PPP_PACK_PATTERN_MDP_BGRA_8888 \
496 MDP_GET_PACK_PATTERN(CLR_ALPHA, CLR_R, CLR_G, CLR_B, 8)
497#define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1 \
498 MDP_GET_PACK_PATTERN(0, 0, CLR_CB, CLR_CR, 8)
499#define PPP_PACK_PATTERN_MDP_Y_CBCR_H2V2 PPP_PACK_PATTERN_MDP_Y_CBCR_H2V1
500#define PPP_PACK_PATTERN_MDP_Y_CRCB_H2V1 \
501 MDP_GET_PACK_PATTERN(0, 0, CLR_CR, CLR_CB, 8)
502#define PPP_PACK_PATTERN_MDP_Y_CRCB_H2V2 PPP_PACK_PATTERN_MDP_Y_CRCB_H2V1
503#define PPP_PACK_PATTERN_MDP_YCRYCB_H2V1 \
504 MDP_GET_PACK_PATTERN(CLR_Y, CLR_R, CLR_Y, CLR_B, 8)
505
506#define PPP_CHROMA_SAMP_MDP_RGB_565(dir) PPP_OP_##dir##_CHROMA_RGB
507#define PPP_CHROMA_SAMP_MDP_RGB_888(dir) PPP_OP_##dir##_CHROMA_RGB
508#define PPP_CHROMA_SAMP_MDP_XRGB_8888(dir) PPP_OP_##dir##_CHROMA_RGB
509#define PPP_CHROMA_SAMP_MDP_ARGB_8888(dir) PPP_OP_##dir##_CHROMA_RGB
510#define PPP_CHROMA_SAMP_MDP_RGBA_8888(dir) PPP_OP_##dir##_CHROMA_RGB
511#define PPP_CHROMA_SAMP_MDP_BGRA_8888(dir) PPP_OP_##dir##_CHROMA_RGB
512#define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1
513#define PPP_CHROMA_SAMP_MDP_Y_CBCR_H2V2(dir) PPP_OP_##dir##_CHROMA_420
514#define PPP_CHROMA_SAMP_MDP_Y_CRCB_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1
515#define PPP_CHROMA_SAMP_MDP_Y_CRCB_H2V2(dir) PPP_OP_##dir##_CHROMA_420
516#define PPP_CHROMA_SAMP_MDP_YCRYCB_H2V1(dir) PPP_OP_##dir##_CHROMA_H2V1
517
518/* Helpful array generation macros */
519#define PPP_ARRAY0(name) \
520 [MDP_RGB_565] = PPP_##name##_MDP_RGB_565,\
521 [MDP_RGB_888] = PPP_##name##_MDP_RGB_888,\
522 [MDP_XRGB_8888] = PPP_##name##_MDP_XRGB_8888,\
523 [MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888,\
524 [MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888,\
525 [MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888,\
526 [MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1,\
527 [MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2,\
528 [MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1,\
529 [MDP_Y_CRCB_H2V2] = PPP_##name##_MDP_Y_CRCB_H2V2,\
530 [MDP_YCRYCB_H2V1] = PPP_##name##_MDP_YCRYCB_H2V1
531
532#define PPP_ARRAY1(name, dir) \
533 [MDP_RGB_565] = PPP_##name##_MDP_RGB_565(dir),\
534 [MDP_RGB_888] = PPP_##name##_MDP_RGB_888(dir),\
535 [MDP_XRGB_8888] = PPP_##name##_MDP_XRGB_8888(dir),\
536 [MDP_ARGB_8888] = PPP_##name##_MDP_ARGB_8888(dir),\
537 [MDP_RGBA_8888] = PPP_##name##_MDP_RGBA_8888(dir),\
538 [MDP_BGRA_8888] = PPP_##name##_MDP_BGRA_8888(dir),\
539 [MDP_Y_CBCR_H2V1] = PPP_##name##_MDP_Y_CBCR_H2V1(dir),\
540 [MDP_Y_CBCR_H2V2] = PPP_##name##_MDP_Y_CBCR_H2V2(dir),\
541 [MDP_Y_CRCB_H2V1] = PPP_##name##_MDP_Y_CRCB_H2V1(dir),\
542 [MDP_Y_CRCB_H2V2] = PPP_##name##_MDP_Y_CRCB_H2V2(dir),\
543 [MDP_YCRYCB_H2V1] = PPP_##name##_MDP_YCRYCB_H2V1(dir)
544
545#define IS_YCRCB(img) ((img == MDP_Y_CRCB_H2V2) | (img == MDP_Y_CBCR_H2V2) | \
546 (img == MDP_Y_CRCB_H2V1) | (img == MDP_Y_CBCR_H2V1) | \
547 (img == MDP_YCRYCB_H2V1))
548#define IS_RGB(img) ((img == MDP_RGB_565) | (img == MDP_RGB_888) | \
549 (img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \
550 (img == MDP_XRGB_8888) | (img == MDP_BGRA_8888))
551#define HAS_ALPHA(img) ((img == MDP_ARGB_8888) | (img == MDP_RGBA_8888) | \
552 (img == MDP_BGRA_8888))
553
554#define IS_PSEUDOPLNR(img) ((img == MDP_Y_CRCB_H2V2) | \
555 (img == MDP_Y_CBCR_H2V2) | \
556 (img == MDP_Y_CRCB_H2V1) | \
557 (img == MDP_Y_CBCR_H2V1))
558
559/* Mappings from addr to purpose */
560#define PPP_ADDR_SRC_ROI MDP_FULL_BYPASS_WORD2
561#define PPP_ADDR_SRC0 MDP_FULL_BYPASS_WORD3
562#define PPP_ADDR_SRC1 MDP_FULL_BYPASS_WORD4
563#define PPP_ADDR_SRC_YSTRIDE MDP_FULL_BYPASS_WORD7
564#define PPP_ADDR_SRC_CFG MDP_FULL_BYPASS_WORD9
565#define PPP_ADDR_SRC_PACK_PATTERN MDP_FULL_BYPASS_WORD10
566#define PPP_ADDR_OPERATION MDP_FULL_BYPASS_WORD14
567#define PPP_ADDR_PHASEX_INIT MDP_FULL_BYPASS_WORD15
568#define PPP_ADDR_PHASEY_INIT MDP_FULL_BYPASS_WORD16
569#define PPP_ADDR_PHASEX_STEP MDP_FULL_BYPASS_WORD17
570#define PPP_ADDR_PHASEY_STEP MDP_FULL_BYPASS_WORD18
571#define PPP_ADDR_ALPHA_TRANSP MDP_FULL_BYPASS_WORD19
572#define PPP_ADDR_DST_CFG MDP_FULL_BYPASS_WORD20
573#define PPP_ADDR_DST_PACK_PATTERN MDP_FULL_BYPASS_WORD21
574#define PPP_ADDR_DST_ROI MDP_FULL_BYPASS_WORD25
575#define PPP_ADDR_DST0 MDP_FULL_BYPASS_WORD26
576#define PPP_ADDR_DST1 MDP_FULL_BYPASS_WORD27
577#define PPP_ADDR_DST_YSTRIDE MDP_FULL_BYPASS_WORD30
578#define PPP_ADDR_EDGE MDP_FULL_BYPASS_WORD46
579#define PPP_ADDR_BG0 MDP_FULL_BYPASS_WORD48
580#define PPP_ADDR_BG1 MDP_FULL_BYPASS_WORD49
581#define PPP_ADDR_BG_YSTRIDE MDP_FULL_BYPASS_WORD51
582#define PPP_ADDR_BG_CFG MDP_FULL_BYPASS_WORD53
583#define PPP_ADDR_BG_PACK_PATTERN MDP_FULL_BYPASS_WORD54
584
585/* MDP_DMA_CONFIG / MDP_FULL_BYPASS_WORD32 */
586#define DMA_DSTC0G_6BITS (1<<1)
587#define DMA_DSTC1B_6BITS (1<<3)
588#define DMA_DSTC2R_6BITS (1<<5)
589#define DMA_DSTC0G_5BITS (1<<0)
590#define DMA_DSTC1B_5BITS (1<<2)
591#define DMA_DSTC2R_5BITS (1<<4)
592
593#define DMA_PACK_TIGHT (1<<6)
594#define DMA_PACK_LOOSE 0
595#define DMA_PACK_ALIGN_LSB 0
596#define DMA_PACK_ALIGN_MSB (1<<7)
597#define DMA_PACK_PATTERN_RGB \
598 (MDP_GET_PACK_PATTERN(0, CLR_R, CLR_G, CLR_B, 2)<<8)
599
600#define DMA_OUT_SEL_AHB 0
601#define DMA_OUT_SEL_MDDI (1<<14)
602#define DMA_AHBM_LCD_SEL_PRIMARY 0
603#define DMA_AHBM_LCD_SEL_SECONDARY (1<<15)
604#define DMA_IBUF_C3ALPHA_EN (1<<16)
605#define DMA_DITHER_EN (1<<17)
606
607#define DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY 0
608#define DMA_MDDI_DMAOUT_LCD_SEL_SECONDARY (1<<18)
609#define DMA_MDDI_DMAOUT_LCD_SEL_EXTERNAL (1<<19)
610
611#define DMA_IBUF_FORMAT_RGB565 (1<<20)
612#define DMA_IBUF_FORMAT_RGB888_OR_ARGB8888 0
613
614#define DMA_IBUF_NONCONTIGUOUS (1<<21)
615
616/* MDDI REGISTER ? */
617#define MDDI_VDO_PACKET_DESC 0x5666
618#define MDDI_VDO_PACKET_PRIM 0xC3
619#define MDDI_VDO_PACKET_SECD 0xC0
620
621#endif
diff --git a/drivers/video/msm/mdp_ppp.c b/drivers/video/msm/mdp_ppp.c
new file mode 100644
index 000000000000..ba2c4673b648
--- /dev/null
+++ b/drivers/video/msm/mdp_ppp.c
@@ -0,0 +1,750 @@
1/* drivers/video/msm/mdp_ppp.c
2 *
3 * Copyright (C) 2007 QUALCOMM Incorporated
4 * Copyright (C) 2007 Google Incorporated
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15#include <linux/fb.h>
16#include <linux/file.h>
17#include <linux/delay.h>
18#include <linux/msm_mdp.h>
19#include <linux/android_pmem.h>
20#include <mach/msm_fb.h>
21
22#include "mdp_hw.h"
23#include "mdp_scale_tables.h"
24
25#define DLOG(x...) do {} while (0)
26
27#define MDP_DOWNSCALE_BLUR (MDP_DOWNSCALE_MAX + 1)
28static int downscale_y_table = MDP_DOWNSCALE_MAX;
29static int downscale_x_table = MDP_DOWNSCALE_MAX;
30
31struct mdp_regs {
32 uint32_t src0;
33 uint32_t src1;
34 uint32_t dst0;
35 uint32_t dst1;
36 uint32_t src_cfg;
37 uint32_t dst_cfg;
38 uint32_t src_pack;
39 uint32_t dst_pack;
40 uint32_t src_rect;
41 uint32_t dst_rect;
42 uint32_t src_ystride;
43 uint32_t dst_ystride;
44 uint32_t op;
45 uint32_t src_bpp;
46 uint32_t dst_bpp;
47 uint32_t edge;
48 uint32_t phasex_init;
49 uint32_t phasey_init;
50 uint32_t phasex_step;
51 uint32_t phasey_step;
52};
53
54static uint32_t pack_pattern[] = {
55 PPP_ARRAY0(PACK_PATTERN)
56};
57
58static uint32_t src_img_cfg[] = {
59 PPP_ARRAY1(CFG, SRC)
60};
61
62static uint32_t dst_img_cfg[] = {
63 PPP_ARRAY1(CFG, DST)
64};
65
66static uint32_t bytes_per_pixel[] = {
67 [MDP_RGB_565] = 2,
68 [MDP_RGB_888] = 3,
69 [MDP_XRGB_8888] = 4,
70 [MDP_ARGB_8888] = 4,
71 [MDP_RGBA_8888] = 4,
72 [MDP_BGRA_8888] = 4,
73 [MDP_Y_CBCR_H2V1] = 1,
74 [MDP_Y_CBCR_H2V2] = 1,
75 [MDP_Y_CRCB_H2V1] = 1,
76 [MDP_Y_CRCB_H2V2] = 1,
77 [MDP_YCRYCB_H2V1] = 2
78};
79
80static uint32_t dst_op_chroma[] = {
81 PPP_ARRAY1(CHROMA_SAMP, DST)
82};
83
84static uint32_t src_op_chroma[] = {
85 PPP_ARRAY1(CHROMA_SAMP, SRC)
86};
87
88static uint32_t bg_op_chroma[] = {
89 PPP_ARRAY1(CHROMA_SAMP, BG)
90};
91
92static void rotate_dst_addr_x(struct mdp_blit_req *req, struct mdp_regs *regs)
93{
94 regs->dst0 += (req->dst_rect.w -
95 min((uint32_t)16, req->dst_rect.w)) * regs->dst_bpp;
96 regs->dst1 += (req->dst_rect.w -
97 min((uint32_t)16, req->dst_rect.w)) * regs->dst_bpp;
98}
99
100static void rotate_dst_addr_y(struct mdp_blit_req *req, struct mdp_regs *regs)
101{
102 regs->dst0 += (req->dst_rect.h -
103 min((uint32_t)16, req->dst_rect.h)) *
104 regs->dst_ystride;
105 regs->dst1 += (req->dst_rect.h -
106 min((uint32_t)16, req->dst_rect.h)) *
107 regs->dst_ystride;
108}
109
110static void blit_rotate(struct mdp_blit_req *req,
111 struct mdp_regs *regs)
112{
113 if (req->flags == MDP_ROT_NOP)
114 return;
115
116 regs->op |= PPP_OP_ROT_ON;
117 if ((req->flags & MDP_ROT_90 || req->flags & MDP_FLIP_LR) &&
118 !(req->flags & MDP_ROT_90 && req->flags & MDP_FLIP_LR))
119 rotate_dst_addr_x(req, regs);
120 if (req->flags & MDP_ROT_90)
121 regs->op |= PPP_OP_ROT_90;
122 if (req->flags & MDP_FLIP_UD) {
123 regs->op |= PPP_OP_FLIP_UD;
124 rotate_dst_addr_y(req, regs);
125 }
126 if (req->flags & MDP_FLIP_LR)
127 regs->op |= PPP_OP_FLIP_LR;
128}
129
130static void blit_convert(struct mdp_blit_req *req, struct mdp_regs *regs)
131{
132 if (req->src.format == req->dst.format)
133 return;
134 if (IS_RGB(req->src.format) && IS_YCRCB(req->dst.format)) {
135 regs->op |= PPP_OP_CONVERT_RGB2YCBCR | PPP_OP_CONVERT_ON;
136 } else if (IS_YCRCB(req->src.format) && IS_RGB(req->dst.format)) {
137 regs->op |= PPP_OP_CONVERT_YCBCR2RGB | PPP_OP_CONVERT_ON;
138 if (req->dst.format == MDP_RGB_565)
139 regs->op |= PPP_OP_CONVERT_MATRIX_SECONDARY;
140 }
141}
142
143#define GET_BIT_RANGE(value, high, low) \
144 (((1 << (high - low + 1)) - 1) & (value >> low))
145static uint32_t transp_convert(struct mdp_blit_req *req)
146{
147 uint32_t transp = 0;
148 if (req->src.format == MDP_RGB_565) {
149 /* pad each value to 8 bits by copying the high bits into the
150 * low end, convert RGB to RBG by switching low 2 components */
151 transp |= ((GET_BIT_RANGE(req->transp_mask, 15, 11) << 3) |
152 (GET_BIT_RANGE(req->transp_mask, 15, 13))) << 16;
153
154 transp |= ((GET_BIT_RANGE(req->transp_mask, 4, 0) << 3) |
155 (GET_BIT_RANGE(req->transp_mask, 4, 2))) << 8;
156
157 transp |= (GET_BIT_RANGE(req->transp_mask, 10, 5) << 2) |
158 (GET_BIT_RANGE(req->transp_mask, 10, 9));
159 } else {
160 /* convert RGB to RBG */
161 transp |= (GET_BIT_RANGE(req->transp_mask, 15, 8)) |
162 (GET_BIT_RANGE(req->transp_mask, 23, 16) << 16) |
163 (GET_BIT_RANGE(req->transp_mask, 7, 0) << 8);
164 }
165 return transp;
166}
167#undef GET_BIT_RANGE
168
169static void blit_blend(struct mdp_blit_req *req, struct mdp_regs *regs)
170{
171 /* TRANSP BLEND */
172 if (req->transp_mask != MDP_TRANSP_NOP) {
173 req->transp_mask = transp_convert(req);
174 if (req->alpha != MDP_ALPHA_NOP) {
175 /* use blended transparancy mode
176 * pixel = (src == transp) ? dst : blend
177 * blend is combo of blend_eq_sel and
178 * blend_alpha_sel */
179 regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
180 PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
181 PPP_OP_BLEND_CONSTANT_ALPHA |
182 PPP_BLEND_ALPHA_TRANSP;
183 } else {
184 /* simple transparancy mode
185 * pixel = (src == transp) ? dst : src */
186 regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
187 PPP_OP_BLEND_SRCPIXEL_TRANSP;
188 }
189 }
190
191 req->alpha &= 0xff;
192 /* ALPHA BLEND */
193 if (HAS_ALPHA(req->src.format)) {
194 regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
195 PPP_OP_BLEND_SRCPIXEL_ALPHA;
196 } else if (req->alpha < MDP_ALPHA_NOP) {
197 /* just blend by alpha */
198 regs->op |= PPP_OP_ROT_ON | PPP_OP_BLEND_ON |
199 PPP_OP_BLEND_ALPHA_BLEND_NORMAL |
200 PPP_OP_BLEND_CONSTANT_ALPHA;
201 }
202
203 regs->op |= bg_op_chroma[req->dst.format];
204}
205
206#define ONE_HALF (1LL << 32)
207#define ONE (1LL << 33)
208#define TWO (2LL << 33)
209#define THREE (3LL << 33)
210#define FRAC_MASK (ONE - 1)
211#define INT_MASK (~FRAC_MASK)
212
213static int scale_params(uint32_t dim_in, uint32_t dim_out, uint32_t origin,
214 uint32_t *phase_init, uint32_t *phase_step)
215{
216 /* to improve precicsion calculations are done in U31.33 and converted
217 * to U3.29 at the end */
218 int64_t k1, k2, k3, k4, tmp;
219 uint64_t n, d, os, os_p, od, od_p, oreq;
220 unsigned rpa = 0;
221 int64_t ip64, delta;
222
223 if (dim_out % 3 == 0)
224 rpa = !(dim_in % (dim_out / 3));
225
226 n = ((uint64_t)dim_out) << 34;
227 d = dim_in;
228 if (!d)
229 return -1;
230 do_div(n, d);
231 k3 = (n + 1) >> 1;
232 if ((k3 >> 4) < (1LL << 27) || (k3 >> 4) > (1LL << 31)) {
233 DLOG("crap bad scale\n");
234 return -1;
235 }
236 n = ((uint64_t)dim_in) << 34;
237 d = (uint64_t)dim_out;
238 if (!d)
239 return -1;
240 do_div(n, d);
241 k1 = (n + 1) >> 1;
242 k2 = (k1 - ONE) >> 1;
243
244 *phase_init = (int)(k2 >> 4);
245 k4 = (k3 - ONE) >> 1;
246
247 if (rpa) {
248 os = ((uint64_t)origin << 33) - ONE_HALF;
249 tmp = (dim_out * os) + ONE_HALF;
250 if (!dim_in)
251 return -1;
252 do_div(tmp, dim_in);
253 od = tmp - ONE_HALF;
254 } else {
255 os = ((uint64_t)origin << 1) - 1;
256 od = (((k3 * os) >> 1) + k4);
257 }
258
259 od_p = od & INT_MASK;
260 if (od_p != od)
261 od_p += ONE;
262
263 if (rpa) {
264 tmp = (dim_in * od_p) + ONE_HALF;
265 if (!dim_in)
266 return -1;
267 do_div(tmp, dim_in);
268 os_p = tmp - ONE_HALF;
269 } else {
270 os_p = ((k1 * (od_p >> 33)) + k2);
271 }
272
273 oreq = (os_p & INT_MASK) - ONE;
274
275 ip64 = os_p - oreq;
276 delta = ((int64_t)(origin) << 33) - oreq;
277 ip64 -= delta;
278 /* limit to valid range before the left shift */
279 delta = (ip64 & (1LL << 63)) ? 4 : -4;
280 delta <<= 33;
281 while (abs((int)(ip64 >> 33)) > 4)
282 ip64 += delta;
283 *phase_init = (int)(ip64 >> 4);
284 *phase_step = (uint32_t)(k1 >> 4);
285 return 0;
286}
287
288static void load_scale_table(const struct mdp_info *mdp,
289 struct mdp_table_entry *table, int len)
290{
291 int i;
292 for (i = 0; i < len; i++)
293 mdp_writel(mdp, table[i].val, table[i].reg);
294}
295
296enum {
297IMG_LEFT,
298IMG_RIGHT,
299IMG_TOP,
300IMG_BOTTOM,
301};
302
303static void get_edge_info(uint32_t src, uint32_t src_coord, uint32_t dst,
304 uint32_t *interp1, uint32_t *interp2,
305 uint32_t *repeat1, uint32_t *repeat2) {
306 if (src > 3 * dst) {
307 *interp1 = 0;
308 *interp2 = src - 1;
309 *repeat1 = 0;
310 *repeat2 = 0;
311 } else if (src == 3 * dst) {
312 *interp1 = 0;
313 *interp2 = src;
314 *repeat1 = 0;
315 *repeat2 = 1;
316 } else if (src > dst && src < 3 * dst) {
317 *interp1 = -1;
318 *interp2 = src;
319 *repeat1 = 1;
320 *repeat2 = 1;
321 } else if (src == dst) {
322 *interp1 = -1;
323 *interp2 = src + 1;
324 *repeat1 = 1;
325 *repeat2 = 2;
326 } else {
327 *interp1 = -2;
328 *interp2 = src + 1;
329 *repeat1 = 2;
330 *repeat2 = 2;
331 }
332 *interp1 += src_coord;
333 *interp2 += src_coord;
334}
335
336static int get_edge_cond(struct mdp_blit_req *req, struct mdp_regs *regs)
337{
338 int32_t luma_interp[4];
339 int32_t luma_repeat[4];
340 int32_t chroma_interp[4];
341 int32_t chroma_bound[4];
342 int32_t chroma_repeat[4];
343 uint32_t dst_w, dst_h;
344
345 memset(&luma_interp, 0, sizeof(int32_t) * 4);
346 memset(&luma_repeat, 0, sizeof(int32_t) * 4);
347 memset(&chroma_interp, 0, sizeof(int32_t) * 4);
348 memset(&chroma_bound, 0, sizeof(int32_t) * 4);
349 memset(&chroma_repeat, 0, sizeof(int32_t) * 4);
350 regs->edge = 0;
351
352 if (req->flags & MDP_ROT_90) {
353 dst_w = req->dst_rect.h;
354 dst_h = req->dst_rect.w;
355 } else {
356 dst_w = req->dst_rect.w;
357 dst_h = req->dst_rect.h;
358 }
359
360 if (regs->op & (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON)) {
361 get_edge_info(req->src_rect.h, req->src_rect.y, dst_h,
362 &luma_interp[IMG_TOP], &luma_interp[IMG_BOTTOM],
363 &luma_repeat[IMG_TOP], &luma_repeat[IMG_BOTTOM]);
364 get_edge_info(req->src_rect.w, req->src_rect.x, dst_w,
365 &luma_interp[IMG_LEFT], &luma_interp[IMG_RIGHT],
366 &luma_repeat[IMG_LEFT], &luma_repeat[IMG_RIGHT]);
367 } else {
368 luma_interp[IMG_LEFT] = req->src_rect.x;
369 luma_interp[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1;
370 luma_interp[IMG_TOP] = req->src_rect.y;
371 luma_interp[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1;
372 luma_repeat[IMG_LEFT] = 0;
373 luma_repeat[IMG_TOP] = 0;
374 luma_repeat[IMG_RIGHT] = 0;
375 luma_repeat[IMG_BOTTOM] = 0;
376 }
377
378 chroma_interp[IMG_LEFT] = luma_interp[IMG_LEFT];
379 chroma_interp[IMG_RIGHT] = luma_interp[IMG_RIGHT];
380 chroma_interp[IMG_TOP] = luma_interp[IMG_TOP];
381 chroma_interp[IMG_BOTTOM] = luma_interp[IMG_BOTTOM];
382
383 chroma_bound[IMG_LEFT] = req->src_rect.x;
384 chroma_bound[IMG_RIGHT] = req->src_rect.x + req->src_rect.w - 1;
385 chroma_bound[IMG_TOP] = req->src_rect.y;
386 chroma_bound[IMG_BOTTOM] = req->src_rect.y + req->src_rect.h - 1;
387
388 if (IS_YCRCB(req->src.format)) {
389 chroma_interp[IMG_LEFT] = chroma_interp[IMG_LEFT] >> 1;
390 chroma_interp[IMG_RIGHT] = (chroma_interp[IMG_RIGHT] + 1) >> 1;
391
392 chroma_bound[IMG_LEFT] = chroma_bound[IMG_LEFT] >> 1;
393 chroma_bound[IMG_RIGHT] = chroma_bound[IMG_RIGHT] >> 1;
394 }
395
396 if (req->src.format == MDP_Y_CBCR_H2V2 ||
397 req->src.format == MDP_Y_CRCB_H2V2) {
398 chroma_interp[IMG_TOP] = (chroma_interp[IMG_TOP] - 1) >> 1;
399 chroma_interp[IMG_BOTTOM] = (chroma_interp[IMG_BOTTOM] + 1)
400 >> 1;
401 chroma_bound[IMG_TOP] = (chroma_bound[IMG_TOP] + 1) >> 1;
402 chroma_bound[IMG_BOTTOM] = chroma_bound[IMG_BOTTOM] >> 1;
403 }
404
405 chroma_repeat[IMG_LEFT] = chroma_bound[IMG_LEFT] -
406 chroma_interp[IMG_LEFT];
407 chroma_repeat[IMG_RIGHT] = chroma_interp[IMG_RIGHT] -
408 chroma_bound[IMG_RIGHT];
409 chroma_repeat[IMG_TOP] = chroma_bound[IMG_TOP] -
410 chroma_interp[IMG_TOP];
411 chroma_repeat[IMG_BOTTOM] = chroma_interp[IMG_BOTTOM] -
412 chroma_bound[IMG_BOTTOM];
413
414 if (chroma_repeat[IMG_LEFT] < 0 || chroma_repeat[IMG_LEFT] > 3 ||
415 chroma_repeat[IMG_RIGHT] < 0 || chroma_repeat[IMG_RIGHT] > 3 ||
416 chroma_repeat[IMG_TOP] < 0 || chroma_repeat[IMG_TOP] > 3 ||
417 chroma_repeat[IMG_BOTTOM] < 0 || chroma_repeat[IMG_BOTTOM] > 3 ||
418 luma_repeat[IMG_LEFT] < 0 || luma_repeat[IMG_LEFT] > 3 ||
419 luma_repeat[IMG_RIGHT] < 0 || luma_repeat[IMG_RIGHT] > 3 ||
420 luma_repeat[IMG_TOP] < 0 || luma_repeat[IMG_TOP] > 3 ||
421 luma_repeat[IMG_BOTTOM] < 0 || luma_repeat[IMG_BOTTOM] > 3)
422 return -1;
423
424 regs->edge |= (chroma_repeat[IMG_LEFT] & 3) << MDP_LEFT_CHROMA;
425 regs->edge |= (chroma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_CHROMA;
426 regs->edge |= (chroma_repeat[IMG_TOP] & 3) << MDP_TOP_CHROMA;
427 regs->edge |= (chroma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_CHROMA;
428 regs->edge |= (luma_repeat[IMG_LEFT] & 3) << MDP_LEFT_LUMA;
429 regs->edge |= (luma_repeat[IMG_RIGHT] & 3) << MDP_RIGHT_LUMA;
430 regs->edge |= (luma_repeat[IMG_TOP] & 3) << MDP_TOP_LUMA;
431 regs->edge |= (luma_repeat[IMG_BOTTOM] & 3) << MDP_BOTTOM_LUMA;
432 return 0;
433}
434
435static int blit_scale(const struct mdp_info *mdp, struct mdp_blit_req *req,
436 struct mdp_regs *regs)
437{
438 uint32_t phase_init_x, phase_init_y, phase_step_x, phase_step_y;
439 uint32_t scale_factor_x, scale_factor_y;
440 uint32_t downscale;
441 uint32_t dst_w, dst_h;
442
443 if (req->flags & MDP_ROT_90) {
444 dst_w = req->dst_rect.h;
445 dst_h = req->dst_rect.w;
446 } else {
447 dst_w = req->dst_rect.w;
448 dst_h = req->dst_rect.h;
449 }
450 if ((req->src_rect.w == dst_w) && (req->src_rect.h == dst_h) &&
451 !(req->flags & MDP_BLUR)) {
452 regs->phasex_init = 0;
453 regs->phasey_init = 0;
454 regs->phasex_step = 0;
455 regs->phasey_step = 0;
456 return 0;
457 }
458
459 if (scale_params(req->src_rect.w, dst_w, 1, &phase_init_x,
460 &phase_step_x) ||
461 scale_params(req->src_rect.h, dst_h, 1, &phase_init_y,
462 &phase_step_y))
463 return -1;
464
465 scale_factor_x = (dst_w * 10) / req->src_rect.w;
466 scale_factor_y = (dst_h * 10) / req->src_rect.h;
467
468 if (scale_factor_x > 8)
469 downscale = MDP_DOWNSCALE_PT8TO1;
470 else if (scale_factor_x > 6)
471 downscale = MDP_DOWNSCALE_PT6TOPT8;
472 else if (scale_factor_x > 4)
473 downscale = MDP_DOWNSCALE_PT4TOPT6;
474 else
475 downscale = MDP_DOWNSCALE_PT2TOPT4;
476 if (downscale != downscale_x_table) {
477 load_scale_table(mdp, mdp_downscale_x_table[downscale], 64);
478 downscale_x_table = downscale;
479 }
480
481 if (scale_factor_y > 8)
482 downscale = MDP_DOWNSCALE_PT8TO1;
483 else if (scale_factor_y > 6)
484 downscale = MDP_DOWNSCALE_PT6TOPT8;
485 else if (scale_factor_y > 4)
486 downscale = MDP_DOWNSCALE_PT4TOPT6;
487 else
488 downscale = MDP_DOWNSCALE_PT2TOPT4;
489 if (downscale != downscale_y_table) {
490 load_scale_table(mdp, mdp_downscale_y_table[downscale], 64);
491 downscale_y_table = downscale;
492 }
493
494 regs->phasex_init = phase_init_x;
495 regs->phasey_init = phase_init_y;
496 regs->phasex_step = phase_step_x;
497 regs->phasey_step = phase_step_y;
498 regs->op |= (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
499 return 0;
500
501}
502
503static void blit_blur(const struct mdp_info *mdp, struct mdp_blit_req *req,
504 struct mdp_regs *regs)
505{
506 if (!(req->flags & MDP_BLUR))
507 return;
508
509 if (!(downscale_x_table == MDP_DOWNSCALE_BLUR &&
510 downscale_y_table == MDP_DOWNSCALE_BLUR)) {
511 load_scale_table(mdp, mdp_gaussian_blur_table, 128);
512 downscale_x_table = MDP_DOWNSCALE_BLUR;
513 downscale_y_table = MDP_DOWNSCALE_BLUR;
514 }
515
516 regs->op |= (PPP_OP_SCALE_Y_ON | PPP_OP_SCALE_X_ON);
517}
518
519
520#define IMG_LEN(rect_h, w, rect_w, bpp) (((rect_h) * w) * bpp)
521
522#define Y_TO_CRCB_RATIO(format) \
523 ((format == MDP_Y_CBCR_H2V2 || format == MDP_Y_CRCB_H2V2) ? 2 :\
524 (format == MDP_Y_CBCR_H2V1 || format == MDP_Y_CRCB_H2V1) ? 1 : 1)
525
526static void get_len(struct mdp_img *img, struct mdp_rect *rect, uint32_t bpp,
527 uint32_t *len0, uint32_t *len1)
528{
529 *len0 = IMG_LEN(rect->h, img->width, rect->w, bpp);
530 if (IS_PSEUDOPLNR(img->format))
531 *len1 = *len0/Y_TO_CRCB_RATIO(img->format);
532 else
533 *len1 = 0;
534}
535
536static int valid_src_dst(unsigned long src_start, unsigned long src_len,
537 unsigned long dst_start, unsigned long dst_len,
538 struct mdp_blit_req *req, struct mdp_regs *regs)
539{
540 unsigned long src_min_ok = src_start;
541 unsigned long src_max_ok = src_start + src_len;
542 unsigned long dst_min_ok = dst_start;
543 unsigned long dst_max_ok = dst_start + dst_len;
544 uint32_t src0_len, src1_len, dst0_len, dst1_len;
545 get_len(&req->src, &req->src_rect, regs->src_bpp, &src0_len,
546 &src1_len);
547 get_len(&req->dst, &req->dst_rect, regs->dst_bpp, &dst0_len,
548 &dst1_len);
549
550 if (regs->src0 < src_min_ok || regs->src0 > src_max_ok ||
551 regs->src0 + src0_len > src_max_ok) {
552 DLOG("invalid_src %x %x %lx %lx\n", regs->src0,
553 src0_len, src_min_ok, src_max_ok);
554 return 0;
555 }
556 if (regs->src_cfg & PPP_SRC_PLANE_PSEUDOPLNR) {
557 if (regs->src1 < src_min_ok || regs->src1 > src_max_ok ||
558 regs->src1 + src1_len > src_max_ok) {
559 DLOG("invalid_src1");
560 return 0;
561 }
562 }
563 if (regs->dst0 < dst_min_ok || regs->dst0 > dst_max_ok ||
564 regs->dst0 + dst0_len > dst_max_ok) {
565 DLOG("invalid_dst");
566 return 0;
567 }
568 if (regs->dst_cfg & PPP_SRC_PLANE_PSEUDOPLNR) {
569 if (regs->dst1 < dst_min_ok || regs->dst1 > dst_max_ok ||
570 regs->dst1 + dst1_len > dst_max_ok) {
571 DLOG("invalid_dst1");
572 return 0;
573 }
574 }
575 return 1;
576}
577
578
579static void flush_imgs(struct mdp_blit_req *req, struct mdp_regs *regs,
580 struct file *src_file, struct file *dst_file)
581{
582#ifdef CONFIG_ANDROID_PMEM
583 uint32_t src0_len, src1_len, dst0_len, dst1_len;
584
585 /* flush src images to memory before dma to mdp */
586 get_len(&req->src, &req->src_rect, regs->src_bpp, &src0_len,
587 &src1_len);
588 flush_pmem_file(src_file, req->src.offset, src0_len);
589 if (IS_PSEUDOPLNR(req->src.format))
590 flush_pmem_file(src_file, req->src.offset + src0_len,
591 src1_len);
592
593 /* flush dst images */
594 get_len(&req->dst, &req->dst_rect, regs->dst_bpp, &dst0_len,
595 &dst1_len);
596 flush_pmem_file(dst_file, req->dst.offset, dst0_len);
597 if (IS_PSEUDOPLNR(req->dst.format))
598 flush_pmem_file(dst_file, req->dst.offset + dst0_len,
599 dst1_len);
600#endif
601}
602
603static void get_chroma_addr(struct mdp_img *img, struct mdp_rect *rect,
604 uint32_t base, uint32_t bpp, uint32_t cfg,
605 uint32_t *addr, uint32_t *ystride)
606{
607 uint32_t compress_v = Y_TO_CRCB_RATIO(img->format);
608 uint32_t compress_h = 2;
609 uint32_t offset;
610
611 if (IS_PSEUDOPLNR(img->format)) {
612 offset = (rect->x / compress_h) * compress_h;
613 offset += rect->y == 0 ? 0 :
614 ((rect->y + 1) / compress_v) * img->width;
615 *addr = base + (img->width * img->height * bpp);
616 *addr += offset * bpp;
617 *ystride |= *ystride << 16;
618 } else {
619 *addr = 0;
620 }
621}
622
623static int send_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
624 struct mdp_regs *regs, struct file *src_file,
625 struct file *dst_file)
626{
627 mdp_writel(mdp, 1, 0x060);
628 mdp_writel(mdp, regs->src_rect, PPP_ADDR_SRC_ROI);
629 mdp_writel(mdp, regs->src0, PPP_ADDR_SRC0);
630 mdp_writel(mdp, regs->src1, PPP_ADDR_SRC1);
631 mdp_writel(mdp, regs->src_ystride, PPP_ADDR_SRC_YSTRIDE);
632 mdp_writel(mdp, regs->src_cfg, PPP_ADDR_SRC_CFG);
633 mdp_writel(mdp, regs->src_pack, PPP_ADDR_SRC_PACK_PATTERN);
634
635 mdp_writel(mdp, regs->op, PPP_ADDR_OPERATION);
636 mdp_writel(mdp, regs->phasex_init, PPP_ADDR_PHASEX_INIT);
637 mdp_writel(mdp, regs->phasey_init, PPP_ADDR_PHASEY_INIT);
638 mdp_writel(mdp, regs->phasex_step, PPP_ADDR_PHASEX_STEP);
639 mdp_writel(mdp, regs->phasey_step, PPP_ADDR_PHASEY_STEP);
640
641 mdp_writel(mdp, (req->alpha << 24) | (req->transp_mask & 0xffffff),
642 PPP_ADDR_ALPHA_TRANSP);
643
644 mdp_writel(mdp, regs->dst_cfg, PPP_ADDR_DST_CFG);
645 mdp_writel(mdp, regs->dst_pack, PPP_ADDR_DST_PACK_PATTERN);
646 mdp_writel(mdp, regs->dst_rect, PPP_ADDR_DST_ROI);
647 mdp_writel(mdp, regs->dst0, PPP_ADDR_DST0);
648 mdp_writel(mdp, regs->dst1, PPP_ADDR_DST1);
649 mdp_writel(mdp, regs->dst_ystride, PPP_ADDR_DST_YSTRIDE);
650
651 mdp_writel(mdp, regs->edge, PPP_ADDR_EDGE);
652 if (regs->op & PPP_OP_BLEND_ON) {
653 mdp_writel(mdp, regs->dst0, PPP_ADDR_BG0);
654 mdp_writel(mdp, regs->dst1, PPP_ADDR_BG1);
655 mdp_writel(mdp, regs->dst_ystride, PPP_ADDR_BG_YSTRIDE);
656 mdp_writel(mdp, src_img_cfg[req->dst.format], PPP_ADDR_BG_CFG);
657 mdp_writel(mdp, pack_pattern[req->dst.format],
658 PPP_ADDR_BG_PACK_PATTERN);
659 }
660 flush_imgs(req, regs, src_file, dst_file);
661 mdp_writel(mdp, 0x1000, MDP_DISPLAY0_START);
662 return 0;
663}
664
665int mdp_ppp_blit(const struct mdp_info *mdp, struct mdp_blit_req *req,
666 struct file *src_file, unsigned long src_start, unsigned long src_len,
667 struct file *dst_file, unsigned long dst_start, unsigned long dst_len)
668{
669 struct mdp_regs regs = {0};
670
671 if (unlikely(req->src.format >= MDP_IMGTYPE_LIMIT ||
672 req->dst.format >= MDP_IMGTYPE_LIMIT)) {
673 printk(KERN_ERR "mpd_ppp: img is of wrong format\n");
674 return -EINVAL;
675 }
676
677 if (unlikely(req->src_rect.x > req->src.width ||
678 req->src_rect.y > req->src.height ||
679 req->dst_rect.x > req->dst.width ||
680 req->dst_rect.y > req->dst.height)) {
681 printk(KERN_ERR "mpd_ppp: img rect is outside of img!\n");
682 return -EINVAL;
683 }
684
685 /* set the src image configuration */
686 regs.src_cfg = src_img_cfg[req->src.format];
687 regs.src_cfg |= (req->src_rect.x & 0x1) ? PPP_SRC_BPP_ROI_ODD_X : 0;
688 regs.src_cfg |= (req->src_rect.y & 0x1) ? PPP_SRC_BPP_ROI_ODD_Y : 0;
689 regs.src_rect = (req->src_rect.h << 16) | req->src_rect.w;
690 regs.src_pack = pack_pattern[req->src.format];
691
692 /* set the dest image configuration */
693 regs.dst_cfg = dst_img_cfg[req->dst.format] | PPP_DST_OUT_SEL_AXI;
694 regs.dst_rect = (req->dst_rect.h << 16) | req->dst_rect.w;
695 regs.dst_pack = pack_pattern[req->dst.format];
696
697 /* set src, bpp, start pixel and ystride */
698 regs.src_bpp = bytes_per_pixel[req->src.format];
699 regs.src0 = src_start + req->src.offset;
700 regs.src_ystride = req->src.width * regs.src_bpp;
701 get_chroma_addr(&req->src, &req->src_rect, regs.src0, regs.src_bpp,
702 regs.src_cfg, &regs.src1, &regs.src_ystride);
703 regs.src0 += (req->src_rect.x + (req->src_rect.y * req->src.width)) *
704 regs.src_bpp;
705
706 /* set dst, bpp, start pixel and ystride */
707 regs.dst_bpp = bytes_per_pixel[req->dst.format];
708 regs.dst0 = dst_start + req->dst.offset;
709 regs.dst_ystride = req->dst.width * regs.dst_bpp;
710 get_chroma_addr(&req->dst, &req->dst_rect, regs.dst0, regs.dst_bpp,
711 regs.dst_cfg, &regs.dst1, &regs.dst_ystride);
712 regs.dst0 += (req->dst_rect.x + (req->dst_rect.y * req->dst.width)) *
713 regs.dst_bpp;
714
715 if (!valid_src_dst(src_start, src_len, dst_start, dst_len, req,
716 &regs)) {
717 printk(KERN_ERR "mpd_ppp: final src or dst location is "
718 "invalid, are you trying to make an image too large "
719 "or to place it outside the screen?\n");
720 return -EINVAL;
721 }
722
723 /* set up operation register */
724 regs.op = 0;
725 blit_rotate(req, &regs);
726 blit_convert(req, &regs);
727 if (req->flags & MDP_DITHER)
728 regs.op |= PPP_OP_DITHER_EN;
729 blit_blend(req, &regs);
730 if (blit_scale(mdp, req, &regs)) {
731 printk(KERN_ERR "mpd_ppp: error computing scale for img.\n");
732 return -EINVAL;
733 }
734 blit_blur(mdp, req, &regs);
735 regs.op |= dst_op_chroma[req->dst.format] |
736 src_op_chroma[req->src.format];
737
738 /* if the image is YCRYCB, the x and w must be even */
739 if (unlikely(req->src.format == MDP_YCRYCB_H2V1)) {
740 req->src_rect.x = req->src_rect.x & (~0x1);
741 req->src_rect.w = req->src_rect.w & (~0x1);
742 req->dst_rect.x = req->dst_rect.x & (~0x1);
743 req->dst_rect.w = req->dst_rect.w & (~0x1);
744 }
745 if (get_edge_cond(req, &regs))
746 return -EINVAL;
747
748 send_blit(mdp, req, &regs, src_file, dst_file);
749 return 0;
750}
diff --git a/drivers/video/msm/mdp_scale_tables.c b/drivers/video/msm/mdp_scale_tables.c
new file mode 100644
index 000000000000..604783b2e17c
--- /dev/null
+++ b/drivers/video/msm/mdp_scale_tables.c
@@ -0,0 +1,766 @@
1/* drivers/video/msm_fb/mdp_scale_tables.c
2 *
3 * Copyright (C) 2007 QUALCOMM Incorporated
4 * Copyright (C) 2007 Google Incorporated
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include "mdp_scale_tables.h"
17#include "mdp_hw.h"
18
19struct mdp_table_entry mdp_upscale_table[] = {
20 { 0x5fffc, 0x0 },
21 { 0x50200, 0x7fc00000 },
22 { 0x5fffc, 0xff80000d },
23 { 0x50204, 0x7ec003f9 },
24 { 0x5fffc, 0xfec0001c },
25 { 0x50208, 0x7d4003f3 },
26 { 0x5fffc, 0xfe40002b },
27 { 0x5020c, 0x7b8003ed },
28 { 0x5fffc, 0xfd80003c },
29 { 0x50210, 0x794003e8 },
30 { 0x5fffc, 0xfcc0004d },
31 { 0x50214, 0x76c003e4 },
32 { 0x5fffc, 0xfc40005f },
33 { 0x50218, 0x73c003e0 },
34 { 0x5fffc, 0xfb800071 },
35 { 0x5021c, 0x708003de },
36 { 0x5fffc, 0xfac00085 },
37 { 0x50220, 0x6d0003db },
38 { 0x5fffc, 0xfa000098 },
39 { 0x50224, 0x698003d9 },
40 { 0x5fffc, 0xf98000ac },
41 { 0x50228, 0x654003d8 },
42 { 0x5fffc, 0xf8c000c1 },
43 { 0x5022c, 0x610003d7 },
44 { 0x5fffc, 0xf84000d5 },
45 { 0x50230, 0x5c8003d7 },
46 { 0x5fffc, 0xf7c000e9 },
47 { 0x50234, 0x580003d7 },
48 { 0x5fffc, 0xf74000fd },
49 { 0x50238, 0x534003d8 },
50 { 0x5fffc, 0xf6c00112 },
51 { 0x5023c, 0x4e8003d8 },
52 { 0x5fffc, 0xf6800126 },
53 { 0x50240, 0x494003da },
54 { 0x5fffc, 0xf600013a },
55 { 0x50244, 0x448003db },
56 { 0x5fffc, 0xf600014d },
57 { 0x50248, 0x3f4003dd },
58 { 0x5fffc, 0xf5c00160 },
59 { 0x5024c, 0x3a4003df },
60 { 0x5fffc, 0xf5c00172 },
61 { 0x50250, 0x354003e1 },
62 { 0x5fffc, 0xf5c00184 },
63 { 0x50254, 0x304003e3 },
64 { 0x5fffc, 0xf6000195 },
65 { 0x50258, 0x2b0003e6 },
66 { 0x5fffc, 0xf64001a6 },
67 { 0x5025c, 0x260003e8 },
68 { 0x5fffc, 0xf6c001b4 },
69 { 0x50260, 0x214003eb },
70 { 0x5fffc, 0xf78001c2 },
71 { 0x50264, 0x1c4003ee },
72 { 0x5fffc, 0xf80001cf },
73 { 0x50268, 0x17c003f1 },
74 { 0x5fffc, 0xf90001db },
75 { 0x5026c, 0x134003f3 },
76 { 0x5fffc, 0xfa0001e5 },
77 { 0x50270, 0xf0003f6 },
78 { 0x5fffc, 0xfb4001ee },
79 { 0x50274, 0xac003f9 },
80 { 0x5fffc, 0xfcc001f5 },
81 { 0x50278, 0x70003fb },
82 { 0x5fffc, 0xfe4001fb },
83 { 0x5027c, 0x34003fe },
84};
85
86static struct mdp_table_entry mdp_downscale_x_table_PT2TOPT4[] = {
87 { 0x5fffc, 0x740008c },
88 { 0x50280, 0x33800088 },
89 { 0x5fffc, 0x800008e },
90 { 0x50284, 0x33400084 },
91 { 0x5fffc, 0x8400092 },
92 { 0x50288, 0x33000080 },
93 { 0x5fffc, 0x9000094 },
94 { 0x5028c, 0x3300007b },
95 { 0x5fffc, 0x9c00098 },
96 { 0x50290, 0x32400077 },
97 { 0x5fffc, 0xa40009b },
98 { 0x50294, 0x32000073 },
99 { 0x5fffc, 0xb00009d },
100 { 0x50298, 0x31c0006f },
101 { 0x5fffc, 0xbc000a0 },
102 { 0x5029c, 0x3140006b },
103 { 0x5fffc, 0xc8000a2 },
104 { 0x502a0, 0x31000067 },
105 { 0x5fffc, 0xd8000a5 },
106 { 0x502a4, 0x30800062 },
107 { 0x5fffc, 0xe4000a8 },
108 { 0x502a8, 0x2fc0005f },
109 { 0x5fffc, 0xec000aa },
110 { 0x502ac, 0x2fc0005b },
111 { 0x5fffc, 0xf8000ad },
112 { 0x502b0, 0x2f400057 },
113 { 0x5fffc, 0x108000b0 },
114 { 0x502b4, 0x2e400054 },
115 { 0x5fffc, 0x114000b2 },
116 { 0x502b8, 0x2e000050 },
117 { 0x5fffc, 0x124000b4 },
118 { 0x502bc, 0x2d80004c },
119 { 0x5fffc, 0x130000b6 },
120 { 0x502c0, 0x2d000049 },
121 { 0x5fffc, 0x140000b8 },
122 { 0x502c4, 0x2c800045 },
123 { 0x5fffc, 0x150000b9 },
124 { 0x502c8, 0x2c000042 },
125 { 0x5fffc, 0x15c000bd },
126 { 0x502cc, 0x2b40003e },
127 { 0x5fffc, 0x16c000bf },
128 { 0x502d0, 0x2a80003b },
129 { 0x5fffc, 0x17c000bf },
130 { 0x502d4, 0x2a000039 },
131 { 0x5fffc, 0x188000c2 },
132 { 0x502d8, 0x29400036 },
133 { 0x5fffc, 0x19c000c4 },
134 { 0x502dc, 0x28800032 },
135 { 0x5fffc, 0x1ac000c5 },
136 { 0x502e0, 0x2800002f },
137 { 0x5fffc, 0x1bc000c7 },
138 { 0x502e4, 0x2740002c },
139 { 0x5fffc, 0x1cc000c8 },
140 { 0x502e8, 0x26c00029 },
141 { 0x5fffc, 0x1dc000c9 },
142 { 0x502ec, 0x26000027 },
143 { 0x5fffc, 0x1ec000cc },
144 { 0x502f0, 0x25000024 },
145 { 0x5fffc, 0x200000cc },
146 { 0x502f4, 0x24800021 },
147 { 0x5fffc, 0x210000cd },
148 { 0x502f8, 0x23800020 },
149 { 0x5fffc, 0x220000ce },
150 { 0x502fc, 0x2300001d },
151};
152
153static struct mdp_table_entry mdp_downscale_x_table_PT4TOPT6[] = {
154 { 0x5fffc, 0x740008c },
155 { 0x50280, 0x33800088 },
156 { 0x5fffc, 0x800008e },
157 { 0x50284, 0x33400084 },
158 { 0x5fffc, 0x8400092 },
159 { 0x50288, 0x33000080 },
160 { 0x5fffc, 0x9000094 },
161 { 0x5028c, 0x3300007b },
162 { 0x5fffc, 0x9c00098 },
163 { 0x50290, 0x32400077 },
164 { 0x5fffc, 0xa40009b },
165 { 0x50294, 0x32000073 },
166 { 0x5fffc, 0xb00009d },
167 { 0x50298, 0x31c0006f },
168 { 0x5fffc, 0xbc000a0 },
169 { 0x5029c, 0x3140006b },
170 { 0x5fffc, 0xc8000a2 },
171 { 0x502a0, 0x31000067 },
172 { 0x5fffc, 0xd8000a5 },
173 { 0x502a4, 0x30800062 },
174 { 0x5fffc, 0xe4000a8 },
175 { 0x502a8, 0x2fc0005f },
176 { 0x5fffc, 0xec000aa },
177 { 0x502ac, 0x2fc0005b },
178 { 0x5fffc, 0xf8000ad },
179 { 0x502b0, 0x2f400057 },
180 { 0x5fffc, 0x108000b0 },
181 { 0x502b4, 0x2e400054 },
182 { 0x5fffc, 0x114000b2 },
183 { 0x502b8, 0x2e000050 },
184 { 0x5fffc, 0x124000b4 },
185 { 0x502bc, 0x2d80004c },
186 { 0x5fffc, 0x130000b6 },
187 { 0x502c0, 0x2d000049 },
188 { 0x5fffc, 0x140000b8 },
189 { 0x502c4, 0x2c800045 },
190 { 0x5fffc, 0x150000b9 },
191 { 0x502c8, 0x2c000042 },
192 { 0x5fffc, 0x15c000bd },
193 { 0x502cc, 0x2b40003e },
194 { 0x5fffc, 0x16c000bf },
195 { 0x502d0, 0x2a80003b },
196 { 0x5fffc, 0x17c000bf },
197 { 0x502d4, 0x2a000039 },
198 { 0x5fffc, 0x188000c2 },
199 { 0x502d8, 0x29400036 },
200 { 0x5fffc, 0x19c000c4 },
201 { 0x502dc, 0x28800032 },
202 { 0x5fffc, 0x1ac000c5 },
203 { 0x502e0, 0x2800002f },
204 { 0x5fffc, 0x1bc000c7 },
205 { 0x502e4, 0x2740002c },
206 { 0x5fffc, 0x1cc000c8 },
207 { 0x502e8, 0x26c00029 },
208 { 0x5fffc, 0x1dc000c9 },
209 { 0x502ec, 0x26000027 },
210 { 0x5fffc, 0x1ec000cc },
211 { 0x502f0, 0x25000024 },
212 { 0x5fffc, 0x200000cc },
213 { 0x502f4, 0x24800021 },
214 { 0x5fffc, 0x210000cd },
215 { 0x502f8, 0x23800020 },
216 { 0x5fffc, 0x220000ce },
217 { 0x502fc, 0x2300001d },
218};
219
220static struct mdp_table_entry mdp_downscale_x_table_PT6TOPT8[] = {
221 { 0x5fffc, 0xfe000070 },
222 { 0x50280, 0x4bc00068 },
223 { 0x5fffc, 0xfe000078 },
224 { 0x50284, 0x4bc00060 },
225 { 0x5fffc, 0xfe000080 },
226 { 0x50288, 0x4b800059 },
227 { 0x5fffc, 0xfe000089 },
228 { 0x5028c, 0x4b000052 },
229 { 0x5fffc, 0xfe400091 },
230 { 0x50290, 0x4a80004b },
231 { 0x5fffc, 0xfe40009a },
232 { 0x50294, 0x4a000044 },
233 { 0x5fffc, 0xfe8000a3 },
234 { 0x50298, 0x4940003d },
235 { 0x5fffc, 0xfec000ac },
236 { 0x5029c, 0x48400037 },
237 { 0x5fffc, 0xff0000b4 },
238 { 0x502a0, 0x47800031 },
239 { 0x5fffc, 0xff8000bd },
240 { 0x502a4, 0x4640002b },
241 { 0x5fffc, 0xc5 },
242 { 0x502a8, 0x45000026 },
243 { 0x5fffc, 0x8000ce },
244 { 0x502ac, 0x43800021 },
245 { 0x5fffc, 0x10000d6 },
246 { 0x502b0, 0x4240001c },
247 { 0x5fffc, 0x18000df },
248 { 0x502b4, 0x40800018 },
249 { 0x5fffc, 0x24000e6 },
250 { 0x502b8, 0x3f000014 },
251 { 0x5fffc, 0x30000ee },
252 { 0x502bc, 0x3d400010 },
253 { 0x5fffc, 0x40000f5 },
254 { 0x502c0, 0x3b80000c },
255 { 0x5fffc, 0x50000fc },
256 { 0x502c4, 0x39800009 },
257 { 0x5fffc, 0x6000102 },
258 { 0x502c8, 0x37c00006 },
259 { 0x5fffc, 0x7000109 },
260 { 0x502cc, 0x35800004 },
261 { 0x5fffc, 0x840010e },
262 { 0x502d0, 0x33800002 },
263 { 0x5fffc, 0x9800114 },
264 { 0x502d4, 0x31400000 },
265 { 0x5fffc, 0xac00119 },
266 { 0x502d8, 0x2f4003fe },
267 { 0x5fffc, 0xc40011e },
268 { 0x502dc, 0x2d0003fc },
269 { 0x5fffc, 0xdc00121 },
270 { 0x502e0, 0x2b0003fb },
271 { 0x5fffc, 0xf400125 },
272 { 0x502e4, 0x28c003fa },
273 { 0x5fffc, 0x11000128 },
274 { 0x502e8, 0x268003f9 },
275 { 0x5fffc, 0x12c0012a },
276 { 0x502ec, 0x244003f9 },
277 { 0x5fffc, 0x1480012c },
278 { 0x502f0, 0x224003f8 },
279 { 0x5fffc, 0x1640012e },
280 { 0x502f4, 0x200003f8 },
281 { 0x5fffc, 0x1800012f },
282 { 0x502f8, 0x1e0003f8 },
283 { 0x5fffc, 0x1a00012f },
284 { 0x502fc, 0x1c0003f8 },
285};
286
287static struct mdp_table_entry mdp_downscale_x_table_PT8TO1[] = {
288 { 0x5fffc, 0x0 },
289 { 0x50280, 0x7fc00000 },
290 { 0x5fffc, 0xff80000d },
291 { 0x50284, 0x7ec003f9 },
292 { 0x5fffc, 0xfec0001c },
293 { 0x50288, 0x7d4003f3 },
294 { 0x5fffc, 0xfe40002b },
295 { 0x5028c, 0x7b8003ed },
296 { 0x5fffc, 0xfd80003c },
297 { 0x50290, 0x794003e8 },
298 { 0x5fffc, 0xfcc0004d },
299 { 0x50294, 0x76c003e4 },
300 { 0x5fffc, 0xfc40005f },
301 { 0x50298, 0x73c003e0 },
302 { 0x5fffc, 0xfb800071 },
303 { 0x5029c, 0x708003de },
304 { 0x5fffc, 0xfac00085 },
305 { 0x502a0, 0x6d0003db },
306 { 0x5fffc, 0xfa000098 },
307 { 0x502a4, 0x698003d9 },
308 { 0x5fffc, 0xf98000ac },
309 { 0x502a8, 0x654003d8 },
310 { 0x5fffc, 0xf8c000c1 },
311 { 0x502ac, 0x610003d7 },
312 { 0x5fffc, 0xf84000d5 },
313 { 0x502b0, 0x5c8003d7 },
314 { 0x5fffc, 0xf7c000e9 },
315 { 0x502b4, 0x580003d7 },
316 { 0x5fffc, 0xf74000fd },
317 { 0x502b8, 0x534003d8 },
318 { 0x5fffc, 0xf6c00112 },
319 { 0x502bc, 0x4e8003d8 },
320 { 0x5fffc, 0xf6800126 },
321 { 0x502c0, 0x494003da },
322 { 0x5fffc, 0xf600013a },
323 { 0x502c4, 0x448003db },
324 { 0x5fffc, 0xf600014d },
325 { 0x502c8, 0x3f4003dd },
326 { 0x5fffc, 0xf5c00160 },
327 { 0x502cc, 0x3a4003df },
328 { 0x5fffc, 0xf5c00172 },
329 { 0x502d0, 0x354003e1 },
330 { 0x5fffc, 0xf5c00184 },
331 { 0x502d4, 0x304003e3 },
332 { 0x5fffc, 0xf6000195 },
333 { 0x502d8, 0x2b0003e6 },
334 { 0x5fffc, 0xf64001a6 },
335 { 0x502dc, 0x260003e8 },
336 { 0x5fffc, 0xf6c001b4 },
337 { 0x502e0, 0x214003eb },
338 { 0x5fffc, 0xf78001c2 },
339 { 0x502e4, 0x1c4003ee },
340 { 0x5fffc, 0xf80001cf },
341 { 0x502e8, 0x17c003f1 },
342 { 0x5fffc, 0xf90001db },
343 { 0x502ec, 0x134003f3 },
344 { 0x5fffc, 0xfa0001e5 },
345 { 0x502f0, 0xf0003f6 },
346 { 0x5fffc, 0xfb4001ee },
347 { 0x502f4, 0xac003f9 },
348 { 0x5fffc, 0xfcc001f5 },
349 { 0x502f8, 0x70003fb },
350 { 0x5fffc, 0xfe4001fb },
351 { 0x502fc, 0x34003fe },
352};
353
354struct mdp_table_entry *mdp_downscale_x_table[MDP_DOWNSCALE_MAX] = {
355 [MDP_DOWNSCALE_PT2TOPT4] = mdp_downscale_x_table_PT2TOPT4,
356 [MDP_DOWNSCALE_PT4TOPT6] = mdp_downscale_x_table_PT4TOPT6,
357 [MDP_DOWNSCALE_PT6TOPT8] = mdp_downscale_x_table_PT6TOPT8,
358 [MDP_DOWNSCALE_PT8TO1] = mdp_downscale_x_table_PT8TO1,
359};
360
361static struct mdp_table_entry mdp_downscale_y_table_PT2TOPT4[] = {
362 { 0x5fffc, 0x740008c },
363 { 0x50300, 0x33800088 },
364 { 0x5fffc, 0x800008e },
365 { 0x50304, 0x33400084 },
366 { 0x5fffc, 0x8400092 },
367 { 0x50308, 0x33000080 },
368 { 0x5fffc, 0x9000094 },
369 { 0x5030c, 0x3300007b },
370 { 0x5fffc, 0x9c00098 },
371 { 0x50310, 0x32400077 },
372 { 0x5fffc, 0xa40009b },
373 { 0x50314, 0x32000073 },
374 { 0x5fffc, 0xb00009d },
375 { 0x50318, 0x31c0006f },
376 { 0x5fffc, 0xbc000a0 },
377 { 0x5031c, 0x3140006b },
378 { 0x5fffc, 0xc8000a2 },
379 { 0x50320, 0x31000067 },
380 { 0x5fffc, 0xd8000a5 },
381 { 0x50324, 0x30800062 },
382 { 0x5fffc, 0xe4000a8 },
383 { 0x50328, 0x2fc0005f },
384 { 0x5fffc, 0xec000aa },
385 { 0x5032c, 0x2fc0005b },
386 { 0x5fffc, 0xf8000ad },
387 { 0x50330, 0x2f400057 },
388 { 0x5fffc, 0x108000b0 },
389 { 0x50334, 0x2e400054 },
390 { 0x5fffc, 0x114000b2 },
391 { 0x50338, 0x2e000050 },
392 { 0x5fffc, 0x124000b4 },
393 { 0x5033c, 0x2d80004c },
394 { 0x5fffc, 0x130000b6 },
395 { 0x50340, 0x2d000049 },
396 { 0x5fffc, 0x140000b8 },
397 { 0x50344, 0x2c800045 },
398 { 0x5fffc, 0x150000b9 },
399 { 0x50348, 0x2c000042 },
400 { 0x5fffc, 0x15c000bd },
401 { 0x5034c, 0x2b40003e },
402 { 0x5fffc, 0x16c000bf },
403 { 0x50350, 0x2a80003b },
404 { 0x5fffc, 0x17c000bf },
405 { 0x50354, 0x2a000039 },
406 { 0x5fffc, 0x188000c2 },
407 { 0x50358, 0x29400036 },
408 { 0x5fffc, 0x19c000c4 },
409 { 0x5035c, 0x28800032 },
410 { 0x5fffc, 0x1ac000c5 },
411 { 0x50360, 0x2800002f },
412 { 0x5fffc, 0x1bc000c7 },
413 { 0x50364, 0x2740002c },
414 { 0x5fffc, 0x1cc000c8 },
415 { 0x50368, 0x26c00029 },
416 { 0x5fffc, 0x1dc000c9 },
417 { 0x5036c, 0x26000027 },
418 { 0x5fffc, 0x1ec000cc },
419 { 0x50370, 0x25000024 },
420 { 0x5fffc, 0x200000cc },
421 { 0x50374, 0x24800021 },
422 { 0x5fffc, 0x210000cd },
423 { 0x50378, 0x23800020 },
424 { 0x5fffc, 0x220000ce },
425 { 0x5037c, 0x2300001d },
426};
427
428static struct mdp_table_entry mdp_downscale_y_table_PT4TOPT6[] = {
429 { 0x5fffc, 0x740008c },
430 { 0x50300, 0x33800088 },
431 { 0x5fffc, 0x800008e },
432 { 0x50304, 0x33400084 },
433 { 0x5fffc, 0x8400092 },
434 { 0x50308, 0x33000080 },
435 { 0x5fffc, 0x9000094 },
436 { 0x5030c, 0x3300007b },
437 { 0x5fffc, 0x9c00098 },
438 { 0x50310, 0x32400077 },
439 { 0x5fffc, 0xa40009b },
440 { 0x50314, 0x32000073 },
441 { 0x5fffc, 0xb00009d },
442 { 0x50318, 0x31c0006f },
443 { 0x5fffc, 0xbc000a0 },
444 { 0x5031c, 0x3140006b },
445 { 0x5fffc, 0xc8000a2 },
446 { 0x50320, 0x31000067 },
447 { 0x5fffc, 0xd8000a5 },
448 { 0x50324, 0x30800062 },
449 { 0x5fffc, 0xe4000a8 },
450 { 0x50328, 0x2fc0005f },
451 { 0x5fffc, 0xec000aa },
452 { 0x5032c, 0x2fc0005b },
453 { 0x5fffc, 0xf8000ad },
454 { 0x50330, 0x2f400057 },
455 { 0x5fffc, 0x108000b0 },
456 { 0x50334, 0x2e400054 },
457 { 0x5fffc, 0x114000b2 },
458 { 0x50338, 0x2e000050 },
459 { 0x5fffc, 0x124000b4 },
460 { 0x5033c, 0x2d80004c },
461 { 0x5fffc, 0x130000b6 },
462 { 0x50340, 0x2d000049 },
463 { 0x5fffc, 0x140000b8 },
464 { 0x50344, 0x2c800045 },
465 { 0x5fffc, 0x150000b9 },
466 { 0x50348, 0x2c000042 },
467 { 0x5fffc, 0x15c000bd },
468 { 0x5034c, 0x2b40003e },
469 { 0x5fffc, 0x16c000bf },
470 { 0x50350, 0x2a80003b },
471 { 0x5fffc, 0x17c000bf },
472 { 0x50354, 0x2a000039 },
473 { 0x5fffc, 0x188000c2 },
474 { 0x50358, 0x29400036 },
475 { 0x5fffc, 0x19c000c4 },
476 { 0x5035c, 0x28800032 },
477 { 0x5fffc, 0x1ac000c5 },
478 { 0x50360, 0x2800002f },
479 { 0x5fffc, 0x1bc000c7 },
480 { 0x50364, 0x2740002c },
481 { 0x5fffc, 0x1cc000c8 },
482 { 0x50368, 0x26c00029 },
483 { 0x5fffc, 0x1dc000c9 },
484 { 0x5036c, 0x26000027 },
485 { 0x5fffc, 0x1ec000cc },
486 { 0x50370, 0x25000024 },
487 { 0x5fffc, 0x200000cc },
488 { 0x50374, 0x24800021 },
489 { 0x5fffc, 0x210000cd },
490 { 0x50378, 0x23800020 },
491 { 0x5fffc, 0x220000ce },
492 { 0x5037c, 0x2300001d },
493};
494
495static struct mdp_table_entry mdp_downscale_y_table_PT6TOPT8[] = {
496 { 0x5fffc, 0xfe000070 },
497 { 0x50300, 0x4bc00068 },
498 { 0x5fffc, 0xfe000078 },
499 { 0x50304, 0x4bc00060 },
500 { 0x5fffc, 0xfe000080 },
501 { 0x50308, 0x4b800059 },
502 { 0x5fffc, 0xfe000089 },
503 { 0x5030c, 0x4b000052 },
504 { 0x5fffc, 0xfe400091 },
505 { 0x50310, 0x4a80004b },
506 { 0x5fffc, 0xfe40009a },
507 { 0x50314, 0x4a000044 },
508 { 0x5fffc, 0xfe8000a3 },
509 { 0x50318, 0x4940003d },
510 { 0x5fffc, 0xfec000ac },
511 { 0x5031c, 0x48400037 },
512 { 0x5fffc, 0xff0000b4 },
513 { 0x50320, 0x47800031 },
514 { 0x5fffc, 0xff8000bd },
515 { 0x50324, 0x4640002b },
516 { 0x5fffc, 0xc5 },
517 { 0x50328, 0x45000026 },
518 { 0x5fffc, 0x8000ce },
519 { 0x5032c, 0x43800021 },
520 { 0x5fffc, 0x10000d6 },
521 { 0x50330, 0x4240001c },
522 { 0x5fffc, 0x18000df },
523 { 0x50334, 0x40800018 },
524 { 0x5fffc, 0x24000e6 },
525 { 0x50338, 0x3f000014 },
526 { 0x5fffc, 0x30000ee },
527 { 0x5033c, 0x3d400010 },
528 { 0x5fffc, 0x40000f5 },
529 { 0x50340, 0x3b80000c },
530 { 0x5fffc, 0x50000fc },
531 { 0x50344, 0x39800009 },
532 { 0x5fffc, 0x6000102 },
533 { 0x50348, 0x37c00006 },
534 { 0x5fffc, 0x7000109 },
535 { 0x5034c, 0x35800004 },
536 { 0x5fffc, 0x840010e },
537 { 0x50350, 0x33800002 },
538 { 0x5fffc, 0x9800114 },
539 { 0x50354, 0x31400000 },
540 { 0x5fffc, 0xac00119 },
541 { 0x50358, 0x2f4003fe },
542 { 0x5fffc, 0xc40011e },
543 { 0x5035c, 0x2d0003fc },
544 { 0x5fffc, 0xdc00121 },
545 { 0x50360, 0x2b0003fb },
546 { 0x5fffc, 0xf400125 },
547 { 0x50364, 0x28c003fa },
548 { 0x5fffc, 0x11000128 },
549 { 0x50368, 0x268003f9 },
550 { 0x5fffc, 0x12c0012a },
551 { 0x5036c, 0x244003f9 },
552 { 0x5fffc, 0x1480012c },
553 { 0x50370, 0x224003f8 },
554 { 0x5fffc, 0x1640012e },
555 { 0x50374, 0x200003f8 },
556 { 0x5fffc, 0x1800012f },
557 { 0x50378, 0x1e0003f8 },
558 { 0x5fffc, 0x1a00012f },
559 { 0x5037c, 0x1c0003f8 },
560};
561
562static struct mdp_table_entry mdp_downscale_y_table_PT8TO1[] = {
563 { 0x5fffc, 0x0 },
564 { 0x50300, 0x7fc00000 },
565 { 0x5fffc, 0xff80000d },
566 { 0x50304, 0x7ec003f9 },
567 { 0x5fffc, 0xfec0001c },
568 { 0x50308, 0x7d4003f3 },
569 { 0x5fffc, 0xfe40002b },
570 { 0x5030c, 0x7b8003ed },
571 { 0x5fffc, 0xfd80003c },
572 { 0x50310, 0x794003e8 },
573 { 0x5fffc, 0xfcc0004d },
574 { 0x50314, 0x76c003e4 },
575 { 0x5fffc, 0xfc40005f },
576 { 0x50318, 0x73c003e0 },
577 { 0x5fffc, 0xfb800071 },
578 { 0x5031c, 0x708003de },
579 { 0x5fffc, 0xfac00085 },
580 { 0x50320, 0x6d0003db },
581 { 0x5fffc, 0xfa000098 },
582 { 0x50324, 0x698003d9 },
583 { 0x5fffc, 0xf98000ac },
584 { 0x50328, 0x654003d8 },
585 { 0x5fffc, 0xf8c000c1 },
586 { 0x5032c, 0x610003d7 },
587 { 0x5fffc, 0xf84000d5 },
588 { 0x50330, 0x5c8003d7 },
589 { 0x5fffc, 0xf7c000e9 },
590 { 0x50334, 0x580003d7 },
591 { 0x5fffc, 0xf74000fd },
592 { 0x50338, 0x534003d8 },
593 { 0x5fffc, 0xf6c00112 },
594 { 0x5033c, 0x4e8003d8 },
595 { 0x5fffc, 0xf6800126 },
596 { 0x50340, 0x494003da },
597 { 0x5fffc, 0xf600013a },
598 { 0x50344, 0x448003db },
599 { 0x5fffc, 0xf600014d },
600 { 0x50348, 0x3f4003dd },
601 { 0x5fffc, 0xf5c00160 },
602 { 0x5034c, 0x3a4003df },
603 { 0x5fffc, 0xf5c00172 },
604 { 0x50350, 0x354003e1 },
605 { 0x5fffc, 0xf5c00184 },
606 { 0x50354, 0x304003e3 },
607 { 0x5fffc, 0xf6000195 },
608 { 0x50358, 0x2b0003e6 },
609 { 0x5fffc, 0xf64001a6 },
610 { 0x5035c, 0x260003e8 },
611 { 0x5fffc, 0xf6c001b4 },
612 { 0x50360, 0x214003eb },
613 { 0x5fffc, 0xf78001c2 },
614 { 0x50364, 0x1c4003ee },
615 { 0x5fffc, 0xf80001cf },
616 { 0x50368, 0x17c003f1 },
617 { 0x5fffc, 0xf90001db },
618 { 0x5036c, 0x134003f3 },
619 { 0x5fffc, 0xfa0001e5 },
620 { 0x50370, 0xf0003f6 },
621 { 0x5fffc, 0xfb4001ee },
622 { 0x50374, 0xac003f9 },
623 { 0x5fffc, 0xfcc001f5 },
624 { 0x50378, 0x70003fb },
625 { 0x5fffc, 0xfe4001fb },
626 { 0x5037c, 0x34003fe },
627};
628
629struct mdp_table_entry *mdp_downscale_y_table[MDP_DOWNSCALE_MAX] = {
630 [MDP_DOWNSCALE_PT2TOPT4] = mdp_downscale_y_table_PT2TOPT4,
631 [MDP_DOWNSCALE_PT4TOPT6] = mdp_downscale_y_table_PT4TOPT6,
632 [MDP_DOWNSCALE_PT6TOPT8] = mdp_downscale_y_table_PT6TOPT8,
633 [MDP_DOWNSCALE_PT8TO1] = mdp_downscale_y_table_PT8TO1,
634};
635
636struct mdp_table_entry mdp_gaussian_blur_table[] = {
637 /* max variance */
638 { 0x5fffc, 0x20000080 },
639 { 0x50280, 0x20000080 },
640 { 0x5fffc, 0x20000080 },
641 { 0x50284, 0x20000080 },
642 { 0x5fffc, 0x20000080 },
643 { 0x50288, 0x20000080 },
644 { 0x5fffc, 0x20000080 },
645 { 0x5028c, 0x20000080 },
646 { 0x5fffc, 0x20000080 },
647 { 0x50290, 0x20000080 },
648 { 0x5fffc, 0x20000080 },
649 { 0x50294, 0x20000080 },
650 { 0x5fffc, 0x20000080 },
651 { 0x50298, 0x20000080 },
652 { 0x5fffc, 0x20000080 },
653 { 0x5029c, 0x20000080 },
654 { 0x5fffc, 0x20000080 },
655 { 0x502a0, 0x20000080 },
656 { 0x5fffc, 0x20000080 },
657 { 0x502a4, 0x20000080 },
658 { 0x5fffc, 0x20000080 },
659 { 0x502a8, 0x20000080 },
660 { 0x5fffc, 0x20000080 },
661 { 0x502ac, 0x20000080 },
662 { 0x5fffc, 0x20000080 },
663 { 0x502b0, 0x20000080 },
664 { 0x5fffc, 0x20000080 },
665 { 0x502b4, 0x20000080 },
666 { 0x5fffc, 0x20000080 },
667 { 0x502b8, 0x20000080 },
668 { 0x5fffc, 0x20000080 },
669 { 0x502bc, 0x20000080 },
670 { 0x5fffc, 0x20000080 },
671 { 0x502c0, 0x20000080 },
672 { 0x5fffc, 0x20000080 },
673 { 0x502c4, 0x20000080 },
674 { 0x5fffc, 0x20000080 },
675 { 0x502c8, 0x20000080 },
676 { 0x5fffc, 0x20000080 },
677 { 0x502cc, 0x20000080 },
678 { 0x5fffc, 0x20000080 },
679 { 0x502d0, 0x20000080 },
680 { 0x5fffc, 0x20000080 },
681 { 0x502d4, 0x20000080 },
682 { 0x5fffc, 0x20000080 },
683 { 0x502d8, 0x20000080 },
684 { 0x5fffc, 0x20000080 },
685 { 0x502dc, 0x20000080 },
686 { 0x5fffc, 0x20000080 },
687 { 0x502e0, 0x20000080 },
688 { 0x5fffc, 0x20000080 },
689 { 0x502e4, 0x20000080 },
690 { 0x5fffc, 0x20000080 },
691 { 0x502e8, 0x20000080 },
692 { 0x5fffc, 0x20000080 },
693 { 0x502ec, 0x20000080 },
694 { 0x5fffc, 0x20000080 },
695 { 0x502f0, 0x20000080 },
696 { 0x5fffc, 0x20000080 },
697 { 0x502f4, 0x20000080 },
698 { 0x5fffc, 0x20000080 },
699 { 0x502f8, 0x20000080 },
700 { 0x5fffc, 0x20000080 },
701 { 0x502fc, 0x20000080 },
702 { 0x5fffc, 0x20000080 },
703 { 0x50300, 0x20000080 },
704 { 0x5fffc, 0x20000080 },
705 { 0x50304, 0x20000080 },
706 { 0x5fffc, 0x20000080 },
707 { 0x50308, 0x20000080 },
708 { 0x5fffc, 0x20000080 },
709 { 0x5030c, 0x20000080 },
710 { 0x5fffc, 0x20000080 },
711 { 0x50310, 0x20000080 },
712 { 0x5fffc, 0x20000080 },
713 { 0x50314, 0x20000080 },
714 { 0x5fffc, 0x20000080 },
715 { 0x50318, 0x20000080 },
716 { 0x5fffc, 0x20000080 },
717 { 0x5031c, 0x20000080 },
718 { 0x5fffc, 0x20000080 },
719 { 0x50320, 0x20000080 },
720 { 0x5fffc, 0x20000080 },
721 { 0x50324, 0x20000080 },
722 { 0x5fffc, 0x20000080 },
723 { 0x50328, 0x20000080 },
724 { 0x5fffc, 0x20000080 },
725 { 0x5032c, 0x20000080 },
726 { 0x5fffc, 0x20000080 },
727 { 0x50330, 0x20000080 },
728 { 0x5fffc, 0x20000080 },
729 { 0x50334, 0x20000080 },
730 { 0x5fffc, 0x20000080 },
731 { 0x50338, 0x20000080 },
732 { 0x5fffc, 0x20000080 },
733 { 0x5033c, 0x20000080 },
734 { 0x5fffc, 0x20000080 },
735 { 0x50340, 0x20000080 },
736 { 0x5fffc, 0x20000080 },
737 { 0x50344, 0x20000080 },
738 { 0x5fffc, 0x20000080 },
739 { 0x50348, 0x20000080 },
740 { 0x5fffc, 0x20000080 },
741 { 0x5034c, 0x20000080 },
742 { 0x5fffc, 0x20000080 },
743 { 0x50350, 0x20000080 },
744 { 0x5fffc, 0x20000080 },
745 { 0x50354, 0x20000080 },
746 { 0x5fffc, 0x20000080 },
747 { 0x50358, 0x20000080 },
748 { 0x5fffc, 0x20000080 },
749 { 0x5035c, 0x20000080 },
750 { 0x5fffc, 0x20000080 },
751 { 0x50360, 0x20000080 },
752 { 0x5fffc, 0x20000080 },
753 { 0x50364, 0x20000080 },
754 { 0x5fffc, 0x20000080 },
755 { 0x50368, 0x20000080 },
756 { 0x5fffc, 0x20000080 },
757 { 0x5036c, 0x20000080 },
758 { 0x5fffc, 0x20000080 },
759 { 0x50370, 0x20000080 },
760 { 0x5fffc, 0x20000080 },
761 { 0x50374, 0x20000080 },
762 { 0x5fffc, 0x20000080 },
763 { 0x50378, 0x20000080 },
764 { 0x5fffc, 0x20000080 },
765 { 0x5037c, 0x20000080 },
766};
diff --git a/drivers/video/msm/mdp_scale_tables.h b/drivers/video/msm/mdp_scale_tables.h
new file mode 100644
index 000000000000..34077b1af603
--- /dev/null
+++ b/drivers/video/msm/mdp_scale_tables.h
@@ -0,0 +1,38 @@
1/* drivers/video/msm_fb/mdp_scale_tables.h
2 *
3 * Copyright (C) 2007 QUALCOMM Incorporated
4 * Copyright (C) 2007 Google Incorporated
5 *
6 * This software is licensed under the terms of the GNU General Public
7 * License version 2, as published by the Free Software Foundation, and
8 * may be copied, distributed, and modified under those terms.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15#ifndef _MDP_SCALE_TABLES_H_
16#define _MDP_SCALE_TABLES_H_
17
18#include <linux/types.h>
19struct mdp_table_entry {
20 uint32_t reg;
21 uint32_t val;
22};
23
24extern struct mdp_table_entry mdp_upscale_table[64];
25
26enum {
27 MDP_DOWNSCALE_PT2TOPT4,
28 MDP_DOWNSCALE_PT4TOPT6,
29 MDP_DOWNSCALE_PT6TOPT8,
30 MDP_DOWNSCALE_PT8TO1,
31 MDP_DOWNSCALE_MAX,
32};
33
34extern struct mdp_table_entry *mdp_downscale_x_table[MDP_DOWNSCALE_MAX];
35extern struct mdp_table_entry *mdp_downscale_y_table[MDP_DOWNSCALE_MAX];
36extern struct mdp_table_entry mdp_gaussian_blur_table[];
37
38#endif
diff --git a/drivers/video/msm/msm_fb.c b/drivers/video/msm/msm_fb.c
new file mode 100644
index 000000000000..49101dda45ee
--- /dev/null
+++ b/drivers/video/msm/msm_fb.c
@@ -0,0 +1,636 @@
1/* drivers/video/msm/msm_fb.c
2 *
3 * Core MSM framebuffer driver.
4 *
5 * Copyright (C) 2007 Google Incorporated
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <linux/platform_device.h>
18#include <linux/module.h>
19#include <linux/fb.h>
20#include <linux/delay.h>
21
22#include <linux/freezer.h>
23#include <linux/wait.h>
24#include <linux/msm_mdp.h>
25#include <linux/io.h>
26#include <linux/uaccess.h>
27#include <mach/msm_fb.h>
28#include <mach/board.h>
29#include <linux/workqueue.h>
30#include <linux/clk.h>
31#include <linux/debugfs.h>
32#include <linux/dma-mapping.h>
33
34#define PRINT_FPS 0
35#define PRINT_BLIT_TIME 0
36
37#define SLEEPING 0x4
38#define UPDATING 0x3
39#define FULL_UPDATE_DONE 0x2
40#define WAKING 0x1
41#define AWAKE 0x0
42
43#define NONE 0
44#define SUSPEND_RESUME 0x1
45#define FPS 0x2
46#define BLIT_TIME 0x4
47#define SHOW_UPDATES 0x8
48
49#define DLOG(mask, fmt, args...) \
50do { \
51 if (msmfb_debug_mask & mask) \
52 printk(KERN_INFO "msmfb: "fmt, ##args); \
53} while (0)
54
55static int msmfb_debug_mask;
56module_param_named(msmfb_debug_mask, msmfb_debug_mask, int,
57 S_IRUGO | S_IWUSR | S_IWGRP);
58
59struct mdp_device *mdp;
60
61struct msmfb_info {
62 struct fb_info *fb;
63 struct msm_panel_data *panel;
64 int xres;
65 int yres;
66 unsigned output_format;
67 unsigned yoffset;
68 unsigned frame_requested;
69 unsigned frame_done;
70 int sleeping;
71 unsigned update_frame;
72 struct {
73 int left;
74 int top;
75 int eright; /* exclusive */
76 int ebottom; /* exclusive */
77 } update_info;
78 char *black;
79
80 spinlock_t update_lock;
81 struct mutex panel_init_lock;
82 wait_queue_head_t frame_wq;
83 struct workqueue_struct *resume_workqueue;
84 struct work_struct resume_work;
85 struct msmfb_callback dma_callback;
86 struct msmfb_callback vsync_callback;
87 struct hrtimer fake_vsync;
88 ktime_t vsync_request_time;
89};
90
91static int msmfb_open(struct fb_info *info, int user)
92{
93 return 0;
94}
95
96static int msmfb_release(struct fb_info *info, int user)
97{
98 return 0;
99}
100
101/* Called from dma interrupt handler, must not sleep */
102static void msmfb_handle_dma_interrupt(struct msmfb_callback *callback)
103{
104 unsigned long irq_flags;
105 struct msmfb_info *msmfb = container_of(callback, struct msmfb_info,
106 dma_callback);
107
108 spin_lock_irqsave(&msmfb->update_lock, irq_flags);
109 msmfb->frame_done = msmfb->frame_requested;
110 if (msmfb->sleeping == UPDATING &&
111 msmfb->frame_done == msmfb->update_frame) {
112 DLOG(SUSPEND_RESUME, "full update completed\n");
113 queue_work(msmfb->resume_workqueue, &msmfb->resume_work);
114 }
115 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
116 wake_up(&msmfb->frame_wq);
117}
118
119static int msmfb_start_dma(struct msmfb_info *msmfb)
120{
121 uint32_t x, y, w, h;
122 unsigned addr;
123 unsigned long irq_flags;
124 uint32_t yoffset;
125 s64 time_since_request;
126 struct msm_panel_data *panel = msmfb->panel;
127
128 spin_lock_irqsave(&msmfb->update_lock, irq_flags);
129 time_since_request = ktime_to_ns(ktime_sub(ktime_get(),
130 msmfb->vsync_request_time));
131 if (time_since_request > 20 * NSEC_PER_MSEC) {
132 uint32_t us;
133 us = do_div(time_since_request, NSEC_PER_MSEC) / NSEC_PER_USEC;
134 printk(KERN_WARNING "msmfb_start_dma %lld.%03u ms after vsync "
135 "request\n", time_since_request, us);
136 }
137 if (msmfb->frame_done == msmfb->frame_requested) {
138 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
139 return -1;
140 }
141 if (msmfb->sleeping == SLEEPING) {
142 DLOG(SUSPEND_RESUME, "tried to start dma while asleep\n");
143 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
144 return -1;
145 }
146 x = msmfb->update_info.left;
147 y = msmfb->update_info.top;
148 w = msmfb->update_info.eright - x;
149 h = msmfb->update_info.ebottom - y;
150 yoffset = msmfb->yoffset;
151 msmfb->update_info.left = msmfb->xres + 1;
152 msmfb->update_info.top = msmfb->yres + 1;
153 msmfb->update_info.eright = 0;
154 msmfb->update_info.ebottom = 0;
155 if (unlikely(w > msmfb->xres || h > msmfb->yres ||
156 w == 0 || h == 0)) {
157 printk(KERN_INFO "invalid update: %d %d %d "
158 "%d\n", x, y, w, h);
159 msmfb->frame_done = msmfb->frame_requested;
160 goto error;
161 }
162 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
163
164 addr = ((msmfb->xres * (yoffset + y) + x) * 2);
165 mdp->dma(mdp, addr + msmfb->fb->fix.smem_start,
166 msmfb->xres * 2, w, h, x, y, &msmfb->dma_callback,
167 panel->interface_type);
168 return 0;
169error:
170 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
171 /* some clients need to clear their vsync interrupt */
172 if (panel->clear_vsync)
173 panel->clear_vsync(panel);
174 wake_up(&msmfb->frame_wq);
175 return 0;
176}
177
178/* Called from esync interrupt handler, must not sleep */
179static void msmfb_handle_vsync_interrupt(struct msmfb_callback *callback)
180{
181 struct msmfb_info *msmfb = container_of(callback, struct msmfb_info,
182 vsync_callback);
183 msmfb_start_dma(msmfb);
184}
185
186static enum hrtimer_restart msmfb_fake_vsync(struct hrtimer *timer)
187{
188 struct msmfb_info *msmfb = container_of(timer, struct msmfb_info,
189 fake_vsync);
190 msmfb_start_dma(msmfb);
191 return HRTIMER_NORESTART;
192}
193
194static void msmfb_pan_update(struct fb_info *info, uint32_t left, uint32_t top,
195 uint32_t eright, uint32_t ebottom,
196 uint32_t yoffset, int pan_display)
197{
198 struct msmfb_info *msmfb = info->par;
199 struct msm_panel_data *panel = msmfb->panel;
200 unsigned long irq_flags;
201 int sleeping;
202 int retry = 1;
203
204 DLOG(SHOW_UPDATES, "update %d %d %d %d %d %d\n",
205 left, top, eright, ebottom, yoffset, pan_display);
206restart:
207 spin_lock_irqsave(&msmfb->update_lock, irq_flags);
208
209 /* if we are sleeping, on a pan_display wait 10ms (to throttle back
210 * drawing otherwise return */
211 if (msmfb->sleeping == SLEEPING) {
212 DLOG(SUSPEND_RESUME, "drawing while asleep\n");
213 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
214 if (pan_display)
215 wait_event_interruptible_timeout(msmfb->frame_wq,
216 msmfb->sleeping != SLEEPING, HZ/10);
217 return;
218 }
219
220 sleeping = msmfb->sleeping;
221 /* on a full update, if the last frame has not completed, wait for it */
222 if (pan_display && (msmfb->frame_requested != msmfb->frame_done ||
223 sleeping == UPDATING)) {
224 int ret;
225 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
226 ret = wait_event_interruptible_timeout(msmfb->frame_wq,
227 msmfb->frame_done == msmfb->frame_requested &&
228 msmfb->sleeping != UPDATING, 5 * HZ);
229 if (ret <= 0 && (msmfb->frame_requested != msmfb->frame_done ||
230 msmfb->sleeping == UPDATING)) {
231 if (retry && panel->request_vsync &&
232 (sleeping == AWAKE)) {
233 panel->request_vsync(panel,
234 &msmfb->vsync_callback);
235 retry = 0;
236 printk(KERN_WARNING "msmfb_pan_display timeout "
237 "rerequest vsync\n");
238 } else {
239 printk(KERN_WARNING "msmfb_pan_display timeout "
240 "waiting for frame start, %d %d\n",
241 msmfb->frame_requested,
242 msmfb->frame_done);
243 return;
244 }
245 }
246 goto restart;
247 }
248
249
250 msmfb->frame_requested++;
251 /* if necessary, update the y offset, if this is the
252 * first full update on resume, set the sleeping state */
253 if (pan_display) {
254 msmfb->yoffset = yoffset;
255 if (left == 0 && top == 0 && eright == info->var.xres &&
256 ebottom == info->var.yres) {
257 if (sleeping == WAKING) {
258 msmfb->update_frame = msmfb->frame_requested;
259 DLOG(SUSPEND_RESUME, "full update starting\n");
260 msmfb->sleeping = UPDATING;
261 }
262 }
263 }
264
265 /* set the update request */
266 if (left < msmfb->update_info.left)
267 msmfb->update_info.left = left;
268 if (top < msmfb->update_info.top)
269 msmfb->update_info.top = top;
270 if (eright > msmfb->update_info.eright)
271 msmfb->update_info.eright = eright;
272 if (ebottom > msmfb->update_info.ebottom)
273 msmfb->update_info.ebottom = ebottom;
274 DLOG(SHOW_UPDATES, "update queued %d %d %d %d %d\n",
275 msmfb->update_info.left, msmfb->update_info.top,
276 msmfb->update_info.eright, msmfb->update_info.ebottom,
277 msmfb->yoffset);
278 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
279
280 /* if the panel is all the way on wait for vsync, otherwise sleep
281 * for 16 ms (long enough for the dma to panel) and then begin dma */
282 msmfb->vsync_request_time = ktime_get();
283 if (panel->request_vsync && (sleeping == AWAKE)) {
284 panel->request_vsync(panel, &msmfb->vsync_callback);
285 } else {
286 if (!hrtimer_active(&msmfb->fake_vsync)) {
287 hrtimer_start(&msmfb->fake_vsync,
288 ktime_set(0, NSEC_PER_SEC/60),
289 HRTIMER_MODE_REL);
290 }
291 }
292}
293
294static void msmfb_update(struct fb_info *info, uint32_t left, uint32_t top,
295 uint32_t eright, uint32_t ebottom)
296{
297 msmfb_pan_update(info, left, top, eright, ebottom, 0, 0);
298}
299
300static void power_on_panel(struct work_struct *work)
301{
302 struct msmfb_info *msmfb =
303 container_of(work, struct msmfb_info, resume_work);
304 struct msm_panel_data *panel = msmfb->panel;
305 unsigned long irq_flags;
306
307 mutex_lock(&msmfb->panel_init_lock);
308 DLOG(SUSPEND_RESUME, "turning on panel\n");
309 if (msmfb->sleeping == UPDATING) {
310 if (panel->unblank(panel)) {
311 printk(KERN_INFO "msmfb: panel unblank failed,"
312 "not starting drawing\n");
313 goto error;
314 }
315 spin_lock_irqsave(&msmfb->update_lock, irq_flags);
316 msmfb->sleeping = AWAKE;
317 wake_up(&msmfb->frame_wq);
318 spin_unlock_irqrestore(&msmfb->update_lock, irq_flags);
319 }
320error:
321 mutex_unlock(&msmfb->panel_init_lock);
322}
323
324
325static int msmfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
326{
327 if ((var->xres != info->var.xres) ||
328 (var->yres != info->var.yres) ||
329 (var->xres_virtual != info->var.xres_virtual) ||
330 (var->yres_virtual != info->var.yres_virtual) ||
331 (var->xoffset != info->var.xoffset) ||
332 (var->bits_per_pixel != info->var.bits_per_pixel) ||
333 (var->grayscale != info->var.grayscale))
334 return -EINVAL;
335 return 0;
336}
337
338int msmfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
339{
340 struct msmfb_info *msmfb = info->par;
341 struct msm_panel_data *panel = msmfb->panel;
342
343 /* "UPDT" */
344 if ((panel->caps & MSMFB_CAP_PARTIAL_UPDATES) &&
345 (var->reserved[0] == 0x54445055)) {
346 msmfb_pan_update(info, var->reserved[1] & 0xffff,
347 var->reserved[1] >> 16,
348 var->reserved[2] & 0xffff,
349 var->reserved[2] >> 16, var->yoffset, 1);
350 } else {
351 msmfb_pan_update(info, 0, 0, info->var.xres, info->var.yres,
352 var->yoffset, 1);
353 }
354 return 0;
355}
356
357static void msmfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
358{
359 cfb_fillrect(p, rect);
360 msmfb_update(p, rect->dx, rect->dy, rect->dx + rect->width,
361 rect->dy + rect->height);
362}
363
364static void msmfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
365{
366 cfb_copyarea(p, area);
367 msmfb_update(p, area->dx, area->dy, area->dx + area->width,
368 area->dy + area->height);
369}
370
371static void msmfb_imageblit(struct fb_info *p, const struct fb_image *image)
372{
373 cfb_imageblit(p, image);
374 msmfb_update(p, image->dx, image->dy, image->dx + image->width,
375 image->dy + image->height);
376}
377
378
379static int msmfb_blit(struct fb_info *info,
380 void __user *p)
381{
382 struct mdp_blit_req req;
383 struct mdp_blit_req_list req_list;
384 int i;
385 int ret;
386
387 if (copy_from_user(&req_list, p, sizeof(req_list)))
388 return -EFAULT;
389
390 for (i = 0; i < req_list.count; i++) {
391 struct mdp_blit_req_list *list =
392 (struct mdp_blit_req_list *)p;
393 if (copy_from_user(&req, &list->req[i], sizeof(req)))
394 return -EFAULT;
395 ret = mdp->blit(mdp, info, &req);
396 if (ret)
397 return ret;
398 }
399 return 0;
400}
401
402
403DEFINE_MUTEX(mdp_ppp_lock);
404
405static int msmfb_ioctl(struct fb_info *p, unsigned int cmd, unsigned long arg)
406{
407 void __user *argp = (void __user *)arg;
408 int ret;
409
410 switch (cmd) {
411 case MSMFB_GRP_DISP:
412 mdp->set_grp_disp(mdp, arg);
413 break;
414 case MSMFB_BLIT:
415 ret = msmfb_blit(p, argp);
416 if (ret)
417 return ret;
418 break;
419 default:
420 printk(KERN_INFO "msmfb unknown ioctl: %d\n", cmd);
421 return -EINVAL;
422 }
423 return 0;
424}
425
426static struct fb_ops msmfb_ops = {
427 .owner = THIS_MODULE,
428 .fb_open = msmfb_open,
429 .fb_release = msmfb_release,
430 .fb_check_var = msmfb_check_var,
431 .fb_pan_display = msmfb_pan_display,
432 .fb_fillrect = msmfb_fillrect,
433 .fb_copyarea = msmfb_copyarea,
434 .fb_imageblit = msmfb_imageblit,
435 .fb_ioctl = msmfb_ioctl,
436};
437
438static unsigned PP[16];
439
440
441
442#define BITS_PER_PIXEL 16
443
444static void setup_fb_info(struct msmfb_info *msmfb)
445{
446 struct fb_info *fb_info = msmfb->fb;
447 int r;
448
449 /* finish setting up the fb_info struct */
450 strncpy(fb_info->fix.id, "msmfb", 16);
451 fb_info->fix.ypanstep = 1;
452
453 fb_info->fbops = &msmfb_ops;
454 fb_info->flags = FBINFO_DEFAULT;
455
456 fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
457 fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
458 fb_info->fix.line_length = msmfb->xres * 2;
459
460 fb_info->var.xres = msmfb->xres;
461 fb_info->var.yres = msmfb->yres;
462 fb_info->var.width = msmfb->panel->fb_data->width;
463 fb_info->var.height = msmfb->panel->fb_data->height;
464 fb_info->var.xres_virtual = msmfb->xres;
465 fb_info->var.yres_virtual = msmfb->yres * 2;
466 fb_info->var.bits_per_pixel = BITS_PER_PIXEL;
467 fb_info->var.accel_flags = 0;
468
469 fb_info->var.yoffset = 0;
470
471 if (msmfb->panel->caps & MSMFB_CAP_PARTIAL_UPDATES) {
472 fb_info->var.reserved[0] = 0x54445055;
473 fb_info->var.reserved[1] = 0;
474 fb_info->var.reserved[2] = (uint16_t)msmfb->xres |
475 ((uint32_t)msmfb->yres << 16);
476 }
477
478 fb_info->var.red.offset = 11;
479 fb_info->var.red.length = 5;
480 fb_info->var.red.msb_right = 0;
481 fb_info->var.green.offset = 5;
482 fb_info->var.green.length = 6;
483 fb_info->var.green.msb_right = 0;
484 fb_info->var.blue.offset = 0;
485 fb_info->var.blue.length = 5;
486 fb_info->var.blue.msb_right = 0;
487
488 r = fb_alloc_cmap(&fb_info->cmap, 16, 0);
489 fb_info->pseudo_palette = PP;
490
491 PP[0] = 0;
492 for (r = 1; r < 16; r++)
493 PP[r] = 0xffffffff;
494}
495
496static int setup_fbmem(struct msmfb_info *msmfb, struct platform_device *pdev)
497{
498 struct fb_info *fb = msmfb->fb;
499 struct resource *resource;
500 unsigned long size = msmfb->xres * msmfb->yres *
501 (BITS_PER_PIXEL >> 3) * 2;
502 unsigned char *fbram;
503
504 /* board file might have attached a resource describing an fb */
505 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
506 if (!resource)
507 return -EINVAL;
508
509 /* check the resource is large enough to fit the fb */
510 if (resource->end - resource->start < size) {
511 printk(KERN_ERR "allocated resource is too small for "
512 "fb\n");
513 return -ENOMEM;
514 }
515 fb->fix.smem_start = resource->start;
516 fb->fix.smem_len = resource->end - resource->start;
517 fbram = ioremap(resource->start,
518 resource->end - resource->start);
519 if (fbram == 0) {
520 printk(KERN_ERR "msmfb: cannot allocate fbram!\n");
521 return -ENOMEM;
522 }
523 fb->screen_base = fbram;
524 return 0;
525}
526
527static int msmfb_probe(struct platform_device *pdev)
528{
529 struct fb_info *fb;
530 struct msmfb_info *msmfb;
531 struct msm_panel_data *panel = pdev->dev.platform_data;
532 int ret;
533
534 if (!panel) {
535 pr_err("msmfb_probe: no platform data\n");
536 return -EINVAL;
537 }
538 if (!panel->fb_data) {
539 pr_err("msmfb_probe: no fb_data\n");
540 return -EINVAL;
541 }
542
543 fb = framebuffer_alloc(sizeof(struct msmfb_info), &pdev->dev);
544 if (!fb)
545 return -ENOMEM;
546 msmfb = fb->par;
547 msmfb->fb = fb;
548 msmfb->panel = panel;
549 msmfb->xres = panel->fb_data->xres;
550 msmfb->yres = panel->fb_data->yres;
551
552 ret = setup_fbmem(msmfb, pdev);
553 if (ret)
554 goto error_setup_fbmem;
555
556 setup_fb_info(msmfb);
557
558 spin_lock_init(&msmfb->update_lock);
559 mutex_init(&msmfb->panel_init_lock);
560 init_waitqueue_head(&msmfb->frame_wq);
561 msmfb->resume_workqueue = create_workqueue("panel_on");
562 if (msmfb->resume_workqueue == NULL) {
563 printk(KERN_ERR "failed to create panel_on workqueue\n");
564 ret = -ENOMEM;
565 goto error_create_workqueue;
566 }
567 INIT_WORK(&msmfb->resume_work, power_on_panel);
568 msmfb->black = kzalloc(msmfb->fb->var.bits_per_pixel*msmfb->xres,
569 GFP_KERNEL);
570
571 printk(KERN_INFO "msmfb_probe() installing %d x %d panel\n",
572 msmfb->xres, msmfb->yres);
573
574 msmfb->dma_callback.func = msmfb_handle_dma_interrupt;
575 msmfb->vsync_callback.func = msmfb_handle_vsync_interrupt;
576 hrtimer_init(&msmfb->fake_vsync, CLOCK_MONOTONIC,
577 HRTIMER_MODE_REL);
578
579
580 msmfb->fake_vsync.function = msmfb_fake_vsync;
581
582 ret = register_framebuffer(fb);
583 if (ret)
584 goto error_register_framebuffer;
585
586 msmfb->sleeping = WAKING;
587
588 return 0;
589
590error_register_framebuffer:
591 destroy_workqueue(msmfb->resume_workqueue);
592error_create_workqueue:
593 iounmap(fb->screen_base);
594error_setup_fbmem:
595 framebuffer_release(msmfb->fb);
596 return ret;
597}
598
599static struct platform_driver msm_panel_driver = {
600 /* need to write remove */
601 .probe = msmfb_probe,
602 .driver = {.name = "msm_panel"},
603};
604
605
606static int msmfb_add_mdp_device(struct device *dev,
607 struct class_interface *class_intf)
608{
609 /* might need locking if mulitple mdp devices */
610 if (mdp)
611 return 0;
612 mdp = container_of(dev, struct mdp_device, dev);
613 return platform_driver_register(&msm_panel_driver);
614}
615
616static void msmfb_remove_mdp_device(struct device *dev,
617 struct class_interface *class_intf)
618{
619 /* might need locking if mulitple mdp devices */
620 if (dev != &mdp->dev)
621 return;
622 platform_driver_unregister(&msm_panel_driver);
623 mdp = NULL;
624}
625
626static struct class_interface msm_fb_interface = {
627 .add_dev = &msmfb_add_mdp_device,
628 .remove_dev = &msmfb_remove_mdp_device,
629};
630
631static int __init msmfb_init(void)
632{
633 return register_mdp_client(&msm_fb_interface);
634}
635
636module_init(msmfb_init);