The Android Open Source Project | 076ef94 | 2009-03-03 19:28:41 -0800 | [diff] [blame] | 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 | |
| 33 | unsigned fb_width = 0; |
| 34 | unsigned fb_height = 0; |
| 35 | |
| 36 | static unsigned short *FB; |
| 37 | static mddi_llentry *mlist; |
| 38 | |
| 39 | void 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 | |
| 50 | void 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 | |
| 71 | mddi_llentry *mlist_remote_write = 0; |
| 72 | |
| 73 | void 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 | |
| 110 | void mddi_start_update(void) |
| 111 | { |
| 112 | writel((unsigned) mlist, MDDI_PRI_PTR); |
| 113 | } |
| 114 | |
| 115 | int mddi_update_done(void) |
| 116 | { |
| 117 | return !!(readl(MDDI_STAT) & MDDI_STAT_PRI_LINK_LIST_DONE); |
| 118 | } |
| 119 | |
| 120 | void 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 | |
| 127 | unsigned char *rev_pkt_buf; |
| 128 | |
| 129 | void 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 | |
| 164 | void 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 | |
| 281 | void *mddi_framebuffer(void) |
| 282 | { |
| 283 | return FB; |
| 284 | } |
| 285 | |