xref: /openbmc/qemu/hw/arm/nseries.c (revision 6da68df7)
153018216SPaolo Bonzini /*
253018216SPaolo Bonzini  * Nokia N-series internet tablets.
353018216SPaolo Bonzini  *
453018216SPaolo Bonzini  * Copyright (C) 2007 Nokia Corporation
553018216SPaolo Bonzini  * Written by Andrzej Zaborowski <andrew@openedhand.com>
653018216SPaolo Bonzini  *
753018216SPaolo Bonzini  * This program is free software; you can redistribute it and/or
853018216SPaolo Bonzini  * modify it under the terms of the GNU General Public License as
953018216SPaolo Bonzini  * published by the Free Software Foundation; either version 2 or
1053018216SPaolo Bonzini  * (at your option) version 3 of the License.
1153018216SPaolo Bonzini  *
1253018216SPaolo Bonzini  * This program is distributed in the hope that it will be useful,
1353018216SPaolo Bonzini  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1453018216SPaolo Bonzini  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1553018216SPaolo Bonzini  * GNU General Public License for more details.
1653018216SPaolo Bonzini  *
1753018216SPaolo Bonzini  * You should have received a copy of the GNU General Public License along
1853018216SPaolo Bonzini  * with this program; if not, see <http://www.gnu.org/licenses/>.
1953018216SPaolo Bonzini  */
2053018216SPaolo Bonzini 
2112b16722SPeter Maydell #include "qemu/osdep.h"
22da34e65cSMarkus Armbruster #include "qapi/error.h"
2333c11879SPaolo Bonzini #include "cpu.h"
24*6da68df7SThomas Huth #include "chardev/char.h"
25f348b6d1SVeronia Bahaa #include "qemu/cutils.h"
2658369e22SPaolo Bonzini #include "qemu/bswap.h"
2771e8a915SMarkus Armbruster #include "sysemu/reset.h"
2854d31236SMarkus Armbruster #include "sysemu/runstate.h"
2953018216SPaolo Bonzini #include "sysemu/sysemu.h"
300d09e41aSPaolo Bonzini #include "hw/arm/omap.h"
3112ec8bd5SPeter Maydell #include "hw/arm/boot.h"
3253018216SPaolo Bonzini #include "hw/irq.h"
3353018216SPaolo Bonzini #include "ui/console.h"
3453018216SPaolo Bonzini #include "hw/boards.h"
350d09e41aSPaolo Bonzini #include "hw/i2c/i2c.h"
368a08cc71SPhilippe Mathieu-Daudé #include "hw/display/blizzard.h"
37a331dd02SPhilippe Mathieu-Daudé #include "hw/input/tsc2xxx.h"
38e8fa3958SPhilippe Mathieu-Daudé #include "hw/misc/cbus.h"
395f299c55SPhilippe Mathieu-Daudé #include "hw/misc/tmp105.h"
40a27bd6c7SMarkus Armbruster #include "hw/qdev-properties.h"
410d09e41aSPaolo Bonzini #include "hw/block/flash.h"
4253018216SPaolo Bonzini #include "hw/hw.h"
4353018216SPaolo Bonzini #include "hw/loader.h"
4453018216SPaolo Bonzini #include "hw/sysbus.h"
4503dd024fSPaolo Bonzini #include "qemu/log.h"
4653018216SPaolo Bonzini #include "exec/address-spaces.h"
4753018216SPaolo Bonzini 
4853018216SPaolo Bonzini /* Nokia N8x0 support */
4953018216SPaolo Bonzini struct n800_s {
50e285e867SPhilippe Mathieu-Daudé     MemoryRegion sdram;
5153018216SPaolo Bonzini     struct omap_mpu_state_s *mpu;
5253018216SPaolo Bonzini 
5353018216SPaolo Bonzini     struct rfbi_chip_s blizzard;
5453018216SPaolo Bonzini     struct {
5553018216SPaolo Bonzini         void *opaque;
5653018216SPaolo Bonzini         uint32_t (*txrx)(void *opaque, uint32_t value, int len);
5753018216SPaolo Bonzini         uWireSlave *chip;
5853018216SPaolo Bonzini     } ts;
5953018216SPaolo Bonzini 
6053018216SPaolo Bonzini     int keymap[0x80];
6153018216SPaolo Bonzini     DeviceState *kbd;
6253018216SPaolo Bonzini 
6353018216SPaolo Bonzini     DeviceState *usb;
6453018216SPaolo Bonzini     void *retu;
6553018216SPaolo Bonzini     void *tahvo;
6653018216SPaolo Bonzini     DeviceState *nand;
6753018216SPaolo Bonzini };
6853018216SPaolo Bonzini 
6953018216SPaolo Bonzini /* GPIO pins */
7053018216SPaolo Bonzini #define N8X0_TUSB_ENABLE_GPIO		0
7153018216SPaolo Bonzini #define N800_MMC2_WP_GPIO		8
7253018216SPaolo Bonzini #define N800_UNKNOWN_GPIO0		9	/* out */
7353018216SPaolo Bonzini #define N810_MMC2_VIOSD_GPIO		9
7453018216SPaolo Bonzini #define N810_HEADSET_AMP_GPIO		10
7553018216SPaolo Bonzini #define N800_CAM_TURN_GPIO		12
7653018216SPaolo Bonzini #define N810_GPS_RESET_GPIO		12
7753018216SPaolo Bonzini #define N800_BLIZZARD_POWERDOWN_GPIO	15
7853018216SPaolo Bonzini #define N800_MMC1_WP_GPIO		23
7953018216SPaolo Bonzini #define N810_MMC2_VSD_GPIO		23
8053018216SPaolo Bonzini #define N8X0_ONENAND_GPIO		26
8153018216SPaolo Bonzini #define N810_BLIZZARD_RESET_GPIO	30
8253018216SPaolo Bonzini #define N800_UNKNOWN_GPIO2		53	/* out */
8353018216SPaolo Bonzini #define N8X0_TUSB_INT_GPIO		58
8453018216SPaolo Bonzini #define N8X0_BT_WKUP_GPIO		61
8553018216SPaolo Bonzini #define N8X0_STI_GPIO			62
8653018216SPaolo Bonzini #define N8X0_CBUS_SEL_GPIO		64
8753018216SPaolo Bonzini #define N8X0_CBUS_DAT_GPIO		65
8853018216SPaolo Bonzini #define N8X0_CBUS_CLK_GPIO		66
8953018216SPaolo Bonzini #define N8X0_WLAN_IRQ_GPIO		87
9053018216SPaolo Bonzini #define N8X0_BT_RESET_GPIO		92
9153018216SPaolo Bonzini #define N8X0_TEA5761_CS_GPIO		93
9253018216SPaolo Bonzini #define N800_UNKNOWN_GPIO		94
9353018216SPaolo Bonzini #define N810_TSC_RESET_GPIO		94
9453018216SPaolo Bonzini #define N800_CAM_ACT_GPIO		95
9553018216SPaolo Bonzini #define N810_GPS_WAKEUP_GPIO		95
9653018216SPaolo Bonzini #define N8X0_MMC_CS_GPIO		96
9753018216SPaolo Bonzini #define N8X0_WLAN_PWR_GPIO		97
9853018216SPaolo Bonzini #define N8X0_BT_HOST_WKUP_GPIO		98
9953018216SPaolo Bonzini #define N810_SPEAKER_AMP_GPIO		101
10053018216SPaolo Bonzini #define N810_KB_LOCK_GPIO		102
10153018216SPaolo Bonzini #define N800_TSC_TS_GPIO		103
10253018216SPaolo Bonzini #define N810_TSC_TS_GPIO		106
10353018216SPaolo Bonzini #define N8X0_HEADPHONE_GPIO		107
10453018216SPaolo Bonzini #define N8X0_RETU_GPIO			108
10553018216SPaolo Bonzini #define N800_TSC_KP_IRQ_GPIO		109
10653018216SPaolo Bonzini #define N810_KEYBOARD_GPIO		109
10753018216SPaolo Bonzini #define N800_BAT_COVER_GPIO		110
10853018216SPaolo Bonzini #define N810_SLIDE_GPIO			110
10953018216SPaolo Bonzini #define N8X0_TAHVO_GPIO			111
11053018216SPaolo Bonzini #define N800_UNKNOWN_GPIO4		112	/* out */
11153018216SPaolo Bonzini #define N810_SLEEPX_LED_GPIO		112
11253018216SPaolo Bonzini #define N800_TSC_RESET_GPIO		118	/* ? */
11353018216SPaolo Bonzini #define N810_AIC33_RESET_GPIO		118
11453018216SPaolo Bonzini #define N800_TSC_UNKNOWN_GPIO		119	/* out */
11553018216SPaolo Bonzini #define N8X0_TMP105_GPIO		125
11653018216SPaolo Bonzini 
11753018216SPaolo Bonzini /* Config */
11853018216SPaolo Bonzini #define BT_UART				0
11953018216SPaolo Bonzini #define XLDR_LL_UART			1
12053018216SPaolo Bonzini 
12153018216SPaolo Bonzini /* Addresses on the I2C bus 0 */
12253018216SPaolo Bonzini #define N810_TLV320AIC33_ADDR		0x18	/* Audio CODEC */
12353018216SPaolo Bonzini #define N8X0_TCM825x_ADDR		0x29	/* Camera */
12453018216SPaolo Bonzini #define N810_LP5521_ADDR		0x32	/* LEDs */
12553018216SPaolo Bonzini #define N810_TSL2563_ADDR		0x3d	/* Light sensor */
12653018216SPaolo Bonzini #define N810_LM8323_ADDR		0x45	/* Keyboard */
12753018216SPaolo Bonzini /* Addresses on the I2C bus 1 */
12853018216SPaolo Bonzini #define N8X0_TMP105_ADDR		0x48	/* Temperature sensor */
12953018216SPaolo Bonzini #define N8X0_MENELAUS_ADDR		0x72	/* Power management */
13053018216SPaolo Bonzini 
13153018216SPaolo Bonzini /* Chipselects on GPMC NOR interface */
13253018216SPaolo Bonzini #define N8X0_ONENAND_CS			0
13353018216SPaolo Bonzini #define N8X0_USB_ASYNC_CS		1
13453018216SPaolo Bonzini #define N8X0_USB_SYNC_CS		4
13553018216SPaolo Bonzini 
13653018216SPaolo Bonzini #define N8X0_BD_ADDR			0x00, 0x1a, 0x89, 0x9e, 0x3e, 0x81
13753018216SPaolo Bonzini 
13853018216SPaolo Bonzini static void n800_mmc_cs_cb(void *opaque, int line, int level)
13953018216SPaolo Bonzini {
14053018216SPaolo Bonzini     /* TODO: this seems to actually be connected to the menelaus, to
14153018216SPaolo Bonzini      * which also both MMC slots connect.  */
14253018216SPaolo Bonzini     omap_mmc_enable((struct omap_mmc_s *) opaque, !level);
14353018216SPaolo Bonzini }
14453018216SPaolo Bonzini 
14553018216SPaolo Bonzini static void n8x0_gpio_setup(struct n800_s *s)
14653018216SPaolo Bonzini {
147294972ceSShannon Zhao     qdev_connect_gpio_out(s->mpu->gpio, N8X0_MMC_CS_GPIO,
148294972ceSShannon Zhao                           qemu_allocate_irq(n800_mmc_cs_cb, s->mpu->mmc, 0));
14953018216SPaolo Bonzini     qemu_irq_lower(qdev_get_gpio_in(s->mpu->gpio, N800_BAT_COVER_GPIO));
15053018216SPaolo Bonzini }
15153018216SPaolo Bonzini 
15253018216SPaolo Bonzini #define MAEMO_CAL_HEADER(...)				\
15353018216SPaolo Bonzini     'C',  'o',  'n',  'F',  0x02, 0x00, 0x04, 0x00,	\
15453018216SPaolo Bonzini     __VA_ARGS__,					\
15553018216SPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
15653018216SPaolo Bonzini 
15753018216SPaolo Bonzini static const uint8_t n8x0_cal_wlan_mac[] = {
15853018216SPaolo Bonzini     MAEMO_CAL_HEADER('w', 'l', 'a', 'n', '-', 'm', 'a', 'c')
15953018216SPaolo Bonzini     0x1c, 0x00, 0x00, 0x00, 0x47, 0xd6, 0x69, 0xb3,
16053018216SPaolo Bonzini     0x30, 0x08, 0xa0, 0x83, 0x00, 0x00, 0x00, 0x00,
16153018216SPaolo Bonzini     0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00,
16253018216SPaolo Bonzini     0x89, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
16353018216SPaolo Bonzini     0x5d, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00,
16453018216SPaolo Bonzini };
16553018216SPaolo Bonzini 
16653018216SPaolo Bonzini static const uint8_t n8x0_cal_bt_id[] = {
16753018216SPaolo Bonzini     MAEMO_CAL_HEADER('b', 't', '-', 'i', 'd', 0, 0, 0)
16853018216SPaolo Bonzini     0x0a, 0x00, 0x00, 0x00, 0xa3, 0x4b, 0xf6, 0x96,
16953018216SPaolo Bonzini     0xa8, 0xeb, 0xb2, 0x41, 0x00, 0x00, 0x00, 0x00,
17053018216SPaolo Bonzini     N8X0_BD_ADDR,
17153018216SPaolo Bonzini };
17253018216SPaolo Bonzini 
17353018216SPaolo Bonzini static void n8x0_nand_setup(struct n800_s *s)
17453018216SPaolo Bonzini {
17553018216SPaolo Bonzini     char *otp_region;
17653018216SPaolo Bonzini     DriveInfo *dinfo;
17753018216SPaolo Bonzini 
17853018216SPaolo Bonzini     s->nand = qdev_create(NULL, "onenand");
17953018216SPaolo Bonzini     qdev_prop_set_uint16(s->nand, "manufacturer_id", NAND_MFR_SAMSUNG);
18053018216SPaolo Bonzini     /* Either 0x40 or 0x48 are OK for the device ID */
18153018216SPaolo Bonzini     qdev_prop_set_uint16(s->nand, "device_id", 0x48);
18253018216SPaolo Bonzini     qdev_prop_set_uint16(s->nand, "version_id", 0);
18353018216SPaolo Bonzini     qdev_prop_set_int32(s->nand, "shift", 1);
18453018216SPaolo Bonzini     dinfo = drive_get(IF_MTD, 0, 0);
185fa1d36dfSMarkus Armbruster     if (dinfo) {
1866231a6daSMarkus Armbruster         qdev_prop_set_drive(s->nand, "drive", blk_by_legacy_dinfo(dinfo),
1876231a6daSMarkus Armbruster                             &error_fatal);
18853018216SPaolo Bonzini     }
18953018216SPaolo Bonzini     qdev_init_nofail(s->nand);
19053018216SPaolo Bonzini     sysbus_connect_irq(SYS_BUS_DEVICE(s->nand), 0,
19153018216SPaolo Bonzini                        qdev_get_gpio_in(s->mpu->gpio, N8X0_ONENAND_GPIO));
19253018216SPaolo Bonzini     omap_gpmc_attach(s->mpu->gpmc, N8X0_ONENAND_CS,
19353018216SPaolo Bonzini                      sysbus_mmio_get_region(SYS_BUS_DEVICE(s->nand), 0));
19453018216SPaolo Bonzini     otp_region = onenand_raw_otp(s->nand);
19553018216SPaolo Bonzini 
19653018216SPaolo Bonzini     memcpy(otp_region + 0x000, n8x0_cal_wlan_mac, sizeof(n8x0_cal_wlan_mac));
19753018216SPaolo Bonzini     memcpy(otp_region + 0x800, n8x0_cal_bt_id, sizeof(n8x0_cal_bt_id));
19853018216SPaolo Bonzini     /* XXX: in theory should also update the OOB for both pages */
19953018216SPaolo Bonzini }
20053018216SPaolo Bonzini 
20153018216SPaolo Bonzini static qemu_irq n8x0_system_powerdown;
20253018216SPaolo Bonzini 
20353018216SPaolo Bonzini static void n8x0_powerdown_req(Notifier *n, void *opaque)
20453018216SPaolo Bonzini {
20553018216SPaolo Bonzini     qemu_irq_raise(n8x0_system_powerdown);
20653018216SPaolo Bonzini }
20753018216SPaolo Bonzini 
20853018216SPaolo Bonzini static Notifier n8x0_system_powerdown_notifier = {
20953018216SPaolo Bonzini     .notify = n8x0_powerdown_req
21053018216SPaolo Bonzini };
21153018216SPaolo Bonzini 
21253018216SPaolo Bonzini static void n8x0_i2c_setup(struct n800_s *s)
21353018216SPaolo Bonzini {
21453018216SPaolo Bonzini     DeviceState *dev;
21553018216SPaolo Bonzini     qemu_irq tmp_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TMP105_GPIO);
216a5c82852SAndreas Färber     I2CBus *i2c = omap_i2c_bus(s->mpu->i2c[0]);
21753018216SPaolo Bonzini 
21853018216SPaolo Bonzini     /* Attach a menelaus PM chip */
21953018216SPaolo Bonzini     dev = i2c_create_slave(i2c, "twl92230", N8X0_MENELAUS_ADDR);
22053018216SPaolo Bonzini     qdev_connect_gpio_out(dev, 3,
22153018216SPaolo Bonzini                           qdev_get_gpio_in(s->mpu->ih[0],
22253018216SPaolo Bonzini                                            OMAP_INT_24XX_SYS_NIRQ));
22353018216SPaolo Bonzini 
22453018216SPaolo Bonzini     n8x0_system_powerdown = qdev_get_gpio_in(dev, 3);
22553018216SPaolo Bonzini     qemu_register_powerdown_notifier(&n8x0_system_powerdown_notifier);
22653018216SPaolo Bonzini 
22753018216SPaolo Bonzini     /* Attach a TMP105 PM chip (A0 wired to ground) */
2285f299c55SPhilippe Mathieu-Daudé     dev = i2c_create_slave(i2c, TYPE_TMP105, N8X0_TMP105_ADDR);
22953018216SPaolo Bonzini     qdev_connect_gpio_out(dev, 0, tmp_irq);
23053018216SPaolo Bonzini }
23153018216SPaolo Bonzini 
23253018216SPaolo Bonzini /* Touchscreen and keypad controller */
23353018216SPaolo Bonzini static MouseTransformInfo n800_pointercal = {
23453018216SPaolo Bonzini     .x = 800,
23553018216SPaolo Bonzini     .y = 480,
23653018216SPaolo Bonzini     .a = { 14560, -68, -3455208, -39, -9621, 35152972, 65536 },
23753018216SPaolo Bonzini };
23853018216SPaolo Bonzini 
23953018216SPaolo Bonzini static MouseTransformInfo n810_pointercal = {
24053018216SPaolo Bonzini     .x = 800,
24153018216SPaolo Bonzini     .y = 480,
24253018216SPaolo Bonzini     .a = { 15041, 148, -4731056, 171, -10238, 35933380, 65536 },
24353018216SPaolo Bonzini };
24453018216SPaolo Bonzini 
24553018216SPaolo Bonzini #define RETU_KEYCODE	61	/* F3 */
24653018216SPaolo Bonzini 
24753018216SPaolo Bonzini static void n800_key_event(void *opaque, int keycode)
24853018216SPaolo Bonzini {
24953018216SPaolo Bonzini     struct n800_s *s = (struct n800_s *) opaque;
25053018216SPaolo Bonzini     int code = s->keymap[keycode & 0x7f];
25153018216SPaolo Bonzini 
25253018216SPaolo Bonzini     if (code == -1) {
253fddbd80cSPaolo Bonzini         if ((keycode & 0x7f) == RETU_KEYCODE) {
25453018216SPaolo Bonzini             retu_key_event(s->retu, !(keycode & 0x80));
255fddbd80cSPaolo Bonzini         }
25653018216SPaolo Bonzini         return;
25753018216SPaolo Bonzini     }
25853018216SPaolo Bonzini 
25953018216SPaolo Bonzini     tsc210x_key_event(s->ts.chip, code, !(keycode & 0x80));
26053018216SPaolo Bonzini }
26153018216SPaolo Bonzini 
26253018216SPaolo Bonzini static const int n800_keys[16] = {
26353018216SPaolo Bonzini     -1,
26453018216SPaolo Bonzini     72,	/* Up */
26553018216SPaolo Bonzini     63,	/* Home (F5) */
26653018216SPaolo Bonzini     -1,
26753018216SPaolo Bonzini     75,	/* Left */
26853018216SPaolo Bonzini     28,	/* Enter */
26953018216SPaolo Bonzini     77,	/* Right */
27053018216SPaolo Bonzini     -1,
27153018216SPaolo Bonzini      1,	/* Cycle (ESC) */
27253018216SPaolo Bonzini     80,	/* Down */
27353018216SPaolo Bonzini     62,	/* Menu (F4) */
27453018216SPaolo Bonzini     -1,
27553018216SPaolo Bonzini     66,	/* Zoom- (F8) */
27653018216SPaolo Bonzini     64,	/* FullScreen (F6) */
27753018216SPaolo Bonzini     65,	/* Zoom+ (F7) */
27853018216SPaolo Bonzini     -1,
27953018216SPaolo Bonzini };
28053018216SPaolo Bonzini 
28153018216SPaolo Bonzini static void n800_tsc_kbd_setup(struct n800_s *s)
28253018216SPaolo Bonzini {
28353018216SPaolo Bonzini     int i;
28453018216SPaolo Bonzini 
28553018216SPaolo Bonzini     /* XXX: are the three pins inverted inside the chip between the
28653018216SPaolo Bonzini      * tsc and the cpu (N4111)?  */
28753018216SPaolo Bonzini     qemu_irq penirq = NULL;	/* NC */
28853018216SPaolo Bonzini     qemu_irq kbirq = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_KP_IRQ_GPIO);
28953018216SPaolo Bonzini     qemu_irq dav = qdev_get_gpio_in(s->mpu->gpio, N800_TSC_TS_GPIO);
29053018216SPaolo Bonzini 
29153018216SPaolo Bonzini     s->ts.chip = tsc2301_init(penirq, kbirq, dav);
29253018216SPaolo Bonzini     s->ts.opaque = s->ts.chip->opaque;
29353018216SPaolo Bonzini     s->ts.txrx = tsc210x_txrx;
29453018216SPaolo Bonzini 
295fddbd80cSPaolo Bonzini     for (i = 0; i < 0x80; i++) {
29653018216SPaolo Bonzini         s->keymap[i] = -1;
297fddbd80cSPaolo Bonzini     }
298fddbd80cSPaolo Bonzini     for (i = 0; i < 0x10; i++) {
299fddbd80cSPaolo Bonzini         if (n800_keys[i] >= 0) {
30053018216SPaolo Bonzini             s->keymap[n800_keys[i]] = i;
301fddbd80cSPaolo Bonzini         }
302fddbd80cSPaolo Bonzini     }
30353018216SPaolo Bonzini 
30453018216SPaolo Bonzini     qemu_add_kbd_event_handler(n800_key_event, s);
30553018216SPaolo Bonzini 
30653018216SPaolo Bonzini     tsc210x_set_transform(s->ts.chip, &n800_pointercal);
30753018216SPaolo Bonzini }
30853018216SPaolo Bonzini 
30953018216SPaolo Bonzini static void n810_tsc_setup(struct n800_s *s)
31053018216SPaolo Bonzini {
31153018216SPaolo Bonzini     qemu_irq pintdav = qdev_get_gpio_in(s->mpu->gpio, N810_TSC_TS_GPIO);
31253018216SPaolo Bonzini 
31353018216SPaolo Bonzini     s->ts.opaque = tsc2005_init(pintdav);
31453018216SPaolo Bonzini     s->ts.txrx = tsc2005_txrx;
31553018216SPaolo Bonzini 
31653018216SPaolo Bonzini     tsc2005_set_transform(s->ts.opaque, &n810_pointercal);
31753018216SPaolo Bonzini }
31853018216SPaolo Bonzini 
31953018216SPaolo Bonzini /* N810 Keyboard controller */
32053018216SPaolo Bonzini static void n810_key_event(void *opaque, int keycode)
32153018216SPaolo Bonzini {
32253018216SPaolo Bonzini     struct n800_s *s = (struct n800_s *) opaque;
32353018216SPaolo Bonzini     int code = s->keymap[keycode & 0x7f];
32453018216SPaolo Bonzini 
32553018216SPaolo Bonzini     if (code == -1) {
326fddbd80cSPaolo Bonzini         if ((keycode & 0x7f) == RETU_KEYCODE) {
32753018216SPaolo Bonzini             retu_key_event(s->retu, !(keycode & 0x80));
328fddbd80cSPaolo Bonzini         }
32953018216SPaolo Bonzini         return;
33053018216SPaolo Bonzini     }
33153018216SPaolo Bonzini 
33253018216SPaolo Bonzini     lm832x_key_event(s->kbd, code, !(keycode & 0x80));
33353018216SPaolo Bonzini }
33453018216SPaolo Bonzini 
33553018216SPaolo Bonzini #define M	0
33653018216SPaolo Bonzini 
33753018216SPaolo Bonzini static int n810_keys[0x80] = {
33853018216SPaolo Bonzini     [0x01] = 16,	/* Q */
33953018216SPaolo Bonzini     [0x02] = 37,	/* K */
34053018216SPaolo Bonzini     [0x03] = 24,	/* O */
34153018216SPaolo Bonzini     [0x04] = 25,	/* P */
34253018216SPaolo Bonzini     [0x05] = 14,	/* Backspace */
34353018216SPaolo Bonzini     [0x06] = 30,	/* A */
34453018216SPaolo Bonzini     [0x07] = 31,	/* S */
34553018216SPaolo Bonzini     [0x08] = 32,	/* D */
34653018216SPaolo Bonzini     [0x09] = 33,	/* F */
34753018216SPaolo Bonzini     [0x0a] = 34,	/* G */
34853018216SPaolo Bonzini     [0x0b] = 35,	/* H */
34953018216SPaolo Bonzini     [0x0c] = 36,	/* J */
35053018216SPaolo Bonzini 
35153018216SPaolo Bonzini     [0x11] = 17,	/* W */
35253018216SPaolo Bonzini     [0x12] = 62,	/* Menu (F4) */
35353018216SPaolo Bonzini     [0x13] = 38,	/* L */
35453018216SPaolo Bonzini     [0x14] = 40,	/* ' (Apostrophe) */
35553018216SPaolo Bonzini     [0x16] = 44,	/* Z */
35653018216SPaolo Bonzini     [0x17] = 45,	/* X */
35753018216SPaolo Bonzini     [0x18] = 46,	/* C */
35853018216SPaolo Bonzini     [0x19] = 47,	/* V */
35953018216SPaolo Bonzini     [0x1a] = 48,	/* B */
36053018216SPaolo Bonzini     [0x1b] = 49,	/* N */
36153018216SPaolo Bonzini     [0x1c] = 42,	/* Shift (Left shift) */
36253018216SPaolo Bonzini     [0x1f] = 65,	/* Zoom+ (F7) */
36353018216SPaolo Bonzini 
36453018216SPaolo Bonzini     [0x21] = 18,	/* E */
36553018216SPaolo Bonzini     [0x22] = 39,	/* ; (Semicolon) */
36653018216SPaolo Bonzini     [0x23] = 12,	/* - (Minus) */
36753018216SPaolo Bonzini     [0x24] = 13,	/* = (Equal) */
36853018216SPaolo Bonzini     [0x2b] = 56,	/* Fn (Left Alt) */
36953018216SPaolo Bonzini     [0x2c] = 50,	/* M */
37053018216SPaolo Bonzini     [0x2f] = 66,	/* Zoom- (F8) */
37153018216SPaolo Bonzini 
37253018216SPaolo Bonzini     [0x31] = 19,	/* R */
37353018216SPaolo Bonzini     [0x32] = 29 | M,	/* Right Ctrl */
37453018216SPaolo Bonzini     [0x34] = 57,	/* Space */
37553018216SPaolo Bonzini     [0x35] = 51,	/* , (Comma) */
37653018216SPaolo Bonzini     [0x37] = 72 | M,	/* Up */
37753018216SPaolo Bonzini     [0x3c] = 82 | M,	/* Compose (Insert) */
37853018216SPaolo Bonzini     [0x3f] = 64,	/* FullScreen (F6) */
37953018216SPaolo Bonzini 
38053018216SPaolo Bonzini     [0x41] = 20,	/* T */
38153018216SPaolo Bonzini     [0x44] = 52,	/* . (Dot) */
38253018216SPaolo Bonzini     [0x46] = 77 | M,	/* Right */
38353018216SPaolo Bonzini     [0x4f] = 63,	/* Home (F5) */
38453018216SPaolo Bonzini     [0x51] = 21,	/* Y */
38553018216SPaolo Bonzini     [0x53] = 80 | M,	/* Down */
38653018216SPaolo Bonzini     [0x55] = 28,	/* Enter */
38753018216SPaolo Bonzini     [0x5f] =  1,	/* Cycle (ESC) */
38853018216SPaolo Bonzini 
38953018216SPaolo Bonzini     [0x61] = 22,	/* U */
39053018216SPaolo Bonzini     [0x64] = 75 | M,	/* Left */
39153018216SPaolo Bonzini 
39253018216SPaolo Bonzini     [0x71] = 23,	/* I */
39353018216SPaolo Bonzini #if 0
39453018216SPaolo Bonzini     [0x75] = 28 | M,	/* KP Enter (KP Enter) */
39553018216SPaolo Bonzini #else
39653018216SPaolo Bonzini     [0x75] = 15,	/* KP Enter (Tab) */
39753018216SPaolo Bonzini #endif
39853018216SPaolo Bonzini };
39953018216SPaolo Bonzini 
40053018216SPaolo Bonzini #undef M
40153018216SPaolo Bonzini 
40253018216SPaolo Bonzini static void n810_kbd_setup(struct n800_s *s)
40353018216SPaolo Bonzini {
40453018216SPaolo Bonzini     qemu_irq kbd_irq = qdev_get_gpio_in(s->mpu->gpio, N810_KEYBOARD_GPIO);
40553018216SPaolo Bonzini     int i;
40653018216SPaolo Bonzini 
407fddbd80cSPaolo Bonzini     for (i = 0; i < 0x80; i++) {
40853018216SPaolo Bonzini         s->keymap[i] = -1;
409fddbd80cSPaolo Bonzini     }
410fddbd80cSPaolo Bonzini     for (i = 0; i < 0x80; i++) {
411fddbd80cSPaolo Bonzini         if (n810_keys[i] > 0) {
41253018216SPaolo Bonzini             s->keymap[n810_keys[i]] = i;
413fddbd80cSPaolo Bonzini         }
414fddbd80cSPaolo Bonzini     }
41553018216SPaolo Bonzini 
41653018216SPaolo Bonzini     qemu_add_kbd_event_handler(n810_key_event, s);
41753018216SPaolo Bonzini 
41853018216SPaolo Bonzini     /* Attach the LM8322 keyboard to the I2C bus,
41953018216SPaolo Bonzini      * should happen in n8x0_i2c_setup and s->kbd be initialised here.  */
42053018216SPaolo Bonzini     s->kbd = i2c_create_slave(omap_i2c_bus(s->mpu->i2c[0]),
42153018216SPaolo Bonzini                            "lm8323", N810_LM8323_ADDR);
42253018216SPaolo Bonzini     qdev_connect_gpio_out(s->kbd, 0, kbd_irq);
42353018216SPaolo Bonzini }
42453018216SPaolo Bonzini 
42553018216SPaolo Bonzini /* LCD MIPI DBI-C controller (URAL) */
42653018216SPaolo Bonzini struct mipid_s {
42753018216SPaolo Bonzini     int resp[4];
42853018216SPaolo Bonzini     int param[4];
42953018216SPaolo Bonzini     int p;
43053018216SPaolo Bonzini     int pm;
43153018216SPaolo Bonzini     int cmd;
43253018216SPaolo Bonzini 
43353018216SPaolo Bonzini     int sleep;
43453018216SPaolo Bonzini     int booster;
43553018216SPaolo Bonzini     int te;
43653018216SPaolo Bonzini     int selfcheck;
43753018216SPaolo Bonzini     int partial;
43853018216SPaolo Bonzini     int normal;
43953018216SPaolo Bonzini     int vscr;
44053018216SPaolo Bonzini     int invert;
44153018216SPaolo Bonzini     int onoff;
44253018216SPaolo Bonzini     int gamma;
44353018216SPaolo Bonzini     uint32_t id;
44453018216SPaolo Bonzini };
44553018216SPaolo Bonzini 
44653018216SPaolo Bonzini static void mipid_reset(struct mipid_s *s)
44753018216SPaolo Bonzini {
44853018216SPaolo Bonzini     s->pm = 0;
44953018216SPaolo Bonzini     s->cmd = 0;
45053018216SPaolo Bonzini 
45153018216SPaolo Bonzini     s->sleep = 1;
45253018216SPaolo Bonzini     s->booster = 0;
45353018216SPaolo Bonzini     s->selfcheck =
45453018216SPaolo Bonzini             (1 << 7) |	/* Register loading OK.  */
45553018216SPaolo Bonzini             (1 << 5) |	/* The chip is attached.  */
45653018216SPaolo Bonzini             (1 << 4);	/* Display glass still in one piece.  */
45753018216SPaolo Bonzini     s->te = 0;
45853018216SPaolo Bonzini     s->partial = 0;
45953018216SPaolo Bonzini     s->normal = 1;
46053018216SPaolo Bonzini     s->vscr = 0;
46153018216SPaolo Bonzini     s->invert = 0;
46253018216SPaolo Bonzini     s->onoff = 1;
46353018216SPaolo Bonzini     s->gamma = 0;
46453018216SPaolo Bonzini }
46553018216SPaolo Bonzini 
46653018216SPaolo Bonzini static uint32_t mipid_txrx(void *opaque, uint32_t cmd, int len)
46753018216SPaolo Bonzini {
46853018216SPaolo Bonzini     struct mipid_s *s = (struct mipid_s *) opaque;
46953018216SPaolo Bonzini     uint8_t ret;
47053018216SPaolo Bonzini 
471fddbd80cSPaolo Bonzini     if (len > 9) {
472a89f364aSAlistair Francis         hw_error("%s: FIXME: bad SPI word width %i\n", __func__, len);
473fddbd80cSPaolo Bonzini     }
47453018216SPaolo Bonzini 
475fddbd80cSPaolo Bonzini     if (s->p >= ARRAY_SIZE(s->resp)) {
47653018216SPaolo Bonzini         ret = 0;
477fddbd80cSPaolo Bonzini     } else {
47853018216SPaolo Bonzini         ret = s->resp[s->p++];
479fddbd80cSPaolo Bonzini     }
480fddbd80cSPaolo Bonzini     if (s->pm-- > 0) {
48153018216SPaolo Bonzini         s->param[s->pm] = cmd;
482fddbd80cSPaolo Bonzini     } else {
48353018216SPaolo Bonzini         s->cmd = cmd;
484fddbd80cSPaolo Bonzini     }
48553018216SPaolo Bonzini 
48653018216SPaolo Bonzini     switch (s->cmd) {
48753018216SPaolo Bonzini     case 0x00:	/* NOP */
48853018216SPaolo Bonzini         break;
48953018216SPaolo Bonzini 
49053018216SPaolo Bonzini     case 0x01:	/* SWRESET */
49153018216SPaolo Bonzini         mipid_reset(s);
49253018216SPaolo Bonzini         break;
49353018216SPaolo Bonzini 
49453018216SPaolo Bonzini     case 0x02:	/* BSTROFF */
49553018216SPaolo Bonzini         s->booster = 0;
49653018216SPaolo Bonzini         break;
49753018216SPaolo Bonzini     case 0x03:	/* BSTRON */
49853018216SPaolo Bonzini         s->booster = 1;
49953018216SPaolo Bonzini         break;
50053018216SPaolo Bonzini 
50153018216SPaolo Bonzini     case 0x04:	/* RDDID */
50253018216SPaolo Bonzini         s->p = 0;
50353018216SPaolo Bonzini         s->resp[0] = (s->id >> 16) & 0xff;
50453018216SPaolo Bonzini         s->resp[1] = (s->id >>  8) & 0xff;
50553018216SPaolo Bonzini         s->resp[2] = (s->id >>  0) & 0xff;
50653018216SPaolo Bonzini         break;
50753018216SPaolo Bonzini 
50853018216SPaolo Bonzini     case 0x06:	/* RD_RED */
50953018216SPaolo Bonzini     case 0x07:	/* RD_GREEN */
51053018216SPaolo Bonzini         /* XXX the bootloader sometimes issues RD_BLUE meaning RDDID so
51153018216SPaolo Bonzini          * for the bootloader one needs to change this.  */
51253018216SPaolo Bonzini     case 0x08:	/* RD_BLUE */
51353018216SPaolo Bonzini         s->p = 0;
51453018216SPaolo Bonzini         /* TODO: return first pixel components */
51553018216SPaolo Bonzini         s->resp[0] = 0x01;
51653018216SPaolo Bonzini         break;
51753018216SPaolo Bonzini 
51853018216SPaolo Bonzini     case 0x09:	/* RDDST */
51953018216SPaolo Bonzini         s->p = 0;
52053018216SPaolo Bonzini         s->resp[0] = s->booster << 7;
52153018216SPaolo Bonzini         s->resp[1] = (5 << 4) | (s->partial << 2) |
52253018216SPaolo Bonzini                 (s->sleep << 1) | s->normal;
52353018216SPaolo Bonzini         s->resp[2] = (s->vscr << 7) | (s->invert << 5) |
52453018216SPaolo Bonzini                 (s->onoff << 2) | (s->te << 1) | (s->gamma >> 2);
52553018216SPaolo Bonzini         s->resp[3] = s->gamma << 6;
52653018216SPaolo Bonzini         break;
52753018216SPaolo Bonzini 
52853018216SPaolo Bonzini     case 0x0a:	/* RDDPM */
52953018216SPaolo Bonzini         s->p = 0;
53053018216SPaolo Bonzini         s->resp[0] = (s->onoff << 2) | (s->normal << 3) | (s->sleep << 4) |
53153018216SPaolo Bonzini                 (s->partial << 5) | (s->sleep << 6) | (s->booster << 7);
53253018216SPaolo Bonzini         break;
53353018216SPaolo Bonzini     case 0x0b:	/* RDDMADCTR */
53453018216SPaolo Bonzini         s->p = 0;
53553018216SPaolo Bonzini         s->resp[0] = 0;
53653018216SPaolo Bonzini         break;
53753018216SPaolo Bonzini     case 0x0c:	/* RDDCOLMOD */
53853018216SPaolo Bonzini         s->p = 0;
53953018216SPaolo Bonzini         s->resp[0] = 5;	/* 65K colours */
54053018216SPaolo Bonzini         break;
54153018216SPaolo Bonzini     case 0x0d:	/* RDDIM */
54253018216SPaolo Bonzini         s->p = 0;
54353018216SPaolo Bonzini         s->resp[0] = (s->invert << 5) | (s->vscr << 7) | s->gamma;
54453018216SPaolo Bonzini         break;
54553018216SPaolo Bonzini     case 0x0e:	/* RDDSM */
54653018216SPaolo Bonzini         s->p = 0;
54753018216SPaolo Bonzini         s->resp[0] = s->te << 7;
54853018216SPaolo Bonzini         break;
54953018216SPaolo Bonzini     case 0x0f:	/* RDDSDR */
55053018216SPaolo Bonzini         s->p = 0;
55153018216SPaolo Bonzini         s->resp[0] = s->selfcheck;
55253018216SPaolo Bonzini         break;
55353018216SPaolo Bonzini 
55453018216SPaolo Bonzini     case 0x10:	/* SLPIN */
55553018216SPaolo Bonzini         s->sleep = 1;
55653018216SPaolo Bonzini         break;
55753018216SPaolo Bonzini     case 0x11:	/* SLPOUT */
55853018216SPaolo Bonzini         s->sleep = 0;
55953018216SPaolo Bonzini         s->selfcheck ^= 1 << 6;	/* POFF self-diagnosis Ok */
56053018216SPaolo Bonzini         break;
56153018216SPaolo Bonzini 
56253018216SPaolo Bonzini     case 0x12:	/* PTLON */
56353018216SPaolo Bonzini         s->partial = 1;
56453018216SPaolo Bonzini         s->normal = 0;
56553018216SPaolo Bonzini         s->vscr = 0;
56653018216SPaolo Bonzini         break;
56753018216SPaolo Bonzini     case 0x13:	/* NORON */
56853018216SPaolo Bonzini         s->partial = 0;
56953018216SPaolo Bonzini         s->normal = 1;
57053018216SPaolo Bonzini         s->vscr = 0;
57153018216SPaolo Bonzini         break;
57253018216SPaolo Bonzini 
57353018216SPaolo Bonzini     case 0x20:	/* INVOFF */
57453018216SPaolo Bonzini         s->invert = 0;
57553018216SPaolo Bonzini         break;
57653018216SPaolo Bonzini     case 0x21:	/* INVON */
57753018216SPaolo Bonzini         s->invert = 1;
57853018216SPaolo Bonzini         break;
57953018216SPaolo Bonzini 
58053018216SPaolo Bonzini     case 0x22:	/* APOFF */
58153018216SPaolo Bonzini     case 0x23:	/* APON */
58253018216SPaolo Bonzini         goto bad_cmd;
58353018216SPaolo Bonzini 
58453018216SPaolo Bonzini     case 0x25:	/* WRCNTR */
585fddbd80cSPaolo Bonzini         if (s->pm < 0) {
58653018216SPaolo Bonzini             s->pm = 1;
587fddbd80cSPaolo Bonzini         }
58853018216SPaolo Bonzini         goto bad_cmd;
58953018216SPaolo Bonzini 
59053018216SPaolo Bonzini     case 0x26:	/* GAMSET */
591fddbd80cSPaolo Bonzini         if (!s->pm) {
592ad5f5fdcSStefan Hajnoczi             s->gamma = ctz32(s->param[0] & 0xf);
593ad5f5fdcSStefan Hajnoczi             if (s->gamma == 32) {
594ad5f5fdcSStefan Hajnoczi                 s->gamma = -1; /* XXX: should this be 0? */
595ad5f5fdcSStefan Hajnoczi             }
596fddbd80cSPaolo Bonzini         } else if (s->pm < 0) {
59753018216SPaolo Bonzini             s->pm = 1;
598fddbd80cSPaolo Bonzini         }
59953018216SPaolo Bonzini         break;
60053018216SPaolo Bonzini 
60153018216SPaolo Bonzini     case 0x28:	/* DISPOFF */
60253018216SPaolo Bonzini         s->onoff = 0;
60353018216SPaolo Bonzini         break;
60453018216SPaolo Bonzini     case 0x29:	/* DISPON */
60553018216SPaolo Bonzini         s->onoff = 1;
60653018216SPaolo Bonzini         break;
60753018216SPaolo Bonzini 
60853018216SPaolo Bonzini     case 0x2a:	/* CASET */
60953018216SPaolo Bonzini     case 0x2b:	/* RASET */
61053018216SPaolo Bonzini     case 0x2c:	/* RAMWR */
61153018216SPaolo Bonzini     case 0x2d:	/* RGBSET */
61253018216SPaolo Bonzini     case 0x2e:	/* RAMRD */
61353018216SPaolo Bonzini     case 0x30:	/* PTLAR */
61453018216SPaolo Bonzini     case 0x33:	/* SCRLAR */
61553018216SPaolo Bonzini         goto bad_cmd;
61653018216SPaolo Bonzini 
61753018216SPaolo Bonzini     case 0x34:	/* TEOFF */
61853018216SPaolo Bonzini         s->te = 0;
61953018216SPaolo Bonzini         break;
62053018216SPaolo Bonzini     case 0x35:	/* TEON */
621fddbd80cSPaolo Bonzini         if (!s->pm) {
62253018216SPaolo Bonzini             s->te = 1;
623fddbd80cSPaolo Bonzini         } else if (s->pm < 0) {
62453018216SPaolo Bonzini             s->pm = 1;
625fddbd80cSPaolo Bonzini         }
62653018216SPaolo Bonzini         break;
62753018216SPaolo Bonzini 
62853018216SPaolo Bonzini     case 0x36:	/* MADCTR */
62953018216SPaolo Bonzini         goto bad_cmd;
63053018216SPaolo Bonzini 
63153018216SPaolo Bonzini     case 0x37:	/* VSCSAD */
63253018216SPaolo Bonzini         s->partial = 0;
63353018216SPaolo Bonzini         s->normal = 0;
63453018216SPaolo Bonzini         s->vscr = 1;
63553018216SPaolo Bonzini         break;
63653018216SPaolo Bonzini 
63753018216SPaolo Bonzini     case 0x38:	/* IDMOFF */
63853018216SPaolo Bonzini     case 0x39:	/* IDMON */
63953018216SPaolo Bonzini     case 0x3a:	/* COLMOD */
64053018216SPaolo Bonzini         goto bad_cmd;
64153018216SPaolo Bonzini 
64253018216SPaolo Bonzini     case 0xb0:	/* CLKINT / DISCTL */
64353018216SPaolo Bonzini     case 0xb1:	/* CLKEXT */
644fddbd80cSPaolo Bonzini         if (s->pm < 0) {
64553018216SPaolo Bonzini             s->pm = 2;
646fddbd80cSPaolo Bonzini         }
64753018216SPaolo Bonzini         break;
64853018216SPaolo Bonzini 
64953018216SPaolo Bonzini     case 0xb4:	/* FRMSEL */
65053018216SPaolo Bonzini         break;
65153018216SPaolo Bonzini 
65253018216SPaolo Bonzini     case 0xb5:	/* FRM8SEL */
65353018216SPaolo Bonzini     case 0xb6:	/* TMPRNG / INIESC */
65453018216SPaolo Bonzini     case 0xb7:	/* TMPHIS / NOP2 */
65553018216SPaolo Bonzini     case 0xb8:	/* TMPREAD / MADCTL */
65653018216SPaolo Bonzini     case 0xba:	/* DISTCTR */
65753018216SPaolo Bonzini     case 0xbb:	/* EPVOL */
65853018216SPaolo Bonzini         goto bad_cmd;
65953018216SPaolo Bonzini 
66053018216SPaolo Bonzini     case 0xbd:	/* Unknown */
66153018216SPaolo Bonzini         s->p = 0;
66253018216SPaolo Bonzini         s->resp[0] = 0;
66353018216SPaolo Bonzini         s->resp[1] = 1;
66453018216SPaolo Bonzini         break;
66553018216SPaolo Bonzini 
66653018216SPaolo Bonzini     case 0xc2:	/* IFMOD */
667fddbd80cSPaolo Bonzini         if (s->pm < 0) {
66853018216SPaolo Bonzini             s->pm = 2;
669fddbd80cSPaolo Bonzini         }
67053018216SPaolo Bonzini         break;
67153018216SPaolo Bonzini 
67253018216SPaolo Bonzini     case 0xc6:	/* PWRCTL */
67353018216SPaolo Bonzini     case 0xc7:	/* PPWRCTL */
67453018216SPaolo Bonzini     case 0xd0:	/* EPWROUT */
67553018216SPaolo Bonzini     case 0xd1:	/* EPWRIN */
67653018216SPaolo Bonzini     case 0xd4:	/* RDEV */
67753018216SPaolo Bonzini     case 0xd5:	/* RDRR */
67853018216SPaolo Bonzini         goto bad_cmd;
67953018216SPaolo Bonzini 
68053018216SPaolo Bonzini     case 0xda:	/* RDID1 */
68153018216SPaolo Bonzini         s->p = 0;
68253018216SPaolo Bonzini         s->resp[0] = (s->id >> 16) & 0xff;
68353018216SPaolo Bonzini         break;
68453018216SPaolo Bonzini     case 0xdb:	/* RDID2 */
68553018216SPaolo Bonzini         s->p = 0;
68653018216SPaolo Bonzini         s->resp[0] = (s->id >>  8) & 0xff;
68753018216SPaolo Bonzini         break;
68853018216SPaolo Bonzini     case 0xdc:	/* RDID3 */
68953018216SPaolo Bonzini         s->p = 0;
69053018216SPaolo Bonzini         s->resp[0] = (s->id >>  0) & 0xff;
69153018216SPaolo Bonzini         break;
69253018216SPaolo Bonzini 
69353018216SPaolo Bonzini     default:
69453018216SPaolo Bonzini     bad_cmd:
695591f73f6SPeter Maydell         qemu_log_mask(LOG_GUEST_ERROR,
696591f73f6SPeter Maydell                       "%s: unknown command %02x\n", __func__, s->cmd);
69753018216SPaolo Bonzini         break;
69853018216SPaolo Bonzini     }
69953018216SPaolo Bonzini 
70053018216SPaolo Bonzini     return ret;
70153018216SPaolo Bonzini }
70253018216SPaolo Bonzini 
70353018216SPaolo Bonzini static void *mipid_init(void)
70453018216SPaolo Bonzini {
70553018216SPaolo Bonzini     struct mipid_s *s = (struct mipid_s *) g_malloc0(sizeof(*s));
70653018216SPaolo Bonzini 
70753018216SPaolo Bonzini     s->id = 0x838f03;
70853018216SPaolo Bonzini     mipid_reset(s);
70953018216SPaolo Bonzini 
71053018216SPaolo Bonzini     return s;
71153018216SPaolo Bonzini }
71253018216SPaolo Bonzini 
71353018216SPaolo Bonzini static void n8x0_spi_setup(struct n800_s *s)
71453018216SPaolo Bonzini {
71553018216SPaolo Bonzini     void *tsc = s->ts.opaque;
71653018216SPaolo Bonzini     void *mipid = mipid_init();
71753018216SPaolo Bonzini 
71853018216SPaolo Bonzini     omap_mcspi_attach(s->mpu->mcspi[0], s->ts.txrx, tsc, 0);
71953018216SPaolo Bonzini     omap_mcspi_attach(s->mpu->mcspi[0], mipid_txrx, mipid, 1);
72053018216SPaolo Bonzini }
72153018216SPaolo Bonzini 
72253018216SPaolo Bonzini /* This task is normally performed by the bootloader.  If we're loading
72353018216SPaolo Bonzini  * a kernel directly, we need to enable the Blizzard ourselves.  */
72453018216SPaolo Bonzini static void n800_dss_init(struct rfbi_chip_s *chip)
72553018216SPaolo Bonzini {
72653018216SPaolo Bonzini     uint8_t *fb_blank;
72753018216SPaolo Bonzini 
72853018216SPaolo Bonzini     chip->write(chip->opaque, 0, 0x2a);		/* LCD Width register */
72953018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x64);
73053018216SPaolo Bonzini     chip->write(chip->opaque, 0, 0x2c);		/* LCD HNDP register */
73153018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x1e);
73253018216SPaolo Bonzini     chip->write(chip->opaque, 0, 0x2e);		/* LCD Height 0 register */
73353018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0xe0);
73453018216SPaolo Bonzini     chip->write(chip->opaque, 0, 0x30);		/* LCD Height 1 register */
73553018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x01);
73653018216SPaolo Bonzini     chip->write(chip->opaque, 0, 0x32);		/* LCD VNDP register */
73753018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x06);
73853018216SPaolo Bonzini     chip->write(chip->opaque, 0, 0x68);		/* Display Mode register */
73953018216SPaolo Bonzini     chip->write(chip->opaque, 1, 1);		/* Enable bit */
74053018216SPaolo Bonzini 
74153018216SPaolo Bonzini     chip->write(chip->opaque, 0, 0x6c);
74253018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Input X Start Position */
74353018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Input X Start Position */
74453018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Input Y Start Position */
74553018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Input Y Start Position */
74653018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x1f);		/* Input X End Position */
74753018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x03);		/* Input X End Position */
74853018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0xdf);		/* Input Y End Position */
74953018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x01);		/* Input Y End Position */
75053018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Output X Start Position */
75153018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Output X Start Position */
75253018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Output Y Start Position */
75353018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x00);		/* Output Y Start Position */
75453018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x1f);		/* Output X End Position */
75553018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x03);		/* Output X End Position */
75653018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0xdf);		/* Output Y End Position */
75753018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x01);		/* Output Y End Position */
75853018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x01);		/* Input Data Format */
75953018216SPaolo Bonzini     chip->write(chip->opaque, 1, 0x01);		/* Data Source Select */
76053018216SPaolo Bonzini 
76153018216SPaolo Bonzini     fb_blank = memset(g_malloc(800 * 480 * 2), 0xff, 800 * 480 * 2);
76253018216SPaolo Bonzini     /* Display Memory Data Port */
76353018216SPaolo Bonzini     chip->block(chip->opaque, 1, fb_blank, 800 * 480 * 2, 800);
76453018216SPaolo Bonzini     g_free(fb_blank);
76553018216SPaolo Bonzini }
76653018216SPaolo Bonzini 
76753018216SPaolo Bonzini static void n8x0_dss_setup(struct n800_s *s)
76853018216SPaolo Bonzini {
76953018216SPaolo Bonzini     s->blizzard.opaque = s1d13745_init(NULL);
77053018216SPaolo Bonzini     s->blizzard.block = s1d13745_write_block;
77153018216SPaolo Bonzini     s->blizzard.write = s1d13745_write;
77253018216SPaolo Bonzini     s->blizzard.read = s1d13745_read;
77353018216SPaolo Bonzini 
77453018216SPaolo Bonzini     omap_rfbi_attach(s->mpu->dss, 0, &s->blizzard);
77553018216SPaolo Bonzini }
77653018216SPaolo Bonzini 
77753018216SPaolo Bonzini static void n8x0_cbus_setup(struct n800_s *s)
77853018216SPaolo Bonzini {
77953018216SPaolo Bonzini     qemu_irq dat_out = qdev_get_gpio_in(s->mpu->gpio, N8X0_CBUS_DAT_GPIO);
78053018216SPaolo Bonzini     qemu_irq retu_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_RETU_GPIO);
78153018216SPaolo Bonzini     qemu_irq tahvo_irq = qdev_get_gpio_in(s->mpu->gpio, N8X0_TAHVO_GPIO);
78253018216SPaolo Bonzini 
78353018216SPaolo Bonzini     CBus *cbus = cbus_init(dat_out);
78453018216SPaolo Bonzini 
78553018216SPaolo Bonzini     qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_CLK_GPIO, cbus->clk);
78653018216SPaolo Bonzini     qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_DAT_GPIO, cbus->dat);
78753018216SPaolo Bonzini     qdev_connect_gpio_out(s->mpu->gpio, N8X0_CBUS_SEL_GPIO, cbus->sel);
78853018216SPaolo Bonzini 
78953018216SPaolo Bonzini     cbus_attach(cbus, s->retu = retu_init(retu_irq, 1));
79053018216SPaolo Bonzini     cbus_attach(cbus, s->tahvo = tahvo_init(tahvo_irq, 1));
79153018216SPaolo Bonzini }
79253018216SPaolo Bonzini 
79353018216SPaolo Bonzini static void n8x0_uart_setup(struct n800_s *s)
79453018216SPaolo Bonzini {
795*6da68df7SThomas Huth     Chardev *radio = qemu_chr_new("bt-dummy-uart", "null", NULL);
796*6da68df7SThomas Huth     /*
797*6da68df7SThomas Huth      * Note: We used to connect N8X0_BT_RESET_GPIO and N8X0_BT_WKUP_GPIO
798*6da68df7SThomas Huth      * here, but this code has been removed with the bluetooth backend.
799*6da68df7SThomas Huth      */
80053018216SPaolo Bonzini     omap_uart_attach(s->mpu->uart[BT_UART], radio);
80153018216SPaolo Bonzini }
80253018216SPaolo Bonzini 
80353018216SPaolo Bonzini static void n8x0_usb_setup(struct n800_s *s)
80453018216SPaolo Bonzini {
80553018216SPaolo Bonzini     SysBusDevice *dev;
80653018216SPaolo Bonzini     s->usb = qdev_create(NULL, "tusb6010");
80753018216SPaolo Bonzini     dev = SYS_BUS_DEVICE(s->usb);
80853018216SPaolo Bonzini     qdev_init_nofail(s->usb);
80953018216SPaolo Bonzini     sysbus_connect_irq(dev, 0,
81053018216SPaolo Bonzini                        qdev_get_gpio_in(s->mpu->gpio, N8X0_TUSB_INT_GPIO));
81153018216SPaolo Bonzini     /* Using the NOR interface */
81253018216SPaolo Bonzini     omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_ASYNC_CS,
81353018216SPaolo Bonzini                      sysbus_mmio_get_region(dev, 0));
81453018216SPaolo Bonzini     omap_gpmc_attach(s->mpu->gpmc, N8X0_USB_SYNC_CS,
81553018216SPaolo Bonzini                      sysbus_mmio_get_region(dev, 1));
81653018216SPaolo Bonzini     qdev_connect_gpio_out(s->mpu->gpio, N8X0_TUSB_ENABLE_GPIO,
81753018216SPaolo Bonzini                           qdev_get_gpio_in(s->usb, 0)); /* tusb_pwr */
81853018216SPaolo Bonzini }
81953018216SPaolo Bonzini 
82053018216SPaolo Bonzini /* Setup done before the main bootloader starts by some early setup code
82153018216SPaolo Bonzini  * - used when we want to run the main bootloader in emulation.  This
82253018216SPaolo Bonzini  * isn't documented.  */
82353018216SPaolo Bonzini static uint32_t n800_pinout[104] = {
82453018216SPaolo Bonzini     0x080f00d8, 0x00d40808, 0x03080808, 0x080800d0,
82553018216SPaolo Bonzini     0x00dc0808, 0x0b0f0f00, 0x080800b4, 0x00c00808,
82653018216SPaolo Bonzini     0x08080808, 0x180800c4, 0x00b80000, 0x08080808,
82753018216SPaolo Bonzini     0x080800bc, 0x00cc0808, 0x08081818, 0x18180128,
82853018216SPaolo Bonzini     0x01241800, 0x18181818, 0x000000f0, 0x01300000,
82953018216SPaolo Bonzini     0x00001b0b, 0x1b0f0138, 0x00e0181b, 0x1b031b0b,
83053018216SPaolo Bonzini     0x180f0078, 0x00740018, 0x0f0f0f1a, 0x00000080,
83153018216SPaolo Bonzini     0x007c0000, 0x00000000, 0x00000088, 0x00840000,
83253018216SPaolo Bonzini     0x00000000, 0x00000094, 0x00980300, 0x0f180003,
83353018216SPaolo Bonzini     0x0000008c, 0x00900f0f, 0x0f0f1b00, 0x0f00009c,
83453018216SPaolo Bonzini     0x01140000, 0x1b1b0f18, 0x0818013c, 0x01400008,
83553018216SPaolo Bonzini     0x00001818, 0x000b0110, 0x010c1800, 0x0b030b0f,
83653018216SPaolo Bonzini     0x181800f4, 0x00f81818, 0x00000018, 0x000000fc,
83753018216SPaolo Bonzini     0x00401808, 0x00000000, 0x0f1b0030, 0x003c0008,
83853018216SPaolo Bonzini     0x00000000, 0x00000038, 0x00340000, 0x00000000,
83953018216SPaolo Bonzini     0x1a080070, 0x00641a1a, 0x08080808, 0x08080060,
84053018216SPaolo Bonzini     0x005c0808, 0x08080808, 0x08080058, 0x00540808,
84153018216SPaolo Bonzini     0x08080808, 0x0808006c, 0x00680808, 0x08080808,
84253018216SPaolo Bonzini     0x000000a8, 0x00b00000, 0x08080808, 0x000000a0,
84353018216SPaolo Bonzini     0x00a40000, 0x00000000, 0x08ff0050, 0x004c0808,
84453018216SPaolo Bonzini     0xffffffff, 0xffff0048, 0x0044ffff, 0xffffffff,
84553018216SPaolo Bonzini     0x000000ac, 0x01040800, 0x08080b0f, 0x18180100,
84653018216SPaolo Bonzini     0x01081818, 0x0b0b1808, 0x1a0300e4, 0x012c0b1a,
84753018216SPaolo Bonzini     0x02020018, 0x0b000134, 0x011c0800, 0x0b1b1b00,
84853018216SPaolo Bonzini     0x0f0000c8, 0x00ec181b, 0x000f0f02, 0x00180118,
84953018216SPaolo Bonzini     0x01200000, 0x0f0b1b1b, 0x0f0200e8, 0x0000020b,
85053018216SPaolo Bonzini };
85153018216SPaolo Bonzini 
85253018216SPaolo Bonzini static void n800_setup_nolo_tags(void *sram_base)
85353018216SPaolo Bonzini {
85453018216SPaolo Bonzini     int i;
85553018216SPaolo Bonzini     uint32_t *p = sram_base + 0x8000;
85653018216SPaolo Bonzini     uint32_t *v = sram_base + 0xa000;
85753018216SPaolo Bonzini 
85853018216SPaolo Bonzini     memset(p, 0, 0x3000);
85953018216SPaolo Bonzini 
86053018216SPaolo Bonzini     strcpy((void *) (p + 0), "QEMU N800");
86153018216SPaolo Bonzini 
86253018216SPaolo Bonzini     strcpy((void *) (p + 8), "F5");
86353018216SPaolo Bonzini 
8640983979bSPaolo Bonzini     stl_p(p + 10, 0x04f70000);
86553018216SPaolo Bonzini     strcpy((void *) (p + 9), "RX-34");
86653018216SPaolo Bonzini 
86753018216SPaolo Bonzini     /* RAM size in MB? */
8680983979bSPaolo Bonzini     stl_p(p + 12, 0x80);
86953018216SPaolo Bonzini 
87053018216SPaolo Bonzini     /* Pointer to the list of tags */
8710983979bSPaolo Bonzini     stl_p(p + 13, OMAP2_SRAM_BASE + 0x9000);
87253018216SPaolo Bonzini 
87353018216SPaolo Bonzini     /* The NOLO tags start here */
87453018216SPaolo Bonzini     p = sram_base + 0x9000;
87553018216SPaolo Bonzini #define ADD_TAG(tag, len)				\
8760983979bSPaolo Bonzini     stw_p((uint16_t *) p + 0, tag);			\
8770983979bSPaolo Bonzini     stw_p((uint16_t *) p + 1, len); p++;		\
8780983979bSPaolo Bonzini     stl_p(p++, OMAP2_SRAM_BASE | (((void *) v - sram_base) & 0xffff));
87953018216SPaolo Bonzini 
88053018216SPaolo Bonzini     /* OMAP STI console? Pin out settings? */
88153018216SPaolo Bonzini     ADD_TAG(0x6e01, 414);
882fddbd80cSPaolo Bonzini     for (i = 0; i < ARRAY_SIZE(n800_pinout); i++) {
8830983979bSPaolo Bonzini         stl_p(v++, n800_pinout[i]);
884fddbd80cSPaolo Bonzini     }
88553018216SPaolo Bonzini 
88653018216SPaolo Bonzini     /* Kernel memsize? */
88753018216SPaolo Bonzini     ADD_TAG(0x6e05, 1);
8880983979bSPaolo Bonzini     stl_p(v++, 2);
88953018216SPaolo Bonzini 
89053018216SPaolo Bonzini     /* NOLO serial console */
89153018216SPaolo Bonzini     ADD_TAG(0x6e02, 4);
8920983979bSPaolo Bonzini     stl_p(v++, XLDR_LL_UART);		/* UART number (1 - 3) */
89353018216SPaolo Bonzini 
89453018216SPaolo Bonzini #if 0
89553018216SPaolo Bonzini     /* CBUS settings (Retu/AVilma) */
89653018216SPaolo Bonzini     ADD_TAG(0x6e03, 6);
8970983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 65);	/* CBUS GPIO0 */
8980983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 66);	/* CBUS GPIO1 */
8990983979bSPaolo Bonzini     stw_p((uint16_t *) v + 2, 64);	/* CBUS GPIO2 */
90053018216SPaolo Bonzini     v += 2;
90153018216SPaolo Bonzini #endif
90253018216SPaolo Bonzini 
90353018216SPaolo Bonzini     /* Nokia ASIC BB5 (Retu/Tahvo) */
90453018216SPaolo Bonzini     ADD_TAG(0x6e0a, 4);
9050983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 111);	/* "Retu" interrupt GPIO */
9060983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 108);	/* "Tahvo" interrupt GPIO */
90753018216SPaolo Bonzini     v++;
90853018216SPaolo Bonzini 
90953018216SPaolo Bonzini     /* LCD console? */
91053018216SPaolo Bonzini     ADD_TAG(0x6e04, 4);
9110983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 30);	/* ??? */
9120983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 24);	/* ??? */
91353018216SPaolo Bonzini     v++;
91453018216SPaolo Bonzini 
91553018216SPaolo Bonzini #if 0
91653018216SPaolo Bonzini     /* LCD settings */
91753018216SPaolo Bonzini     ADD_TAG(0x6e06, 2);
9180983979bSPaolo Bonzini     stw_p((uint16_t *) (v++), 15);	/* ??? */
91953018216SPaolo Bonzini #endif
92053018216SPaolo Bonzini 
92153018216SPaolo Bonzini     /* I^2C (Menelaus) */
92253018216SPaolo Bonzini     ADD_TAG(0x6e07, 4);
9230983979bSPaolo Bonzini     stl_p(v++, 0x00720000);		/* ??? */
92453018216SPaolo Bonzini 
92553018216SPaolo Bonzini     /* Unknown */
92653018216SPaolo Bonzini     ADD_TAG(0x6e0b, 6);
9270983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 94);	/* ??? */
9280983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 23);	/* ??? */
9290983979bSPaolo Bonzini     stw_p((uint16_t *) v + 2, 0);	/* ??? */
93053018216SPaolo Bonzini     v += 2;
93153018216SPaolo Bonzini 
93253018216SPaolo Bonzini     /* OMAP gpio switch info */
93353018216SPaolo Bonzini     ADD_TAG(0x6e0c, 80);
93453018216SPaolo Bonzini     strcpy((void *) v, "bat_cover");	v += 3;
9350983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 110);	/* GPIO num ??? */
9360983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 1);	/* GPIO num ??? */
93753018216SPaolo Bonzini     v += 2;
93853018216SPaolo Bonzini     strcpy((void *) v, "cam_act");	v += 3;
9390983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 95);	/* GPIO num ??? */
9400983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 32);	/* GPIO num ??? */
94153018216SPaolo Bonzini     v += 2;
94253018216SPaolo Bonzini     strcpy((void *) v, "cam_turn");	v += 3;
9430983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 12);	/* GPIO num ??? */
9440983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 33);	/* GPIO num ??? */
94553018216SPaolo Bonzini     v += 2;
94653018216SPaolo Bonzini     strcpy((void *) v, "headphone");	v += 3;
9470983979bSPaolo Bonzini     stw_p((uint16_t *) v + 0, 107);	/* GPIO num ??? */
9480983979bSPaolo Bonzini     stw_p((uint16_t *) v + 1, 17);	/* GPIO num ??? */
94953018216SPaolo Bonzini     v += 2;
95053018216SPaolo Bonzini 
95153018216SPaolo Bonzini     /* Bluetooth */
95253018216SPaolo Bonzini     ADD_TAG(0x6e0e, 12);
9530983979bSPaolo Bonzini     stl_p(v++, 0x5c623d01);		/* ??? */
9540983979bSPaolo Bonzini     stl_p(v++, 0x00000201);		/* ??? */
9550983979bSPaolo Bonzini     stl_p(v++, 0x00000000);		/* ??? */
95653018216SPaolo Bonzini 
95753018216SPaolo Bonzini     /* CX3110x WLAN settings */
95853018216SPaolo Bonzini     ADD_TAG(0x6e0f, 8);
9590983979bSPaolo Bonzini     stl_p(v++, 0x00610025);		/* ??? */
9600983979bSPaolo Bonzini     stl_p(v++, 0xffff0057);		/* ??? */
96153018216SPaolo Bonzini 
96253018216SPaolo Bonzini     /* MMC host settings */
96353018216SPaolo Bonzini     ADD_TAG(0x6e10, 12);
9640983979bSPaolo Bonzini     stl_p(v++, 0xffff000f);		/* ??? */
9650983979bSPaolo Bonzini     stl_p(v++, 0xffffffff);		/* ??? */
9660983979bSPaolo Bonzini     stl_p(v++, 0x00000060);		/* ??? */
96753018216SPaolo Bonzini 
96853018216SPaolo Bonzini     /* OneNAND chip select */
96953018216SPaolo Bonzini     ADD_TAG(0x6e11, 10);
9700983979bSPaolo Bonzini     stl_p(v++, 0x00000401);		/* ??? */
9710983979bSPaolo Bonzini     stl_p(v++, 0x0002003a);		/* ??? */
9720983979bSPaolo Bonzini     stl_p(v++, 0x00000002);		/* ??? */
97353018216SPaolo Bonzini 
97453018216SPaolo Bonzini     /* TEA5761 sensor settings */
97553018216SPaolo Bonzini     ADD_TAG(0x6e12, 2);
9760983979bSPaolo Bonzini     stl_p(v++, 93);			/* GPIO num ??? */
97753018216SPaolo Bonzini 
97853018216SPaolo Bonzini #if 0
97953018216SPaolo Bonzini     /* Unknown tag */
98053018216SPaolo Bonzini     ADD_TAG(6e09, 0);
98153018216SPaolo Bonzini 
98253018216SPaolo Bonzini     /* Kernel UART / console */
98353018216SPaolo Bonzini     ADD_TAG(6e12, 0);
98453018216SPaolo Bonzini #endif
98553018216SPaolo Bonzini 
98653018216SPaolo Bonzini     /* End of the list */
9870983979bSPaolo Bonzini     stl_p(p++, 0x00000000);
9880983979bSPaolo Bonzini     stl_p(p++, 0x00000000);
98953018216SPaolo Bonzini }
99053018216SPaolo Bonzini 
99153018216SPaolo Bonzini /* This task is normally performed by the bootloader.  If we're loading
99253018216SPaolo Bonzini  * a kernel directly, we need to set up GPMC mappings ourselves.  */
99353018216SPaolo Bonzini static void n800_gpmc_init(struct n800_s *s)
99453018216SPaolo Bonzini {
99553018216SPaolo Bonzini     uint32_t config7 =
99653018216SPaolo Bonzini             (0xf << 8) |	/* MASKADDRESS */
99753018216SPaolo Bonzini             (1 << 6) |		/* CSVALID */
99853018216SPaolo Bonzini             (4 << 0);		/* BASEADDRESS */
99953018216SPaolo Bonzini 
100053018216SPaolo Bonzini     cpu_physical_memory_write(0x6800a078,		/* GPMC_CONFIG7_0 */
1001e1fe50dcSStefan Weil                               &config7, sizeof(config7));
100253018216SPaolo Bonzini }
100353018216SPaolo Bonzini 
100453018216SPaolo Bonzini /* Setup sequence done by the bootloader */
100553018216SPaolo Bonzini static void n8x0_boot_init(void *opaque)
100653018216SPaolo Bonzini {
100753018216SPaolo Bonzini     struct n800_s *s = (struct n800_s *) opaque;
100853018216SPaolo Bonzini     uint32_t buf;
100953018216SPaolo Bonzini 
101053018216SPaolo Bonzini     /* PRCM setup */
101153018216SPaolo Bonzini #define omap_writel(addr, val)	\
101253018216SPaolo Bonzini     buf = (val);			\
1013e1fe50dcSStefan Weil     cpu_physical_memory_write(addr, &buf, sizeof(buf))
101453018216SPaolo Bonzini 
101553018216SPaolo Bonzini     omap_writel(0x48008060, 0x41);		/* PRCM_CLKSRC_CTRL */
101653018216SPaolo Bonzini     omap_writel(0x48008070, 1);			/* PRCM_CLKOUT_CTRL */
101753018216SPaolo Bonzini     omap_writel(0x48008078, 0);			/* PRCM_CLKEMUL_CTRL */
101853018216SPaolo Bonzini     omap_writel(0x48008090, 0);			/* PRCM_VOLTSETUP */
101953018216SPaolo Bonzini     omap_writel(0x48008094, 0);			/* PRCM_CLKSSETUP */
102053018216SPaolo Bonzini     omap_writel(0x48008098, 0);			/* PRCM_POLCTRL */
102153018216SPaolo Bonzini     omap_writel(0x48008140, 2);			/* CM_CLKSEL_MPU */
102253018216SPaolo Bonzini     omap_writel(0x48008148, 0);			/* CM_CLKSTCTRL_MPU */
102353018216SPaolo Bonzini     omap_writel(0x48008158, 1);			/* RM_RSTST_MPU */
102453018216SPaolo Bonzini     omap_writel(0x480081c8, 0x15);		/* PM_WKDEP_MPU */
102553018216SPaolo Bonzini     omap_writel(0x480081d4, 0x1d4);		/* PM_EVGENCTRL_MPU */
102653018216SPaolo Bonzini     omap_writel(0x480081d8, 0);			/* PM_EVEGENONTIM_MPU */
102753018216SPaolo Bonzini     omap_writel(0x480081dc, 0);			/* PM_EVEGENOFFTIM_MPU */
102853018216SPaolo Bonzini     omap_writel(0x480081e0, 0xc);		/* PM_PWSTCTRL_MPU */
102953018216SPaolo Bonzini     omap_writel(0x48008200, 0x047e7ff7);	/* CM_FCLKEN1_CORE */
103053018216SPaolo Bonzini     omap_writel(0x48008204, 0x00000004);	/* CM_FCLKEN2_CORE */
103153018216SPaolo Bonzini     omap_writel(0x48008210, 0x047e7ff1);	/* CM_ICLKEN1_CORE */
103253018216SPaolo Bonzini     omap_writel(0x48008214, 0x00000004);	/* CM_ICLKEN2_CORE */
103353018216SPaolo Bonzini     omap_writel(0x4800821c, 0x00000000);	/* CM_ICLKEN4_CORE */
103453018216SPaolo Bonzini     omap_writel(0x48008230, 0);			/* CM_AUTOIDLE1_CORE */
103553018216SPaolo Bonzini     omap_writel(0x48008234, 0);			/* CM_AUTOIDLE2_CORE */
103653018216SPaolo Bonzini     omap_writel(0x48008238, 7);			/* CM_AUTOIDLE3_CORE */
103753018216SPaolo Bonzini     omap_writel(0x4800823c, 0);			/* CM_AUTOIDLE4_CORE */
103853018216SPaolo Bonzini     omap_writel(0x48008240, 0x04360626);	/* CM_CLKSEL1_CORE */
103953018216SPaolo Bonzini     omap_writel(0x48008244, 0x00000014);	/* CM_CLKSEL2_CORE */
104053018216SPaolo Bonzini     omap_writel(0x48008248, 0);			/* CM_CLKSTCTRL_CORE */
104153018216SPaolo Bonzini     omap_writel(0x48008300, 0x00000000);	/* CM_FCLKEN_GFX */
104253018216SPaolo Bonzini     omap_writel(0x48008310, 0x00000000);	/* CM_ICLKEN_GFX */
104353018216SPaolo Bonzini     omap_writel(0x48008340, 0x00000001);	/* CM_CLKSEL_GFX */
104453018216SPaolo Bonzini     omap_writel(0x48008400, 0x00000004);	/* CM_FCLKEN_WKUP */
104553018216SPaolo Bonzini     omap_writel(0x48008410, 0x00000004);	/* CM_ICLKEN_WKUP */
104653018216SPaolo Bonzini     omap_writel(0x48008440, 0x00000000);	/* CM_CLKSEL_WKUP */
104753018216SPaolo Bonzini     omap_writel(0x48008500, 0x000000cf);	/* CM_CLKEN_PLL */
104853018216SPaolo Bonzini     omap_writel(0x48008530, 0x0000000c);	/* CM_AUTOIDLE_PLL */
104953018216SPaolo Bonzini     omap_writel(0x48008540,			/* CM_CLKSEL1_PLL */
105053018216SPaolo Bonzini                     (0x78 << 12) | (6 << 8));
105153018216SPaolo Bonzini     omap_writel(0x48008544, 2);			/* CM_CLKSEL2_PLL */
105253018216SPaolo Bonzini 
105353018216SPaolo Bonzini     /* GPMC setup */
105453018216SPaolo Bonzini     n800_gpmc_init(s);
105553018216SPaolo Bonzini 
105653018216SPaolo Bonzini     /* Video setup */
105753018216SPaolo Bonzini     n800_dss_init(&s->blizzard);
105853018216SPaolo Bonzini 
105953018216SPaolo Bonzini     /* CPU setup */
106053018216SPaolo Bonzini     s->mpu->cpu->env.GE = 0x5;
106153018216SPaolo Bonzini 
106253018216SPaolo Bonzini     /* If the machine has a slided keyboard, open it */
1063fddbd80cSPaolo Bonzini     if (s->kbd) {
106453018216SPaolo Bonzini         qemu_irq_raise(qdev_get_gpio_in(s->mpu->gpio, N810_SLIDE_GPIO));
106553018216SPaolo Bonzini     }
1066fddbd80cSPaolo Bonzini }
106753018216SPaolo Bonzini 
106853018216SPaolo Bonzini #define OMAP_TAG_NOKIA_BT	0x4e01
106953018216SPaolo Bonzini #define OMAP_TAG_WLAN_CX3110X	0x4e02
107053018216SPaolo Bonzini #define OMAP_TAG_CBUS		0x4e03
107153018216SPaolo Bonzini #define OMAP_TAG_EM_ASIC_BB5	0x4e04
107253018216SPaolo Bonzini 
107353018216SPaolo Bonzini static struct omap_gpiosw_info_s {
107453018216SPaolo Bonzini     const char *name;
107553018216SPaolo Bonzini     int line;
107653018216SPaolo Bonzini     int type;
107753018216SPaolo Bonzini } n800_gpiosw_info[] = {
107853018216SPaolo Bonzini     {
107953018216SPaolo Bonzini         "bat_cover", N800_BAT_COVER_GPIO,
108053018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
108153018216SPaolo Bonzini     }, {
108253018216SPaolo Bonzini         "cam_act", N800_CAM_ACT_GPIO,
108353018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_ACTIVITY,
108453018216SPaolo Bonzini     }, {
108553018216SPaolo Bonzini         "cam_turn", N800_CAM_TURN_GPIO,
108653018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED,
108753018216SPaolo Bonzini     }, {
108853018216SPaolo Bonzini         "headphone", N8X0_HEADPHONE_GPIO,
108953018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
109053018216SPaolo Bonzini     },
109153018216SPaolo Bonzini     { NULL }
109253018216SPaolo Bonzini }, n810_gpiosw_info[] = {
109353018216SPaolo Bonzini     {
109453018216SPaolo Bonzini         "gps_reset", N810_GPS_RESET_GPIO,
109553018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
109653018216SPaolo Bonzini     }, {
109753018216SPaolo Bonzini         "gps_wakeup", N810_GPS_WAKEUP_GPIO,
109853018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_OUTPUT,
109953018216SPaolo Bonzini     }, {
110053018216SPaolo Bonzini         "headphone", N8X0_HEADPHONE_GPIO,
110153018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_CONNECTION | OMAP_GPIOSW_INVERTED,
110253018216SPaolo Bonzini     }, {
110353018216SPaolo Bonzini         "kb_lock", N810_KB_LOCK_GPIO,
110453018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
110553018216SPaolo Bonzini     }, {
110653018216SPaolo Bonzini         "sleepx_led", N810_SLEEPX_LED_GPIO,
110753018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_ACTIVITY | OMAP_GPIOSW_INVERTED | OMAP_GPIOSW_OUTPUT,
110853018216SPaolo Bonzini     }, {
110953018216SPaolo Bonzini         "slide", N810_SLIDE_GPIO,
111053018216SPaolo Bonzini         OMAP_GPIOSW_TYPE_COVER | OMAP_GPIOSW_INVERTED,
111153018216SPaolo Bonzini     },
111253018216SPaolo Bonzini     { NULL }
111353018216SPaolo Bonzini };
111453018216SPaolo Bonzini 
111553018216SPaolo Bonzini static struct omap_partition_info_s {
111653018216SPaolo Bonzini     uint32_t offset;
111753018216SPaolo Bonzini     uint32_t size;
111853018216SPaolo Bonzini     int mask;
111953018216SPaolo Bonzini     const char *name;
112053018216SPaolo Bonzini } n800_part_info[] = {
112153018216SPaolo Bonzini     { 0x00000000, 0x00020000, 0x3, "bootloader" },
112253018216SPaolo Bonzini     { 0x00020000, 0x00060000, 0x0, "config" },
112353018216SPaolo Bonzini     { 0x00080000, 0x00200000, 0x0, "kernel" },
112453018216SPaolo Bonzini     { 0x00280000, 0x00200000, 0x3, "initfs" },
112553018216SPaolo Bonzini     { 0x00480000, 0x0fb80000, 0x3, "rootfs" },
112653018216SPaolo Bonzini 
112753018216SPaolo Bonzini     { 0, 0, 0, NULL }
112853018216SPaolo Bonzini }, n810_part_info[] = {
112953018216SPaolo Bonzini     { 0x00000000, 0x00020000, 0x3, "bootloader" },
113053018216SPaolo Bonzini     { 0x00020000, 0x00060000, 0x0, "config" },
113153018216SPaolo Bonzini     { 0x00080000, 0x00220000, 0x0, "kernel" },
113253018216SPaolo Bonzini     { 0x002a0000, 0x00400000, 0x0, "initfs" },
113353018216SPaolo Bonzini     { 0x006a0000, 0x0f960000, 0x0, "rootfs" },
113453018216SPaolo Bonzini 
113553018216SPaolo Bonzini     { 0, 0, 0, NULL }
113653018216SPaolo Bonzini };
113753018216SPaolo Bonzini 
1138*6da68df7SThomas Huth static uint8_t n8x0_bd_addr[6] = { N8X0_BD_ADDR };
113953018216SPaolo Bonzini 
114053018216SPaolo Bonzini static int n8x0_atag_setup(void *p, int model)
114153018216SPaolo Bonzini {
114253018216SPaolo Bonzini     uint8_t *b;
114353018216SPaolo Bonzini     uint16_t *w;
114453018216SPaolo Bonzini     uint32_t *l;
114553018216SPaolo Bonzini     struct omap_gpiosw_info_s *gpiosw;
114653018216SPaolo Bonzini     struct omap_partition_info_s *partition;
114753018216SPaolo Bonzini     const char *tag;
114853018216SPaolo Bonzini 
114953018216SPaolo Bonzini     w = p;
115053018216SPaolo Bonzini 
11510983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_UART);			/* u16 tag */
11520983979bSPaolo Bonzini     stw_p(w++, 4);				/* u16 len */
11530983979bSPaolo Bonzini     stw_p(w++, (1 << 2) | (1 << 1) | (1 << 0)); /* uint enabled_uarts */
115453018216SPaolo Bonzini     w++;
115553018216SPaolo Bonzini 
115653018216SPaolo Bonzini #if 0
11570983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_SERIAL_CONSOLE);	/* u16 tag */
11580983979bSPaolo Bonzini     stw_p(w++, 4);				/* u16 len */
11590983979bSPaolo Bonzini     stw_p(w++, XLDR_LL_UART + 1);		/* u8 console_uart */
11600983979bSPaolo Bonzini     stw_p(w++, 115200);				/* u32 console_speed */
116153018216SPaolo Bonzini #endif
116253018216SPaolo Bonzini 
11630983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_LCD);			/* u16 tag */
11640983979bSPaolo Bonzini     stw_p(w++, 36);				/* u16 len */
116553018216SPaolo Bonzini     strcpy((void *) w, "QEMU LCD panel");	/* char panel_name[16] */
116653018216SPaolo Bonzini     w += 8;
116753018216SPaolo Bonzini     strcpy((void *) w, "blizzard");		/* char ctrl_name[16] */
116853018216SPaolo Bonzini     w += 8;
11690983979bSPaolo Bonzini     stw_p(w++, N810_BLIZZARD_RESET_GPIO);	/* TODO: n800 s16 nreset_gpio */
11700983979bSPaolo Bonzini     stw_p(w++, 24);				/* u8 data_lines */
117153018216SPaolo Bonzini 
11720983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_CBUS);			/* u16 tag */
11730983979bSPaolo Bonzini     stw_p(w++, 8);				/* u16 len */
11740983979bSPaolo Bonzini     stw_p(w++, N8X0_CBUS_CLK_GPIO);		/* s16 clk_gpio */
11750983979bSPaolo Bonzini     stw_p(w++, N8X0_CBUS_DAT_GPIO);		/* s16 dat_gpio */
11760983979bSPaolo Bonzini     stw_p(w++, N8X0_CBUS_SEL_GPIO);		/* s16 sel_gpio */
117753018216SPaolo Bonzini     w++;
117853018216SPaolo Bonzini 
11790983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_EM_ASIC_BB5);		/* u16 tag */
11800983979bSPaolo Bonzini     stw_p(w++, 4);				/* u16 len */
11810983979bSPaolo Bonzini     stw_p(w++, N8X0_RETU_GPIO);			/* s16 retu_irq_gpio */
11820983979bSPaolo Bonzini     stw_p(w++, N8X0_TAHVO_GPIO);		/* s16 tahvo_irq_gpio */
118353018216SPaolo Bonzini 
118453018216SPaolo Bonzini     gpiosw = (model == 810) ? n810_gpiosw_info : n800_gpiosw_info;
118553018216SPaolo Bonzini     for (; gpiosw->name; gpiosw++) {
11860983979bSPaolo Bonzini         stw_p(w++, OMAP_TAG_GPIO_SWITCH);	/* u16 tag */
11870983979bSPaolo Bonzini         stw_p(w++, 20);				/* u16 len */
118853018216SPaolo Bonzini         strcpy((void *) w, gpiosw->name);	/* char name[12] */
118953018216SPaolo Bonzini         w += 6;
11900983979bSPaolo Bonzini         stw_p(w++, gpiosw->line);		/* u16 gpio */
11910983979bSPaolo Bonzini         stw_p(w++, gpiosw->type);
11920983979bSPaolo Bonzini         stw_p(w++, 0);
11930983979bSPaolo Bonzini         stw_p(w++, 0);
119453018216SPaolo Bonzini     }
119553018216SPaolo Bonzini 
11960983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_NOKIA_BT);		/* u16 tag */
11970983979bSPaolo Bonzini     stw_p(w++, 12);				/* u16 len */
119853018216SPaolo Bonzini     b = (void *) w;
11990983979bSPaolo Bonzini     stb_p(b++, 0x01);				/* u8 chip_type	(CSR) */
12000983979bSPaolo Bonzini     stb_p(b++, N8X0_BT_WKUP_GPIO);		/* u8 bt_wakeup_gpio */
12010983979bSPaolo Bonzini     stb_p(b++, N8X0_BT_HOST_WKUP_GPIO);		/* u8 host_wakeup_gpio */
12020983979bSPaolo Bonzini     stb_p(b++, N8X0_BT_RESET_GPIO);		/* u8 reset_gpio */
12030983979bSPaolo Bonzini     stb_p(b++, BT_UART + 1);			/* u8 bt_uart */
120453018216SPaolo Bonzini     memcpy(b, &n8x0_bd_addr, 6);		/* u8 bd_addr[6] */
120553018216SPaolo Bonzini     b += 6;
12060983979bSPaolo Bonzini     stb_p(b++, 0x02);				/* u8 bt_sysclk (38.4) */
120753018216SPaolo Bonzini     w = (void *) b;
120853018216SPaolo Bonzini 
12090983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_WLAN_CX3110X);		/* u16 tag */
12100983979bSPaolo Bonzini     stw_p(w++, 8);				/* u16 len */
12110983979bSPaolo Bonzini     stw_p(w++, 0x25);				/* u8 chip_type */
12120983979bSPaolo Bonzini     stw_p(w++, N8X0_WLAN_PWR_GPIO);		/* s16 power_gpio */
12130983979bSPaolo Bonzini     stw_p(w++, N8X0_WLAN_IRQ_GPIO);		/* s16 irq_gpio */
12140983979bSPaolo Bonzini     stw_p(w++, -1);				/* s16 spi_cs_gpio */
121553018216SPaolo Bonzini 
12160983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_MMC);			/* u16 tag */
12170983979bSPaolo Bonzini     stw_p(w++, 16);				/* u16 len */
121853018216SPaolo Bonzini     if (model == 810) {
12190983979bSPaolo Bonzini         stw_p(w++, 0x23f);			/* unsigned flags */
12200983979bSPaolo Bonzini         stw_p(w++, -1);				/* s16 power_pin */
12210983979bSPaolo Bonzini         stw_p(w++, -1);				/* s16 switch_pin */
12220983979bSPaolo Bonzini         stw_p(w++, -1);				/* s16 wp_pin */
12230983979bSPaolo Bonzini         stw_p(w++, 0x240);			/* unsigned flags */
12240983979bSPaolo Bonzini         stw_p(w++, 0xc000);			/* s16 power_pin */
12250983979bSPaolo Bonzini         stw_p(w++, 0x0248);			/* s16 switch_pin */
12260983979bSPaolo Bonzini         stw_p(w++, 0xc000);			/* s16 wp_pin */
122753018216SPaolo Bonzini     } else {
12280983979bSPaolo Bonzini         stw_p(w++, 0xf);			/* unsigned flags */
12290983979bSPaolo Bonzini         stw_p(w++, -1);				/* s16 power_pin */
12300983979bSPaolo Bonzini         stw_p(w++, -1);				/* s16 switch_pin */
12310983979bSPaolo Bonzini         stw_p(w++, -1);				/* s16 wp_pin */
12320983979bSPaolo Bonzini         stw_p(w++, 0);				/* unsigned flags */
12330983979bSPaolo Bonzini         stw_p(w++, 0);				/* s16 power_pin */
12340983979bSPaolo Bonzini         stw_p(w++, 0);				/* s16 switch_pin */
12350983979bSPaolo Bonzini         stw_p(w++, 0);				/* s16 wp_pin */
123653018216SPaolo Bonzini     }
123753018216SPaolo Bonzini 
12380983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_TEA5761);		/* u16 tag */
12390983979bSPaolo Bonzini     stw_p(w++, 4);				/* u16 len */
12400983979bSPaolo Bonzini     stw_p(w++, N8X0_TEA5761_CS_GPIO);		/* u16 enable_gpio */
124153018216SPaolo Bonzini     w++;
124253018216SPaolo Bonzini 
124353018216SPaolo Bonzini     partition = (model == 810) ? n810_part_info : n800_part_info;
124453018216SPaolo Bonzini     for (; partition->name; partition++) {
12450983979bSPaolo Bonzini         stw_p(w++, OMAP_TAG_PARTITION);		/* u16 tag */
12460983979bSPaolo Bonzini         stw_p(w++, 28);				/* u16 len */
124753018216SPaolo Bonzini         strcpy((void *) w, partition->name);	/* char name[16] */
124853018216SPaolo Bonzini         l = (void *) (w + 8);
12490983979bSPaolo Bonzini         stl_p(l++, partition->size);		/* unsigned int size */
12500983979bSPaolo Bonzini         stl_p(l++, partition->offset);		/* unsigned int offset */
12510983979bSPaolo Bonzini         stl_p(l++, partition->mask);		/* unsigned int mask_flags */
125253018216SPaolo Bonzini         w = (void *) l;
125353018216SPaolo Bonzini     }
125453018216SPaolo Bonzini 
12550983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_BOOT_REASON);		/* u16 tag */
12560983979bSPaolo Bonzini     stw_p(w++, 12);				/* u16 len */
125753018216SPaolo Bonzini #if 0
125853018216SPaolo Bonzini     strcpy((void *) w, "por");			/* char reason_str[12] */
125953018216SPaolo Bonzini     strcpy((void *) w, "charger");		/* char reason_str[12] */
126053018216SPaolo Bonzini     strcpy((void *) w, "32wd_to");		/* char reason_str[12] */
126153018216SPaolo Bonzini     strcpy((void *) w, "sw_rst");		/* char reason_str[12] */
126253018216SPaolo Bonzini     strcpy((void *) w, "mbus");			/* char reason_str[12] */
126353018216SPaolo Bonzini     strcpy((void *) w, "unknown");		/* char reason_str[12] */
126453018216SPaolo Bonzini     strcpy((void *) w, "swdg_to");		/* char reason_str[12] */
126553018216SPaolo Bonzini     strcpy((void *) w, "sec_vio");		/* char reason_str[12] */
126653018216SPaolo Bonzini     strcpy((void *) w, "pwr_key");		/* char reason_str[12] */
126753018216SPaolo Bonzini     strcpy((void *) w, "rtc_alarm");		/* char reason_str[12] */
126853018216SPaolo Bonzini #else
126953018216SPaolo Bonzini     strcpy((void *) w, "pwr_key");		/* char reason_str[12] */
127053018216SPaolo Bonzini #endif
127153018216SPaolo Bonzini     w += 6;
127253018216SPaolo Bonzini 
127353018216SPaolo Bonzini     tag = (model == 810) ? "RX-44" : "RX-34";
12740983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_VERSION_STR);		/* u16 tag */
12750983979bSPaolo Bonzini     stw_p(w++, 24);				/* u16 len */
127653018216SPaolo Bonzini     strcpy((void *) w, "product");		/* char component[12] */
127753018216SPaolo Bonzini     w += 6;
127853018216SPaolo Bonzini     strcpy((void *) w, tag);			/* char version[12] */
127953018216SPaolo Bonzini     w += 6;
128053018216SPaolo Bonzini 
12810983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_VERSION_STR);		/* u16 tag */
12820983979bSPaolo Bonzini     stw_p(w++, 24);				/* u16 len */
128353018216SPaolo Bonzini     strcpy((void *) w, "hw-build");		/* char component[12] */
128453018216SPaolo Bonzini     w += 6;
128553018216SPaolo Bonzini     strcpy((void *) w, "QEMU ");
128635c2c8dcSEduardo Habkost     pstrcat((void *) w, 12, qemu_hw_version()); /* char version[12] */
128753018216SPaolo Bonzini     w += 6;
128853018216SPaolo Bonzini 
128953018216SPaolo Bonzini     tag = (model == 810) ? "1.1.10-qemu" : "1.1.6-qemu";
12900983979bSPaolo Bonzini     stw_p(w++, OMAP_TAG_VERSION_STR);		/* u16 tag */
12910983979bSPaolo Bonzini     stw_p(w++, 24);				/* u16 len */
129253018216SPaolo Bonzini     strcpy((void *) w, "nolo");			/* char component[12] */
129353018216SPaolo Bonzini     w += 6;
129453018216SPaolo Bonzini     strcpy((void *) w, tag);			/* char version[12] */
129553018216SPaolo Bonzini     w += 6;
129653018216SPaolo Bonzini 
129753018216SPaolo Bonzini     return (void *) w - p;
129853018216SPaolo Bonzini }
129953018216SPaolo Bonzini 
130053018216SPaolo Bonzini static int n800_atag_setup(const struct arm_boot_info *info, void *p)
130153018216SPaolo Bonzini {
130253018216SPaolo Bonzini     return n8x0_atag_setup(p, 800);
130353018216SPaolo Bonzini }
130453018216SPaolo Bonzini 
130553018216SPaolo Bonzini static int n810_atag_setup(const struct arm_boot_info *info, void *p)
130653018216SPaolo Bonzini {
130753018216SPaolo Bonzini     return n8x0_atag_setup(p, 810);
130853018216SPaolo Bonzini }
130953018216SPaolo Bonzini 
13103ef96221SMarcel Apfelbaum static void n8x0_init(MachineState *machine,
131153018216SPaolo Bonzini                       struct arm_boot_info *binfo, int model)
131253018216SPaolo Bonzini {
131353018216SPaolo Bonzini     struct n800_s *s = (struct n800_s *) g_malloc0(sizeof(*s));
1314e285e867SPhilippe Mathieu-Daudé     uint64_t sdram_size = binfo->ram_size;
131553018216SPaolo Bonzini 
1316e285e867SPhilippe Mathieu-Daudé     memory_region_allocate_system_memory(&s->sdram, NULL, "omap2.dram",
1317e285e867SPhilippe Mathieu-Daudé                                          sdram_size);
1318e285e867SPhilippe Mathieu-Daudé     memory_region_add_subregion(get_system_memory(), OMAP2_Q2_BASE, &s->sdram);
1319e285e867SPhilippe Mathieu-Daudé 
1320e285e867SPhilippe Mathieu-Daudé     s->mpu = omap2420_mpu_init(&s->sdram, machine->cpu_type);
132153018216SPaolo Bonzini 
132253018216SPaolo Bonzini     /* Setup peripherals
132353018216SPaolo Bonzini      *
132453018216SPaolo Bonzini      * Believed external peripherals layout in the N810:
132553018216SPaolo Bonzini      * (spi bus 1)
132653018216SPaolo Bonzini      *   tsc2005
132753018216SPaolo Bonzini      *   lcd_mipid
132853018216SPaolo Bonzini      * (spi bus 2)
132953018216SPaolo Bonzini      *   Conexant cx3110x (WLAN)
133053018216SPaolo Bonzini      *   optional: pc2400m (WiMAX)
133153018216SPaolo Bonzini      * (i2c bus 0)
133253018216SPaolo Bonzini      *   TLV320AIC33 (audio codec)
133353018216SPaolo Bonzini      *   TCM825x (camera by Toshiba)
133453018216SPaolo Bonzini      *   lp5521 (clever LEDs)
133553018216SPaolo Bonzini      *   tsl2563 (light sensor, hwmon, model 7, rev. 0)
133653018216SPaolo Bonzini      *   lm8323 (keypad, manf 00, rev 04)
133753018216SPaolo Bonzini      * (i2c bus 1)
133853018216SPaolo Bonzini      *   tmp105 (temperature sensor, hwmon)
133953018216SPaolo Bonzini      *   menelaus (pm)
134053018216SPaolo Bonzini      * (somewhere on i2c - maybe N800-only)
134153018216SPaolo Bonzini      *   tea5761 (FM tuner)
134253018216SPaolo Bonzini      * (serial 0)
134353018216SPaolo Bonzini      *   GPS
134453018216SPaolo Bonzini      * (some serial port)
134553018216SPaolo Bonzini      *   csr41814 (Bluetooth)
134653018216SPaolo Bonzini      */
134753018216SPaolo Bonzini     n8x0_gpio_setup(s);
134853018216SPaolo Bonzini     n8x0_nand_setup(s);
134953018216SPaolo Bonzini     n8x0_i2c_setup(s);
1350fddbd80cSPaolo Bonzini     if (model == 800) {
135153018216SPaolo Bonzini         n800_tsc_kbd_setup(s);
1352fddbd80cSPaolo Bonzini     } else if (model == 810) {
135353018216SPaolo Bonzini         n810_tsc_setup(s);
135453018216SPaolo Bonzini         n810_kbd_setup(s);
135553018216SPaolo Bonzini     }
135653018216SPaolo Bonzini     n8x0_spi_setup(s);
135753018216SPaolo Bonzini     n8x0_dss_setup(s);
135853018216SPaolo Bonzini     n8x0_cbus_setup(s);
135953018216SPaolo Bonzini     n8x0_uart_setup(s);
13604bcbe0b6SEduardo Habkost     if (machine_usb(machine)) {
136153018216SPaolo Bonzini         n8x0_usb_setup(s);
136253018216SPaolo Bonzini     }
136353018216SPaolo Bonzini 
13643ef96221SMarcel Apfelbaum     if (machine->kernel_filename) {
136553018216SPaolo Bonzini         /* Or at the linux loader.  */
13662744ece8STao Xu         arm_load_kernel(s->mpu->cpu, machine, binfo);
136753018216SPaolo Bonzini 
136853018216SPaolo Bonzini         qemu_register_reset(n8x0_boot_init, s);
136953018216SPaolo Bonzini     }
137053018216SPaolo Bonzini 
137153018216SPaolo Bonzini     if (option_rom[0].name &&
13723ef96221SMarcel Apfelbaum         (machine->boot_order[0] == 'n' || !machine->kernel_filename)) {
13730b062eb0SZhou Jie         uint8_t *nolo_tags = g_new(uint8_t, 0x10000);
137453018216SPaolo Bonzini         /* No, wait, better start at the ROM.  */
137553018216SPaolo Bonzini         s->mpu->cpu->env.regs[15] = OMAP2_Q2_BASE + 0x400000;
137653018216SPaolo Bonzini 
137753018216SPaolo Bonzini         /* This is intended for loading the `secondary.bin' program from
137853018216SPaolo Bonzini          * Nokia images (the NOLO bootloader).  The entry point seems
137953018216SPaolo Bonzini          * to be at OMAP2_Q2_BASE + 0x400000.
138053018216SPaolo Bonzini          *
138153018216SPaolo Bonzini          * The `2nd.bin' files contain some kind of earlier boot code and
138253018216SPaolo Bonzini          * for them the entry point needs to be set to OMAP2_SRAM_BASE.
138353018216SPaolo Bonzini          *
138453018216SPaolo Bonzini          * The code above is for loading the `zImage' file from Nokia
138553018216SPaolo Bonzini          * images.  */
1386591f73f6SPeter Maydell         load_image_targphys(option_rom[0].name,
138753018216SPaolo Bonzini                             OMAP2_Q2_BASE + 0x400000,
138853018216SPaolo Bonzini                             sdram_size - 0x400000);
138953018216SPaolo Bonzini 
139053018216SPaolo Bonzini         n800_setup_nolo_tags(nolo_tags);
139153018216SPaolo Bonzini         cpu_physical_memory_write(OMAP2_SRAM_BASE, nolo_tags, 0x10000);
13920b062eb0SZhou Jie         g_free(nolo_tags);
139353018216SPaolo Bonzini     }
139453018216SPaolo Bonzini }
139553018216SPaolo Bonzini 
139653018216SPaolo Bonzini static struct arm_boot_info n800_binfo = {
139753018216SPaolo Bonzini     .loader_start = OMAP2_Q2_BASE,
139853018216SPaolo Bonzini     /* Actually two chips of 0x4000000 bytes each */
139953018216SPaolo Bonzini     .ram_size = 0x08000000,
140053018216SPaolo Bonzini     .board_id = 0x4f7,
140153018216SPaolo Bonzini     .atag_board = n800_atag_setup,
140253018216SPaolo Bonzini };
140353018216SPaolo Bonzini 
140453018216SPaolo Bonzini static struct arm_boot_info n810_binfo = {
140553018216SPaolo Bonzini     .loader_start = OMAP2_Q2_BASE,
140653018216SPaolo Bonzini     /* Actually two chips of 0x4000000 bytes each */
140753018216SPaolo Bonzini     .ram_size = 0x08000000,
140853018216SPaolo Bonzini     /* 0x60c and 0x6bf (WiMAX Edition) have been assigned but are not
140953018216SPaolo Bonzini      * used by some older versions of the bootloader and 5555 is used
141053018216SPaolo Bonzini      * instead (including versions that shipped with many devices).  */
141153018216SPaolo Bonzini     .board_id = 0x60c,
141253018216SPaolo Bonzini     .atag_board = n810_atag_setup,
141353018216SPaolo Bonzini };
141453018216SPaolo Bonzini 
14153ef96221SMarcel Apfelbaum static void n800_init(MachineState *machine)
141653018216SPaolo Bonzini {
141730d76f13SStefan Weil     n8x0_init(machine, &n800_binfo, 800);
141853018216SPaolo Bonzini }
141953018216SPaolo Bonzini 
14203ef96221SMarcel Apfelbaum static void n810_init(MachineState *machine)
142153018216SPaolo Bonzini {
142230d76f13SStefan Weil     n8x0_init(machine, &n810_binfo, 810);
142353018216SPaolo Bonzini }
142453018216SPaolo Bonzini 
14258a661aeaSAndreas Färber static void n800_class_init(ObjectClass *oc, void *data)
142653018216SPaolo Bonzini {
14278a661aeaSAndreas Färber     MachineClass *mc = MACHINE_CLASS(oc);
14288a661aeaSAndreas Färber 
1429e264d29dSEduardo Habkost     mc->desc = "Nokia N800 tablet aka. RX-34 (OMAP2420)";
1430e264d29dSEduardo Habkost     mc->init = n800_init;
1431e264d29dSEduardo Habkost     mc->default_boot_order = "";
14324672cbd7SPeter Maydell     mc->ignore_memory_transaction_failures = true;
1433ba1ba5ccSIgor Mammedov     mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm1136-r2");
143453018216SPaolo Bonzini }
143553018216SPaolo Bonzini 
14368a661aeaSAndreas Färber static const TypeInfo n800_type = {
14378a661aeaSAndreas Färber     .name = MACHINE_TYPE_NAME("n800"),
14388a661aeaSAndreas Färber     .parent = TYPE_MACHINE,
14398a661aeaSAndreas Färber     .class_init = n800_class_init,
14408a661aeaSAndreas Färber };
1441e264d29dSEduardo Habkost 
14428a661aeaSAndreas Färber static void n810_class_init(ObjectClass *oc, void *data)
1443e264d29dSEduardo Habkost {
14448a661aeaSAndreas Färber     MachineClass *mc = MACHINE_CLASS(oc);
14458a661aeaSAndreas Färber 
1446e264d29dSEduardo Habkost     mc->desc = "Nokia N810 tablet aka. RX-44 (OMAP2420)";
1447e264d29dSEduardo Habkost     mc->init = n810_init;
1448e264d29dSEduardo Habkost     mc->default_boot_order = "";
14494672cbd7SPeter Maydell     mc->ignore_memory_transaction_failures = true;
1450ba1ba5ccSIgor Mammedov     mc->default_cpu_type = ARM_CPU_TYPE_NAME("arm1136-r2");
1451e264d29dSEduardo Habkost }
1452e264d29dSEduardo Habkost 
14538a661aeaSAndreas Färber static const TypeInfo n810_type = {
14548a661aeaSAndreas Färber     .name = MACHINE_TYPE_NAME("n810"),
14558a661aeaSAndreas Färber     .parent = TYPE_MACHINE,
14568a661aeaSAndreas Färber     .class_init = n810_class_init,
14578a661aeaSAndreas Färber };
14588a661aeaSAndreas Färber 
14598a661aeaSAndreas Färber static void nseries_machine_init(void)
14608a661aeaSAndreas Färber {
14618a661aeaSAndreas Färber     type_register_static(&n800_type);
14628a661aeaSAndreas Färber     type_register_static(&n810_type);
14638a661aeaSAndreas Färber }
14648a661aeaSAndreas Färber 
14650e6aac87SEduardo Habkost type_init(nseries_machine_init)
1466