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