1/*
2 * Copyright (c) 2008, Google Inc.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *  * Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 *  * Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in
12 *    the documentation and/or other materials provided with the
13 *    distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29#include <boot/boot.h>
30#include <boot/board.h>
31#include <msm7k/mddi.h>
32
33unsigned fb_width = 0;
34unsigned fb_height = 0;
35
36static unsigned short *FB;
37static mddi_llentry *mlist;
38
39void wr32(void *_dst, unsigned n)
40{
41    unsigned char *src = (unsigned char*) &n;
42    unsigned char *dst = _dst;
43
44    dst[0] = src[0];
45    dst[1] = src[1];
46    dst[2] = src[2];
47    dst[3] = src[3];
48};
49
50void printcaps(mddi_client_caps *c)
51{
52    if((c->length != 0x4a) || (c->type != 0x42)) {
53        dprintf("bad caps header\n");
54        memset(c, 0, sizeof(*c));
55        return;
56    }
57
58    dprintf("mddi: bm: %d,%d win %d,%d rgb %x\n",
59            c->bitmap_width, c->bitmap_height,
60            c->display_window_width, c->display_window_height,
61            c->rgb_cap);
62    dprintf("mddi: vend %x prod %x\n",
63            c->manufacturer_name, c->product_code);
64
65    fb_width = c->bitmap_width;
66    fb_height = c->bitmap_height;
67
68    panel_init(c);
69}
70
71mddi_llentry *mlist_remote_write = 0;
72
73void mddi_remote_write(unsigned val, unsigned reg)
74{
75    mddi_llentry *ll;
76    mddi_register_access *ra;
77    unsigned s;
78
79    if(mlist_remote_write == 0) {
80        mlist_remote_write = alloc(sizeof(mddi_llentry));
81    }
82
83    ll = mlist_remote_write;
84
85    ra = &(ll->u.r);
86    ra->length = 14 + 4;
87    ra->type = TYPE_REGISTER_ACCESS;
88    ra->client_id = 0;
89    ra->rw_info = MDDI_WRITE | 1;
90    ra->crc = 0;
91
92    wr32(&ra->reg_addr, reg);
93    wr32(&ra->reg_data, val);
94
95    ll->flags = 1;
96    ll->header_count = 14;
97    ll->data_count = 4;
98    wr32(&ll->data, (unsigned) &ra->reg_data);
99    wr32(&ll->next, 0);
100    ll->reserved = 0;
101
102    writel((unsigned) ll, MDDI_PRI_PTR);
103
104    s = readl(MDDI_STAT);
105    while((s & 0x20) == 0){
106        s = readl(MDDI_STAT);
107    }
108}
109
110void mddi_start_update(void)
111{
112    writel((unsigned) mlist, MDDI_PRI_PTR);
113}
114
115int mddi_update_done(void)
116{
117    return !!(readl(MDDI_STAT) & MDDI_STAT_PRI_LINK_LIST_DONE);
118}
119
120void mddi_do_cmd(unsigned cmd)
121{
122    writel(cmd, MDDI_CMD);
123
124    while (!(readl(MDDI_INT) & MDDI_INT_NO_REQ_PKTS_PENDING)) ;
125}
126
127unsigned char *rev_pkt_buf;
128
129void mddi_get_caps(void)
130{
131    unsigned timeout = 100000;
132    unsigned n;
133
134    memset(rev_pkt_buf, 0xee, 256);
135
136//    writel(CMD_HIBERNATE, MDDI_CMD);
137//    writel(CMD_LINK_ACTIVE, MDDI_CMD);
138
139    writel(256, MDDI_REV_SIZE);
140    writel((unsigned) rev_pkt_buf, MDDI_REV_PTR);
141    mddi_do_cmd(CMD_FORCE_NEW_REV_PTR);
142
143        /* sometimes this will fail -- do it three times for luck... */
144    mddi_do_cmd(CMD_RTD_MEASURE);
145    mdelay(1);
146
147    mddi_do_cmd(CMD_RTD_MEASURE);
148    mdelay(1);
149
150    mddi_do_cmd(CMD_RTD_MEASURE);
151    mdelay(1);
152
153    mddi_do_cmd(CMD_GET_CLIENT_CAP);
154
155    do {
156        n = readl(MDDI_INT);
157    } while(!(n & MDDI_INT_REV_DATA_AVAIL) && (--timeout));
158
159    if(timeout == 0) dprintf("timeout\n");
160    printcaps((mddi_client_caps*) rev_pkt_buf);
161}
162
163
164void mddi_init(void)
165{
166    unsigned n;
167
168//    dprintf("mddi_init()\n");
169
170    rev_pkt_buf = alloc(256);
171
172    mddi_do_cmd(CMD_RESET);
173
174        /* disable periodic rev encap */
175    mddi_do_cmd(CMD_PERIODIC_REV_ENC | 0);
176
177    writel(0x0001, MDDI_VERSION);
178    writel(0x3C00, MDDI_BPS);
179    writel(0x0003, MDDI_SPM);
180
181    writel(0x0005, MDDI_TA1_LEN);
182    writel(0x000C, MDDI_TA2_LEN);
183    writel(0x0096, MDDI_DRIVE_HI);
184    writel(0x0050, MDDI_DRIVE_LO);
185    writel(0x003C, MDDI_DISP_WAKE);
186    writel(0x0002, MDDI_REV_RATE_DIV);
187
188        /* needs to settle for 5uS */
189    if (readl(MDDI_PAD_CTL) == 0) {
190        writel(0x08000, MDDI_PAD_CTL);
191        udelay(5);
192    }
193
194    writel(0xA850F, MDDI_PAD_CTL);
195    writel(0x60006, MDDI_DRIVER_START_CNT);
196
197    writel((unsigned) rev_pkt_buf, MDDI_REV_PTR);
198    writel(256, MDDI_REV_SIZE);
199    writel(256, MDDI_REV_ENCAP_SZ);
200
201    mddi_do_cmd(CMD_FORCE_NEW_REV_PTR);
202
203        /* disable hibernate */
204    mddi_do_cmd(CMD_HIBERNATE | 0);
205
206    panel_backlight(0);
207
208    panel_poweron();
209
210    mddi_do_cmd(CMD_LINK_ACTIVE);
211
212    do {
213        n = readl(MDDI_STAT);
214    } while(!(n & MDDI_STAT_LINK_ACTIVE));
215
216        /* v > 8?  v > 8 && < 0x19 ? */
217    writel(2, MDDI_TEST);
218
219//    writel(CMD_PERIODIC_REV_ENC | 0, MDDI_CMD); /* disable */
220
221	mddi_get_caps();
222
223#if 0
224    writel(0x5666, MDDI_MDP_VID_FMT_DES);
225    writel(0x00C3, MDDI_MDP_VID_PIX_ATTR);
226    writel(0x0000, MDDI_MDP_CLIENTID);
227#endif
228
229    dprintf("panel is %d x %d\n", fb_width, fb_height);
230
231    FB = alloc(2 * fb_width * fb_height);
232    mlist = alloc(sizeof(mddi_llentry) * (fb_height / 8));
233
234//    dprintf("FB @ %x  mlist @ %x\n", (unsigned) FB, (unsigned) mlist);
235
236    for(n = 0; n < (fb_height / 8); n++) {
237        unsigned y = n * 8;
238        unsigned pixels = fb_width * 8;
239        mddi_video_stream *vs = &(mlist[n].u.v);
240
241        vs->length = sizeof(mddi_video_stream) - 2 + (pixels * 2);
242        vs->type = TYPE_VIDEO_STREAM;
243        vs->client_id = 0;
244        vs->format = 0x5565; // FORMAT_16BPP;
245        vs->pixattr = PIXATTR_BOTH_EYES | PIXATTR_TO_ALL;
246
247        vs->left = 0;
248        vs->right = fb_width - 1;
249        vs->top = y;
250        vs->bottom = y + 7;
251
252        vs->start_x = 0;
253        vs->start_y = y;
254
255        vs->pixels = pixels;
256        vs->crc = 0;
257        vs->reserved = 0;
258
259        mlist[n].header_count = sizeof(mddi_video_stream) - 2;
260        mlist[n].data_count = pixels * 2;
261        mlist[n].reserved = 0;
262        wr32(&mlist[n].data, ((unsigned) FB) + (y * fb_width * 2));
263
264        mlist[n].flags = 0;
265        wr32(&mlist[n].next, (unsigned) (mlist + n + 1));
266    }
267
268    mlist[n-1].flags = 1;
269    wr32(&mlist[n-1].next, 0);
270
271    writel(CMD_HIBERNATE, MDDI_CMD);
272    writel(CMD_LINK_ACTIVE, MDDI_CMD);
273
274    for(n = 0; n < (fb_width * fb_height); n++) FB[n] = 0;
275
276    mddi_start_update();
277
278    panel_backlight(1);
279}
280
281void *mddi_framebuffer(void)
282{
283    return FB;
284}
285
286