r2d.c 9.2 KB
Newer Older
T
ths 已提交
1 2 3 4
/*
 * Renesas SH7751R R2D-PLUS emulation
 *
 * Copyright (c) 2007 Magnus Damm
A
aurel32 已提交
5
 * Copyright (c) 2008 Paul Mundt
T
ths 已提交
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

A
Aurelien Jarno 已提交
26
#include "sysbus.h"
P
pbrook 已提交
27 28
#include "hw.h"
#include "sh.h"
B
blueswir1 已提交
29
#include "devices.h"
P
pbrook 已提交
30 31
#include "sysemu.h"
#include "boards.h"
B
balrog 已提交
32 33 34
#include "pci.h"
#include "net.h"
#include "sh7750_regs.h"
G
Gerd Hoffmann 已提交
35
#include "ide.h"
B
Blue Swirl 已提交
36
#include "loader.h"
A
Aurelien Jarno 已提交
37
#include "usb.h"
A
Aurelien Jarno 已提交
38
#include "flash.h"
B
Blue Swirl 已提交
39
#include "blockdev.h"
A
Aurelien Jarno 已提交
40 41 42

#define FLASH_BASE 0x00000000
#define FLASH_SIZE 0x02000000
T
ths 已提交
43 44 45 46

#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
#define SDRAM_SIZE 0x04000000

B
blueswir1 已提交
47 48
#define SM501_VRAM_SIZE 0x800000

A
Aurelien Jarno 已提交
49
#define BOOT_PARAMS_OFFSET 0x0010000
50
/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */
A
Aurelien Jarno 已提交
51 52
#define LINUX_LOAD_OFFSET  0x0800000
#define INITRD_LOAD_OFFSET 0x1800000
53

54
#define PA_IRLMSK	0x00
A
aurel32 已提交
55 56 57 58 59 60
#define PA_POWOFF	0x30
#define PA_VERREG	0x32
#define PA_OUTPORT	0x36

typedef struct {
    uint16_t bcr;
61
    uint16_t irlmsk;
A
aurel32 已提交
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
    uint16_t irlmon;
    uint16_t cfctl;
    uint16_t cfpow;
    uint16_t dispctl;
    uint16_t sdmpow;
    uint16_t rtcce;
    uint16_t pcicd;
    uint16_t voyagerrts;
    uint16_t cfrst;
    uint16_t admrts;
    uint16_t extrst;
    uint16_t cfcdintclr;
    uint16_t keyctlclr;
    uint16_t pad0;
    uint16_t pad1;
    uint16_t verreg;
    uint16_t inport;
    uint16_t outport;
    uint16_t bverreg;
81 82 83

/* output pin */
    qemu_irq irl;
A
Anthony Liguori 已提交
84
} r2d_fpga_t;
A
aurel32 已提交
85

86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107
enum r2d_fpga_irq {
    PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
    SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
    NR_IRQS
};

static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
    [CF_IDE]	= {  1, 1<<9 },
    [CF_CD]	= {  2, 1<<8 },
    [PCI_INTA]	= {  9, 1<<14 },
    [PCI_INTB]	= { 10, 1<<13 },
    [PCI_INTC]	= {  3, 1<<12 },
    [PCI_INTD]	= {  0, 1<<11 },
    [SM501]	= {  4, 1<<10 },
    [KEY]	= {  5, 1<<6 },
    [RTC_A]	= {  6, 1<<5 },
    [RTC_T]	= {  7, 1<<4 },
    [SDCARD]	= {  8, 1<<7 },
    [EXT]	= { 11, 1<<0 },
    [TP]	= { 12, 1<<15 },
};

A
Anthony Liguori 已提交
108
static void update_irl(r2d_fpga_t *fpga)
109 110 111 112 113 114 115 116 117 118 119
{
    int i, irl = 15;
    for (i = 0; i < NR_IRQS; i++)
        if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
            if (irqtab[i].irl < irl)
                irl = irqtab[i].irl;
    qemu_set_irq(fpga->irl, irl ^ 15);
}

static void r2d_fpga_irq_set(void *opaque, int n, int level)
{
A
Anthony Liguori 已提交
120
    r2d_fpga_t *fpga = opaque;
121 122 123 124 125 126 127
    if (level)
        fpga->irlmon |= irqtab[n].msk;
    else
        fpga->irlmon &= ~irqtab[n].msk;
    update_irl(fpga);
}

A
Anthony Liguori 已提交
128
static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr)
A
aurel32 已提交
129
{
A
Anthony Liguori 已提交
130
    r2d_fpga_t *s = opaque;
A
aurel32 已提交
131 132

    switch (addr) {
133 134
    case PA_IRLMSK:
        return s->irlmsk;
A
aurel32 已提交
135 136 137
    case PA_OUTPORT:
	return s->outport;
    case PA_POWOFF:
A
Aurelien Jarno 已提交
138
	return 0x00;
A
aurel32 已提交
139 140 141 142 143 144 145 146
    case PA_VERREG:
	return 0x10;
    }

    return 0;
}

static void
A
Anthony Liguori 已提交
147
r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value)
A
aurel32 已提交
148
{
A
Anthony Liguori 已提交
149
    r2d_fpga_t *s = opaque;
A
aurel32 已提交
150 151

    switch (addr) {
152 153 154 155
    case PA_IRLMSK:
        s->irlmsk = value;
        update_irl(s);
	break;
A
aurel32 已提交
156 157 158 159
    case PA_OUTPORT:
	s->outport = value;
	break;
    case PA_POWOFF:
A
Aurelien Jarno 已提交
160 161 162 163
        if (value & 1) {
            qemu_system_shutdown_request();
        }
        break;
A
aurel32 已提交
164 165 166 167 168 169
    case PA_VERREG:
	/* Discard writes */
	break;
    }
}

170
static CPUReadMemoryFunc * const r2d_fpga_readfn[] = {
A
aurel32 已提交
171 172
    r2d_fpga_read,
    r2d_fpga_read,
173
    NULL,
A
aurel32 已提交
174 175
};

176
static CPUWriteMemoryFunc * const r2d_fpga_writefn[] = {
A
aurel32 已提交
177 178
    r2d_fpga_write,
    r2d_fpga_write,
179
    NULL,
A
aurel32 已提交
180 181
};

A
Anthony Liguori 已提交
182
static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
A
aurel32 已提交
183 184
{
    int iomemtype;
A
Anthony Liguori 已提交
185
    r2d_fpga_t *s;
A
aurel32 已提交
186

187
    s = g_malloc0(sizeof(r2d_fpga_t));
188 189

    s->irl = irl;
A
aurel32 已提交
190

191
    iomemtype = cpu_register_io_memory(r2d_fpga_readfn,
192 193
				       r2d_fpga_writefn, s,
                                       DEVICE_NATIVE_ENDIAN);
A
aurel32 已提交
194
    cpu_register_physical_memory(base, 0x40, iomemtype);
195
    return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
A
aurel32 已提交
196 197
}

A
Aurelien Jarno 已提交
198 199 200 201 202 203 204 205 206 207 208 209 210 211
typedef struct ResetData {
    CPUState *env;
    uint32_t vector;
} ResetData;

static void main_cpu_reset(void *opaque)
{
    ResetData *s = (ResetData *)opaque;
    CPUState *env = s->env;

    cpu_reset(env);
    env->pc = s->vector;
}

A
Aurelien Jarno 已提交
212 213 214 215 216 217 218 219 220 221 222 223 224 225
static struct __attribute__((__packed__))
{
    int mount_root_rdonly;
    int ramdisk_flags;
    int orig_root_dev;
    int loader_type;
    int initrd_start;
    int initrd_size;

    char pad[232];

    char kernel_cmdline[256];
} boot_params;

A
Anthony Liguori 已提交
226
static void r2d_init(ram_addr_t ram_size,
227
              const char *boot_device,
T
ths 已提交
228 229 230 231
	      const char *kernel_filename, const char *kernel_cmdline,
	      const char *initrd_filename, const char *cpu_model)
{
    CPUState *env;
A
Aurelien Jarno 已提交
232
    ResetData *reset_info;
T
ths 已提交
233
    struct SH7750State *s;
A
Anthony Liguori 已提交
234
    ram_addr_t sdram_addr;
235
    qemu_irq *irq;
G
Gerd Hoffmann 已提交
236
    DriveInfo *dinfo;
B
balrog 已提交
237
    int i;
238
    MemoryRegion *flash = g_new(MemoryRegion, 1);
T
ths 已提交
239

B
bellard 已提交
240
    if (!cpu_model)
A
aurel32 已提交
241
        cpu_model = "SH7751R";
B
bellard 已提交
242 243 244 245 246 247

    env = cpu_init(cpu_model);
    if (!env) {
        fprintf(stderr, "Unable to find CPU definition\n");
        exit(1);
    }
248
    reset_info = g_malloc0(sizeof(ResetData));
A
Aurelien Jarno 已提交
249 250 251
    reset_info->env = env;
    reset_info->vector = env->pc;
    qemu_register_reset(main_cpu_reset, reset_info);
T
ths 已提交
252 253

    /* Allocate memory space */
254
    sdram_addr = qemu_ram_alloc(NULL, "r2d.sdram", SDRAM_SIZE);
B
blueswir1 已提交
255
    cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr);
T
ths 已提交
256 257
    /* Register peripherals */
    s = sh7750_init(env);
258
    irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
A
Aurelien Jarno 已提交
259 260
    sysbus_create_varargs("sh_pci", 0x1e200000, irq[PCI_INTA], irq[PCI_INTB],
                          irq[PCI_INTC], irq[PCI_INTD], NULL);
261

A
aurel32 已提交
262
    sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]);
263 264

    /* onboard CF (True IDE mode, Master only). */
265 266 267
    dinfo = drive_get(IF_IDE, 0, 0);
    mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1,
                  dinfo, NULL);
268

A
Aurelien Jarno 已提交
269
    /* onboard flash memory */
A
Aurelien Jarno 已提交
270
    dinfo = drive_get(IF_PFLASH, 0, 0);
271 272 273
    memory_region_init_rom_device(flash, &pflash_cfi02_ops_le,
                                  NULL, "r2d.flash", FLASH_SIZE);
    pflash_cfi02_register(0x0, flash,
274 275 276
                          dinfo ? dinfo->bdrv : NULL, (16 * 1024),
                          FLASH_SIZE >> 16,
                          1, 4, 0x0000, 0x0000, 0x0000, 0x0000,
277
                          0x555, 0x2aa);
A
Aurelien Jarno 已提交
278

B
balrog 已提交
279
    /* NIC: rtl8139 on-board, and 2 slots. */
A
aurel32 已提交
280
    for (i = 0; i < nb_nics; i++)
281
        pci_nic_init_nofail(&nd_table[i], "rtl8139", i==0 ? "2" : NULL);
B
balrog 已提交
282

A
Aurelien Jarno 已提交
283 284 285
    /* USB keyboard */
    usbdevice_create("keyboard");

T
ths 已提交
286
    /* Todo: register on board registers */
A
Aurelien Jarno 已提交
287 288
    memset(&boot_params, 0, sizeof(boot_params));

289
    if (kernel_filename) {
A
Aurelien Jarno 已提交
290 291 292 293 294 295 296 297 298 299 300 301 302
        int kernel_size;

        kernel_size = load_image_targphys(kernel_filename,
                                          SDRAM_BASE + LINUX_LOAD_OFFSET,
                                          INITRD_LOAD_OFFSET - LINUX_LOAD_OFFSET);
        if (kernel_size < 0) {
          fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
          exit(1);
        }

        /* initialization which should be done by firmware */
        stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */
        stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */
A
Aurelien Jarno 已提交
303
        reset_info->vector = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000; /* Start from P2 area */
T
ths 已提交
304
    }
A
Aurelien Jarno 已提交
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330

    if (initrd_filename) {
        int initrd_size;

        initrd_size = load_image_targphys(initrd_filename,
                                          SDRAM_BASE + INITRD_LOAD_OFFSET,
                                          SDRAM_SIZE - INITRD_LOAD_OFFSET);

        if (initrd_size < 0) {
          fprintf(stderr, "qemu: could not load initrd '%s'\n", initrd_filename);
          exit(1);
        }

        /* initialization which should be done by firmware */
        boot_params.loader_type = 1;
        boot_params.initrd_start = INITRD_LOAD_OFFSET;
        boot_params.initrd_size = initrd_size;
    }

    if (kernel_cmdline) {
        strncpy(boot_params.kernel_cmdline, kernel_cmdline,
                sizeof(boot_params.kernel_cmdline));
    }

    rom_add_blob_fixed("boot_params", &boot_params, sizeof(boot_params),
                       SDRAM_BASE + BOOT_PARAMS_OFFSET);
T
ths 已提交
331 332
}

333
static QEMUMachine r2d_machine = {
334 335 336
    .name = "r2d",
    .desc = "r2d-plus board",
    .init = r2d_init,
T
ths 已提交
337
};
338 339 340 341 342 343 344

static void r2d_machine_init(void)
{
    qemu_register_machine(&r2d_machine);
}

machine_init(r2d_machine_init);