diff options
Diffstat (limited to 'drivers/video/msm')
-rw-r--r-- | drivers/video/msm/Makefile | 19 | ||||
-rw-r--r-- | drivers/video/msm/mddi.c | 828 | ||||
-rw-r--r-- | drivers/video/msm/mddi_client_dummy.c | 97 | ||||
-rw-r--r-- | drivers/video/msm/mddi_client_nt35399.c | 255 | ||||
-rw-r--r-- | drivers/video/msm/mddi_client_toshiba.c | 283 | ||||
-rw-r--r-- | drivers/video/msm/mddi_hw.h | 305 | ||||
-rw-r--r-- | drivers/video/msm/mdp.c | 538 | ||||
-rw-r--r-- | drivers/video/msm/mdp_csc_table.h | 582 | ||||
-rw-r--r-- | drivers/video/msm/mdp_hw.h | 621 | ||||
-rw-r--r-- | drivers/video/msm/mdp_ppp.c | 750 | ||||
-rw-r--r-- | drivers/video/msm/mdp_scale_tables.c | 766 | ||||
-rw-r--r-- | drivers/video/msm/mdp_scale_tables.h | 38 | ||||
-rw-r--r-- | drivers/video/msm/msm_fb.c | 636 |
13 files changed, 5718 insertions, 0 deletions
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 | # | ||
4 | obj-y := msm_fb.o | ||
5 | |||
6 | # MDP DMA/PPP engine | ||
7 | # | ||
8 | obj-y += mdp.o mdp_scale_tables.o mdp_ppp.o | ||
9 | |||
10 | # MDDI interface | ||
11 | # | ||
12 | obj-y += mddi.o | ||
13 | |||
14 | # MDDI client/panel drivers | ||
15 | # | ||
16 | obj-y += mddi_client_dummy.o | ||
17 | obj-y += mddi_client_toshiba.o | ||
18 | obj-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 | |||
43 | union 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 | |||
51 | struct reg_read_info { | ||
52 | struct completion done; | ||
53 | uint32_t reg; | ||
54 | uint32_t status; | ||
55 | uint32_t result; | ||
56 | }; | ||
57 | |||
58 | struct 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 | |||
97 | static 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 | |||
102 | void 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 | |||
110 | static void mddi_handle_link_list_done(struct mddi_info *mddi) | ||
111 | { | ||
112 | } | ||
113 | |||
114 | static 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 | |||
123 | static 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 | |||
186 | static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask); | ||
187 | |||
188 | static 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 | |||
260 | static 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 | |||
306 | static 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 | |||
320 | static 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 | |||
329 | static 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 | |||
337 | void 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 | |||
348 | static 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 | |||
391 | static 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 | |||
405 | static 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 | |||
425 | static 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 */ | ||
477 | int 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 | |||
514 | void 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 | |||
550 | uint32_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 | |||
626 | static struct mddi_info mddi_info[2]; | ||
627 | |||
628 | static 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 | |||
648 | fail: | ||
649 | clk_put(mddi->clk); | ||
650 | return ret; | ||
651 | } | ||
652 | |||
653 | static 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 | |||
673 | static 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 | |||
802 | error_mddi_interface: | ||
803 | error_mddi_version: | ||
804 | free_irq(mddi->irq, 0); | ||
805 | error_request_irq: | ||
806 | dma_free_coherent(NULL, 0x1000, mddi->rev_data, mddi->rev_addr); | ||
807 | error_rev_data: | ||
808 | error_clk_setup: | ||
809 | error_get_irq_resource: | ||
810 | iounmap(mddi->base); | ||
811 | error_ioremap: | ||
812 | |||
813 | printk(KERN_INFO "mddi: mddi_init() failed (%d)\n", ret); | ||
814 | return ret; | ||
815 | } | ||
816 | |||
817 | |||
818 | static struct platform_driver mddi_driver = { | ||
819 | .probe = mddi_probe, | ||
820 | .driver = { .name = "msm_mddi" }, | ||
821 | }; | ||
822 | |||
823 | static int __init _mddi_init(void) | ||
824 | { | ||
825 | return platform_driver_register(&mddi_driver); | ||
826 | } | ||
827 | |||
828 | module_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 | |||
24 | struct panel_info { | ||
25 | struct platform_device pdev; | ||
26 | struct msm_panel_data panel_data; | ||
27 | }; | ||
28 | |||
29 | static int mddi_dummy_suspend(struct msm_panel_data *panel_data) | ||
30 | { | ||
31 | return 0; | ||
32 | } | ||
33 | |||
34 | static int mddi_dummy_resume(struct msm_panel_data *panel_data) | ||
35 | { | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int mddi_dummy_blank(struct msm_panel_data *panel_data) | ||
40 | { | ||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int mddi_dummy_unblank(struct msm_panel_data *panel_data) | ||
45 | { | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static 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 | |||
77 | static 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 | |||
84 | static struct platform_driver mddi_client_dummy = { | ||
85 | .probe = mddi_dummy_probe, | ||
86 | .remove = mddi_dummy_remove, | ||
87 | .driver = { .name = "mddi_c_dummy" }, | ||
88 | }; | ||
89 | |||
90 | static int __init mddi_client_dummy_init(void) | ||
91 | { | ||
92 | platform_driver_register(&mddi_client_dummy); | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | module_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 | |||
25 | static DECLARE_WAIT_QUEUE_HEAD(nt35399_vsync_wait); | ||
26 | |||
27 | struct 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 | |||
37 | static void | ||
38 | nt35399_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 | |||
52 | static 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 | |||
71 | static 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 | |||
91 | static 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 | |||
108 | static 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 | |||
119 | static 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 | |||
130 | irqreturn_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 | |||
146 | static 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 | |||
177 | uninit: | ||
178 | free_irq(gpio_to_irq(gpio), panel->client_data); | ||
179 | err_request_irq_failed: | ||
180 | err_get_irq_num_failed: | ||
181 | err_gpio_direction_input_failed: | ||
182 | gpio_free(gpio); | ||
183 | err_request_gpio_failed: | ||
184 | return ret; | ||
185 | } | ||
186 | |||
187 | static 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 | |||
234 | static 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 | |||
243 | static 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 | |||
249 | static int __init mddi_client_nt35399_init(void) | ||
250 | { | ||
251 | return platform_driver_register(&mddi_client_0bda_8a47); | ||
252 | } | ||
253 | |||
254 | module_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 | |||
53 | static DECLARE_WAIT_QUEUE_HEAD(toshiba_vsync_wait); | ||
54 | |||
55 | struct 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 | |||
64 | static 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 | |||
78 | static 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 | |||
87 | static 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 | |||
104 | static 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 | |||
124 | static 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 | |||
141 | static 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 | |||
152 | static 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 | |||
163 | irqreturn_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 | |||
176 | static 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 | |||
207 | uninit: | ||
208 | free_irq(gpio_to_irq(gpio), panel); | ||
209 | err_request_irq_failed: | ||
210 | err_get_irq_num_failed: | ||
211 | err_gpio_direction_input_failed: | ||
212 | gpio_free(gpio); | ||
213 | err_request_gpio_failed: | ||
214 | return ret; | ||
215 | } | ||
216 | |||
217 | static 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 | |||
261 | static 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 | |||
270 | static 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 | |||
276 | static int __init mddi_client_toshiba_init(void) | ||
277 | { | ||
278 | platform_driver_register(&mddi_client_d263_0000); | ||
279 | return 0; | ||
280 | } | ||
281 | |||
282 | module_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 | |||
132 | struct __attribute__((packed)) mddi_rev_packet { | ||
133 | uint16_t length; | ||
134 | uint16_t type; | ||
135 | uint16_t client_id; | ||
136 | }; | ||
137 | |||
138 | struct __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 | |||
149 | struct __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 | |||
196 | struct __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 | |||
265 | struct __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 | |||
291 | struct __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 | |||
36 | struct class *mdp_class; | ||
37 | |||
38 | #define MDP_CMD_DEBUG_ACCESS_BASE (0x10000) | ||
39 | |||
40 | static uint16_t mdp_default_ccs[] = { | ||
41 | 0x254, 0x000, 0x331, 0x254, 0xF38, 0xE61, 0x254, 0x409, 0x000, | ||
42 | 0x010, 0x080, 0x080 | ||
43 | }; | ||
44 | |||
45 | static DECLARE_WAIT_QUEUE_HEAD(mdp_dma2_waitqueue); | ||
46 | static DECLARE_WAIT_QUEUE_HEAD(mdp_ppp_waitqueue); | ||
47 | static struct msmfb_callback *dma_callback; | ||
48 | static struct clk *clk; | ||
49 | static unsigned int mdp_irq_mask; | ||
50 | static DEFINE_SPINLOCK(mdp_lock); | ||
51 | DEFINE_MUTEX(mdp_mutex); | ||
52 | |||
53 | static int enable_mdp_irq(struct mdp_info *mdp, uint32_t mask) | ||
54 | { | ||
55 | unsigned long irq_flags; | ||
56 | int ret = 0; | ||
57 | |||
58 | BUG_ON(!mask); | ||
59 | |||
60 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
61 | /* if the mask bits are already set return an error, this interrupt | ||
62 | * is already enabled */ | ||
63 | if (mdp_irq_mask & mask) { | ||
64 | printk(KERN_ERR "mdp irq already on already on %x %x\n", | ||
65 | mdp_irq_mask, mask); | ||
66 | ret = -1; | ||
67 | } | ||
68 | /* if the mdp irq is not already enabled enable it */ | ||
69 | if (!mdp_irq_mask) { | ||
70 | if (clk) | ||
71 | clk_enable(clk); | ||
72 | enable_irq(mdp->irq); | ||
73 | } | ||
74 | |||
75 | /* update the irq mask to reflect the fact that the interrupt is | ||
76 | * enabled */ | ||
77 | mdp_irq_mask |= mask; | ||
78 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
79 | return ret; | ||
80 | } | ||
81 | |||
82 | static int locked_disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) | ||
83 | { | ||
84 | /* this interrupt is already disabled! */ | ||
85 | if (!(mdp_irq_mask & mask)) { | ||
86 | printk(KERN_ERR "mdp irq already off %x %x\n", | ||
87 | mdp_irq_mask, mask); | ||
88 | return -1; | ||
89 | } | ||
90 | /* update the irq mask to reflect the fact that the interrupt is | ||
91 | * disabled */ | ||
92 | mdp_irq_mask &= ~(mask); | ||
93 | /* if no one is waiting on the interrupt, disable it */ | ||
94 | if (!mdp_irq_mask) { | ||
95 | disable_irq(mdp->irq); | ||
96 | if (clk) | ||
97 | clk_disable(clk); | ||
98 | } | ||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static int disable_mdp_irq(struct mdp_info *mdp, uint32_t mask) | ||
103 | { | ||
104 | unsigned long irq_flags; | ||
105 | int ret; | ||
106 | |||
107 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
108 | ret = locked_disable_mdp_irq(mdp, mask); | ||
109 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
110 | return ret; | ||
111 | } | ||
112 | |||
113 | static irqreturn_t mdp_isr(int irq, void *data) | ||
114 | { | ||
115 | uint32_t status; | ||
116 | unsigned long irq_flags; | ||
117 | struct mdp_info *mdp = data; | ||
118 | |||
119 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
120 | |||
121 | status = mdp_readl(mdp, MDP_INTR_STATUS); | ||
122 | mdp_writel(mdp, status, MDP_INTR_CLEAR); | ||
123 | |||
124 | status &= mdp_irq_mask; | ||
125 | if (status & DL0_DMA2_TERM_DONE) { | ||
126 | if (dma_callback) { | ||
127 | dma_callback->func(dma_callback); | ||
128 | dma_callback = NULL; | ||
129 | } | ||
130 | wake_up(&mdp_dma2_waitqueue); | ||
131 | } | ||
132 | |||
133 | if (status & DL0_ROI_DONE) | ||
134 | wake_up(&mdp_ppp_waitqueue); | ||
135 | |||
136 | if (status) | ||
137 | locked_disable_mdp_irq(mdp, status); | ||
138 | |||
139 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
140 | return IRQ_HANDLED; | ||
141 | } | ||
142 | |||
143 | static uint32_t mdp_check_mask(uint32_t mask) | ||
144 | { | ||
145 | uint32_t ret; | ||
146 | unsigned long irq_flags; | ||
147 | |||
148 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
149 | ret = mdp_irq_mask & mask; | ||
150 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
151 | return ret; | ||
152 | } | ||
153 | |||
154 | static int mdp_wait(struct mdp_info *mdp, uint32_t mask, wait_queue_head_t *wq) | ||
155 | { | ||
156 | int ret = 0; | ||
157 | unsigned long irq_flags; | ||
158 | |||
159 | wait_event_timeout(*wq, !mdp_check_mask(mask), HZ); | ||
160 | |||
161 | spin_lock_irqsave(&mdp_lock, irq_flags); | ||
162 | if (mdp_irq_mask & mask) { | ||
163 | locked_disable_mdp_irq(mdp, mask); | ||
164 | printk(KERN_WARNING "timeout waiting for mdp to complete %x\n", | ||
165 | mask); | ||
166 | ret = -ETIMEDOUT; | ||
167 | } | ||
168 | spin_unlock_irqrestore(&mdp_lock, irq_flags); | ||
169 | |||
170 | return ret; | ||
171 | } | ||
172 | |||
173 | void mdp_dma_wait(struct mdp_device *mdp_dev) | ||
174 | { | ||
175 | #define MDP_MAX_TIMEOUTS 20 | ||
176 | static int timeout_count; | ||
177 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
178 | |||
179 | if (mdp_wait(mdp, DL0_DMA2_TERM_DONE, &mdp_dma2_waitqueue) == -ETIMEDOUT) | ||
180 | timeout_count++; | ||
181 | else | ||
182 | timeout_count = 0; | ||
183 | |||
184 | if (timeout_count > MDP_MAX_TIMEOUTS) { | ||
185 | printk(KERN_ERR "mdp: dma failed %d times, somethings wrong!\n", | ||
186 | MDP_MAX_TIMEOUTS); | ||
187 | BUG(); | ||
188 | } | ||
189 | } | ||
190 | |||
191 | static int mdp_ppp_wait(struct mdp_info *mdp) | ||
192 | { | ||
193 | return mdp_wait(mdp, DL0_ROI_DONE, &mdp_ppp_waitqueue); | ||
194 | } | ||
195 | |||
196 | void mdp_dma_to_mddi(struct mdp_info *mdp, uint32_t addr, uint32_t stride, | ||
197 | uint32_t width, uint32_t height, uint32_t x, uint32_t y, | ||
198 | struct msmfb_callback *callback) | ||
199 | { | ||
200 | uint32_t dma2_cfg; | ||
201 | uint16_t ld_param = 0; /* 0=PRIM, 1=SECD, 2=EXT */ | ||
202 | |||
203 | if (enable_mdp_irq(mdp, DL0_DMA2_TERM_DONE)) { | ||
204 | printk(KERN_ERR "mdp_dma_to_mddi: busy\n"); | ||
205 | return; | ||
206 | } | ||
207 | |||
208 | dma_callback = callback; | ||
209 | |||
210 | dma2_cfg = DMA_PACK_TIGHT | | ||
211 | DMA_PACK_ALIGN_LSB | | ||
212 | DMA_PACK_PATTERN_RGB | | ||
213 | DMA_OUT_SEL_AHB | | ||
214 | DMA_IBUF_NONCONTIGUOUS; | ||
215 | |||
216 | dma2_cfg |= DMA_IBUF_FORMAT_RGB565; | ||
217 | |||
218 | dma2_cfg |= DMA_OUT_SEL_MDDI; | ||
219 | |||
220 | dma2_cfg |= DMA_MDDI_DMAOUT_LCD_SEL_PRIMARY; | ||
221 | |||
222 | dma2_cfg |= DMA_DITHER_EN; | ||
223 | |||
224 | /* setup size, address, and stride */ | ||
225 | mdp_writel(mdp, (height << 16) | (width), | ||
226 | MDP_CMD_DEBUG_ACCESS_BASE + 0x0184); | ||
227 | mdp_writel(mdp, addr, MDP_CMD_DEBUG_ACCESS_BASE + 0x0188); | ||
228 | mdp_writel(mdp, stride, MDP_CMD_DEBUG_ACCESS_BASE + 0x018C); | ||
229 | |||
230 | /* 666 18BPP */ | ||
231 | dma2_cfg |= DMA_DSTC0G_6BITS | DMA_DSTC1B_6BITS | DMA_DSTC2R_6BITS; | ||
232 | |||
233 | /* set y & x offset and MDDI transaction parameters */ | ||
234 | mdp_writel(mdp, (y << 16) | (x), MDP_CMD_DEBUG_ACCESS_BASE + 0x0194); | ||
235 | mdp_writel(mdp, ld_param, MDP_CMD_DEBUG_ACCESS_BASE + 0x01a0); | ||
236 | mdp_writel(mdp, (MDDI_VDO_PACKET_DESC << 16) | MDDI_VDO_PACKET_PRIM, | ||
237 | MDP_CMD_DEBUG_ACCESS_BASE + 0x01a4); | ||
238 | |||
239 | mdp_writel(mdp, dma2_cfg, MDP_CMD_DEBUG_ACCESS_BASE + 0x0180); | ||
240 | |||
241 | /* start DMA2 */ | ||
242 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0044); | ||
243 | } | ||
244 | |||
245 | void mdp_dma(struct mdp_device *mdp_dev, uint32_t addr, uint32_t stride, | ||
246 | uint32_t width, uint32_t height, uint32_t x, uint32_t y, | ||
247 | struct msmfb_callback *callback, int interface) | ||
248 | { | ||
249 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
250 | |||
251 | if (interface == MSM_MDDI_PMDH_INTERFACE) { | ||
252 | mdp_dma_to_mddi(mdp, addr, stride, width, height, x, y, | ||
253 | callback); | ||
254 | } | ||
255 | } | ||
256 | |||
257 | int get_img(struct mdp_img *img, struct fb_info *info, | ||
258 | unsigned long *start, unsigned long *len, | ||
259 | struct file **filep) | ||
260 | { | ||
261 | int put_needed, ret = 0; | ||
262 | struct file *file; | ||
263 | unsigned long vstart; | ||
264 | |||
265 | #ifdef CONFIG_ANDROID_PMEM | ||
266 | if (!get_pmem_file(img->memory_id, start, &vstart, len, filep)) | ||
267 | return 0; | ||
268 | #endif | ||
269 | |||
270 | file = fget_light(img->memory_id, &put_needed); | ||
271 | if (file == NULL) | ||
272 | return -1; | ||
273 | |||
274 | if (MAJOR(file->f_dentry->d_inode->i_rdev) == FB_MAJOR) { | ||
275 | *start = info->fix.smem_start; | ||
276 | *len = info->fix.smem_len; | ||
277 | } else | ||
278 | ret = -1; | ||
279 | fput_light(file, put_needed); | ||
280 | |||
281 | return ret; | ||
282 | } | ||
283 | |||
284 | void put_img(struct file *src_file, struct file *dst_file) | ||
285 | { | ||
286 | #ifdef CONFIG_ANDROID_PMEM | ||
287 | if (src_file) | ||
288 | put_pmem_file(src_file); | ||
289 | if (dst_file) | ||
290 | put_pmem_file(dst_file); | ||
291 | #endif | ||
292 | } | ||
293 | |||
294 | int mdp_blit(struct mdp_device *mdp_dev, struct fb_info *fb, | ||
295 | struct mdp_blit_req *req) | ||
296 | { | ||
297 | int ret; | ||
298 | unsigned long src_start = 0, src_len = 0, dst_start = 0, dst_len = 0; | ||
299 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
300 | struct file *src_file = 0, *dst_file = 0; | ||
301 | |||
302 | /* WORKAROUND FOR HARDWARE BUG IN BG TILE FETCH */ | ||
303 | if (unlikely(req->src_rect.h == 0 || | ||
304 | req->src_rect.w == 0)) { | ||
305 | printk(KERN_ERR "mpd_ppp: src img of zero size!\n"); | ||
306 | return -EINVAL; | ||
307 | } | ||
308 | if (unlikely(req->dst_rect.h == 0 || | ||
309 | req->dst_rect.w == 0)) | ||
310 | return -EINVAL; | ||
311 | |||
312 | /* do this first so that if this fails, the caller can always | ||
313 | * safely call put_img */ | ||
314 | if (unlikely(get_img(&req->src, fb, &src_start, &src_len, &src_file))) { | ||
315 | printk(KERN_ERR "mpd_ppp: could not retrieve src image from " | ||
316 | "memory\n"); | ||
317 | return -EINVAL; | ||
318 | } | ||
319 | |||
320 | if (unlikely(get_img(&req->dst, fb, &dst_start, &dst_len, &dst_file))) { | ||
321 | printk(KERN_ERR "mpd_ppp: could not retrieve dst image from " | ||
322 | "memory\n"); | ||
323 | #ifdef CONFIG_ANDROID_PMEM | ||
324 | put_pmem_file(src_file); | ||
325 | #endif | ||
326 | return -EINVAL; | ||
327 | } | ||
328 | mutex_lock(&mdp_mutex); | ||
329 | |||
330 | /* transp_masking unimplemented */ | ||
331 | req->transp_mask = MDP_TRANSP_NOP; | ||
332 | if (unlikely((req->transp_mask != MDP_TRANSP_NOP || | ||
333 | req->alpha != MDP_ALPHA_NOP || | ||
334 | HAS_ALPHA(req->src.format)) && | ||
335 | (req->flags & MDP_ROT_90 && | ||
336 | req->dst_rect.w <= 16 && req->dst_rect.h >= 16))) { | ||
337 | int i; | ||
338 | unsigned int tiles = req->dst_rect.h / 16; | ||
339 | unsigned int remainder = req->dst_rect.h % 16; | ||
340 | req->src_rect.w = 16*req->src_rect.w / req->dst_rect.h; | ||
341 | req->dst_rect.h = 16; | ||
342 | for (i = 0; i < tiles; i++) { | ||
343 | enable_mdp_irq(mdp, DL0_ROI_DONE); | ||
344 | ret = mdp_ppp_blit(mdp, req, src_file, src_start, | ||
345 | src_len, dst_file, dst_start, | ||
346 | dst_len); | ||
347 | if (ret) | ||
348 | goto err_bad_blit; | ||
349 | ret = mdp_ppp_wait(mdp); | ||
350 | if (ret) | ||
351 | goto err_wait_failed; | ||
352 | req->dst_rect.y += 16; | ||
353 | req->src_rect.x += req->src_rect.w; | ||
354 | } | ||
355 | if (!remainder) | ||
356 | goto end; | ||
357 | req->src_rect.w = remainder*req->src_rect.w / req->dst_rect.h; | ||
358 | req->dst_rect.h = remainder; | ||
359 | } | ||
360 | enable_mdp_irq(mdp, DL0_ROI_DONE); | ||
361 | ret = mdp_ppp_blit(mdp, req, src_file, src_start, src_len, dst_file, | ||
362 | dst_start, | ||
363 | dst_len); | ||
364 | if (ret) | ||
365 | goto err_bad_blit; | ||
366 | ret = mdp_ppp_wait(mdp); | ||
367 | if (ret) | ||
368 | goto err_wait_failed; | ||
369 | end: | ||
370 | put_img(src_file, dst_file); | ||
371 | mutex_unlock(&mdp_mutex); | ||
372 | return 0; | ||
373 | err_bad_blit: | ||
374 | disable_mdp_irq(mdp, DL0_ROI_DONE); | ||
375 | err_wait_failed: | ||
376 | put_img(src_file, dst_file); | ||
377 | mutex_unlock(&mdp_mutex); | ||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | void mdp_set_grp_disp(struct mdp_device *mdp_dev, unsigned disp_id) | ||
382 | { | ||
383 | struct mdp_info *mdp = container_of(mdp_dev, struct mdp_info, mdp_dev); | ||
384 | |||
385 | disp_id &= 0xf; | ||
386 | mdp_writel(mdp, disp_id, MDP_FULL_BYPASS_WORD43); | ||
387 | } | ||
388 | |||
389 | int register_mdp_client(struct class_interface *cint) | ||
390 | { | ||
391 | if (!mdp_class) { | ||
392 | pr_err("mdp: no mdp_class when registering mdp client\n"); | ||
393 | return -ENODEV; | ||
394 | } | ||
395 | cint->class = mdp_class; | ||
396 | return class_interface_register(cint); | ||
397 | } | ||
398 | |||
399 | #include "mdp_csc_table.h" | ||
400 | #include "mdp_scale_tables.h" | ||
401 | |||
402 | int mdp_probe(struct platform_device *pdev) | ||
403 | { | ||
404 | struct resource *resource; | ||
405 | int ret; | ||
406 | int n; | ||
407 | struct mdp_info *mdp; | ||
408 | |||
409 | resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
410 | if (!resource) { | ||
411 | pr_err("mdp: can not get mdp mem resource!\n"); | ||
412 | return -ENOMEM; | ||
413 | } | ||
414 | |||
415 | mdp = kzalloc(sizeof(struct mdp_info), GFP_KERNEL); | ||
416 | if (!mdp) | ||
417 | return -ENOMEM; | ||
418 | |||
419 | mdp->irq = platform_get_irq(pdev, 0); | ||
420 | if (mdp->irq < 0) { | ||
421 | pr_err("mdp: can not get mdp irq\n"); | ||
422 | ret = mdp->irq; | ||
423 | goto error_get_irq; | ||
424 | } | ||
425 | |||
426 | mdp->base = ioremap(resource->start, | ||
427 | resource->end - resource->start); | ||
428 | if (mdp->base == 0) { | ||
429 | printk(KERN_ERR "msmfb: cannot allocate mdp regs!\n"); | ||
430 | ret = -ENOMEM; | ||
431 | goto error_ioremap; | ||
432 | } | ||
433 | |||
434 | mdp->mdp_dev.dma = mdp_dma; | ||
435 | mdp->mdp_dev.dma_wait = mdp_dma_wait; | ||
436 | mdp->mdp_dev.blit = mdp_blit; | ||
437 | mdp->mdp_dev.set_grp_disp = mdp_set_grp_disp; | ||
438 | |||
439 | clk = clk_get(&pdev->dev, "mdp_clk"); | ||
440 | if (IS_ERR(clk)) { | ||
441 | printk(KERN_INFO "mdp: failed to get mdp clk"); | ||
442 | return PTR_ERR(clk); | ||
443 | } | ||
444 | |||
445 | ret = request_irq(mdp->irq, mdp_isr, IRQF_DISABLED, "msm_mdp", mdp); | ||
446 | if (ret) | ||
447 | goto error_request_irq; | ||
448 | disable_irq(mdp->irq); | ||
449 | mdp_irq_mask = 0; | ||
450 | |||
451 | /* debug interface write access */ | ||
452 | mdp_writel(mdp, 1, 0x60); | ||
453 | |||
454 | mdp_writel(mdp, MDP_ANY_INTR_MASK, MDP_INTR_ENABLE); | ||
455 | mdp_writel(mdp, 1, MDP_EBI2_PORTMAP_MODE); | ||
456 | |||
457 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01f8); | ||
458 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01fc); | ||
459 | |||
460 | for (n = 0; n < ARRAY_SIZE(csc_table); n++) | ||
461 | mdp_writel(mdp, csc_table[n].val, csc_table[n].reg); | ||
462 | |||
463 | /* clear up unused fg/main registers */ | ||
464 | /* comp.plane 2&3 ystride */ | ||
465 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0120); | ||
466 | |||
467 | /* unpacked pattern */ | ||
468 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x012c); | ||
469 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0130); | ||
470 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0134); | ||
471 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0158); | ||
472 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x015c); | ||
473 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0160); | ||
474 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0170); | ||
475 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0174); | ||
476 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x017c); | ||
477 | |||
478 | /* comp.plane 2 & 3 */ | ||
479 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0114); | ||
480 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x0118); | ||
481 | |||
482 | /* clear unused bg registers */ | ||
483 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01c8); | ||
484 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01d0); | ||
485 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01dc); | ||
486 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e0); | ||
487 | mdp_writel(mdp, 0, MDP_CMD_DEBUG_ACCESS_BASE + 0x01e4); | ||
488 | |||
489 | for (n = 0; n < ARRAY_SIZE(mdp_upscale_table); n++) | ||
490 | mdp_writel(mdp, mdp_upscale_table[n].val, | ||
491 | mdp_upscale_table[n].reg); | ||
492 | |||
493 | for (n = 0; n < 9; n++) | ||
494 | mdp_writel(mdp, mdp_default_ccs[n], 0x40440 + 4 * n); | ||
495 | mdp_writel(mdp, mdp_default_ccs[9], 0x40500 + 4 * 0); | ||
496 | mdp_writel(mdp, mdp_default_ccs[10], 0x40500 + 4 * 0); | ||
497 | mdp_writel(mdp, mdp_default_ccs[11], 0x40500 + 4 * 0); | ||
498 | |||
499 | /* register mdp device */ | ||
500 | mdp->mdp_dev.dev.parent = &pdev->dev; | ||
501 | mdp->mdp_dev.dev.class = mdp_class; | ||
502 | snprintf(mdp->mdp_dev.dev.bus_id, BUS_ID_SIZE, "mdp%d", pdev->id); | ||
503 | |||
504 | /* if you can remove the platform device you'd have to implement | ||
505 | * this: | ||
506 | mdp_dev.release = mdp_class; */ | ||
507 | |||
508 | ret = device_register(&mdp->mdp_dev.dev); | ||
509 | if (ret) | ||
510 | goto error_device_register; | ||
511 | return 0; | ||
512 | |||
513 | error_device_register: | ||
514 | free_irq(mdp->irq, mdp); | ||
515 | error_request_irq: | ||
516 | iounmap(mdp->base); | ||
517 | error_get_irq: | ||
518 | error_ioremap: | ||
519 | kfree(mdp); | ||
520 | return ret; | ||
521 | } | ||
522 | |||
523 | static struct platform_driver msm_mdp_driver = { | ||
524 | .probe = mdp_probe, | ||
525 | .driver = {.name = "msm_mdp"}, | ||
526 | }; | ||
527 | |||
528 | static int __init mdp_init(void) | ||
529 | { | ||
530 | mdp_class = class_create(THIS_MODULE, "msm_mdp"); | ||
531 | if (IS_ERR(mdp_class)) { | ||
532 | printk(KERN_ERR "Error creating mdp class\n"); | ||
533 | return PTR_ERR(mdp_class); | ||
534 | } | ||
535 | return platform_driver_register(&msm_mdp_driver); | ||
536 | } | ||
537 | |||
538 | subsys_initcall(mdp_init); | ||
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 | |||
16 | static 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 | |||
21 | struct mdp_info { | ||
22 | struct mdp_device mdp_dev; | ||
23 | char * __iomem base; | ||
24 | int irq; | ||
25 | }; | ||
26 | struct mdp_blit_req; | ||
27 | struct mdp_device; | ||
28 | int 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) | ||
28 | static int downscale_y_table = MDP_DOWNSCALE_MAX; | ||
29 | static int downscale_x_table = MDP_DOWNSCALE_MAX; | ||
30 | |||
31 | struct 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 | |||
54 | static uint32_t pack_pattern[] = { | ||
55 | PPP_ARRAY0(PACK_PATTERN) | ||
56 | }; | ||
57 | |||
58 | static uint32_t src_img_cfg[] = { | ||
59 | PPP_ARRAY1(CFG, SRC) | ||
60 | }; | ||
61 | |||
62 | static uint32_t dst_img_cfg[] = { | ||
63 | PPP_ARRAY1(CFG, DST) | ||
64 | }; | ||
65 | |||
66 | static 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 | |||
80 | static uint32_t dst_op_chroma[] = { | ||
81 | PPP_ARRAY1(CHROMA_SAMP, DST) | ||
82 | }; | ||
83 | |||
84 | static uint32_t src_op_chroma[] = { | ||
85 | PPP_ARRAY1(CHROMA_SAMP, SRC) | ||
86 | }; | ||
87 | |||
88 | static uint32_t bg_op_chroma[] = { | ||
89 | PPP_ARRAY1(CHROMA_SAMP, BG) | ||
90 | }; | ||
91 | |||
92 | static 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 | |||
100 | static 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 | |||
110 | static 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 | |||
130 | static 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)) | ||
145 | static 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 | |||
169 | static 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 | |||
213 | static 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 | |||
288 | static 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 | |||
296 | enum { | ||
297 | IMG_LEFT, | ||
298 | IMG_RIGHT, | ||
299 | IMG_TOP, | ||
300 | IMG_BOTTOM, | ||
301 | }; | ||
302 | |||
303 | static 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 | |||
336 | static 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 | |||
435 | static 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 | |||
503 | static 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 | |||
526 | static 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 | |||
536 | static 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 | |||
579 | static 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 | |||
603 | static 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 | |||
623 | static 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 | |||
665 | int 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, ®s.src1, ®s.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, ®s.dst1, ®s.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 | ®s)) { | ||
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, ®s); | ||
726 | blit_convert(req, ®s); | ||
727 | if (req->flags & MDP_DITHER) | ||
728 | regs.op |= PPP_OP_DITHER_EN; | ||
729 | blit_blend(req, ®s); | ||
730 | if (blit_scale(mdp, req, ®s)) { | ||
731 | printk(KERN_ERR "mpd_ppp: error computing scale for img.\n"); | ||
732 | return -EINVAL; | ||
733 | } | ||
734 | blit_blur(mdp, req, ®s); | ||
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, ®s)) | ||
746 | return -EINVAL; | ||
747 | |||
748 | send_blit(mdp, req, ®s, 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 | |||
19 | struct 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 | |||
86 | static 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 | |||
153 | static 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 | |||
220 | static 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 | |||
287 | static 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 | |||
354 | struct 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 | |||
361 | static 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 | |||
428 | static 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 | |||
495 | static 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 | |||
562 | static 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 | |||
629 | struct 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 | |||
636 | struct 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> | ||
19 | struct mdp_table_entry { | ||
20 | uint32_t reg; | ||
21 | uint32_t val; | ||
22 | }; | ||
23 | |||
24 | extern struct mdp_table_entry mdp_upscale_table[64]; | ||
25 | |||
26 | enum { | ||
27 | MDP_DOWNSCALE_PT2TOPT4, | ||
28 | MDP_DOWNSCALE_PT4TOPT6, | ||
29 | MDP_DOWNSCALE_PT6TOPT8, | ||
30 | MDP_DOWNSCALE_PT8TO1, | ||
31 | MDP_DOWNSCALE_MAX, | ||
32 | }; | ||
33 | |||
34 | extern struct mdp_table_entry *mdp_downscale_x_table[MDP_DOWNSCALE_MAX]; | ||
35 | extern struct mdp_table_entry *mdp_downscale_y_table[MDP_DOWNSCALE_MAX]; | ||
36 | extern 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...) \ | ||
50 | do { \ | ||
51 | if (msmfb_debug_mask & mask) \ | ||
52 | printk(KERN_INFO "msmfb: "fmt, ##args); \ | ||
53 | } while (0) | ||
54 | |||
55 | static int msmfb_debug_mask; | ||
56 | module_param_named(msmfb_debug_mask, msmfb_debug_mask, int, | ||
57 | S_IRUGO | S_IWUSR | S_IWGRP); | ||
58 | |||
59 | struct mdp_device *mdp; | ||
60 | |||
61 | struct 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 | |||
91 | static int msmfb_open(struct fb_info *info, int user) | ||
92 | { | ||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int msmfb_release(struct fb_info *info, int user) | ||
97 | { | ||
98 | return 0; | ||
99 | } | ||
100 | |||
101 | /* Called from dma interrupt handler, must not sleep */ | ||
102 | static 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 | |||
119 | static 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; | ||
169 | error: | ||
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 */ | ||
179 | static 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 | |||
186 | static 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 | |||
194 | static 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); | ||
206 | restart: | ||
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 | |||
294 | static 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 | |||
300 | static 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 | } | ||
320 | error: | ||
321 | mutex_unlock(&msmfb->panel_init_lock); | ||
322 | } | ||
323 | |||
324 | |||
325 | static 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 | |||
338 | int 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 | |||
357 | static 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 | |||
364 | static 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 | |||
371 | static 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 | |||
379 | static 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 | |||
403 | DEFINE_MUTEX(mdp_ppp_lock); | ||
404 | |||
405 | static 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 | |||
426 | static 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 | |||
438 | static unsigned PP[16]; | ||
439 | |||
440 | |||
441 | |||
442 | #define BITS_PER_PIXEL 16 | ||
443 | |||
444 | static 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 | |||
496 | static 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 | |||
527 | static 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 | |||
590 | error_register_framebuffer: | ||
591 | destroy_workqueue(msmfb->resume_workqueue); | ||
592 | error_create_workqueue: | ||
593 | iounmap(fb->screen_base); | ||
594 | error_setup_fbmem: | ||
595 | framebuffer_release(msmfb->fb); | ||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | static struct platform_driver msm_panel_driver = { | ||
600 | /* need to write remove */ | ||
601 | .probe = msmfb_probe, | ||
602 | .driver = {.name = "msm_panel"}, | ||
603 | }; | ||
604 | |||
605 | |||
606 | static 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 | |||
616 | static 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 | |||
626 | static struct class_interface msm_fb_interface = { | ||
627 | .add_dev = &msmfb_add_mdp_device, | ||
628 | .remove_dev = &msmfb_remove_mdp_device, | ||
629 | }; | ||
630 | |||
631 | static int __init msmfb_init(void) | ||
632 | { | ||
633 | return register_mdp_client(&msm_fb_interface); | ||
634 | } | ||
635 | |||
636 | module_init(msmfb_init); | ||