blob: cfa95270391bbfa84390c02ff22c7aae4cb2f908 [file] [log] [blame]
Dima Zavin36785e32009-01-28 17:26:43 -08001/*
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 <debug.h>
30#include <reg.h>
31#include <stdlib.h>
32#include <string.h>
33#include <dev/fbcon.h>
34#include <kernel/thread.h>
Chandan Uddaraju2943fd62010-06-21 10:56:39 -070035#include <mddi.h>
36#include <target/display.h>
Greg Griscod2471ef2011-07-14 13:00:42 -070037#include <platform/timer.h>
Dima Zavin36785e32009-01-28 17:26:43 -080038
39#include "mddi_hw.h"
40
41static mddi_llentry *mlist = NULL;
42static mddi_llentry *mlist_remote_write = NULL;
43
44#define MDDI_MAX_REV_PKT_SIZE 0x60
Chandan Uddaraju2943fd62010-06-21 10:56:39 -070045#define MDDI_REV_PKT_BUF_SIZE 256
Dima Zavin36785e32009-01-28 17:26:43 -080046static void *rev_pkt_buf;
47
48/* functions provided by the target specific panel code */
49void panel_init(struct mddi_client_caps *client_caps);
50void panel_poweron(void);
51void panel_backlight(int on);
52
53/* forward decls */
54static void mddi_start_update(void);
55static int mddi_update_done(void);
56
57static struct fbcon_config fb_cfg = {
Ajay Dudanib01e5062011-12-03 23:23:42 -080058 .format = FB_FORMAT_RGB565,
59 .bpp = 16,
60 .update_start = mddi_start_update,
61 .update_done = mddi_update_done,
Dima Zavin36785e32009-01-28 17:26:43 -080062};
63
64static void printcaps(struct mddi_client_caps *c)
65{
66 if ((c->length != 0x4a) || (c->type != 0x42)) {
67 dprintf(INFO, "bad caps header\n");
68 memset(c, 0, sizeof(*c));
69 return;
70 }
71
72 dprintf(INFO, "mddi: bm: %d,%d win %d,%d rgb %x\n",
73 c->bitmap_width, c->bitmap_height,
Ajay Dudanib01e5062011-12-03 23:23:42 -080074 c->display_window_width, c->display_window_height, c->rgb_cap);
Dima Zavin36785e32009-01-28 17:26:43 -080075 dprintf(INFO, "mddi: vend %x prod %x\n",
76 c->manufacturer_name, c->product_code);
77}
78
79/* TODO: add timeout */
80static int mddi_wait_status(unsigned statmask)
81{
Ajay Dudanib01e5062011-12-03 23:23:42 -080082 while ((readl(MDDI_STAT) & statmask) == 0) ;
Dima Zavin36785e32009-01-28 17:26:43 -080083 return 0;
84}
85
86/* TODO: add timeout */
87static int mddi_wait_interrupt(unsigned intmask)
88{
Ajay Dudanib01e5062011-12-03 23:23:42 -080089 while ((readl(MDDI_INT) & intmask) == 0) ;
Dima Zavin36785e32009-01-28 17:26:43 -080090 return 0;
91}
92
93void mddi_remote_write(unsigned val, unsigned reg)
94{
95 mddi_llentry *ll;
96 mddi_register_access *ra;
97
98 ll = mlist_remote_write;
Ajay Dudanib01e5062011-12-03 23:23:42 -080099
Dima Zavin36785e32009-01-28 17:26:43 -0800100 ra = &(ll->u.r);
101 ra->length = 14 + 4;
102 ra->type = TYPE_REGISTER_ACCESS;
103 ra->client_id = 0;
104 ra->rw_info = MDDI_WRITE | 1;
105 ra->crc = 0;
106
107 ra->reg_addr = reg;
Channagoud Kadabi51ea9722011-08-25 14:56:53 +0530108 ra->reg_data[0] = val;
Dima Zavin36785e32009-01-28 17:26:43 -0800109
110 ll->flags = 1;
111 ll->header_count = 14;
112 ll->data_count = 4;
Channagoud Kadabi51ea9722011-08-25 14:56:53 +0530113 ll->data = &ra->reg_data[0];
Ajay Dudanib01e5062011-12-03 23:23:42 -0800114 ll->next = (void *)0;
Channagoud Kadabi51ea9722011-08-25 14:56:53 +0530115 ll->reserved = 0;
116
Ajay Dudanib01e5062011-12-03 23:23:42 -0800117 writel((unsigned)ll, MDDI_PRI_PTR);
Channagoud Kadabi51ea9722011-08-25 14:56:53 +0530118
119 mddi_wait_status(MDDI_STAT_PRI_LINK_LIST_DONE);
120}
121
122#ifdef MDDI_MULTI_WRITE
Ajay Dudanib01e5062011-12-03 23:23:42 -0800123void
124mddi_remote_multiwrite(unsigned *val_list, unsigned reg, unsigned val_count)
Channagoud Kadabi51ea9722011-08-25 14:56:53 +0530125{
126 mddi_llentry *ll;
127 mddi_register_access *ra;
128
129 ll = mlist_remote_write;
130
131 ra = &(ll->u.r);
132 ra->length = 14 + (val_count * 4);
133 ra->type = TYPE_REGISTER_ACCESS;
134 ra->client_id = 0;
135 ra->rw_info = MDDI_WRITE | val_count;
136 ra->crc = 0;
137
138 ra->reg_addr = reg;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800139 memcpy((void *)&ra->reg_data[0], val_list, val_count);
Channagoud Kadabi51ea9722011-08-25 14:56:53 +0530140
141 ll->flags = 1;
142 ll->header_count = 14;
143 ll->data_count = val_count * 4;
Dima Zavin36785e32009-01-28 17:26:43 -0800144 ll->data = &ra->reg_data;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800145 ll->next = (void *)0;
Dima Zavin36785e32009-01-28 17:26:43 -0800146 ll->reserved = 0;
147
Ajay Dudanib01e5062011-12-03 23:23:42 -0800148 writel((unsigned)ll, MDDI_PRI_PTR);
Dima Zavin36785e32009-01-28 17:26:43 -0800149
150 mddi_wait_status(MDDI_STAT_PRI_LINK_LIST_DONE);
151}
Channagoud Kadabi51ea9722011-08-25 14:56:53 +0530152#endif
Dima Zavin36785e32009-01-28 17:26:43 -0800153
154static void mddi_start_update(void)
155{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800156 writel((unsigned)mlist, MDDI_PRI_PTR);
Dima Zavin36785e32009-01-28 17:26:43 -0800157}
158
159static int mddi_update_done(void)
160{
161 return !!(readl(MDDI_STAT) & MDDI_STAT_PRI_LINK_LIST_DONE);
162}
163
164static void mddi_do_cmd(unsigned cmd)
165{
166 writel(cmd, MDDI_CMD);
167 mddi_wait_interrupt(MDDI_INT_NO_REQ_PKTS_PENDING);
168}
169
170static void mddi_init_rev_encap(void)
171{
172 memset(rev_pkt_buf, 0xee, MDDI_REV_PKT_BUF_SIZE);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800173 writel((unsigned)rev_pkt_buf, MDDI_REV_PTR);
174 writel((unsigned)rev_pkt_buf, MDDI_REV_PTR);
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700175 writel(MDDI_REV_PKT_BUF_SIZE, MDDI_REV_SIZE);
176 writel(MDDI_REV_PKT_BUF_SIZE, MDDI_REV_ENCAP_SZ);
Dima Zavin36785e32009-01-28 17:26:43 -0800177 mddi_do_cmd(CMD_FORCE_NEW_REV_PTR);
178}
179
180static void mddi_set_auto_hibernate(unsigned on)
181{
182 writel(CMD_POWER_DOWN, MDDI_CMD);
183 mddi_wait_interrupt(MDDI_INT_IN_HIBERNATION);
184 mddi_do_cmd(CMD_HIBERNATE | !!on);
185}
186
Ajay Dudanib01e5062011-12-03 23:23:42 -0800187void mddi_set_caps(mddi_client_caps * c)
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700188{
Ajay Dudanib01e5062011-12-03 23:23:42 -0800189 /* Hardcoding the capability values */
190 c->length = 74;
191 c->type = 66;
192 c->client_id = 0;
193 c->protocol_ver = 1;
194 c->min_protocol_ver = 1;
195 c->data_rate_cap = 400;
196 c->interface_type_cap = 0;
197 c->num_alt_displays = 1;
198 c->postcal_data_rate = 400;
199 c->bitmap_width = TARGET_XRES;
200 c->bitmap_height = TARGET_YRES;
201 c->display_window_width = TARGET_XRES;
202 c->display_window_height = TARGET_YRES;
203 c->cmap_size = 0;
204 c->cmap_rgb_width = 0;
205 c->rgb_cap = 34592;
206 c->mono_cap = 0;
207 c->reserved1 = 0;
208 c->ycbcr_cap = 0;
209 c->bayer_cap = 0;
210 c->alpha_cursor_planes = 0;
211 c->client_feature_cap = 4489216;
212 c->max_video_frame_rate_cap = 60;
213 c->min_video_frame_rate_cap = 0;
214 c->min_sub_frame_rate = 0;
215 c->audio_buf_depth = 0;
216 c->audio_channel_cap = 0;
217 c->audio_sampe_rate_rap = 0;
218 c->audio_sample_res = 0;
219 c->mic_audio_sample_res = 0;
220 c->mic_sample_rate_cap = 0;
221 c->keyboard_data_fmt = 0;
222 c->pointing_device_data_fmt = 0;
223 c->content_protection_type = 0;
224 c->manufacturer_name = 53859;
225 c->product_code = 34594;
226 c->reserved3 = 0;
227 c->serial_no = 1;
228 c->week_of_manufacture = 0;
229 c->year_of_manufacture = 0;
230 c->crc = 53536;
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700231}
232
Dima Zavin36785e32009-01-28 17:26:43 -0800233static void mddi_get_caps(struct mddi_client_caps *caps)
234{
235 unsigned timeout = 100000;
236 unsigned n;
237
238 writel(0xffffffff, MDDI_INT);
239 mddi_do_cmd(CMD_LINK_ACTIVE);
240
241 /* sometimes this will fail -- do it three times for luck... */
242 mddi_do_cmd(CMD_RTD_MEASURE);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800243 thread_sleep(1); //mdelay(1);
Dima Zavin36785e32009-01-28 17:26:43 -0800244
245 mddi_do_cmd(CMD_RTD_MEASURE);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800246 thread_sleep(1); //mdelay(1);
Dima Zavin36785e32009-01-28 17:26:43 -0800247
248 mddi_do_cmd(CMD_RTD_MEASURE);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800249 thread_sleep(1); //mdelay(1);
Dima Zavin36785e32009-01-28 17:26:43 -0800250
251 mddi_do_cmd(CMD_GET_CLIENT_CAP);
252
253 do {
254 n = readl(MDDI_INT);
Ajay Dudanib01e5062011-12-03 23:23:42 -0800255 }
256 while (!(n & MDDI_INT_REV_DATA_AVAIL) && (--timeout));
257
Dima Zavin36785e32009-01-28 17:26:43 -0800258 if (timeout == 0)
259 dprintf(INFO, "timeout\n");
260
261 memcpy(caps, rev_pkt_buf, sizeof(struct mddi_client_caps));
262}
263
264static unsigned mddi_init_regs(void)
265{
Dima Zavin36785e32009-01-28 17:26:43 -0800266 mddi_do_cmd(CMD_RESET);
267
268 mddi_do_cmd(CMD_PERIODIC_REV_ENC);
269
270 writel(0x0001, MDDI_VERSION);
271 writel(0x3C00, MDDI_BPS);
272 writel(0x0003, MDDI_SPM);
273
274 writel(0x0005, MDDI_TA1_LEN);
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700275 writel(0x001A, MDDI_TA2_LEN);
Dima Zavin36785e32009-01-28 17:26:43 -0800276 writel(0x0096, MDDI_DRIVE_HI);
277 writel(0x0050, MDDI_DRIVE_LO);
278 writel(0x003C, MDDI_DISP_WAKE);
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700279 writel(0x0004, MDDI_REV_RATE_DIV);
Dima Zavin36785e32009-01-28 17:26:43 -0800280
281 /* needs to settle for 5uS */
282 if (readl(MDDI_PAD_CTL) == 0) {
283 writel(0x08000, MDDI_PAD_CTL);
Chandan Uddaraju61e6d7c2010-07-20 17:57:06 -0700284 udelay(5);
Dima Zavin36785e32009-01-28 17:26:43 -0800285 }
286
287 writel(0xA850F, MDDI_PAD_CTL);
288 writel(0x60006, MDDI_DRIVER_START_CNT);
289
Dima Zavin36785e32009-01-28 17:26:43 -0800290 mddi_init_rev_encap();
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700291
292 /* disable hibernate */
293 mddi_do_cmd(CMD_HIBERNATE | 0);
294
Dima Zavin36785e32009-01-28 17:26:43 -0800295 return readl(MDDI_CORE_VER) & 0xffff;
296}
297
298struct fbcon_config *mddi_init(void)
299{
300 unsigned n;
301 struct mddi_client_caps client_caps;
302
303 dprintf(INFO, "mddi_init()\n");
304
305 rev_pkt_buf = memalign(32, MDDI_REV_PKT_BUF_SIZE);
306 mlist_remote_write = memalign(32, sizeof(struct mddi_llentry));
307
308 n = mddi_init_regs();
309 dprintf(INFO, "mddi version: 0x%08x\n", n);
310
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700311 //mddi_get_caps(&client_caps);
312 //if(!(client_caps.length == 0x4a && client_caps.type == 0x42))
313 {
Ajay Dudanib01e5062011-12-03 23:23:42 -0800314 mddi_set_caps(&client_caps);
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700315 }
Dima Zavin36785e32009-01-28 17:26:43 -0800316
317 fb_cfg.width = client_caps.bitmap_width;
318 fb_cfg.stride = fb_cfg.width;
319 fb_cfg.height = client_caps.bitmap_height;
320
Dima Zavin36785e32009-01-28 17:26:43 -0800321 panel_init(&client_caps);
322
323 panel_backlight(0);
324 panel_poweron();
325
326 /* v > 8? v > 8 && < 0x19 ? */
327 writel(2, MDDI_TEST);
328
329 dprintf(INFO, "panel is %d x %d\n", fb_cfg.width, fb_cfg.height);
330
331 fb_cfg.base =
Ajay Dudanib01e5062011-12-03 23:23:42 -0800332 memalign(4096, fb_cfg.width * fb_cfg.height * (fb_cfg.bpp / 8));
Dima Zavin36785e32009-01-28 17:26:43 -0800333
334 mlist = memalign(32, sizeof(mddi_llentry) * (fb_cfg.height / 8));
Ajay Dudanib01e5062011-12-03 23:23:42 -0800335 dprintf(INFO, "FB @ %p mlist @ %x\n", fb_cfg.base, (unsigned)mlist);
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700336
Ajay Dudanib01e5062011-12-03 23:23:42 -0800337 for (n = 0; n < (fb_cfg.height / 8); n++) {
Dima Zavin36785e32009-01-28 17:26:43 -0800338 unsigned y = n * 8;
339 unsigned pixels = fb_cfg.width * 8;
340 mddi_video_stream *vs = &(mlist[n].u.v);
341
342 vs->length = sizeof(mddi_video_stream) - 2 + (pixels * 2);
343 vs->type = TYPE_VIDEO_STREAM;
344 vs->client_id = 0;
Ajay Dudanib01e5062011-12-03 23:23:42 -0800345 vs->format = 0x5565; // FORMAT_16BPP;
Dima Zavin36785e32009-01-28 17:26:43 -0800346 vs->pixattr = PIXATTR_BOTH_EYES | PIXATTR_TO_ALL;
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700347
Dima Zavin36785e32009-01-28 17:26:43 -0800348 vs->left = 0;
349 vs->right = fb_cfg.width - 1;
350 vs->top = y;
351 vs->bottom = y + 7;
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700352
Dima Zavin36785e32009-01-28 17:26:43 -0800353 vs->start_x = 0;
354 vs->start_y = y;
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700355
Dima Zavin36785e32009-01-28 17:26:43 -0800356 vs->pixels = pixels;
357 vs->crc = 0;
358 vs->reserved = 0;
Chandan Uddaraju2943fd62010-06-21 10:56:39 -0700359
Dima Zavin36785e32009-01-28 17:26:43 -0800360 mlist[n].header_count = sizeof(mddi_video_stream) - 2;
361 mlist[n].data_count = pixels * 2;
362 mlist[n].reserved = 0;
363 mlist[n].data = fb_cfg.base + (y * fb_cfg.width * 2);
364 mlist[n].next = &mlist[n + 1];
365 mlist[n].flags = 0;
366 }
367
Ajay Dudanib01e5062011-12-03 23:23:42 -0800368 mlist[n - 1].flags = 1;
369 mlist[n - 1].next = 0;
Dima Zavin36785e32009-01-28 17:26:43 -0800370
371 mddi_set_auto_hibernate(1);
372 mddi_do_cmd(CMD_LINK_ACTIVE);
373
374 panel_backlight(1);
375
376 return &fb_cfg;
377}