|
|
1.1 ! root 1: /* ! 2: * Nokia N-series internet tablets. ! 3: * ! 4: * Copyright (C) 2007 Nokia Corporation ! 5: * Written by Andrzej Zaborowski <[email protected]> ! 6: * ! 7: * This program is free software; you can redistribute it and/or ! 8: * modify it under the terms of the GNU General Public License as ! 9: * published by the Free Software Foundation; either version 2 or ! 10: * (at your option) version 3 of the License. ! 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: * You should have received a copy of the GNU General Public License along ! 18: * with this program; if not, write to the Free Software Foundation, Inc., ! 19: * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ! 20: */ ! 21: ! 22: #include "qemu-common.h" ! 23: #include "sysemu.h" ! 24: #include "omap.h" ! 25: #include "arm-misc.h" ! 26: #include "irq.h" ! 27: #include "console.h" ! 28: #include "boards.h" ! 29: #include "i2c.h" ! 30: #include "devices.h" ! 31: #include "flash.h" ! 32: #include "hw.h" ! 33: #include "bt.h" ! 34: ! 35: /* Nokia N8x0 support */ ! 36: struct n800_s { ! 37: struct omap_mpu_state_s *cpu; ! 38: ! 39: struct rfbi_chip_s blizzard; ! 40: struct { ! 41: void *opaque; ! 42: uint32_t (*txrx)(void *opaque, uint32_t value, int len); ! 43: struct uwire_slave_s *chip; ! 44: } ts; ! 45: i2c_bus *i2c; ! 46: ! 47: int keymap[0x80]; ! 48: i2c_slave *kbd; ! 49: ! 50: struct tusb_s *usb; ! 51: void *retu; ! 52: void *tahvo; ! 53: void *nand; ! 54: }; ! 55: ! 56: /* GPIO pins */ ! 57: #define N8X0_TUSB_ENABLE_GPIO 0 ! 58: #define N800_MMC2_WP_GPIO 8 ! 59: #define N800_UNKNOWN_GPIO0 9 /* out */ ! 60: #define N810_MMC2_VIOSD_GPIO 9 ! 61: #define N810_HEADSET_AMP_GPIO 10 ! 62: #define N800_CAM_TURN_GPIO 12 ! 63: #define N810_GPS_RESET_GPIO 12 ! 64: #define N800_BLIZZARD_POWERDOWN_GPIO 15 ! 65: #define N800_MMC1_WP_GPIO 23 ! 66: #define N810_MMC2_VSD_GPIO 23 ! 67: #define N8X0_ONENAND_GPIO 26 ! 68: #define N810_BLIZZARD_RESET_GPIO 30 ! 69: #define N800_UNKNOWN_GPIO2 53 /* out */ ! 70: #define N8X0_TUSB_INT_GPIO 58 ! 71: #define N8X0_BT_WKUP_GPIO 61 ! 72: #define N8X0_STI_GPIO 62 ! 73: #define N8X0_CBUS_SEL_GPIO 64 ! 74: #define N8X0_CBUS_DAT_GPIO 65 ! 75: #define N8X0_CBUS_CLK_GPIO 66 ! 76: #define N8X0_WLAN_IRQ_GPIO 87 ! 77: #define N8X0_BT_RESET_GPIO 92 ! 78: #define N8X0_TEA5761_CS_GPIO 93 ! 79: #define N800_UNKNOWN_GPIO 94 ! 80: #define N810_TSC_RESET_GPIO 94 ! 81: #define N800_CAM_ACT_GPIO 95 ! 82: #define N810_GPS_WAKEUP_GPIO 95 ! 83: #define N8X0_MMC_CS_GPIO 96 ! 84: #define N8X0_WLAN_PWR_GPIO 97 ! 85: #define N8X0_BT_HOST_WKUP_GPIO 98 ! 86: #define N810_SPEAKER_AMP_GPIO 101 ! 87: #define N810_KB_LOCK_GPIO 102 ! 88: #define N800_TSC_TS_GPIO 103 ! 89: #define N810_TSC_TS_GPIO 106 ! 90: #define N8X0_HEADPHONE_GPIO 107 ! 91: #define N8X0_RETU_GPIO 108 ! 92: #define N800_TSC_KP_IRQ_GPIO 109 ! 93: #define N810_KEYBOARD_GPIO 109 ! 94: #define N800_BAT_COVER_GPIO 110 ! 95: #define N810_SLIDE_GPIO 110 ! 96: #define N8X0_TAHVO_GPIO 111 ! 97: #define N800_UNKNOWN_GPIO4 112 /* out */ ! 98: #define N810_SLEEPX_LED_GPIO 112 ! 99: #define N800_TSC_RESET_GPIO 118 /* ? */ ! 100: #define N810_AIC33_RESET_GPIO 118 ! 101: #define N800_TSC_UNKNOWN_GPIO 119 /* out */ ! 102: #define N8X0_TMP105_GPIO 125 ! 103: ! 104: /* Config */ ! 105: #define BT_UART 0 ! 106: #define XLDR_LL_UART 1 ! 107: ! 108: /* Addresses on the I2C bus 0 */ ! 109: #define N810_TLV320AIC33_ADDR 0x18 /* Audio CODEC */ ! 110: #define N8X0_TCM825x_ADDR 0x29 /* Camera */ ! 111: #define N810_LP5521_ADDR 0x32 /* LEDs */ ! 112: #define N810_TSL2563_ADDR 0x3d /* Light sensor */ ! 113: #define N810_LM8323_ADDR 0x45 /* Keyboard */ ! 114: /* Addresses on the I2C bus 1 */ ! 115: #define N8X0_TMP105_ADDR 0x48 /* Temperature sensor */ ! 116: #define N8X0_MENELAUS_ADDR 0x72 /* Power management */ ! 117: ! 118: /* Chipselects on GPMC NOR interface */ ! 119: #define N8X0_ONENAND_CS 0 ! 120: #define N8X0_USB_ASYNC_CS 1 ! 121: #define N8X0_USB_SYNC_CS 4 ! 122: ! 123: #define N8X0_BD_ADDR 0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81 ! 124: ! 125: static void n800_mmc_cs_cb(void *opaque, int line, int level) ! 126: { ! 127: /* TODO: this seems to actually be connected to the menelaus, to ! 128: * which also both MMC slots connect. */ ! 129: omap_mmc_enable((struct omap_mmc_s *) opaque, !level); ! 130: ! 131: printf("%s: MMC slot %i active\n", __FUNCTION__, level + 1); ! 132: } ! 133: ! 134: static void n8x0_gpio_setup(struct n800_s *s) ! 135: { ! 136: qemu_irq *mmc_cs = qemu_allocate_irqs(n800_mmc_cs_cb, s->cpu->mmc, 1); ! 137: omap2_gpio_out_set(s->cpu->gpif, N8X0_MMC_CS_GPIO, mmc_cs[0]); ! 138: ! 139: qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N800_BAT_COVER_GPIO)[0]); ! 140: } ! 141: ! 142: #define MAEMO_CAL_HEADER(...) \ ! 143: 'C', 'o', 'n', 'F', 0x02, 0x00, 0x04, 0x00, \ ! 144: __VA_ARGS__, \ ! 145: 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ! 146: ! 147: static const uint8_t n8x0_cal_wlan_mac[] = { ! 148: MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c') ! 149: 0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3, ! 150: 0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00, ! 151: 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, ! 152: 0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, ! 153: 0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, ! 154: }; ! 155: ! 156: static const uint8_t n8x0_cal_bt_id[] = { ! 157: MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0) ! 158: 0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96, ! 159: 0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00, ! 160: N8X0_BD_ADDR, ! 161: }; ! 162: ! 163: static void n8x0_nand_setup(struct n800_s *s) ! 164: { ! 165: char *otp_region; ! 166: ! 167: /* Either ec40xx or ec48xx are OK for the ID */ ! 168: omap_gpmc_attach(s->cpu->gpmc, N8X0_ONENAND_CS, 0, onenand_base_update, ! 169: onenand_base_unmap, ! 170: (s->nand = onenand_init(0xec4800, 1, ! 171: omap2_gpio_in_get(s->cpu->gpif, ! 172: N8X0_ONENAND_GPIO)[0]))); ! 173: otp_region = onenand_raw_otp(s->nand); ! 174: ! 175: memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac)); ! 176: memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id)); ! 177: /* XXX: in theory should also update the OOB for both pages */ ! 178: } ! 179: ! 180: static void n8x0_i2c_setup(struct n800_s *s) ! 181: { ! 182: qemu_irq tmp_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TMP105_GPIO)[0]; ! 183: ! 184: /* Attach the CPU on one end of our I2C bus. */ ! 185: s->i2c = omap_i2c_bus(s->cpu->i2c[0]); ! 186: ! 187: /* Attach a menelaus PM chip */ ! 188: i2c_set_slave_address( ! 189: twl92230_init(s->i2c, ! 190: s->cpu->irq[0][OMAP_INT_24XX_SYS_NIRQ]), ! 191: N8X0_MENELAUS_ADDR); ! 192: ! 193: /* Attach a TMP105 PM chip (A0 wired to ground) */ ! 194: i2c_set_slave_address(tmp105_init(s->i2c, tmp_irq), N8X0_TMP105_ADDR); ! 195: } ! 196: ! 197: /* Touchscreen and keypad controller */ ! 198: static struct mouse_transform_info_s n800_pointercal = { ! 199: .x = 800, ! 200: .y = 480, ! 201: .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 }, ! 202: }; ! 203: ! 204: static struct mouse_transform_info_s n810_pointercal = { ! 205: .x = 800, ! 206: .y = 480, ! 207: .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 }, ! 208: }; ! 209: ! 210: #define RETU_KEYCODE 61 /* F3 */ ! 211: ! 212: static void n800_key_event(void *opaque, int keycode) ! 213: { ! 214: struct n800_s *s = (struct n800_s *) opaque; ! 215: int code = s->keymap[keycode & 0x7f]; ! 216: ! 217: if (code == -1) { ! 218: if ((keycode & 0x7f) == RETU_KEYCODE) ! 219: retu_key_event(s->retu, !(keycode & 0x80)); ! 220: return; ! 221: } ! 222: ! 223: tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80)); ! 224: } ! 225: ! 226: static const int n800_keys[16] = { ! 227: -1, ! 228: 72, /* Up */ ! 229: 63, /* Home (F5) */ ! 230: -1, ! 231: 75, /* Left */ ! 232: 28, /* Enter */ ! 233: 77, /* Right */ ! 234: -1, ! 235: 1, /* Cycle (ESC) */ ! 236: 80, /* Down */ ! 237: 62, /* Menu (F4) */ ! 238: -1, ! 239: 66, /* Zoom- (F8) */ ! 240: 64, /* FullScreen (F6) */ ! 241: 65, /* Zoom+ (F7) */ ! 242: -1, ! 243: }; ! 244: ! 245: static void n800_tsc_kbd_setup(struct n800_s *s) ! 246: { ! 247: int i; ! 248: ! 249: /* XXX: are the three pins inverted inside the chip between the ! 250: * tsc and the cpu (N4111)? */ ! 251: qemu_irq penirq = 0; /* NC */ ! 252: qemu_irq kbirq = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_KP_IRQ_GPIO)[0]; ! 253: qemu_irq dav = omap2_gpio_in_get(s->cpu->gpif, N800_TSC_TS_GPIO)[0]; ! 254: ! 255: s->ts.chip = tsc2301_init(penirq, kbirq, dav, 0); ! 256: s->ts.opaque = s->ts.chip->opaque; ! 257: s->ts.txrx = tsc210x_txrx; ! 258: ! 259: for (i = 0; i < 0x80; i ++) ! 260: s->keymap[i] = -1; ! 261: for (i = 0; i < 0x10; i ++) ! 262: if (n800_keys[i] >= 0) ! 263: s->keymap[n800_keys[i]] = i; ! 264: ! 265: qemu_add_kbd_event_handler(n800_key_event, s); ! 266: ! 267: tsc210x_set_transform(s->ts.chip, &n800_pointercal); ! 268: } ! 269: ! 270: static void n810_tsc_setup(struct n800_s *s) ! 271: { ! 272: qemu_irq pintdav = omap2_gpio_in_get(s->cpu->gpif, N810_TSC_TS_GPIO)[0]; ! 273: ! 274: s->ts.opaque = tsc2005_init(pintdav); ! 275: s->ts.txrx = tsc2005_txrx; ! 276: ! 277: tsc2005_set_transform(s->ts.opaque, &n810_pointercal); ! 278: } ! 279: ! 280: /* N810 Keyboard controller */ ! 281: static void n810_key_event(void *opaque, int keycode) ! 282: { ! 283: struct n800_s *s = (struct n800_s *) opaque; ! 284: int code = s->keymap[keycode & 0x7f]; ! 285: ! 286: if (code == -1) { ! 287: if ((keycode & 0x7f) == RETU_KEYCODE) ! 288: retu_key_event(s->retu, !(keycode & 0x80)); ! 289: return; ! 290: } ! 291: ! 292: lm832x_key_event(s->kbd, code, !(keycode & 0x80)); ! 293: } ! 294: ! 295: #define M 0 ! 296: ! 297: static int n810_keys[0x80] = { ! 298: [0x01] = 16, /* Q */ ! 299: [0x02] = 37, /* K */ ! 300: [0x03] = 24, /* O */ ! 301: [0x04] = 25, /* P */ ! 302: [0x05] = 14, /* Backspace */ ! 303: [0x06] = 30, /* A */ ! 304: [0x07] = 31, /* S */ ! 305: [0x08] = 32, /* D */ ! 306: [0x09] = 33, /* F */ ! 307: [0x0a] = 34, /* G */ ! 308: [0x0b] = 35, /* H */ ! 309: [0x0c] = 36, /* J */ ! 310: ! 311: [0x11] = 17, /* W */ ! 312: [0x12] = 62, /* Menu (F4) */ ! 313: [0x13] = 38, /* L */ ! 314: [0x14] = 40, /* ' (Apostrophe) */ ! 315: [0x16] = 44, /* Z */ ! 316: [0x17] = 45, /* X */ ! 317: [0x18] = 46, /* C */ ! 318: [0x19] = 47, /* V */ ! 319: [0x1a] = 48, /* B */ ! 320: [0x1b] = 49, /* N */ ! 321: [0x1c] = 42, /* Shift (Left shift) */ ! 322: [0x1f] = 65, /* Zoom+ (F7) */ ! 323: ! 324: [0x21] = 18, /* E */ ! 325: [0x22] = 39, /* ; (Semicolon) */ ! 326: [0x23] = 12, /* - (Minus) */ ! 327: [0x24] = 13, /* = (Equal) */ ! 328: [0x2b] = 56, /* Fn (Left Alt) */ ! 329: [0x2c] = 50, /* M */ ! 330: [0x2f] = 66, /* Zoom- (F8) */ ! 331: ! 332: [0x31] = 19, /* R */ ! 333: [0x32] = 29 | M, /* Right Ctrl */ ! 334: [0x34] = 57, /* Space */ ! 335: [0x35] = 51, /* , (Comma) */ ! 336: [0x37] = 72 | M, /* Up */ ! 337: [0x3c] = 82 | M, /* Compose (Insert) */ ! 338: [0x3f] = 64, /* FullScreen (F6) */ ! 339: ! 340: [0x41] = 20, /* T */ ! 341: [0x44] = 52, /* . (Dot) */ ! 342: [0x46] = 77 | M, /* Right */ ! 343: [0x4f] = 63, /* Home (F5) */ ! 344: [0x51] = 21, /* Y */ ! 345: [0x53] = 80 | M, /* Down */ ! 346: [0x55] = 28, /* Enter */ ! 347: [0x5f] = 1, /* Cycle (ESC) */ ! 348: ! 349: [0x61] = 22, /* U */ ! 350: [0x64] = 75 | M, /* Left */ ! 351: ! 352: [0x71] = 23, /* I */ ! 353: #if 0 ! 354: [0x75] = 28 | M, /* KP Enter (KP Enter) */ ! 355: #else ! 356: [0x75] = 15, /* KP Enter (Tab) */ ! 357: #endif ! 358: }; ! 359: ! 360: #undef M ! 361: ! 362: static void n810_kbd_setup(struct n800_s *s) ! 363: { ! 364: qemu_irq kbd_irq = omap2_gpio_in_get(s->cpu->gpif, N810_KEYBOARD_GPIO)[0]; ! 365: int i; ! 366: ! 367: for (i = 0; i < 0x80; i ++) ! 368: s->keymap[i] = -1; ! 369: for (i = 0; i < 0x80; i ++) ! 370: if (n810_keys[i] > 0) ! 371: s->keymap[n810_keys[i]] = i; ! 372: ! 373: qemu_add_kbd_event_handler(n810_key_event, s); ! 374: ! 375: /* Attach the LM8322 keyboard to the I2C bus, ! 376: * should happen in n8x0_i2c_setup and s->kbd be initialised here. */ ! 377: s->kbd = lm8323_init(s->i2c, kbd_irq); ! 378: i2c_set_slave_address(s->kbd, N810_LM8323_ADDR); ! 379: } ! 380: ! 381: /* LCD MIPI DBI-C controller (URAL) */ ! 382: struct mipid_s { ! 383: int resp[4]; ! 384: int param[4]; ! 385: int p; ! 386: int pm; ! 387: int cmd; ! 388: ! 389: int sleep; ! 390: int booster; ! 391: int te; ! 392: int selfcheck; ! 393: int partial; ! 394: int normal; ! 395: int vscr; ! 396: int invert; ! 397: int onoff; ! 398: int gamma; ! 399: uint32_t id; ! 400: }; ! 401: ! 402: static void mipid_reset(struct mipid_s *s) ! 403: { ! 404: if (!s->sleep) ! 405: fprintf(stderr, "%s: Display off\n", __FUNCTION__); ! 406: ! 407: s->pm = 0; ! 408: s->cmd = 0; ! 409: ! 410: s->sleep = 1; ! 411: s->booster = 0; ! 412: s->selfcheck = ! 413: (1 << 7) | /* Register loading OK. */ ! 414: (1 << 5) | /* The chip is attached. */ ! 415: (1 << 4); /* Display glass still in one piece. */ ! 416: s->te = 0; ! 417: s->partial = 0; ! 418: s->normal = 1; ! 419: s->vscr = 0; ! 420: s->invert = 0; ! 421: s->onoff = 1; ! 422: s->gamma = 0; ! 423: } ! 424: ! 425: static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len) ! 426: { ! 427: struct mipid_s *s = (struct mipid_s *) opaque; ! 428: uint8_t ret; ! 429: ! 430: if (len > 9) ! 431: cpu_abort(cpu_single_env, "%s: FIXME: bad SPI word width %i\n", ! 432: __FUNCTION__, len); ! 433: ! 434: if (s->p >= ARRAY_SIZE(s->resp)) ! 435: ret = 0; ! 436: else ! 437: ret = s->resp[s->p ++]; ! 438: if (s->pm --> 0) ! 439: s->param[s->pm] = cmd; ! 440: else ! 441: s->cmd = cmd; ! 442: ! 443: switch (s->cmd) { ! 444: case 0x00: /* NOP */ ! 445: break; ! 446: ! 447: case 0x01: /* SWRESET */ ! 448: mipid_reset(s); ! 449: break; ! 450: ! 451: case 0x02: /* BSTROFF */ ! 452: s->booster = 0; ! 453: break; ! 454: case 0x03: /* BSTRON */ ! 455: s->booster = 1; ! 456: break; ! 457: ! 458: case 0x04: /* RDDID */ ! 459: s->p = 0; ! 460: s->resp[0] = (s->id >> 16) & 0xff; ! 461: s->resp[1] = (s->id >> 8) & 0xff; ! 462: s->resp[2] = (s->id >> 0) & 0xff; ! 463: break; ! 464: ! 465: case 0x06: /* RD_RED */ ! 466: case 0x07: /* RD_GREEN */ ! 467: /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so ! 468: * for the bootloader one needs to change this. */ ! 469: case 0x08: /* RD_BLUE */ ! 470: s->p = 0; ! 471: /* TODO: return first pixel components */ ! 472: s->resp[0] = 0x01; ! 473: break; ! 474: ! 475: case 0x09: /* RDDST */ ! 476: s->p = 0; ! 477: s->resp[0] = s->booster << 7; ! 478: s->resp[1] = (5 << 4) | (s->partial << 2) | ! 479: (s->sleep << 1) | s->normal; ! 480: s->resp[2] = (s->vscr << 7) | (s->invert << 5) | ! 481: (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2); ! 482: s->resp[3] = s->gamma << 6; ! 483: break; ! 484: ! 485: case 0x0a: /* RDDPM */ ! 486: s->p = 0; ! 487: s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) | ! 488: (s->partial << 5) | (s->sleep << 6) | (s->booster << 7); ! 489: break; ! 490: case 0x0b: /* RDDMADCTR */ ! 491: s->p = 0; ! 492: s->resp[0] = 0; ! 493: break; ! 494: case 0x0c: /* RDDCOLMOD */ ! 495: s->p = 0; ! 496: s->resp[0] = 5; /* 65K colours */ ! 497: break; ! 498: case 0x0d: /* RDDIM */ ! 499: s->p = 0; ! 500: s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma; ! 501: break; ! 502: case 0x0e: /* RDDSM */ ! 503: s->p = 0; ! 504: s->resp[0] = s->te << 7; ! 505: break; ! 506: case 0x0f: /* RDDSDR */ ! 507: s->p = 0; ! 508: s->resp[0] = s->selfcheck; ! 509: break; ! 510: ! 511: case 0x10: /* SLPIN */ ! 512: s->sleep = 1; ! 513: break; ! 514: case 0x11: /* SLPOUT */ ! 515: s->sleep = 0; ! 516: s->selfcheck ^= 1 << 6; /* POFF self-diagnosis Ok */ ! 517: break; ! 518: ! 519: case 0x12: /* PTLON */ ! 520: s->partial = 1; ! 521: s->normal = 0; ! 522: s->vscr = 0; ! 523: break; ! 524: case 0x13: /* NORON */ ! 525: s->partial = 0; ! 526: s->normal = 1; ! 527: s->vscr = 0; ! 528: break; ! 529: ! 530: case 0x20: /* INVOFF */ ! 531: s->invert = 0; ! 532: break; ! 533: case 0x21: /* INVON */ ! 534: s->invert = 1; ! 535: break; ! 536: ! 537: case 0x22: /* APOFF */ ! 538: case 0x23: /* APON */ ! 539: goto bad_cmd; ! 540: ! 541: case 0x25: /* WRCNTR */ ! 542: if (s->pm < 0) ! 543: s->pm = 1; ! 544: goto bad_cmd; ! 545: ! 546: case 0x26: /* GAMSET */ ! 547: if (!s->pm) ! 548: s->gamma = ffs(s->param[0] & 0xf) - 1; ! 549: else if (s->pm < 0) ! 550: s->pm = 1; ! 551: break; ! 552: ! 553: case 0x28: /* DISPOFF */ ! 554: s->onoff = 0; ! 555: fprintf(stderr, "%s: Display off\n", __FUNCTION__); ! 556: break; ! 557: case 0x29: /* DISPON */ ! 558: s->onoff = 1; ! 559: fprintf(stderr, "%s: Display on\n", __FUNCTION__); ! 560: break; ! 561: ! 562: case 0x2a: /* CASET */ ! 563: case 0x2b: /* RASET */ ! 564: case 0x2c: /* RAMWR */ ! 565: case 0x2d: /* RGBSET */ ! 566: case 0x2e: /* RAMRD */ ! 567: case 0x30: /* PTLAR */ ! 568: case 0x33: /* SCRLAR */ ! 569: goto bad_cmd; ! 570: ! 571: case 0x34: /* TEOFF */ ! 572: s->te = 0; ! 573: break; ! 574: case 0x35: /* TEON */ ! 575: if (!s->pm) ! 576: s->te = 1; ! 577: else if (s->pm < 0) ! 578: s->pm = 1; ! 579: break; ! 580: ! 581: case 0x36: /* MADCTR */ ! 582: goto bad_cmd; ! 583: ! 584: case 0x37: /* VSCSAD */ ! 585: s->partial = 0; ! 586: s->normal = 0; ! 587: s->vscr = 1; ! 588: break; ! 589: ! 590: case 0x38: /* IDMOFF */ ! 591: case 0x39: /* IDMON */ ! 592: case 0x3a: /* COLMOD */ ! 593: goto bad_cmd; ! 594: ! 595: case 0xb0: /* CLKINT / DISCTL */ ! 596: case 0xb1: /* CLKEXT */ ! 597: if (s->pm < 0) ! 598: s->pm = 2; ! 599: break; ! 600: ! 601: case 0xb4: /* FRMSEL */ ! 602: break; ! 603: ! 604: case 0xb5: /* FRM8SEL */ ! 605: case 0xb6: /* TMPRNG / INIESC */ ! 606: case 0xb7: /* TMPHIS / NOP2 */ ! 607: case 0xb8: /* TMPREAD / MADCTL */ ! 608: case 0xba: /* DISTCTR */ ! 609: case 0xbb: /* EPVOL */ ! 610: goto bad_cmd; ! 611: ! 612: case 0xbd: /* Unknown */ ! 613: s->p = 0; ! 614: s->resp[0] = 0; ! 615: s->resp[1] = 1; ! 616: break; ! 617: ! 618: case 0xc2: /* IFMOD */ ! 619: if (s->pm < 0) ! 620: s->pm = 2; ! 621: break; ! 622: ! 623: case 0xc6: /* PWRCTL */ ! 624: case 0xc7: /* PPWRCTL */ ! 625: case 0xd0: /* EPWROUT */ ! 626: case 0xd1: /* EPWRIN */ ! 627: case 0xd4: /* RDEV */ ! 628: case 0xd5: /* RDRR */ ! 629: goto bad_cmd; ! 630: ! 631: case 0xda: /* RDID1 */ ! 632: s->p = 0; ! 633: s->resp[0] = (s->id >> 16) & 0xff; ! 634: break; ! 635: case 0xdb: /* RDID2 */ ! 636: s->p = 0; ! 637: s->resp[0] = (s->id >> 8) & 0xff; ! 638: break; ! 639: case 0xdc: /* RDID3 */ ! 640: s->p = 0; ! 641: s->resp[0] = (s->id >> 0) & 0xff; ! 642: break; ! 643: ! 644: default: ! 645: bad_cmd: ! 646: fprintf(stderr, "%s: unknown command %02x\n", __FUNCTION__, s->cmd); ! 647: break; ! 648: } ! 649: ! 650: return ret; ! 651: } ! 652: ! 653: static void *mipid_init(void) ! 654: { ! 655: struct mipid_s *s = (struct mipid_s *) qemu_mallocz(sizeof(*s)); ! 656: ! 657: s->id = 0x838f03; ! 658: mipid_reset(s); ! 659: ! 660: return s; ! 661: } ! 662: ! 663: static void n8x0_spi_setup(struct n800_s *s) ! 664: { ! 665: void *tsc = s->ts.opaque; ! 666: void *mipid = mipid_init(); ! 667: ! 668: omap_mcspi_attach(s->cpu->mcspi[0], s->ts.txrx, tsc, 0); ! 669: omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, mipid, 1); ! 670: } ! 671: ! 672: /* This task is normally performed by the bootloader. If we're loading ! 673: * a kernel directly, we need to enable the Blizzard ourselves. */ ! 674: static void n800_dss_init(struct rfbi_chip_s *chip) ! 675: { ! 676: uint8_t *fb_blank; ! 677: ! 678: chip->write(chip->opaque, 0, 0x2a); /* LCD Width register */ ! 679: chip->write(chip->opaque, 1, 0x64); ! 680: chip->write(chip->opaque, 0, 0x2c); /* LCD HNDP register */ ! 681: chip->write(chip->opaque, 1, 0x1e); ! 682: chip->write(chip->opaque, 0, 0x2e); /* LCD Height 0 register */ ! 683: chip->write(chip->opaque, 1, 0xe0); ! 684: chip->write(chip->opaque, 0, 0x30); /* LCD Height 1 register */ ! 685: chip->write(chip->opaque, 1, 0x01); ! 686: chip->write(chip->opaque, 0, 0x32); /* LCD VNDP register */ ! 687: chip->write(chip->opaque, 1, 0x06); ! 688: chip->write(chip->opaque, 0, 0x68); /* Display Mode register */ ! 689: chip->write(chip->opaque, 1, 1); /* Enable bit */ ! 690: ! 691: chip->write(chip->opaque, 0, 0x6c); ! 692: chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ ! 693: chip->write(chip->opaque, 1, 0x00); /* Input X Start Position */ ! 694: chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ ! 695: chip->write(chip->opaque, 1, 0x00); /* Input Y Start Position */ ! 696: chip->write(chip->opaque, 1, 0x1f); /* Input X End Position */ ! 697: chip->write(chip->opaque, 1, 0x03); /* Input X End Position */ ! 698: chip->write(chip->opaque, 1, 0xdf); /* Input Y End Position */ ! 699: chip->write(chip->opaque, 1, 0x01); /* Input Y End Position */ ! 700: chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ ! 701: chip->write(chip->opaque, 1, 0x00); /* Output X Start Position */ ! 702: chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ ! 703: chip->write(chip->opaque, 1, 0x00); /* Output Y Start Position */ ! 704: chip->write(chip->opaque, 1, 0x1f); /* Output X End Position */ ! 705: chip->write(chip->opaque, 1, 0x03); /* Output X End Position */ ! 706: chip->write(chip->opaque, 1, 0xdf); /* Output Y End Position */ ! 707: chip->write(chip->opaque, 1, 0x01); /* Output Y End Position */ ! 708: chip->write(chip->opaque, 1, 0x01); /* Input Data Format */ ! 709: chip->write(chip->opaque, 1, 0x01); /* Data Source Select */ ! 710: ! 711: fb_blank = memset(qemu_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2); ! 712: /* Display Memory Data Port */ ! 713: chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800); ! 714: free(fb_blank); ! 715: } ! 716: ! 717: static void n8x0_dss_setup(struct n800_s *s) ! 718: { ! 719: s->blizzard.opaque = s1d13745_init(0); ! 720: s->blizzard.block = s1d13745_write_block; ! 721: s->blizzard.write = s1d13745_write; ! 722: s->blizzard.read = s1d13745_read; ! 723: ! 724: omap_rfbi_attach(s->cpu->dss, 0, &s->blizzard); ! 725: } ! 726: ! 727: static void n8x0_cbus_setup(struct n800_s *s) ! 728: { ! 729: qemu_irq dat_out = omap2_gpio_in_get(s->cpu->gpif, N8X0_CBUS_DAT_GPIO)[0]; ! 730: qemu_irq retu_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_RETU_GPIO)[0]; ! 731: qemu_irq tahvo_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TAHVO_GPIO)[0]; ! 732: ! 733: struct cbus_s *cbus = cbus_init(dat_out); ! 734: ! 735: omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_CLK_GPIO, cbus->clk); ! 736: omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_DAT_GPIO, cbus->dat); ! 737: omap2_gpio_out_set(s->cpu->gpif, N8X0_CBUS_SEL_GPIO, cbus->sel); ! 738: ! 739: cbus_attach(cbus, s->retu = retu_init(retu_irq, 1)); ! 740: cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1)); ! 741: } ! 742: ! 743: static void n8x0_uart_setup(struct n800_s *s) ! 744: { ! 745: CharDriverState *radio = uart_hci_init( ! 746: omap2_gpio_in_get(s->cpu->gpif, ! 747: N8X0_BT_HOST_WKUP_GPIO)[0]); ! 748: ! 749: omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_RESET_GPIO, ! 750: csrhci_pins_get(radio)[csrhci_pin_reset]); ! 751: omap2_gpio_out_set(s->cpu->gpif, N8X0_BT_WKUP_GPIO, ! 752: csrhci_pins_get(radio)[csrhci_pin_wakeup]); ! 753: ! 754: omap_uart_attach(s->cpu->uart[BT_UART], radio); ! 755: } ! 756: ! 757: static void n8x0_usb_power_cb(void *opaque, int line, int level) ! 758: { ! 759: struct n800_s *s = opaque; ! 760: ! 761: tusb6010_power(s->usb, level); ! 762: } ! 763: ! 764: static void n8x0_usb_setup(struct n800_s *s) ! 765: { ! 766: qemu_irq tusb_irq = omap2_gpio_in_get(s->cpu->gpif, N8X0_TUSB_INT_GPIO)[0]; ! 767: qemu_irq tusb_pwr = qemu_allocate_irqs(n8x0_usb_power_cb, s, 1)[0]; ! 768: struct tusb_s *tusb = tusb6010_init(tusb_irq); ! 769: ! 770: /* Using the NOR interface */ ! 771: omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_ASYNC_CS, ! 772: tusb6010_async_io(tusb), 0, 0, tusb); ! 773: omap_gpmc_attach(s->cpu->gpmc, N8X0_USB_SYNC_CS, ! 774: tusb6010_sync_io(tusb), 0, 0, tusb); ! 775: ! 776: s->usb = tusb; ! 777: omap2_gpio_out_set(s->cpu->gpif, N8X0_TUSB_ENABLE_GPIO, tusb_pwr); ! 778: } ! 779: ! 780: /* Setup done before the main bootloader starts by some early setup code ! 781: * - used when we want to run the main bootloader in emulation. This ! 782: * isn't documented. */ ! 783: static uint32_t n800_pinout[104] = { ! 784: 0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0, ! 785: 0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808, ! 786: 0x08080808, 0x180800c4, 0x00b80000, 0x08080808, ! 787: 0x080800bc, 0x00cc0808, 0x08081818, 0x18180128, ! 788: 0x01241800, 0x18181818, 0x000000f0, 0x01300000, ! 789: 0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b, ! 790: 0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080, ! 791: 0x007c0000, 0x00000000, 0x00000088, 0x00840000, ! 792: 0x00000000, 0x00000094, 0x00980300, 0x0f180003, ! 793: 0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c, ! 794: 0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008, ! 795: 0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f, ! 796: 0x181800f4, 0x00f81818, 0x00000018, 0x000000fc, ! 797: 0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008, ! 798: 0x00000000, 0x00000038, 0x00340000, 0x00000000, ! 799: 0x1a080070, 0x00641a1a, 0x08080808, 0x08080060, ! 800: 0x005c0808, 0x08080808, 0x08080058, 0x00540808, ! 801: 0x08080808, 0x0808006c, 0x00680808, 0x08080808, ! 802: 0x000000a8, 0x00b00000, 0x08080808, 0x000000a0, ! 803: 0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808, ! 804: 0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff, ! 805: 0x000000ac, 0x01040800, 0x08080b0f, 0x18180100, ! 806: 0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a, ! 807: 0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00, ! 808: 0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118, ! 809: 0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b, ! 810: }; ! 811: ! 812: static void n800_setup_nolo_tags(void *sram_base) ! 813: { ! 814: int i; ! 815: uint32_t *p = sram_base + 0x8000; ! 816: uint32_t *v = sram_base + 0xa000; ! 817: ! 818: memset(p, 0, 0x3000); ! 819: ! 820: strcpy((void *) (p + 0), "QEMU N800"); ! 821: ! 822: strcpy((void *) (p + 8), "F5"); ! 823: ! 824: stl_raw(p + 10, 0x04f70000); ! 825: strcpy((void *) (p + 9), "RX-34"); ! 826: ! 827: /* RAM size in MB? */ ! 828: stl_raw(p + 12, 0x80); ! 829: ! 830: /* Pointer to the list of tags */ ! 831: stl_raw(p + 13, OMAP2_SRAM_BASE + 0x9000); ! 832: ! 833: /* The NOLO tags start here */ ! 834: p = sram_base + 0x9000; ! 835: #define ADD_TAG(tag, len) \ ! 836: stw_raw((uint16_t *) p + 0, tag); \ ! 837: stw_raw((uint16_t *) p + 1, len); p ++; \ ! 838: stl_raw(p ++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff)); ! 839: ! 840: /* OMAP STI console? Pin out settings? */ ! 841: ADD_TAG(0x6e01, 414); ! 842: for (i = 0; i < ARRAY_SIZE(n800_pinout); i ++) ! 843: stl_raw(v ++, n800_pinout[i]); ! 844: ! 845: /* Kernel memsize? */ ! 846: ADD_TAG(0x6e05, 1); ! 847: stl_raw(v ++, 2); ! 848: ! 849: /* NOLO serial console */ ! 850: ADD_TAG(0x6e02, 4); ! 851: stl_raw(v ++, XLDR_LL_UART); /* UART number (1 - 3) */ ! 852: ! 853: #if 0 ! 854: /* CBUS settings (Retu/AVilma) */ ! 855: ADD_TAG(0x6e03, 6); ! 856: stw_raw((uint16_t *) v + 0, 65); /* CBUS GPIO0 */ ! 857: stw_raw((uint16_t *) v + 1, 66); /* CBUS GPIO1 */ ! 858: stw_raw((uint16_t *) v + 2, 64); /* CBUS GPIO2 */ ! 859: v += 2; ! 860: #endif ! 861: ! 862: /* Nokia ASIC BB5 (Retu/Tahvo) */ ! 863: ADD_TAG(0x6e0a, 4); ! 864: stw_raw((uint16_t *) v + 0, 111); /* "Retu" interrupt GPIO */ ! 865: stw_raw((uint16_t *) v + 1, 108); /* "Tahvo" interrupt GPIO */ ! 866: v ++; ! 867: ! 868: /* LCD console? */ ! 869: ADD_TAG(0x6e04, 4); ! 870: stw_raw((uint16_t *) v + 0, 30); /* ??? */ ! 871: stw_raw((uint16_t *) v + 1, 24); /* ??? */ ! 872: v ++; ! 873: ! 874: #if 0 ! 875: /* LCD settings */ ! 876: ADD_TAG(0x6e06, 2); ! 877: stw_raw((uint16_t *) (v ++), 15); /* ??? */ ! 878: #endif ! 879: ! 880: /* I^2C (Menelaus) */ ! 881: ADD_TAG(0x6e07, 4); ! 882: stl_raw(v ++, 0x00720000); /* ??? */ ! 883: ! 884: /* Unknown */ ! 885: ADD_TAG(0x6e0b, 6); ! 886: stw_raw((uint16_t *) v + 0, 94); /* ??? */ ! 887: stw_raw((uint16_t *) v + 1, 23); /* ??? */ ! 888: stw_raw((uint16_t *) v + 2, 0); /* ??? */ ! 889: v += 2; ! 890: ! 891: /* OMAP gpio switch info */ ! 892: ADD_TAG(0x6e0c, 80); ! 893: strcpy((void *) v, "bat_cover"); v += 3; ! 894: stw_raw((uint16_t *) v + 0, 110); /* GPIO num ??? */ ! 895: stw_raw((uint16_t *) v + 1, 1); /* GPIO num ??? */ ! 896: v += 2; ! 897: strcpy((void *) v, "cam_act"); v += 3; ! 898: stw_raw((uint16_t *) v + 0, 95); /* GPIO num ??? */ ! 899: stw_raw((uint16_t *) v + 1, 32); /* GPIO num ??? */ ! 900: v += 2; ! 901: strcpy((void *) v, "cam_turn"); v += 3; ! 902: stw_raw((uint16_t *) v + 0, 12); /* GPIO num ??? */ ! 903: stw_raw((uint16_t *) v + 1, 33); /* GPIO num ??? */ ! 904: v += 2; ! 905: strcpy((void *) v, "headphone"); v += 3; ! 906: stw_raw((uint16_t *) v + 0, 107); /* GPIO num ??? */ ! 907: stw_raw((uint16_t *) v + 1, 17); /* GPIO num ??? */ ! 908: v += 2; ! 909: ! 910: /* Bluetooth */ ! 911: ADD_TAG(0x6e0e, 12); ! 912: stl_raw(v ++, 0x5c623d01); /* ??? */ ! 913: stl_raw(v ++, 0x00000201); /* ??? */ ! 914: stl_raw(v ++, 0x00000000); /* ??? */ ! 915: ! 916: /* CX3110x WLAN settings */ ! 917: ADD_TAG(0x6e0f, 8); ! 918: stl_raw(v ++, 0x00610025); /* ??? */ ! 919: stl_raw(v ++, 0xffff0057); /* ??? */ ! 920: ! 921: /* MMC host settings */ ! 922: ADD_TAG(0x6e10, 12); ! 923: stl_raw(v ++, 0xffff000f); /* ??? */ ! 924: stl_raw(v ++, 0xffffffff); /* ??? */ ! 925: stl_raw(v ++, 0x00000060); /* ??? */ ! 926: ! 927: /* OneNAND chip select */ ! 928: ADD_TAG(0x6e11, 10); ! 929: stl_raw(v ++, 0x00000401); /* ??? */ ! 930: stl_raw(v ++, 0x0002003a); /* ??? */ ! 931: stl_raw(v ++, 0x00000002); /* ??? */ ! 932: ! 933: /* TEA5761 sensor settings */ ! 934: ADD_TAG(0x6e12, 2); ! 935: stl_raw(v ++, 93); /* GPIO num ??? */ ! 936: ! 937: #if 0 ! 938: /* Unknown tag */ ! 939: ADD_TAG(6e09, 0); ! 940: ! 941: /* Kernel UART / console */ ! 942: ADD_TAG(6e12, 0); ! 943: #endif ! 944: ! 945: /* End of the list */ ! 946: stl_raw(p ++, 0x00000000); ! 947: stl_raw(p ++, 0x00000000); ! 948: } ! 949: ! 950: /* This task is normally performed by the bootloader. If we're loading ! 951: * a kernel directly, we need to set up GPMC mappings ourselves. */ ! 952: static void n800_gpmc_init(struct n800_s *s) ! 953: { ! 954: uint32_t config7 = ! 955: (0xf << 8) | /* MASKADDRESS */ ! 956: (1 << 6) | /* CSVALID */ ! 957: (4 << 0); /* BASEADDRESS */ ! 958: ! 959: cpu_physical_memory_write(0x6800a078, /* GPMC_CONFIG7_0 */ ! 960: (void *) &config7, sizeof(config7)); ! 961: } ! 962: ! 963: /* Setup sequence done by the bootloader */ ! 964: static void n8x0_boot_init(void *opaque) ! 965: { ! 966: struct n800_s *s = (struct n800_s *) opaque; ! 967: uint32_t buf; ! 968: ! 969: /* PRCM setup */ ! 970: #define omap_writel(addr, val) \ ! 971: buf = (val); \ ! 972: cpu_physical_memory_write(addr, (void *) &buf, sizeof(buf)) ! 973: ! 974: omap_writel(0x48008060, 0x41); /* PRCM_CLKSRC_CTRL */ ! 975: omap_writel(0x48008070, 1); /* PRCM_CLKOUT_CTRL */ ! 976: omap_writel(0x48008078, 0); /* PRCM_CLKEMUL_CTRL */ ! 977: omap_writel(0x48008090, 0); /* PRCM_VOLTSETUP */ ! 978: omap_writel(0x48008094, 0); /* PRCM_CLKSSETUP */ ! 979: omap_writel(0x48008098, 0); /* PRCM_POLCTRL */ ! 980: omap_writel(0x48008140, 2); /* CM_CLKSEL_MPU */ ! 981: omap_writel(0x48008148, 0); /* CM_CLKSTCTRL_MPU */ ! 982: omap_writel(0x48008158, 1); /* RM_RSTST_MPU */ ! 983: omap_writel(0x480081c8, 0x15); /* PM_WKDEP_MPU */ ! 984: omap_writel(0x480081d4, 0x1d4); /* PM_EVGENCTRL_MPU */ ! 985: omap_writel(0x480081d8, 0); /* PM_EVEGENONTIM_MPU */ ! 986: omap_writel(0x480081dc, 0); /* PM_EVEGENOFFTIM_MPU */ ! 987: omap_writel(0x480081e0, 0xc); /* PM_PWSTCTRL_MPU */ ! 988: omap_writel(0x48008200, 0x047e7ff7); /* CM_FCLKEN1_CORE */ ! 989: omap_writel(0x48008204, 0x00000004); /* CM_FCLKEN2_CORE */ ! 990: omap_writel(0x48008210, 0x047e7ff1); /* CM_ICLKEN1_CORE */ ! 991: omap_writel(0x48008214, 0x00000004); /* CM_ICLKEN2_CORE */ ! 992: omap_writel(0x4800821c, 0x00000000); /* CM_ICLKEN4_CORE */ ! 993: omap_writel(0x48008230, 0); /* CM_AUTOIDLE1_CORE */ ! 994: omap_writel(0x48008234, 0); /* CM_AUTOIDLE2_CORE */ ! 995: omap_writel(0x48008238, 7); /* CM_AUTOIDLE3_CORE */ ! 996: omap_writel(0x4800823c, 0); /* CM_AUTOIDLE4_CORE */ ! 997: omap_writel(0x48008240, 0x04360626); /* CM_CLKSEL1_CORE */ ! 998: omap_writel(0x48008244, 0x00000014); /* CM_CLKSEL2_CORE */ ! 999: omap_writel(0x48008248, 0); /* CM_CLKSTCTRL_CORE */ ! 1000: omap_writel(0x48008300, 0x00000000); /* CM_FCLKEN_GFX */ ! 1001: omap_writel(0x48008310, 0x00000000); /* CM_ICLKEN_GFX */ ! 1002: omap_writel(0x48008340, 0x00000001); /* CM_CLKSEL_GFX */ ! 1003: omap_writel(0x48008400, 0x00000004); /* CM_FCLKEN_WKUP */ ! 1004: omap_writel(0x48008410, 0x00000004); /* CM_ICLKEN_WKUP */ ! 1005: omap_writel(0x48008440, 0x00000000); /* CM_CLKSEL_WKUP */ ! 1006: omap_writel(0x48008500, 0x000000cf); /* CM_CLKEN_PLL */ ! 1007: omap_writel(0x48008530, 0x0000000c); /* CM_AUTOIDLE_PLL */ ! 1008: omap_writel(0x48008540, /* CM_CLKSEL1_PLL */ ! 1009: (0x78 << 12) | (6 << 8)); ! 1010: omap_writel(0x48008544, 2); /* CM_CLKSEL2_PLL */ ! 1011: ! 1012: /* GPMC setup */ ! 1013: n800_gpmc_init(s); ! 1014: ! 1015: /* Video setup */ ! 1016: n800_dss_init(&s->blizzard); ! 1017: ! 1018: /* CPU setup */ ! 1019: s->cpu->env->regs[15] = s->cpu->env->boot_info->loader_start; ! 1020: s->cpu->env->GE = 0x5; ! 1021: ! 1022: /* If the machine has a slided keyboard, open it */ ! 1023: if (s->kbd) ! 1024: qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N810_SLIDE_GPIO)[0]); ! 1025: } ! 1026: ! 1027: #define OMAP_TAG_NOKIA_BT 0x4e01 ! 1028: #define OMAP_TAG_WLAN_CX3110X 0x4e02 ! 1029: #define OMAP_TAG_CBUS 0x4e03 ! 1030: #define OMAP_TAG_EM_ASIC_BB5 0x4e04 ! 1031: ! 1032: static struct omap_gpiosw_info_s { ! 1033: const char *name; ! 1034: int line; ! 1035: int type; ! 1036: } n800_gpiosw_info[] = { ! 1037: { ! 1038: "bat_cover", N800_BAT_COVER_GPIO, ! 1039: OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, ! 1040: }, { ! 1041: "cam_act", N800_CAM_ACT_GPIO, ! 1042: OMAP_GPIOSW_TYPE_ACTIVITY, ! 1043: }, { ! 1044: "cam_turn", N800_CAM_TURN_GPIO, ! 1045: OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED, ! 1046: }, { ! 1047: "headphone", N8X0_HEADPHONE_GPIO, ! 1048: OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, ! 1049: }, ! 1050: { 0 } ! 1051: }, n810_gpiosw_info[] = { ! 1052: { ! 1053: "gps_reset", N810_GPS_RESET_GPIO, ! 1054: OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, ! 1055: }, { ! 1056: "gps_wakeup", N810_GPS_WAKEUP_GPIO, ! 1057: OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT, ! 1058: }, { ! 1059: "headphone", N8X0_HEADPHONE_GPIO, ! 1060: OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED, ! 1061: }, { ! 1062: "kb_lock", N810_KB_LOCK_GPIO, ! 1063: OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, ! 1064: }, { ! 1065: "sleepx_led", N810_SLEEPX_LED_GPIO, ! 1066: OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT, ! 1067: }, { ! 1068: "slide", N810_SLIDE_GPIO, ! 1069: OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED, ! 1070: }, ! 1071: { 0 } ! 1072: }; ! 1073: ! 1074: static struct omap_partition_info_s { ! 1075: uint32_t offset; ! 1076: uint32_t size; ! 1077: int mask; ! 1078: const char *name; ! 1079: } n800_part_info[] = { ! 1080: { 0x00000000, 0x00020000, 0x3, "bootloader" }, ! 1081: { 0x00020000, 0x00060000, 0x0, "config" }, ! 1082: { 0x00080000, 0x00200000, 0x0, "kernel" }, ! 1083: { 0x00280000, 0x00200000, 0x3, "initfs" }, ! 1084: { 0x00480000, 0x0fb80000, 0x3, "rootfs" }, ! 1085: ! 1086: { 0, 0, 0, 0 } ! 1087: }, n810_part_info[] = { ! 1088: { 0x00000000, 0x00020000, 0x3, "bootloader" }, ! 1089: { 0x00020000, 0x00060000, 0x0, "config" }, ! 1090: { 0x00080000, 0x00220000, 0x0, "kernel" }, ! 1091: { 0x002a0000, 0x00400000, 0x0, "initfs" }, ! 1092: { 0x006a0000, 0x0f960000, 0x0, "rootfs" }, ! 1093: ! 1094: { 0, 0, 0, 0 } ! 1095: }; ! 1096: ! 1097: static bdaddr_t n8x0_bd_addr = {{ N8X0_BD_ADDR }}; ! 1098: ! 1099: static int n8x0_atag_setup(void *p, int model) ! 1100: { ! 1101: uint8_t *b; ! 1102: uint16_t *w; ! 1103: uint32_t *l; ! 1104: struct omap_gpiosw_info_s *gpiosw; ! 1105: struct omap_partition_info_s *partition; ! 1106: const char *tag; ! 1107: ! 1108: w = p; ! 1109: ! 1110: stw_raw(w ++, OMAP_TAG_UART); /* u16 tag */ ! 1111: stw_raw(w ++, 4); /* u16 len */ ! 1112: stw_raw(w ++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */ ! 1113: w ++; ! 1114: ! 1115: #if 0 ! 1116: stw_raw(w ++, OMAP_TAG_SERIAL_CONSOLE); /* u16 tag */ ! 1117: stw_raw(w ++, 4); /* u16 len */ ! 1118: stw_raw(w ++, XLDR_LL_UART + 1); /* u8 console_uart */ ! 1119: stw_raw(w ++, 115200); /* u32 console_speed */ ! 1120: #endif ! 1121: ! 1122: stw_raw(w ++, OMAP_TAG_LCD); /* u16 tag */ ! 1123: stw_raw(w ++, 36); /* u16 len */ ! 1124: strcpy((void *) w, "QEMU LCD panel"); /* char panel_name[16] */ ! 1125: w += 8; ! 1126: strcpy((void *) w, "blizzard"); /* char ctrl_name[16] */ ! 1127: w += 8; ! 1128: stw_raw(w ++, N810_BLIZZARD_RESET_GPIO); /* TODO: n800 s16 nreset_gpio */ ! 1129: stw_raw(w ++, 24); /* u8 data_lines */ ! 1130: ! 1131: stw_raw(w ++, OMAP_TAG_CBUS); /* u16 tag */ ! 1132: stw_raw(w ++, 8); /* u16 len */ ! 1133: stw_raw(w ++, N8X0_CBUS_CLK_GPIO); /* s16 clk_gpio */ ! 1134: stw_raw(w ++, N8X0_CBUS_DAT_GPIO); /* s16 dat_gpio */ ! 1135: stw_raw(w ++, N8X0_CBUS_SEL_GPIO); /* s16 sel_gpio */ ! 1136: w ++; ! 1137: ! 1138: stw_raw(w ++, OMAP_TAG_EM_ASIC_BB5); /* u16 tag */ ! 1139: stw_raw(w ++, 4); /* u16 len */ ! 1140: stw_raw(w ++, N8X0_RETU_GPIO); /* s16 retu_irq_gpio */ ! 1141: stw_raw(w ++, N8X0_TAHVO_GPIO); /* s16 tahvo_irq_gpio */ ! 1142: ! 1143: gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info; ! 1144: for (; gpiosw->name; gpiosw ++) { ! 1145: stw_raw(w ++, OMAP_TAG_GPIO_SWITCH); /* u16 tag */ ! 1146: stw_raw(w ++, 20); /* u16 len */ ! 1147: strcpy((void *) w, gpiosw->name); /* char name[12] */ ! 1148: w += 6; ! 1149: stw_raw(w ++, gpiosw->line); /* u16 gpio */ ! 1150: stw_raw(w ++, gpiosw->type); ! 1151: stw_raw(w ++, 0); ! 1152: stw_raw(w ++, 0); ! 1153: } ! 1154: ! 1155: stw_raw(w ++, OMAP_TAG_NOKIA_BT); /* u16 tag */ ! 1156: stw_raw(w ++, 12); /* u16 len */ ! 1157: b = (void *) w; ! 1158: stb_raw(b ++, 0x01); /* u8 chip_type (CSR) */ ! 1159: stb_raw(b ++, N8X0_BT_WKUP_GPIO); /* u8 bt_wakeup_gpio */ ! 1160: stb_raw(b ++, N8X0_BT_HOST_WKUP_GPIO); /* u8 host_wakeup_gpio */ ! 1161: stb_raw(b ++, N8X0_BT_RESET_GPIO); /* u8 reset_gpio */ ! 1162: stb_raw(b ++, BT_UART + 1); /* u8 bt_uart */ ! 1163: memcpy(b, &n8x0_bd_addr, 6); /* u8 bd_addr[6] */ ! 1164: b += 6; ! 1165: stb_raw(b ++, 0x02); /* u8 bt_sysclk (38.4) */ ! 1166: w = (void *) b; ! 1167: ! 1168: stw_raw(w ++, OMAP_TAG_WLAN_CX3110X); /* u16 tag */ ! 1169: stw_raw(w ++, 8); /* u16 len */ ! 1170: stw_raw(w ++, 0x25); /* u8 chip_type */ ! 1171: stw_raw(w ++, N8X0_WLAN_PWR_GPIO); /* s16 power_gpio */ ! 1172: stw_raw(w ++, N8X0_WLAN_IRQ_GPIO); /* s16 irq_gpio */ ! 1173: stw_raw(w ++, -1); /* s16 spi_cs_gpio */ ! 1174: ! 1175: stw_raw(w ++, OMAP_TAG_MMC); /* u16 tag */ ! 1176: stw_raw(w ++, 16); /* u16 len */ ! 1177: if (model == 810) { ! 1178: stw_raw(w ++, 0x23f); /* unsigned flags */ ! 1179: stw_raw(w ++, -1); /* s16 power_pin */ ! 1180: stw_raw(w ++, -1); /* s16 switch_pin */ ! 1181: stw_raw(w ++, -1); /* s16 wp_pin */ ! 1182: stw_raw(w ++, 0x240); /* unsigned flags */ ! 1183: stw_raw(w ++, 0xc000); /* s16 power_pin */ ! 1184: stw_raw(w ++, 0x0248); /* s16 switch_pin */ ! 1185: stw_raw(w ++, 0xc000); /* s16 wp_pin */ ! 1186: } else { ! 1187: stw_raw(w ++, 0xf); /* unsigned flags */ ! 1188: stw_raw(w ++, -1); /* s16 power_pin */ ! 1189: stw_raw(w ++, -1); /* s16 switch_pin */ ! 1190: stw_raw(w ++, -1); /* s16 wp_pin */ ! 1191: stw_raw(w ++, 0); /* unsigned flags */ ! 1192: stw_raw(w ++, 0); /* s16 power_pin */ ! 1193: stw_raw(w ++, 0); /* s16 switch_pin */ ! 1194: stw_raw(w ++, 0); /* s16 wp_pin */ ! 1195: } ! 1196: ! 1197: stw_raw(w ++, OMAP_TAG_TEA5761); /* u16 tag */ ! 1198: stw_raw(w ++, 4); /* u16 len */ ! 1199: stw_raw(w ++, N8X0_TEA5761_CS_GPIO); /* u16 enable_gpio */ ! 1200: w ++; ! 1201: ! 1202: partition = (model == 810) ? n810_part_info : n800_part_info; ! 1203: for (; partition->name; partition ++) { ! 1204: stw_raw(w ++, OMAP_TAG_PARTITION); /* u16 tag */ ! 1205: stw_raw(w ++, 28); /* u16 len */ ! 1206: strcpy((void *) w, partition->name); /* char name[16] */ ! 1207: l = (void *) (w + 8); ! 1208: stl_raw(l ++, partition->size); /* unsigned int size */ ! 1209: stl_raw(l ++, partition->offset); /* unsigned int offset */ ! 1210: stl_raw(l ++, partition->mask); /* unsigned int mask_flags */ ! 1211: w = (void *) l; ! 1212: } ! 1213: ! 1214: stw_raw(w ++, OMAP_TAG_BOOT_REASON); /* u16 tag */ ! 1215: stw_raw(w ++, 12); /* u16 len */ ! 1216: #if 0 ! 1217: strcpy((void *) w, "por"); /* char reason_str[12] */ ! 1218: strcpy((void *) w, "charger"); /* char reason_str[12] */ ! 1219: strcpy((void *) w, "32wd_to"); /* char reason_str[12] */ ! 1220: strcpy((void *) w, "sw_rst"); /* char reason_str[12] */ ! 1221: strcpy((void *) w, "mbus"); /* char reason_str[12] */ ! 1222: strcpy((void *) w, "unknown"); /* char reason_str[12] */ ! 1223: strcpy((void *) w, "swdg_to"); /* char reason_str[12] */ ! 1224: strcpy((void *) w, "sec_vio"); /* char reason_str[12] */ ! 1225: strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ ! 1226: strcpy((void *) w, "rtc_alarm"); /* char reason_str[12] */ ! 1227: #else ! 1228: strcpy((void *) w, "pwr_key"); /* char reason_str[12] */ ! 1229: #endif ! 1230: w += 6; ! 1231: ! 1232: tag = (model == 810) ? "RX-44" : "RX-34"; ! 1233: stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ ! 1234: stw_raw(w ++, 24); /* u16 len */ ! 1235: strcpy((void *) w, "product"); /* char component[12] */ ! 1236: w += 6; ! 1237: strcpy((void *) w, tag); /* char version[12] */ ! 1238: w += 6; ! 1239: ! 1240: stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ ! 1241: stw_raw(w ++, 24); /* u16 len */ ! 1242: strcpy((void *) w, "hw-build"); /* char component[12] */ ! 1243: w += 6; ! 1244: strcpy((void *) w, "QEMU " QEMU_VERSION); /* char version[12] */ ! 1245: w += 6; ! 1246: ! 1247: tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu"; ! 1248: stw_raw(w ++, OMAP_TAG_VERSION_STR); /* u16 tag */ ! 1249: stw_raw(w ++, 24); /* u16 len */ ! 1250: strcpy((void *) w, "nolo"); /* char component[12] */ ! 1251: w += 6; ! 1252: strcpy((void *) w, tag); /* char version[12] */ ! 1253: w += 6; ! 1254: ! 1255: return (void *) w - p; ! 1256: } ! 1257: ! 1258: static int n800_atag_setup(struct arm_boot_info *info, void *p) ! 1259: { ! 1260: return n8x0_atag_setup(p, 800); ! 1261: } ! 1262: ! 1263: static int n810_atag_setup(struct arm_boot_info *info, void *p) ! 1264: { ! 1265: return n8x0_atag_setup(p, 810); ! 1266: } ! 1267: ! 1268: static void n8x0_init(ram_addr_t ram_size, const char *boot_device, ! 1269: const char *kernel_filename, ! 1270: const char *kernel_cmdline, const char *initrd_filename, ! 1271: const char *cpu_model, struct arm_boot_info *binfo, int model) ! 1272: { ! 1273: struct n800_s *s = (struct n800_s *) qemu_mallocz(sizeof(*s)); ! 1274: int sdram_size = binfo->ram_size; ! 1275: int onenandram_size = 0x00010000; ! 1276: DisplayState *ds; ! 1277: ! 1278: if (ram_size < sdram_size + onenandram_size + OMAP242X_SRAM_SIZE) { ! 1279: fprintf(stderr, "This architecture uses %i bytes of memory\n", ! 1280: sdram_size + onenandram_size + OMAP242X_SRAM_SIZE); ! 1281: exit(1); ! 1282: } ! 1283: ! 1284: s->cpu = omap2420_mpu_init(sdram_size, cpu_model); ! 1285: ! 1286: /* Setup peripherals ! 1287: * ! 1288: * Believed external peripherals layout in the N810: ! 1289: * (spi bus 1) ! 1290: * tsc2005 ! 1291: * lcd_mipid ! 1292: * (spi bus 2) ! 1293: * Conexant cx3110x (WLAN) ! 1294: * optional: pc2400m (WiMAX) ! 1295: * (i2c bus 0) ! 1296: * TLV320AIC33 (audio codec) ! 1297: * TCM825x (camera by Toshiba) ! 1298: * lp5521 (clever LEDs) ! 1299: * tsl2563 (light sensor, hwmon, model 7, rev. 0) ! 1300: * lm8323 (keypad, manf 00, rev 04) ! 1301: * (i2c bus 1) ! 1302: * tmp105 (temperature sensor, hwmon) ! 1303: * menelaus (pm) ! 1304: * (somewhere on i2c - maybe N800-only) ! 1305: * tea5761 (FM tuner) ! 1306: * (serial 0) ! 1307: * GPS ! 1308: * (some serial port) ! 1309: * csr41814 (Bluetooth) ! 1310: */ ! 1311: n8x0_gpio_setup(s); ! 1312: n8x0_nand_setup(s); ! 1313: n8x0_i2c_setup(s); ! 1314: if (model == 800) ! 1315: n800_tsc_kbd_setup(s); ! 1316: else if (model == 810) { ! 1317: n810_tsc_setup(s); ! 1318: n810_kbd_setup(s); ! 1319: } ! 1320: n8x0_spi_setup(s); ! 1321: n8x0_dss_setup(s); ! 1322: n8x0_cbus_setup(s); ! 1323: n8x0_uart_setup(s); ! 1324: if (usb_enabled) ! 1325: n8x0_usb_setup(s); ! 1326: ! 1327: /* Setup initial (reset) machine state */ ! 1328: ! 1329: /* Start at the OneNAND bootloader. */ ! 1330: s->cpu->env->regs[15] = 0; ! 1331: ! 1332: if (kernel_filename) { ! 1333: /* Or at the linux loader. */ ! 1334: binfo->kernel_filename = kernel_filename; ! 1335: binfo->kernel_cmdline = kernel_cmdline; ! 1336: binfo->initrd_filename = initrd_filename; ! 1337: arm_load_kernel(s->cpu->env, binfo); ! 1338: ! 1339: qemu_register_reset(n8x0_boot_init, s); ! 1340: n8x0_boot_init(s); ! 1341: } ! 1342: ! 1343: if (option_rom[0] && (boot_device[0] == 'n' || !kernel_filename)) { ! 1344: /* No, wait, better start at the ROM. */ ! 1345: s->cpu->env->regs[15] = OMAP2_Q2_BASE + 0x400000; ! 1346: ! 1347: /* This is intended for loading the `secondary.bin' program from ! 1348: * Nokia images (the NOLO bootloader). The entry point seems ! 1349: * to be at OMAP2_Q2_BASE + 0x400000. ! 1350: * ! 1351: * The `2nd.bin' files contain some kind of earlier boot code and ! 1352: * for them the entry point needs to be set to OMAP2_SRAM_BASE. ! 1353: * ! 1354: * The code above is for loading the `zImage' file from Nokia ! 1355: * images. */ ! 1356: printf("%i bytes of image loaded\n", load_image(option_rom[0], ! 1357: phys_ram_base + 0x400000)); ! 1358: ! 1359: n800_setup_nolo_tags(phys_ram_base + sdram_size); ! 1360: } ! 1361: /* FIXME: We shouldn't really be doing this here. The LCD controller ! 1362: will set the size once configured, so this just sets an initial ! 1363: size until the guest activates the display. */ ! 1364: ds = get_displaystate(); ! 1365: ds->surface = qemu_resize_displaysurface(ds->surface, 800, 480, 32, 4 * 800); ! 1366: dpy_resize(ds); ! 1367: } ! 1368: ! 1369: static struct arm_boot_info n800_binfo = { ! 1370: .loader_start = OMAP2_Q2_BASE, ! 1371: /* Actually two chips of 0x4000000 bytes each */ ! 1372: .ram_size = 0x08000000, ! 1373: .board_id = 0x4f7, ! 1374: .atag_board = n800_atag_setup, ! 1375: }; ! 1376: ! 1377: static struct arm_boot_info n810_binfo = { ! 1378: .loader_start = OMAP2_Q2_BASE, ! 1379: /* Actually two chips of 0x4000000 bytes each */ ! 1380: .ram_size = 0x08000000, ! 1381: /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not ! 1382: * used by some older versions of the bootloader and 5555 is used ! 1383: * instead (including versions that shipped with many devices). */ ! 1384: .board_id = 0x60c, ! 1385: .atag_board = n810_atag_setup, ! 1386: }; ! 1387: ! 1388: static void n800_init(ram_addr_t ram_size, int vga_ram_size, ! 1389: const char *boot_device, ! 1390: const char *kernel_filename, const char *kernel_cmdline, ! 1391: const char *initrd_filename, const char *cpu_model) ! 1392: { ! 1393: return n8x0_init(ram_size, boot_device, ! 1394: kernel_filename, kernel_cmdline, initrd_filename, ! 1395: cpu_model, &n800_binfo, 800); ! 1396: } ! 1397: ! 1398: static void n810_init(ram_addr_t ram_size, int vga_ram_size, ! 1399: const char *boot_device, ! 1400: const char *kernel_filename, const char *kernel_cmdline, ! 1401: const char *initrd_filename, const char *cpu_model) ! 1402: { ! 1403: return n8x0_init(ram_size, boot_device, ! 1404: kernel_filename, kernel_cmdline, initrd_filename, ! 1405: cpu_model, &n810_binfo, 810); ! 1406: } ! 1407: ! 1408: QEMUMachine n800_machine = { ! 1409: .name = "n800", ! 1410: .desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)", ! 1411: .init = n800_init, ! 1412: .ram_require = (0x08000000 + 0x00010000 + OMAP242X_SRAM_SIZE) | ! 1413: RAMSIZE_FIXED, ! 1414: }; ! 1415: ! 1416: QEMUMachine n810_machine = { ! 1417: .name = "n810", ! 1418: .desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)", ! 1419: .init = n810_init, ! 1420: .ram_require = (0x08000000 + 0x00010000 + OMAP242X_SRAM_SIZE) | ! 1421: RAMSIZE_FIXED, ! 1422: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.