aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/video/msm/mddi.c
diff options
context:
space:
mode:
authorPavel Machek <pavel@ucw.cz>2009-09-22 19:47:03 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 10:39:50 -0400
commitd480ace08d5b59133575e672a0bd1c97b0f8400f (patch)
tree3e2e0edd582d7f511544ad87a6095c6227d280aa /drivers/video/msm/mddi.c
parent689620100172e24fdf0981e9978a9559e8769258 (diff)
fbdev: framebuffer support for HTC Dream
Add a framebuffer driver for Qualcomm MSM/QSD SoCs, tested on HTC Dream smartphone (aka T-Mobile G1, aka ADP1). Brian said: I did the original quick and dirty version for bringup. Rebecca took over and (re)wrote the bulk of the driver, getting things stable for production ship of Dream and Sapphire, and Dima is currently adding support for later Qualcomm chipsets (QSD8x50, etc). Signed-off-by: Pavel Machek <pavel@ucw.cz> Cc: Brian Swetland <swetland@google.com> Cc: Krzysztof Helt <krzysztof.h1@poczta.fm> Cc: Rebecca Schultz Zavin <rebecca@android.com> Cc: Dima Zavin <dima@android.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/video/msm/mddi.c')
-rw-r--r--drivers/video/msm/mddi.c828
1 files changed, 828 insertions, 0 deletions
diff --git a/drivers/video/msm/mddi.c b/drivers/video/msm/mddi.c
new file mode 100644
index 00000000000..f2de5a1acd6
--- /dev/null
+++ b/drivers/video/msm/mddi.c
@@ -0,0 +1,828 @@
1/*
2 * MSM MDDI Transport
3 *
4 * Copyright (C) 2007 Google Incorporated
5 * Copyright (C) 2007 QUALCOMM Incorporated
6 *
7 * This software is licensed under the terms of the GNU General Public
8 * License version 2, as published by the Free Software Foundation, and
9 * may be copied, distributed, and modified under those terms.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 */
17
18#include <linux/module.h>
19#include <linux/kernel.h>
20#include <linux/dma-mapping.h>
21#include <linux/interrupt.h>
22#include <linux/platform_device.h>
23#include <linux/delay.h>
24#include <linux/spinlock.h>
25#include <linux/clk.h>
26#include <linux/io.h>
27#include <mach/msm_iomap.h>
28#include <mach/irqs.h>
29#include <mach/board.h>
30#include <linux/delay.h>
31
32#include <mach/msm_fb.h>
33#include "mddi_hw.h"
34
35#define FLAG_DISABLE_HIBERNATION 0x0001
36#define FLAG_HAVE_CAPS 0x0002
37#define FLAG_HAS_VSYNC_IRQ 0x0004
38#define FLAG_HAVE_STATUS 0x0008
39
40#define CMD_GET_CLIENT_CAP 0x0601
41#define CMD_GET_CLIENT_STATUS 0x0602
42
43union mddi_rev {
44 unsigned char raw[MDDI_REV_BUFFER_SIZE];
45 struct mddi_rev_packet hdr;
46 struct mddi_client_status status;
47 struct mddi_client_caps caps;
48 struct mddi_register_access reg;
49};
50
51struct reg_read_info {
52 struct completion done;
53 uint32_t reg;
54 uint32_t status;
55 uint32_t result;
56};
57
58struct mddi_info {
59 uint16_t flags;
60 uint16_t version;
61 char __iomem *base;
62 int irq;
63 struct clk *clk;
64 struct msm_mddi_client_data client_data;
65
66 /* buffer for rev encap packets */
67 void *rev_data;
68 dma_addr_t rev_addr;
69 struct mddi_llentry *reg_write_data;
70 dma_addr_t reg_write_addr;
71 struct mddi_llentry *reg_read_data;
72 dma_addr_t reg_read_addr;
73 size_t rev_data_curr;
74
75 spinlock_t int_lock;
76 uint32_t int_enable;
77 uint32_t got_int;
78 wait_queue_head_t int_wait;
79
80 struct mutex reg_write_lock;
81 struct mutex reg_read_lock;
82 struct reg_read_info *reg_read;
83
84 struct mddi_client_caps caps;
85 struct mddi_client_status status;
86
87 void (*power_client)(struct msm_mddi_client_data *, int);
88
89 /* client device published to bind us to the
90 * appropriate mddi_client driver
91 */
92 char client_name[20];
93
94 struct platform_device client_pdev;
95};
96
97static void mddi_init_rev_encap(struct mddi_info *mddi);
98
99#define mddi_readl(r) readl(mddi->base + (MDDI_##r))
100#define mddi_writel(v, r) writel((v), mddi->base + (MDDI_##r))
101
102void mddi_activate_link(struct msm_mddi_client_data *cdata)
103{
104 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
105 client_data);
106
107 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
108}
109
110static void mddi_handle_link_list_done(struct mddi_info *mddi)
111{
112}
113
114static void mddi_reset_rev_encap_ptr(struct mddi_info *mddi)
115{
116 printk(KERN_INFO "mddi: resetting rev ptr\n");
117 mddi->rev_data_curr = 0;
118 mddi_writel(mddi->rev_addr, REV_PTR);
119 mddi_writel(mddi->rev_addr, REV_PTR);
120 mddi_writel(MDDI_CMD_FORCE_NEW_REV_PTR, CMD);
121}
122
123static void mddi_handle_rev_data(struct mddi_info *mddi, union mddi_rev *rev)
124{
125 int i;
126 struct reg_read_info *ri;
127
128 if ((rev->hdr.length <= MDDI_REV_BUFFER_SIZE - 2) &&
129 (rev->hdr.length >= sizeof(struct mddi_rev_packet) - 2)) {
130
131 switch (rev->hdr.type) {
132 case TYPE_CLIENT_CAPS:
133 memcpy(&mddi->caps, &rev->caps,
134 sizeof(struct mddi_client_caps));
135 mddi->flags |= FLAG_HAVE_CAPS;
136 wake_up(&mddi->int_wait);
137 break;
138 case TYPE_CLIENT_STATUS:
139 memcpy(&mddi->status, &rev->status,
140 sizeof(struct mddi_client_status));
141 mddi->flags |= FLAG_HAVE_STATUS;
142 wake_up(&mddi->int_wait);
143 break;
144 case TYPE_REGISTER_ACCESS:
145 ri = mddi->reg_read;
146 if (ri == 0) {
147 printk(KERN_INFO "rev: got reg %x = %x without "
148 " pending read\n",
149 rev->reg.register_address,
150 rev->reg.register_data_list);
151 break;
152 }
153 if (ri->reg != rev->reg.register_address) {
154 printk(KERN_INFO "rev: got reg %x = %x for "
155 "wrong register, expected "
156 "%x\n",
157 rev->reg.register_address,
158 rev->reg.register_data_list, ri->reg);
159 break;
160 }
161 mddi->reg_read = NULL;
162 ri->status = 0;
163 ri->result = rev->reg.register_data_list;
164 complete(&ri->done);
165 break;
166 default:
167 printk(KERN_INFO "rev: unknown reverse packet: "
168 "len=%04x type=%04x CURR_REV_PTR=%x\n",
169 rev->hdr.length, rev->hdr.type,
170 mddi_readl(CURR_REV_PTR));
171 for (i = 0; i < rev->hdr.length + 2; i++) {
172 if ((i % 16) == 0)
173 printk(KERN_INFO "\n");
174 printk(KERN_INFO " %02x", rev->raw[i]);
175 }
176 printk(KERN_INFO "\n");
177 mddi_reset_rev_encap_ptr(mddi);
178 }
179 } else {
180 printk(KERN_INFO "bad rev length, %d, CURR_REV_PTR %x\n",
181 rev->hdr.length, mddi_readl(CURR_REV_PTR));
182 mddi_reset_rev_encap_ptr(mddi);
183 }
184}
185
186static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask);
187
188static void mddi_handle_rev_data_avail(struct mddi_info *mddi)
189{
190 union mddi_rev *rev = mddi->rev_data;
191 uint32_t rev_data_count;
192 uint32_t rev_crc_err_count;
193 int i;
194 struct reg_read_info *ri;
195 size_t prev_offset;
196 uint16_t length;
197
198 union mddi_rev *crev = mddi->rev_data + mddi->rev_data_curr;
199
200 /* clear the interrupt */
201 mddi_writel(MDDI_INT_REV_DATA_AVAIL, INT);
202 rev_data_count = mddi_readl(REV_PKT_CNT);
203 rev_crc_err_count = mddi_readl(REV_CRC_ERR);
204 if (rev_data_count > 1)
205 printk(KERN_INFO "rev_data_count %d\n", rev_data_count);
206
207 if (rev_crc_err_count) {
208 printk(KERN_INFO "rev_crc_err_count %d, INT %x\n",
209 rev_crc_err_count, mddi_readl(INT));
210 ri = mddi->reg_read;
211 if (ri == 0) {
212 printk(KERN_INFO "rev: got crc error without pending "
213 "read\n");
214 } else {
215 mddi->reg_read = NULL;
216 ri->status = -EIO;
217 ri->result = -1;
218 complete(&ri->done);
219 }
220 }
221
222 if (rev_data_count == 0)
223 return;
224
225 prev_offset = mddi->rev_data_curr;
226
227 length = *((uint8_t *)mddi->rev_data + mddi->rev_data_curr);
228 mddi->rev_data_curr++;
229 if (mddi->rev_data_curr == MDDI_REV_BUFFER_SIZE)
230 mddi->rev_data_curr = 0;
231 length += *((uint8_t *)mddi->rev_data + mddi->rev_data_curr) << 8;
232 mddi->rev_data_curr += 1 + length;
233 if (mddi->rev_data_curr >= MDDI_REV_BUFFER_SIZE)
234 mddi->rev_data_curr =
235 mddi->rev_data_curr % MDDI_REV_BUFFER_SIZE;
236
237 if (length > MDDI_REV_BUFFER_SIZE - 2) {
238 printk(KERN_INFO "mddi: rev data length greater than buffer"
239 "size\n");
240 mddi_reset_rev_encap_ptr(mddi);
241 return;
242 }
243
244 if (prev_offset + 2 + length >= MDDI_REV_BUFFER_SIZE) {
245 union mddi_rev tmprev;
246 size_t rem = MDDI_REV_BUFFER_SIZE - prev_offset;
247 memcpy(&tmprev.raw[0], mddi->rev_data + prev_offset, rem);
248 memcpy(&tmprev.raw[rem], mddi->rev_data, 2 + length - rem);
249 mddi_handle_rev_data(mddi, &tmprev);
250 } else {
251 mddi_handle_rev_data(mddi, crev);
252 }
253
254 if (prev_offset < MDDI_REV_BUFFER_SIZE / 2 &&
255 mddi->rev_data_curr >= MDDI_REV_BUFFER_SIZE / 2) {
256 mddi_writel(mddi->rev_addr, REV_PTR);
257 }
258}
259
260static irqreturn_t mddi_isr(int irq, void *data)
261{
262 struct msm_mddi_client_data *cdata = data;
263 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
264 client_data);
265 uint32_t active, status;
266
267 spin_lock(&mddi->int_lock);
268
269 active = mddi_readl(INT);
270 status = mddi_readl(STAT);
271
272 mddi_writel(active, INT);
273
274 /* ignore any interrupts we have disabled */
275 active &= mddi->int_enable;
276
277 mddi->got_int |= active;
278 wake_up(&mddi->int_wait);
279
280 if (active & MDDI_INT_PRI_LINK_LIST_DONE) {
281 mddi->int_enable &= (~MDDI_INT_PRI_LINK_LIST_DONE);
282 mddi_handle_link_list_done(mddi);
283 }
284 if (active & MDDI_INT_REV_DATA_AVAIL)
285 mddi_handle_rev_data_avail(mddi);
286
287 if (active & ~MDDI_INT_NEED_CLEAR)
288 mddi->int_enable &= ~(active & ~MDDI_INT_NEED_CLEAR);
289
290 if (active & MDDI_INT_LINK_ACTIVE) {
291 mddi->int_enable &= (~MDDI_INT_LINK_ACTIVE);
292 mddi->int_enable |= MDDI_INT_IN_HIBERNATION;
293 }
294
295 if (active & MDDI_INT_IN_HIBERNATION) {
296 mddi->int_enable &= (~MDDI_INT_IN_HIBERNATION);
297 mddi->int_enable |= MDDI_INT_LINK_ACTIVE;
298 }
299
300 mddi_writel(mddi->int_enable, INTEN);
301 spin_unlock(&mddi->int_lock);
302
303 return IRQ_HANDLED;
304}
305
306static long mddi_wait_interrupt_timeout(struct mddi_info *mddi,
307 uint32_t intmask, int timeout)
308{
309 unsigned long irq_flags;
310
311 spin_lock_irqsave(&mddi->int_lock, irq_flags);
312 mddi->got_int &= ~intmask;
313 mddi->int_enable |= intmask;
314 mddi_writel(mddi->int_enable, INTEN);
315 spin_unlock_irqrestore(&mddi->int_lock, irq_flags);
316 return wait_event_timeout(mddi->int_wait, mddi->got_int & intmask,
317 timeout);
318}
319
320static void mddi_wait_interrupt(struct mddi_info *mddi, uint32_t intmask)
321{
322 if (mddi_wait_interrupt_timeout(mddi, intmask, HZ/10) == 0)
323 printk(KERN_INFO KERN_ERR "mddi_wait_interrupt %d, timeout "
324 "waiting for %x, INT = %x, STAT = %x gotint = %x\n",
325 current->pid, intmask, mddi_readl(INT), mddi_readl(STAT),
326 mddi->got_int);
327}
328
329static void mddi_init_rev_encap(struct mddi_info *mddi)
330{
331 memset(mddi->rev_data, 0xee, MDDI_REV_BUFFER_SIZE);
332 mddi_writel(mddi->rev_addr, REV_PTR);
333 mddi_writel(MDDI_CMD_FORCE_NEW_REV_PTR, CMD);
334 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
335}
336
337void mddi_set_auto_hibernate(struct msm_mddi_client_data *cdata, int on)
338{
339 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
340 client_data);
341 mddi_writel(MDDI_CMD_POWERDOWN, CMD);
342 mddi_wait_interrupt(mddi, MDDI_INT_IN_HIBERNATION);
343 mddi_writel(MDDI_CMD_HIBERNATE | !!on, CMD);
344 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
345}
346
347
348static uint16_t mddi_init_registers(struct mddi_info *mddi)
349{
350 mddi_writel(0x0001, VERSION);
351 mddi_writel(MDDI_HOST_BYTES_PER_SUBFRAME, BPS);
352 mddi_writel(0x0003, SPM); /* subframes per media */
353 mddi_writel(0x0005, TA1_LEN);
354 mddi_writel(MDDI_HOST_TA2_LEN, TA2_LEN);
355 mddi_writel(0x0096, DRIVE_HI);
356 /* 0x32 normal, 0x50 for Toshiba display */
357 mddi_writel(0x0050, DRIVE_LO);
358 mddi_writel(0x003C, DISP_WAKE); /* wakeup counter */
359 mddi_writel(MDDI_HOST_REV_RATE_DIV, REV_RATE_DIV);
360
361 mddi_writel(MDDI_REV_BUFFER_SIZE, REV_SIZE);
362 mddi_writel(MDDI_MAX_REV_PKT_SIZE, REV_ENCAP_SZ);
363
364 /* disable periodic rev encap */
365 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP, CMD);
366 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
367
368 if (mddi_readl(PAD_CTL) == 0) {
369 /* If we are turning on band gap, need to wait 5us before
370 * turning on the rest of the PAD */
371 mddi_writel(0x08000, PAD_CTL);
372 udelay(5);
373 }
374
375 /* Recommendation from PAD hw team */
376 mddi_writel(0xa850f, PAD_CTL);
377
378
379 /* Need an even number for counts */
380 mddi_writel(0x60006, DRIVER_START_CNT);
381
382 mddi_set_auto_hibernate(&mddi->client_data, 0);
383
384 mddi_writel(MDDI_CMD_DISP_IGNORE, CMD);
385 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
386
387 mddi_init_rev_encap(mddi);
388 return mddi_readl(CORE_VER) & 0xffff;
389}
390
391static void mddi_suspend(struct msm_mddi_client_data *cdata)
392{
393 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
394 client_data);
395 /* turn off the client */
396 if (mddi->power_client)
397 mddi->power_client(&mddi->client_data, 0);
398 /* turn off the link */
399 mddi_writel(MDDI_CMD_RESET, CMD);
400 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
401 /* turn off the clock */
402 clk_disable(mddi->clk);
403}
404
405static void mddi_resume(struct msm_mddi_client_data *cdata)
406{
407 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
408 client_data);
409 mddi_set_auto_hibernate(&mddi->client_data, 0);
410 /* turn on the client */
411 if (mddi->power_client)
412 mddi->power_client(&mddi->client_data, 1);
413 /* turn on the clock */
414 clk_enable(mddi->clk);
415 /* set up the local registers */
416 mddi->rev_data_curr = 0;
417 mddi_init_registers(mddi);
418 mddi_writel(mddi->int_enable, INTEN);
419 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
420 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
421 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
422 mddi_set_auto_hibernate(&mddi->client_data, 1);
423}
424
425static int __init mddi_get_client_caps(struct mddi_info *mddi)
426{
427 int i, j;
428
429 /* clear any stale interrupts */
430 mddi_writel(0xffffffff, INT);
431
432 mddi->int_enable = MDDI_INT_LINK_ACTIVE |
433 MDDI_INT_IN_HIBERNATION |
434 MDDI_INT_PRI_LINK_LIST_DONE |
435 MDDI_INT_REV_DATA_AVAIL |
436 MDDI_INT_REV_OVERFLOW |
437 MDDI_INT_REV_OVERWRITE |
438 MDDI_INT_RTD_FAILURE;
439 mddi_writel(mddi->int_enable, INTEN);
440
441 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
442 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
443
444 for (j = 0; j < 3; j++) {
445 /* the toshiba vga panel does not respond to get
446 * caps unless you SEND_RTD, but the first SEND_RTD
447 * will fail...
448 */
449 for (i = 0; i < 4; i++) {
450 uint32_t stat;
451
452 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
453 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
454 stat = mddi_readl(STAT);
455 printk(KERN_INFO "mddi cmd send rtd: int %x, stat %x, "
456 "rtd val %x\n", mddi_readl(INT), stat,
457 mddi_readl(RTD_VAL));
458 if ((stat & MDDI_STAT_RTD_MEAS_FAIL) == 0)
459 break;
460 msleep(1);
461 }
462
463 mddi_writel(CMD_GET_CLIENT_CAP, CMD);
464 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
465 wait_event_timeout(mddi->int_wait, mddi->flags & FLAG_HAVE_CAPS,
466 HZ / 100);
467
468 if (mddi->flags & FLAG_HAVE_CAPS)
469 break;
470 printk(KERN_INFO KERN_ERR "mddi_init, timeout waiting for "
471 "caps\n");
472 }
473 return mddi->flags & FLAG_HAVE_CAPS;
474}
475
476/* link must be active when this is called */
477int mddi_check_status(struct mddi_info *mddi)
478{
479 int ret = -1, retry = 3;
480 mutex_lock(&mddi->reg_read_lock);
481 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD);
482 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
483
484 do {
485 mddi->flags &= ~FLAG_HAVE_STATUS;
486 mddi_writel(CMD_GET_CLIENT_STATUS, CMD);
487 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
488 wait_event_timeout(mddi->int_wait,
489 mddi->flags & FLAG_HAVE_STATUS,
490 HZ / 100);
491
492 if (mddi->flags & FLAG_HAVE_STATUS) {
493 if (mddi->status.crc_error_count)
494 printk(KERN_INFO "mddi status: crc_error "
495 "count: %d\n",
496 mddi->status.crc_error_count);
497 else
498 ret = 0;
499 break;
500 } else
501 printk(KERN_INFO "mddi status: failed to get client "
502 "status\n");
503 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
504 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
505 } while (--retry);
506
507 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD);
508 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
509 mutex_unlock(&mddi->reg_read_lock);
510 return ret;
511}
512
513
514void mddi_remote_write(struct msm_mddi_client_data *cdata, uint32_t val,
515 uint32_t reg)
516{
517 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
518 client_data);
519 struct mddi_llentry *ll;
520 struct mddi_register_access *ra;
521
522 mutex_lock(&mddi->reg_write_lock);
523
524 ll = mddi->reg_write_data;
525
526 ra = &(ll->u.r);
527 ra->length = 14 + 4;
528 ra->type = TYPE_REGISTER_ACCESS;
529 ra->client_id = 0;
530 ra->read_write_info = MDDI_WRITE | 1;
531 ra->crc16 = 0;
532
533 ra->register_address = reg;
534 ra->register_data_list = val;
535
536 ll->flags = 1;
537 ll->header_count = 14;
538 ll->data_count = 4;
539 ll->data = mddi->reg_write_addr + offsetof(struct mddi_llentry,
540 u.r.register_data_list);
541 ll->next = 0;
542 ll->reserved = 0;
543
544 mddi_writel(mddi->reg_write_addr, PRI_PTR);
545
546 mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE);
547 mutex_unlock(&mddi->reg_write_lock);
548}
549
550uint32_t mddi_remote_read(struct msm_mddi_client_data *cdata, uint32_t reg)
551{
552 struct mddi_info *mddi = container_of(cdata, struct mddi_info,
553 client_data);
554 struct mddi_llentry *ll;
555 struct mddi_register_access *ra;
556 struct reg_read_info ri;
557 unsigned s;
558 int retry_count = 2;
559 unsigned long irq_flags;
560
561 mutex_lock(&mddi->reg_read_lock);
562
563 ll = mddi->reg_read_data;
564
565 ra = &(ll->u.r);
566 ra->length = 14;
567 ra->type = TYPE_REGISTER_ACCESS;
568 ra->client_id = 0;
569 ra->read_write_info = MDDI_READ | 1;
570 ra->crc16 = 0;
571
572 ra->register_address = reg;
573
574 ll->flags = 0x11;
575 ll->header_count = 14;
576 ll->data_count = 0;
577 ll->data = 0;
578 ll->next = 0;
579 ll->reserved = 0;
580
581 s = mddi_readl(STAT);
582
583 ri.reg = reg;
584 ri.status = -1;
585
586 do {
587 init_completion(&ri.done);
588 mddi->reg_read = &ri;
589 mddi_writel(mddi->reg_read_addr, PRI_PTR);
590
591 mddi_wait_interrupt(mddi, MDDI_INT_PRI_LINK_LIST_DONE);
592
593 /* Enable Periodic Reverse Encapsulation. */
594 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 1, CMD);
595 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
596 if (wait_for_completion_timeout(&ri.done, HZ/10) == 0 &&
597 !ri.done.done) {
598 printk(KERN_INFO "mddi_remote_read(%x) timeout "
599 "(%d %d %d)\n",
600 reg, ri.status, ri.result, ri.done.done);
601 spin_lock_irqsave(&mddi->int_lock, irq_flags);
602 mddi->reg_read = NULL;
603 spin_unlock_irqrestore(&mddi->int_lock, irq_flags);
604 ri.status = -1;
605 ri.result = -1;
606 }
607 if (ri.status == 0)
608 break;
609
610 mddi_writel(MDDI_CMD_SEND_RTD, CMD);
611 mddi_writel(MDDI_CMD_LINK_ACTIVE, CMD);
612 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
613 printk(KERN_INFO "mddi_remote_read: failed, sent "
614 "MDDI_CMD_SEND_RTD: int %x, stat %x, rtd val %x "
615 "curr_rev_ptr %x\n", mddi_readl(INT), mddi_readl(STAT),
616 mddi_readl(RTD_VAL), mddi_readl(CURR_REV_PTR));
617 } while (retry_count-- > 0);
618 /* Disable Periodic Reverse Encapsulation. */
619 mddi_writel(MDDI_CMD_PERIODIC_REV_ENCAP | 0, CMD);
620 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
621 mddi->reg_read = NULL;
622 mutex_unlock(&mddi->reg_read_lock);
623 return ri.result;
624}
625
626static struct mddi_info mddi_info[2];
627
628static int __init mddi_clk_setup(struct platform_device *pdev,
629 struct mddi_info *mddi,
630 unsigned long clk_rate)
631{
632 int ret;
633
634 /* set up the clocks */
635 mddi->clk = clk_get(&pdev->dev, "mddi_clk");
636 if (IS_ERR(mddi->clk)) {
637 printk(KERN_INFO "mddi: failed to get clock\n");
638 return PTR_ERR(mddi->clk);
639 }
640 ret = clk_enable(mddi->clk);
641 if (ret)
642 goto fail;
643 ret = clk_set_rate(mddi->clk, clk_rate);
644 if (ret)
645 goto fail;
646 return 0;
647
648fail:
649 clk_put(mddi->clk);
650 return ret;
651}
652
653static int __init mddi_rev_data_setup(struct mddi_info *mddi)
654{
655 void *dma;
656 dma_addr_t dma_addr;
657
658 /* set up dma buffer */
659 dma = dma_alloc_coherent(NULL, 0x1000, &dma_addr, GFP_KERNEL);
660 if (dma == 0)
661 return -ENOMEM;
662 mddi->rev_data = dma;
663 mddi->rev_data_curr = 0;
664 mddi->rev_addr = dma_addr;
665 mddi->reg_write_data = dma + MDDI_REV_BUFFER_SIZE;
666 mddi->reg_write_addr = dma_addr + MDDI_REV_BUFFER_SIZE;
667 mddi->reg_read_data = mddi->reg_write_data + 1;
668 mddi->reg_read_addr = mddi->reg_write_addr +
669 sizeof(*mddi->reg_write_data);
670 return 0;
671}
672
673static int __init mddi_probe(struct platform_device *pdev)
674{
675 struct msm_mddi_platform_data *pdata = pdev->dev.platform_data;
676 struct mddi_info *mddi = &mddi_info[pdev->id];
677 struct resource *resource;
678 int ret, i;
679
680 resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
681 if (!resource) {
682 printk(KERN_ERR "mddi: no associated mem resource!\n");
683 return -ENOMEM;
684 }
685 mddi->base = ioremap(resource->start, resource->end - resource->start);
686 if (!mddi->base) {
687 printk(KERN_ERR "mddi: failed to remap base!\n");
688 ret = -EINVAL;
689 goto error_ioremap;
690 }
691 resource = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
692 if (!resource) {
693 printk(KERN_ERR "mddi: no associated irq resource!\n");
694 ret = -EINVAL;
695 goto error_get_irq_resource;
696 }
697 mddi->irq = resource->start;
698 printk(KERN_INFO "mddi: init() base=0x%p irq=%d\n", mddi->base,
699 mddi->irq);
700 mddi->power_client = pdata->power_client;
701
702 mutex_init(&mddi->reg_write_lock);
703 mutex_init(&mddi->reg_read_lock);
704 spin_lock_init(&mddi->int_lock);
705 init_waitqueue_head(&mddi->int_wait);
706
707 ret = mddi_clk_setup(pdev, mddi, pdata->clk_rate);
708 if (ret) {
709 printk(KERN_ERR "mddi: failed to setup clock!\n");
710 goto error_clk_setup;
711 }
712
713 ret = mddi_rev_data_setup(mddi);
714 if (ret) {
715 printk(KERN_ERR "mddi: failed to setup rev data!\n");
716 goto error_rev_data;
717 }
718
719 mddi->int_enable = 0;
720 mddi_writel(mddi->int_enable, INTEN);
721 ret = request_irq(mddi->irq, mddi_isr, IRQF_DISABLED, "mddi",
722 &mddi->client_data);
723 if (ret) {
724 printk(KERN_ERR "mddi: failed to request enable irq!\n");
725 goto error_request_irq;
726 }
727
728 /* turn on the mddi client bridge chip */
729 if (mddi->power_client)
730 mddi->power_client(&mddi->client_data, 1);
731
732 /* initialize the mddi registers */
733 mddi_set_auto_hibernate(&mddi->client_data, 0);
734 mddi_writel(MDDI_CMD_RESET, CMD);
735 mddi_wait_interrupt(mddi, MDDI_INT_NO_CMD_PKTS_PEND);
736 mddi->version = mddi_init_registers(mddi);
737 if (mddi->version < 0x20) {
738 printk(KERN_ERR "mddi: unsupported version 0x%x\n",
739 mddi->version);
740 ret = -ENODEV;
741 goto error_mddi_version;
742 }
743
744 /* read the capabilities off the client */
745 if (!mddi_get_client_caps(mddi)) {
746 printk(KERN_INFO "mddi: no client found\n");
747 /* power down the panel */
748 mddi_writel(MDDI_CMD_POWERDOWN, CMD);
749 printk(KERN_INFO "mddi powerdown: stat %x\n", mddi_readl(STAT));
750 msleep(100);
751 printk(KERN_INFO "mddi powerdown: stat %x\n", mddi_readl(STAT));
752 return 0;
753 }
754 mddi_set_auto_hibernate(&mddi->client_data, 1);
755
756 if (mddi->caps.Mfr_Name == 0 && mddi->caps.Product_Code == 0)
757 pdata->fixup(&mddi->caps.Mfr_Name, &mddi->caps.Product_Code);
758
759 mddi->client_pdev.id = 0;
760 for (i = 0; i < pdata->num_clients; i++) {
761 if (pdata->client_platform_data[i].product_id ==
762 (mddi->caps.Mfr_Name << 16 | mddi->caps.Product_Code)) {
763 mddi->client_data.private_client_data =
764 pdata->client_platform_data[i].client_data;
765 mddi->client_pdev.name =
766 pdata->client_platform_data[i].name;
767 mddi->client_pdev.id =
768 pdata->client_platform_data[i].id;
769 /* XXX: possibly set clock */
770 break;
771 }
772 }
773
774 if (i >= pdata->num_clients)
775 mddi->client_pdev.name = "mddi_c_dummy";
776 printk(KERN_INFO "mddi: registering panel %s\n",
777 mddi->client_pdev.name);
778
779 mddi->client_data.suspend = mddi_suspend;
780 mddi->client_data.resume = mddi_resume;
781 mddi->client_data.activate_link = mddi_activate_link;
782 mddi->client_data.remote_write = mddi_remote_write;
783 mddi->client_data.remote_read = mddi_remote_read;
784 mddi->client_data.auto_hibernate = mddi_set_auto_hibernate;
785 mddi->client_data.fb_resource = pdata->fb_resource;
786 if (pdev->id == 0)
787 mddi->client_data.interface_type = MSM_MDDI_PMDH_INTERFACE;
788 else if (pdev->id == 1)
789 mddi->client_data.interface_type = MSM_MDDI_EMDH_INTERFACE;
790 else {
791 printk(KERN_ERR "mddi: can not determine interface %d!\n",
792 pdev->id);
793 ret = -EINVAL;
794 goto error_mddi_interface;
795 }
796
797 mddi->client_pdev.dev.platform_data = &mddi->client_data;
798 printk(KERN_INFO "mddi: publish: %s\n", mddi->client_name);
799 platform_device_register(&mddi->client_pdev);
800 return 0;
801
802error_mddi_interface:
803error_mddi_version:
804 free_irq(mddi->irq, 0);
805error_request_irq:
806 dma_free_coherent(NULL, 0x1000, mddi->rev_data, mddi->rev_addr);
807error_rev_data:
808error_clk_setup:
809error_get_irq_resource:
810 iounmap(mddi->base);
811error_ioremap:
812
813 printk(KERN_INFO "mddi: mddi_init() failed (%d)\n", ret);
814 return ret;
815}
816
817
818static struct platform_driver mddi_driver = {
819 .probe = mddi_probe,
820 .driver = { .name = "msm_mddi" },
821};
822
823static int __init _mddi_init(void)
824{
825 return platform_driver_register(&mddi_driver);
826}
827
828module_init(_mddi_init);