palm.c 9.2 KB
Newer Older
1 2 3 4 5 6 7
/*
 * PalmOne's (TM) PDAs.
 *
 * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
B
balrog 已提交
8 9
 * published by the Free Software Foundation; either version 2 or
 * (at your option) version 3 of the License.
10 11 12 13 14 15
 *
 * 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.
 *
16
 * You should have received a copy of the GNU General Public License along
17
 * with this program; if not, see <http://www.gnu.org/licenses/>.
18
 */
19
#include "hw/hw.h"
P
pbrook 已提交
20
#include "audio/audio.h"
21
#include "sysemu/sysemu.h"
22
#include "ui/console.h"
P
Paolo Bonzini 已提交
23
#include "hw/arm/omap.h"
24
#include "hw/boards.h"
25 26
#include "hw/arm/arm.h"
#include "hw/devices.h"
27
#include "hw/loader.h"
28
#include "exec/address-spaces.h"
29

A
Avi Kivity 已提交
30
static uint32_t static_readb(void *opaque, hwaddr offset)
31 32 33 34 35
{
    uint32_t *val = (uint32_t *) opaque;
    return *val >> ((offset & 3) << 3);
}

A
Avi Kivity 已提交
36
static uint32_t static_readh(void *opaque, hwaddr offset)
B
balrog 已提交
37
{
38 39 40 41
    uint32_t *val = (uint32_t *) opaque;
    return *val >> ((offset & 1) << 3);
}

A
Avi Kivity 已提交
42
static uint32_t static_readw(void *opaque, hwaddr offset)
B
balrog 已提交
43
{
44 45 46 47
    uint32_t *val = (uint32_t *) opaque;
    return *val >> ((offset & 0) << 3);
}

A
Avi Kivity 已提交
48
static void static_write(void *opaque, hwaddr offset,
B
balrog 已提交
49 50
                uint32_t value)
{
51 52 53 54 55 56
#ifdef SPY
    printf("%s: value %08lx written at " PA_FMT "\n",
                    __FUNCTION__, value, offset);
#endif
}

A
Avi Kivity 已提交
57 58 59 60 61 62
static const MemoryRegionOps static_ops = {
    .old_mmio = {
        .read = { static_readb, static_readh, static_readw, },
        .write = { static_write, static_write, static_write, },
    },
    .endianness = DEVICE_NATIVE_ENDIAN,
63 64 65
};

/* Palm Tunsgten|E support */
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83

/* Shared GPIOs */
#define PALMTE_USBDETECT_GPIO	0
#define PALMTE_USB_OR_DC_GPIO	1
#define PALMTE_TSC_GPIO		4
#define PALMTE_PINTDAV_GPIO	6
#define PALMTE_MMC_WP_GPIO	8
#define PALMTE_MMC_POWER_GPIO	9
#define PALMTE_HDQ_GPIO		11
#define PALMTE_HEADPHONES_GPIO	14
#define PALMTE_SPEAKER_GPIO	15
/* MPU private GPIOs */
#define PALMTE_DC_GPIO		2
#define PALMTE_MMC_SWITCH_GPIO	4
#define PALMTE_MMC1_GPIO	6
#define PALMTE_MMC2_GPIO	7
#define PALMTE_MMC3_GPIO	11

P
Paul Brook 已提交
84
static MouseTransformInfo palmte_pointercal = {
85 86 87 88 89
    .x = 320,
    .y = 320,
    .a = { -5909, 8, 22465308, 104, 7644, -1219972, 65536 },
};

90 91
static void palmte_microwire_setup(struct omap_mpu_state_s *cpu)
{
P
Paul Brook 已提交
92
    uWireSlave *tsc;
B
balrog 已提交
93

94
    tsc = tsc2102_init(qdev_get_gpio_in(cpu->gpio, PALMTE_PINTDAV_GPIO));
B
balrog 已提交
95 96 97

    omap_uwire_attach(cpu->microwire, tsc, 0);
    omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc));
98 99

    tsc210x_set_transform(tsc, &palmte_pointercal);
100 101
}

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
static struct {
    int row;
    int column;
} palmte_keymap[0x80] = {
    [0 ... 0x7f] = { -1, -1 },
    [0x3b] = { 0, 0 },	/* F1	-> Calendar */
    [0x3c] = { 1, 0 },	/* F2	-> Contacts */
    [0x3d] = { 2, 0 },	/* F3	-> Tasks List */
    [0x3e] = { 3, 0 },	/* F4	-> Note Pad */
    [0x01] = { 4, 0 },	/* Esc	-> Power */
    [0x4b] = { 0, 1 },	/* 	   Left */
    [0x50] = { 1, 1 },	/* 	   Down */
    [0x48] = { 2, 1 },	/*	   Up */
    [0x4d] = { 3, 1 },	/*	   Right */
    [0x4c] = { 4, 1 },	/* 	   Centre */
    [0x39] = { 4, 1 },	/* Spc	-> Centre */
};

static void palmte_button_event(void *opaque, int keycode)
{
    struct omap_mpu_state_s *cpu = (struct omap_mpu_state_s *) opaque;

    if (palmte_keymap[keycode & 0x7f].row != -1)
        omap_mpuio_key(cpu->mpuio,
                        palmte_keymap[keycode & 0x7f].row,
                        palmte_keymap[keycode & 0x7f].column,
                        !(keycode & 0x80));
}

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
static void palmte_onoff_gpios(void *opaque, int line, int level)
{
    switch (line) {
    case 0:
        printf("%s: current to MMC/SD card %sabled.\n",
                        __FUNCTION__, level ? "dis" : "en");
        break;
    case 1:
        printf("%s: internal speaker amplifier %s.\n",
                        __FUNCTION__, level ? "down" : "on");
        break;

    /* These LCD & Audio output signals have not been identified yet.  */
    case 2:
    case 3:
    case 4:
        printf("%s: LCD GPIO%i %s.\n",
                        __FUNCTION__, line - 1, level ? "high" : "low");
        break;
    case 5:
    case 6:
        printf("%s: Audio GPIO%i %s.\n",
                        __FUNCTION__, line - 4, level ? "high" : "low");
        break;
    }
}

static void palmte_gpio_setup(struct omap_mpu_state_s *cpu)
{
    qemu_irq *misc_gpio;

    omap_mmc_handlers(cpu->mmc,
163
                    qdev_get_gpio_in(cpu->gpio, PALMTE_MMC_WP_GPIO),
164 165 166 167
                    qemu_irq_invert(omap_mpuio_in_get(cpu->mpuio)
                            [PALMTE_MMC_SWITCH_GPIO]));

    misc_gpio = qemu_allocate_irqs(palmte_onoff_gpios, cpu, 7);
168 169 170 171 172 173 174
    qdev_connect_gpio_out(cpu->gpio, PALMTE_MMC_POWER_GPIO,	misc_gpio[0]);
    qdev_connect_gpio_out(cpu->gpio, PALMTE_SPEAKER_GPIO,	misc_gpio[1]);
    qdev_connect_gpio_out(cpu->gpio, 11,			misc_gpio[2]);
    qdev_connect_gpio_out(cpu->gpio, 12,			misc_gpio[3]);
    qdev_connect_gpio_out(cpu->gpio, 13,			misc_gpio[4]);
    omap_mpuio_out_set(cpu->mpuio, 1,				misc_gpio[5]);
    omap_mpuio_out_set(cpu->mpuio, 3,				misc_gpio[6]);
175 176

    /* Reset some inputs to initial state.  */
177 178 179 180
    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USBDETECT_GPIO));
    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_USB_OR_DC_GPIO));
    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, 4));
    qemu_irq_lower(qdev_get_gpio_in(cpu->gpio, PALMTE_HEADPHONES_GPIO));
181 182 183 184 185 186
    qemu_irq_lower(omap_mpuio_in_get(cpu->mpuio)[PALMTE_DC_GPIO]);
    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[6]);
    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[7]);
    qemu_irq_raise(omap_mpuio_in_get(cpu->mpuio)[11]);
}

187 188 189 190 191 192
static struct arm_boot_info palmte_binfo = {
    .loader_start = OMAP_EMIFF_BASE,
    .ram_size = 0x02000000,
    .board_id = 0x331,
};

193
static void palmte_init(QEMUMachineInitArgs *args)
194
{
195 196 197 198
    const char *cpu_model = args->cpu_model;
    const char *kernel_filename = args->kernel_filename;
    const char *kernel_cmdline = args->kernel_cmdline;
    const char *initrd_filename = args->initrd_filename;
199
    MemoryRegion *address_space_mem = get_system_memory();
200
    struct omap_mpu_state_s *mpu;
201
    int flash_size = 0x00800000;
202
    int sdram_size = palmte_binfo.ram_size;
203 204 205 206 207
    static uint32_t cs0val = 0xffffffff;
    static uint32_t cs1val = 0x0000e1a0;
    static uint32_t cs2val = 0x0000e1a0;
    static uint32_t cs3val = 0xe1a0e1a0;
    int rom_size, rom_loaded = 0;
A
Avi Kivity 已提交
208 209
    MemoryRegion *flash = g_new(MemoryRegion, 1);
    MemoryRegion *cs = g_new(MemoryRegion, 4);
210

211
    mpu = omap310_mpu_init(address_space_mem, sdram_size, cpu_model);
212 213

    /* External Flash (EMIFS) */
214
    memory_region_init_ram(flash, NULL, "palmte.flash", flash_size);
215
    vmstate_register_ram_global(flash);
A
Avi Kivity 已提交
216 217 218
    memory_region_set_readonly(flash, true);
    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE, flash);

219
    memory_region_init_io(&cs[0], NULL, &static_ops, &cs0val, "palmte-cs0",
A
Avi Kivity 已提交
220 221 222
                          OMAP_CS0_SIZE - flash_size);
    memory_region_add_subregion(address_space_mem, OMAP_CS0_BASE + flash_size,
                                &cs[0]);
223
    memory_region_init_io(&cs[1], NULL, &static_ops, &cs1val, "palmte-cs1",
A
Avi Kivity 已提交
224 225
                          OMAP_CS1_SIZE);
    memory_region_add_subregion(address_space_mem, OMAP_CS1_BASE, &cs[1]);
226
    memory_region_init_io(&cs[2], NULL, &static_ops, &cs2val, "palmte-cs2",
A
Avi Kivity 已提交
227 228
                          OMAP_CS2_SIZE);
    memory_region_add_subregion(address_space_mem, OMAP_CS2_BASE, &cs[2]);
229
    memory_region_init_io(&cs[3], NULL, &static_ops, &cs3val, "palmte-cs3",
A
Avi Kivity 已提交
230 231
                          OMAP_CS3_SIZE);
    memory_region_add_subregion(address_space_mem, OMAP_CS3_BASE, &cs[3]);
232

233
    palmte_microwire_setup(mpu);
234

235
    qemu_add_kbd_event_handler(palmte_button_event, mpu);
236

237
    palmte_gpio_setup(mpu);
238

239 240
    /* Setup initial (reset) machine state */
    if (nb_option_roms) {
G
Gleb Natapov 已提交
241
        rom_size = get_image_size(option_rom[0].name);
242
        if (rom_size > flash_size) {
243 244
            fprintf(stderr, "%s: ROM image too big (%x > %x)\n",
                            __FUNCTION__, rom_size, flash_size);
245 246 247
            rom_size = 0;
        }
        if (rom_size > 0) {
G
Gleb Natapov 已提交
248
            rom_size = load_image_targphys(option_rom[0].name, OMAP_CS0_BASE,
249
                                           flash_size);
250
            rom_loaded = 1;
251 252
        }
        if (rom_size < 0) {
253
            fprintf(stderr, "%s: error loading '%s'\n",
G
Gleb Natapov 已提交
254
                            __FUNCTION__, option_rom[0].name);
255
        }
256 257 258 259 260 261 262 263
    }

    if (!rom_loaded && !kernel_filename) {
        fprintf(stderr, "Kernel or ROM image must be specified\n");
        exit(1);
    }

    /* Load the kernel.  */
264 265 266 267
    palmte_binfo.kernel_filename = kernel_filename;
    palmte_binfo.kernel_cmdline = kernel_cmdline;
    palmte_binfo.initrd_filename = initrd_filename;
    arm_load_kernel(mpu->cpu, &palmte_binfo);
268 269
}

270
static QEMUMachine palmte_machine = {
271 272 273
    .name = "cheetah",
    .desc = "Palm Tungsten|E aka. Cheetah PDA (OMAP310)",
    .init = palmte_init,
274
};
275 276 277 278 279 280 281

static void palmte_machine_init(void)
{
    qemu_register_machine(&palmte_machine);
}

machine_init(palmte_machine_init);