qemu/hw/r2d.c
<<
>>
Prefs
   1/*
   2 * Renesas SH7751R R2D-PLUS emulation
   3 *
   4 * Copyright (c) 2007 Magnus Damm
   5 * Copyright (c) 2008 Paul Mundt
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#include "hw.h"
  27#include "sh.h"
  28#include "devices.h"
  29#include "sysemu.h"
  30#include "boards.h"
  31#include "pci.h"
  32#include "net.h"
  33#include "sh7750_regs.h"
  34
  35#define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
  36#define SDRAM_SIZE 0x04000000
  37
  38#define SM501_VRAM_SIZE 0x800000
  39
  40/* CONFIG_BOOT_LINK_OFFSET of Linux kernel */
  41#define LINUX_LOAD_OFFSET 0x800000
  42
  43#define PA_IRLMSK       0x00
  44#define PA_POWOFF       0x30
  45#define PA_VERREG       0x32
  46#define PA_OUTPORT      0x36
  47
  48typedef struct {
  49    uint16_t bcr;
  50    uint16_t irlmsk;
  51    uint16_t irlmon;
  52    uint16_t cfctl;
  53    uint16_t cfpow;
  54    uint16_t dispctl;
  55    uint16_t sdmpow;
  56    uint16_t rtcce;
  57    uint16_t pcicd;
  58    uint16_t voyagerrts;
  59    uint16_t cfrst;
  60    uint16_t admrts;
  61    uint16_t extrst;
  62    uint16_t cfcdintclr;
  63    uint16_t keyctlclr;
  64    uint16_t pad0;
  65    uint16_t pad1;
  66    uint16_t powoff;
  67    uint16_t verreg;
  68    uint16_t inport;
  69    uint16_t outport;
  70    uint16_t bverreg;
  71
  72/* output pin */
  73    qemu_irq irl;
  74} r2d_fpga_t;
  75
  76enum r2d_fpga_irq {
  77    PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
  78    SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
  79    NR_IRQS
  80};
  81
  82static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
  83    [CF_IDE]    = {  1, 1<<9 },
  84    [CF_CD]     = {  2, 1<<8 },
  85    [PCI_INTA]  = {  9, 1<<14 },
  86    [PCI_INTB]  = { 10, 1<<13 },
  87    [PCI_INTC]  = {  3, 1<<12 },
  88    [PCI_INTD]  = {  0, 1<<11 },
  89    [SM501]     = {  4, 1<<10 },
  90    [KEY]       = {  5, 1<<6 },
  91    [RTC_A]     = {  6, 1<<5 },
  92    [RTC_T]     = {  7, 1<<4 },
  93    [SDCARD]    = {  8, 1<<7 },
  94    [EXT]       = { 11, 1<<0 },
  95    [TP]        = { 12, 1<<15 },
  96};
  97
  98static void update_irl(r2d_fpga_t *fpga)
  99{
 100    int i, irl = 15;
 101    for (i = 0; i < NR_IRQS; i++)
 102        if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
 103            if (irqtab[i].irl < irl)
 104                irl = irqtab[i].irl;
 105    qemu_set_irq(fpga->irl, irl ^ 15);
 106}
 107
 108static void r2d_fpga_irq_set(void *opaque, int n, int level)
 109{
 110    r2d_fpga_t *fpga = opaque;
 111    if (level)
 112        fpga->irlmon |= irqtab[n].msk;
 113    else
 114        fpga->irlmon &= ~irqtab[n].msk;
 115    update_irl(fpga);
 116}
 117
 118static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr)
 119{
 120    r2d_fpga_t *s = opaque;
 121
 122    switch (addr) {
 123    case PA_IRLMSK:
 124        return s->irlmsk;
 125    case PA_OUTPORT:
 126        return s->outport;
 127    case PA_POWOFF:
 128        return s->powoff;
 129    case PA_VERREG:
 130        return 0x10;
 131    }
 132
 133    return 0;
 134}
 135
 136static void
 137r2d_fpga_write(void *opaque, target_phys_addr_t addr, uint32_t value)
 138{
 139    r2d_fpga_t *s = opaque;
 140
 141    switch (addr) {
 142    case PA_IRLMSK:
 143        s->irlmsk = value;
 144        update_irl(s);
 145        break;
 146    case PA_OUTPORT:
 147        s->outport = value;
 148        break;
 149    case PA_POWOFF:
 150        s->powoff = value;
 151        break;
 152    case PA_VERREG:
 153        /* Discard writes */
 154        break;
 155    }
 156}
 157
 158static CPUReadMemoryFunc *r2d_fpga_readfn[] = {
 159    r2d_fpga_read,
 160    r2d_fpga_read,
 161    NULL,
 162};
 163
 164static CPUWriteMemoryFunc *r2d_fpga_writefn[] = {
 165    r2d_fpga_write,
 166    r2d_fpga_write,
 167    NULL,
 168};
 169
 170static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
 171{
 172    int iomemtype;
 173    r2d_fpga_t *s;
 174
 175    s = qemu_mallocz(sizeof(r2d_fpga_t));
 176
 177    s->irl = irl;
 178
 179    iomemtype = cpu_register_io_memory(r2d_fpga_readfn,
 180                                       r2d_fpga_writefn, s);
 181    cpu_register_physical_memory(base, 0x40, iomemtype);
 182    return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
 183}
 184
 185static void r2d_pci_set_irq(qemu_irq *p, int n, int l)
 186{
 187    qemu_set_irq(p[n], l);
 188}
 189
 190static int r2d_pci_map_irq(PCIDevice *d, int irq_num)
 191{
 192    const int intx[] = { PCI_INTA, PCI_INTB, PCI_INTC, PCI_INTD };
 193    return intx[d->devfn >> 3];
 194}
 195
 196static void r2d_init(ram_addr_t ram_size,
 197              const char *boot_device,
 198              const char *kernel_filename, const char *kernel_cmdline,
 199              const char *initrd_filename, const char *cpu_model)
 200{
 201    CPUState *env;
 202    struct SH7750State *s;
 203    ram_addr_t sdram_addr;
 204    qemu_irq *irq;
 205    PCIBus *pci;
 206    int i;
 207
 208    if (!cpu_model)
 209        cpu_model = "SH7751R";
 210
 211    env = cpu_init(cpu_model);
 212    if (!env) {
 213        fprintf(stderr, "Unable to find CPU definition\n");
 214        exit(1);
 215    }
 216
 217    /* Allocate memory space */
 218    sdram_addr = qemu_ram_alloc(SDRAM_SIZE);
 219    cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr);
 220    /* Register peripherals */
 221    s = sh7750_init(env);
 222    irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
 223    pci = sh_pci_register_bus(r2d_pci_set_irq, r2d_pci_map_irq, irq, 0, 4);
 224
 225    sm501_init(0x10000000, SM501_VRAM_SIZE, irq[SM501], serial_hds[2]);
 226
 227    /* onboard CF (True IDE mode, Master only). */
 228    if ((i = drive_get_index(IF_IDE, 0, 0)) != -1)
 229        mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1,
 230                      drives_table[i].bdrv, NULL);
 231
 232    /* NIC: rtl8139 on-board, and 2 slots. */
 233    for (i = 0; i < nb_nics; i++)
 234        pci_nic_init(&nd_table[i], "rtl8139", i==0 ? "2" : NULL);
 235
 236    /* Todo: register on board registers */
 237    if (kernel_filename) {
 238      int kernel_size;
 239      /* initialization which should be done by firmware */
 240      stl_phys(SH7750_BCR1, 1<<3); /* cs3 SDRAM */
 241      stw_phys(SH7750_BCR2, 3<<(3*2)); /* cs3 32bit */
 242
 243      if (kernel_cmdline) {
 244          kernel_size = load_image_targphys(kernel_filename,
 245                                   SDRAM_BASE + LINUX_LOAD_OFFSET,
 246                                   SDRAM_SIZE - LINUX_LOAD_OFFSET);
 247          env->pc = (SDRAM_BASE + LINUX_LOAD_OFFSET) | 0xa0000000;
 248          pstrcpy_targphys(SDRAM_BASE + 0x10100, 256, kernel_cmdline);
 249      } else {
 250          kernel_size = load_image_targphys(kernel_filename, SDRAM_BASE, SDRAM_SIZE);
 251          env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */
 252      }
 253
 254      if (kernel_size < 0) {
 255        fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
 256        exit(1);
 257      }
 258    }
 259}
 260
 261static QEMUMachine r2d_machine = {
 262    .name = "r2d",
 263    .desc = "r2d-plus board",
 264    .init = r2d_init,
 265};
 266
 267static void r2d_machine_init(void)
 268{
 269    qemu_register_machine(&r2d_machine);
 270}
 271
 272machine_init(r2d_machine_init);
 273