diff mbox

[32/48] Add beagleboard and n900 machine definitions

Message ID 28d02f3566af81a62325a039f896ead5eaaf0bd8.1269617186.git.riku.voipio@nokia.com
State New
Headers show

Commit Message

Riku Voipio March 26, 2010, 4:06 p.m. UTC
From: Riku Voipio <riku.voipio@nokia.com>

Wire in all the code from previous patches. Beagleboard code based on
Yajin's initial work.

Cc: yajin@vm-kernel.org
Signed-Off-By: Riku Voipio <riku.voipio@nokia.com>
Signed-Off-By: Juha Riihimäki <juha.riihimaki@nokia.com>

---
 Makefile.target |    7 +-
 hw/beagle.c     |  108 +++++++++++++++++++++
 hw/nseries.c    |  288 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 397 insertions(+), 6 deletions(-)
 create mode 100644 hw/beagle.c
diff mbox

Patch

diff --git a/Makefile.target b/Makefile.target
index eb4d010..c14d496 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -269,8 +269,11 @@  obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
 obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
 obj-arm-y += pflash_cfi01.o gumstix.o
 obj-arm-y += zaurus.o ide/core.o ide/microdrive.o spitz.o tosa.o tc6393xb.o
-obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
-obj-arm-y += omap2.o omap_dss.o soc_dma.o
+obj-arm-y += omap_gpio.o omap_uart.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o
+obj-arm-y += omap_i2c.o omap_spi.o omap_intc.o omap_dss.o soc_dma.o omap_gptimer.o
+obj-arm-y += omap_synctimer.o omap_sdrc.o omap_gpmc.o omap_tap.o omap_l4.o
+obj-arm-y += omap_usb.o omap3_mmc.o omap3_lcd.o omap3_boot.o omap1.o omap2.o omap3.o
+obj-arm-y += beagle.o twl4030.o
 obj-arm-y += omap_sx1.o palm.o tsc210x.o
 obj-arm-y += nseries.o blizzard.o onenand.o vga.o cbus.o tusb6010.o usb-musb.o
 obj-arm-y += mst_fpga.o mainstone.o
diff --git a/hw/beagle.c b/hw/beagle.c
new file mode 100644
index 0000000..ae4da1c
--- /dev/null
+++ b/hw/beagle.c
@@ -0,0 +1,108 @@ 
+/*
+ * Beagle board emulation. http://beagleboard.org/
+ * 
+ * Copyright (c) 2009 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 or
+ * (at your option) any later version of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include "qemu-common.h"
+#include "sysemu.h"
+#include "omap.h"
+#include "arm-misc.h"
+#include "boards.h"
+#include "i2c.h"
+#include "net.h"
+#include "devices.h"
+#include "flash.h"
+
+#ifdef CONFIG_GLHW
+#include "helper_opengl.h"
+#endif
+
+#define BEAGLE_NAND_CS       0
+#define BEAGLE_SMC_CS        1
+#define BEAGLE_NAND_PAGESIZE 0x800
+#define BEAGLE_SDRAM_SIZE    (128 * 1024 * 1024) /* 128MB */
+
+/* Beagle board support */
+struct beagle_s {
+    struct omap_mpu_state_s *cpu;
+    
+    NANDFlashState *nand;
+    struct omap3_lcd_panel_s *lcd_panel;
+    i2c_bus *i2c;
+    void *twl4030;
+    void *smc;
+#ifdef CONFIG_GLHW
+    void *gl;
+#endif
+};
+
+static void beagle_init(ram_addr_t ram_size,
+                        const char *boot_device,
+                        const char *kernel_filename,
+                        const char *kernel_cmdline,
+                        const char *initrd_filename,
+                        const char *cpu_model)
+{
+    struct beagle_s *s = (struct beagle_s *) qemu_mallocz(sizeof(*s));
+    DriveInfo *dmtd = drive_get(IF_MTD, 0, 0);
+    DriveInfo *dsd  = drive_get(IF_SD, 0, 0);
+    
+    if (!dmtd && !dsd) {
+        hw_error("%s: SD or NAND image required", __FUNCTION__);
+    }
+   	s->cpu = omap3530_mpu_init(ram_size, NULL, NULL, serial_hds[0]);
+
+	s->nand = nand_init(NAND_MFR_MICRON, 0xba, dmtd);
+	nand_setpins(s->nand, 0, 0, 0, 1, 0); /* no write-protect */
+    omap_gpmc_attach(s->cpu->gpmc, BEAGLE_NAND_CS, 0, NULL, NULL, s->nand, 2);
+    if (dsd) {
+        omap3_mmc_attach(s->cpu->omap3_mmc[0], dsd, 0, 0);
+    }
+
+    s->i2c = omap_i2c_bus(s->cpu->i2c[0]);
+    s->twl4030 = twl4030_init(s->i2c,
+                              s->cpu->irq[0][OMAP_INT_3XXX_SYS_NIRQ],
+                              NULL, NULL);
+    s->smc = smc91c111_init_lite(&nd_table[0], /*0x08000000,*/
+                                 omap2_gpio_in_get(s->cpu->gpif, 54));
+    omap_gpmc_attach(s->cpu->gpmc, BEAGLE_SMC_CS, smc91c111_iomemtype(s->smc),
+                     NULL, NULL, s->smc, 0);
+
+	s->lcd_panel = omap3_lcd_panel_init(s->cpu->dss);
+    omap_lcd_panel_attach(s->cpu->dss, omap3_lcd_panel_get(s->lcd_panel));
+
+#ifdef CONFIG_GLHW
+    s->gl = helper_opengl_init(s->cpu->env);
+#endif
+    
+    omap3_boot_rom_emu(s->cpu);
+}
+
+QEMUMachine beagle_machine = {
+    .name =        "beagle",
+    .desc =        "Beagle board (OMAP3530)",
+    .init =        beagle_init,
+};
+
+static void beagle_machine_init(void)
+{
+    qemu_register_machine(&beagle_machine);
+}
+
+machine_init(beagle_machine_init);
diff --git a/hw/nseries.c b/hw/nseries.c
index ec8f8d1..27d517b 100644
--- a/hw/nseries.c
+++ b/hw/nseries.c
@@ -1554,10 +1554,6 @@  static QEMUMachine n810_machine = {
     .init = n810_init,
 };
 
-#ifdef CONFIG_GLES2
-#include "gles2.h"
-#endif
-
 #define N900_SDRAM_SIZE (256 * 1024 * 1024)
 #define N900_ONENAND_CS 0
 #define N900_ONENAND_BUFSIZE (0xc000 << 1)
@@ -2128,6 +2124,289 @@  static I2CSlaveInfo tpa6130_info = {
     .send = tpa6130_tx
 };
 
+struct n900_s {
+    struct omap_mpu_state_s *cpu;
+    void *twl4030;
+    void *nand;
+    void *lcd;
+    struct mipid_s *mipid;
+    void *tsc2005;
+    void *bq2415x;
+    void *tpa6130;
+    void *lis302dl;
+    void *smc;
+    int extended_key;
+    int slide_open;
+    int camera_cover_open;
+    int headphone_connected;
+    QEMUTimer *shutdown_timer;
+};
+
+/* this takes care of the keys which are not located on the
+ * n900 keypad (note that volume up/down keys are handled by
+ * the keypad eventhough the keys are not located on the keypad)
+ * as well as triggering some other hardware button/switch-like
+ * events that are mapped to the host keyboard:
+ *
+ * escape ... power
+ * f1 ....... keypad slider open/close
+ * f2 ....... keypad lock
+ * f3 ....... camera lens cover open/close
+ * f4 ....... camera focus
+ * f5 ....... camera take picture
+ * f6 ....... stereo headphone connect/disconnect
+ * kp1 ...... decrease accelerometer x axis value
+ * kp2 ...... increase accelerometer x axis value
+ * kp4 ...... decrease accelerometer y axis value
+ * kp5 ...... increase accelerometer y axis value
+ * kp7 ...... decrease accelerometer z axis value
+ * kp8 ...... increase accelerometer z axis value
+ */
+static void n900_key_handler(void *opaque, int keycode)
+{
+    struct n900_s *s = opaque;
+    if (!s->extended_key && keycode == 0xe0) {
+        s->extended_key = 0x80;
+    } else {
+        int release = keycode & 0x80;
+        keycode = (keycode & 0x7f) | s->extended_key;
+        s->extended_key = 0;
+        switch (keycode) {
+            case 0x01: /* escape */
+                twl4030_set_powerbutton_state(s->twl4030, !release);
+                break;
+            case 0x3b: /* f1 */
+                if (release) {
+                    s->slide_open = !s->slide_open;
+                    qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+                                                   N900_SLIDE_GPIO),
+                                 !s->slide_open);
+                }
+                break;
+            case 0x3c: /* f2 */
+                qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+                                               N900_KBLOCK_GPIO),
+                             !!release);
+                break;
+            case 0x3d: /* f3 */
+                if (release) {
+                    s->camera_cover_open = !s->camera_cover_open;
+                    qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+                                                   N900_CAMCOVER_GPIO),
+                                 s->camera_cover_open);
+                }
+                break;
+            case 0x3e: /* f4 */
+                qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+                                               N900_CAMFOCUS_GPIO),
+                             !!release);
+                break;
+            case 0x3f: /* f5 */
+                qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+                                               N900_CAMLAUNCH_GPIO),
+                             !!release);
+                break;
+            case 0x40: /* f6 */
+                if (release) {
+                    s->headphone_connected = !s->headphone_connected;
+                    qemu_set_irq(omap2_gpio_in_get(s->cpu->gpif,
+                                                   N900_HEADPHONE_GPIO),
+                                 !s->headphone_connected);
+                }
+                break;
+            case 0x4f ... 0x50: /* kp1,2 */
+                lis302dl_trigger(s->lis302dl, 0, keycode - 0x4f, !release);
+                break;
+            case 0x4b ... 0x4c: /* kp4,5 */
+                lis302dl_trigger(s->lis302dl, 1, keycode - 0x4b, !release);
+                break;
+            case 0x47 ... 0x48: /* kp7,8 */
+                lis302dl_trigger(s->lis302dl, 2, keycode - 0x47, !release);
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+static void n900_reset(void *opaque)
+{
+    struct n900_s *s = opaque;
+    omap_gpmc_attach(s->cpu->gpmc, N900_ONENAND_CS, 0, onenand_base_update,
+                     onenand_base_unmap, s->nand, 0);
+    omap_gpmc_attach(s->cpu->gpmc, N900_SMC_CS, smc91c111_iomemtype(s->smc),
+                     NULL, NULL, s->smc, 0);
+    qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_KBLOCK_GPIO));
+    qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_HEADPHONE_GPIO));
+    qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_CAMLAUNCH_GPIO));
+    qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_CAMFOCUS_GPIO));
+    qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N900_CAMCOVER_GPIO));
+    qemu_irq_lower(omap2_gpio_in_get(s->cpu->gpif, N900_SLIDE_GPIO));
+    s->slide_open = 1;
+    s->camera_cover_open = 0;
+    s->headphone_connected = 0;
+    omap3_boot_rom_emu(s->cpu);
+}
+
+static void n900_shutdown_timer_callback(void *opaque)
+{
+    static int power_state = 0;
+    struct n900_s *s = opaque;
+    power_state = !power_state;
+    twl4030_set_powerbutton_state(s->twl4030, power_state);
+    qemu_mod_timer(s->shutdown_timer,
+                   qemu_get_clock(vm_clock)
+                   + get_ticks_per_sec() * (power_state ? 5LL : 1LL));
+}
+
+static int n900_display_close_callback(void *opaque)
+{
+    struct n900_s *s = opaque;
+    if (s->shutdown_timer == NULL) {
+        s->shutdown_timer = qemu_new_timer(vm_clock,
+                                           n900_shutdown_timer_callback,
+                                           s);
+        n900_shutdown_timer_callback(s);
+    }
+    return 0;
+}
+
+static const TWL4030KeyMap n900_twl4030_keymap[] = {
+    {0x10, 0, 0}, /* Q */
+    {0x11, 0, 1}, /* W */
+    {0x12, 0, 2}, /* E */
+    {0x13, 0, 3}, /* R */
+    {0x14, 0, 4}, /* T */
+    {0x15, 0, 5}, /* Y */
+    {0x16, 0, 6}, /* U */
+    {0x17, 0, 7}, /* I */
+    {0x18, 1, 0}, /* O */
+    {0x20, 1, 1}, /* D */
+    {0x34, 1, 2}, /* . */
+    {0x2f, 1, 3}, /* V */
+    {0xd0, 1, 4}, /* DOWN */
+    {0x41, 1, 7}, /* F7 -- volume/zoom down */
+    {0x19, 2, 0}, /* P */
+    {0x21, 2, 1}, /* F */
+    {0xc8, 2, 2}, /* UP */
+    {0x30, 2, 3}, /* B */
+    {0xcd, 2, 4}, /* RIGHT */
+    {0x42, 2, 7}, /* F8 -- volume/zoom up */
+    {0x33, 3, 0}, /* , */
+    {0x22, 3, 1}, /* G */
+    {0x1c, 3, 2}, /* ENTER */
+    {0x31, 3, 3}, /* N */
+    {0x0e, 4, 0}, /* BACKSPACE */
+    {0x23, 4, 1}, /* H */
+    {0x32, 4, 3}, /* M */
+    {0x1d, 4, 4}, /* LEFTCTRL */
+    {0x24, 5, 1}, /* J */
+    {0x2c, 5, 2}, /* Z */
+    {0x39, 5, 3}, /* SPACE */
+    {0x38, 5, 4}, /* LEFTALT -- "fn" */
+    {0x1e, 6, 0}, /* A */
+    {0x25, 6, 1}, /* K */
+    {0x2d, 6, 2}, /* X */
+    {0x39, 6, 3}, /* SPACE */
+    {0x2a, 6, 4}, /* LEFTSHIFT */
+    {0x1f, 7, 0}, /* S */
+    {0x26, 7, 1}, /* L */
+    {0x2e, 7, 2}, /* C */
+    {0xcb, 7, 3}, /* LEFT */
+    //    {0x10, 0xff, 2}, /* F9 */
+    //    {0x10, 0xff, 4}, /* F10 */
+    //    {0x10, 0xff, 5}, /* F11 */
+    {-1, -1, -1}
+};
+
+static MouseTransformInfo n900_pointercal = {
+    .x = 800,
+    .y = 480,
+    .a = {14114,  18, -2825064,  34,  -8765, 32972906, 65536},
+};
+
+static void n900_init(ram_addr_t ram_size,
+                      const char *boot_device,
+                      const char *kernel_filename,
+                      const char *kernel_cmdline,
+                      const char *initrd_filename,
+                      const char *cpu_model)
+{
+    struct n900_s *s = qemu_mallocz(sizeof(*s));
+    DriveInfo *dmtd = drive_get(IF_MTD, 0, 0);
+    DriveInfo *dsd  = drive_get(IF_SD, 0, 0);
+
+    if (!dmtd && !dsd) {
+        hw_error("%s: SD or NAND image required", __FUNCTION__);
+    }
+    s->cpu = omap3530_mpu_init(N900_SDRAM_SIZE,
+                               serial_hds[1],
+                               serial_hds[2],
+                               serial_hds[0]);
+    s->lcd = omap3_lcd_panel_init(s->cpu->dss);
+    omap_lcd_panel_attach(s->cpu->dss, omap3_lcd_panel_get(s->lcd));
+
+    s->tsc2005 = tsc2005_init(omap2_gpio_in_get(s->cpu->gpif,
+                                                N900_TSC2005_IRQ_GPIO));
+    tsc2005_set_transform(s->tsc2005, &n900_pointercal, 600, 1500);
+    omap_mcspi_attach(s->cpu->mcspi[0], tsc2005_txrx, s->tsc2005, 0);
+    cursor_hide = 0; // who wants to use touchscreen without a pointer?
+    cursor_allow_grab = 0; // ...and please, don't stop the host cursor
+
+    s->mipid = mipid_init();
+    s->mipid->n900 = 1;
+    s->mipid->id = 0x101234;
+    omap_mcspi_attach(s->cpu->mcspi[0], mipid_txrx, s->mipid, 2);
+
+    s->nand = onenand_init(NAND_MFR_SAMSUNG, 0x40, 0x121, 1, 
+                           omap2_gpio_in_get(s->cpu->gpif, N900_ONENAND_GPIO),
+                           dmtd);
+
+    if (dsd) {
+        omap3_mmc_attach(s->cpu->omap3_mmc[1], dsd, 0, 1);
+    }
+    if ((dsd = drive_get(IF_SD, 0, 1)) >= 0) {
+        omap3_mmc_attach(s->cpu->omap3_mmc[0], dsd, 0, 0);
+        //qemu_irq_raise(omap2_gpio_in_get(s->cpu->gpif, N900_SDCOVER_GPIO));
+    }
+
+    cpu_register_physical_memory(0x48058000, 0x3c00,
+                                 cpu_register_io_memory(ssi_read_func,
+                                                        ssi_write_func,
+                                                        0));
+
+    s->twl4030 = twl4030_init(omap_i2c_bus(s->cpu->i2c[0]),
+                              s->cpu->irq[0][OMAP_INT_3XXX_SYS_NIRQ],
+                              NULL, n900_twl4030_keymap);
+    s->bq2415x = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[1]),
+                                  "bq2415x", 0x6b);
+    s->tpa6130 = i2c_create_slave(omap_i2c_bus(s->cpu->i2c[1]),
+                                  "tpa6130", 0x60);
+    omap2_gpio_out_set(s->cpu->gpif, N900_HEADPHONE_EN_GPIO,
+                       tpa6130_get_irq(s->tpa6130, 0));
+    s->lis302dl = lis302dl_init(i2c_create_slave(omap_i2c_bus(s->cpu->i2c[2]),
+                                                 "lis302dl", 0x1d),
+                                omap2_gpio_in_get(s->cpu->gpif,
+                                                  N900_LIS302DL_INT1_GPIO),
+                                omap2_gpio_in_get(s->cpu->gpif,
+                                                  N900_LIS302DL_INT2_GPIO));
+
+    s->smc = smc91c111_init_lite(&nd_table[0], /*0x08000000,*/
+                                 omap2_gpio_in_get(s->cpu->gpif, 54));
+
+    qemu_add_kbd_event_handler(n900_key_handler, s);
+    qemu_set_display_close_handler(n900_display_close_callback, s);
+
+    qemu_register_reset(n900_reset, s);
+    n900_reset(s);
+}
+
+static QEMUMachine n900_machine = {
+    .name = "n900",
+    .desc = "Nokia N900 (OMAP3)",
+    .init = n900_init,
+};
+
 static void nseries_register_devices(void)
 {
     i2c_register_slave(&bq2415x_info);
@@ -2139,6 +2418,7 @@  static void nseries_machine_init(void)
 {
     qemu_register_machine(&n800_machine);
     qemu_register_machine(&n810_machine);
+    qemu_register_machine(&n900_machine);
 }
 
 device_init(nseries_register_devices);