qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

axis_dev88.c (10626B)


      1 /*
      2  * QEMU model for the AXIS devboard 88.
      3  *
      4  * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be included in
     14  * all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     22  * THE SOFTWARE.
     23  */
     24 
     25 #include "qemu/osdep.h"
     26 #include "qemu/units.h"
     27 #include "qapi/error.h"
     28 #include "cpu.h"
     29 #include "hw/sysbus.h"
     30 #include "net/net.h"
     31 #include "hw/block/flash.h"
     32 #include "hw/boards.h"
     33 #include "hw/cris/etraxfs.h"
     34 #include "hw/loader.h"
     35 #include "elf.h"
     36 #include "boot.h"
     37 #include "sysemu/qtest.h"
     38 #include "sysemu/sysemu.h"
     39 
     40 #define D(x)
     41 #define DNAND(x)
     42 
     43 struct nand_state_t
     44 {
     45     DeviceState *nand;
     46     MemoryRegion iomem;
     47     unsigned int rdy:1;
     48     unsigned int ale:1;
     49     unsigned int cle:1;
     50     unsigned int ce:1;
     51 };
     52 
     53 static struct nand_state_t nand_state;
     54 static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size)
     55 {
     56     struct nand_state_t *s = opaque;
     57     uint32_t r;
     58     int rdy;
     59 
     60     r = nand_getio(s->nand);
     61     nand_getpins(s->nand, &rdy);
     62     s->rdy = rdy;
     63 
     64     DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
     65     return r;
     66 }
     67 
     68 static void
     69 nand_write(void *opaque, hwaddr addr, uint64_t value,
     70            unsigned size)
     71 {
     72     struct nand_state_t *s = opaque;
     73     int rdy;
     74 
     75     DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value));
     76     nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
     77     nand_setio(s->nand, value);
     78     nand_getpins(s->nand, &rdy);
     79     s->rdy = rdy;
     80 }
     81 
     82 static const MemoryRegionOps nand_ops = {
     83     .read = nand_read,
     84     .write = nand_write,
     85     .endianness = DEVICE_NATIVE_ENDIAN,
     86 };
     87 
     88 struct tempsensor_t
     89 {
     90     unsigned int shiftreg;
     91     unsigned int count;
     92     enum {
     93         ST_OUT, ST_IN, ST_Z
     94     } state;
     95 
     96     uint16_t regs[3];
     97 };
     98 
     99 static void tempsensor_clkedge(struct tempsensor_t *s,
    100                                unsigned int clk, unsigned int data_in)
    101 {
    102     D(printf("%s clk=%d state=%d sr=%x\n", __func__,
    103              clk, s->state, s->shiftreg));
    104     if (s->count == 0) {
    105         s->count = 16;
    106         s->state = ST_OUT;
    107     }
    108     switch (s->state) {
    109         case ST_OUT:
    110             /* Output reg is clocked at negedge.  */
    111             if (!clk) {
    112                 s->count--;
    113                 s->shiftreg <<= 1;
    114                 if (s->count == 0) {
    115                     s->shiftreg = 0;
    116                     s->state = ST_IN;
    117                     s->count = 16;
    118                 }
    119             }
    120             break;
    121         case ST_Z:
    122             if (clk) {
    123                 s->count--;
    124                 if (s->count == 0) {
    125                     s->shiftreg = 0;
    126                     s->state = ST_OUT;
    127                     s->count = 16;
    128                 }
    129             }
    130             break;
    131         case ST_IN:
    132             /* Indata is sampled at posedge.  */
    133             if (clk) {
    134                 s->count--;
    135                 s->shiftreg <<= 1;
    136                 s->shiftreg |= data_in & 1;
    137                 if (s->count == 0) {
    138                     D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
    139                     s->regs[0] = s->shiftreg;
    140                     s->state = ST_OUT;
    141                     s->count = 16;
    142 
    143                     if ((s->regs[0] & 0xff) == 0) {
    144                         /* 25 degrees celsius.  */
    145                         s->shiftreg = 0x0b9f;
    146                     } else if ((s->regs[0] & 0xff) == 0xff) {
    147                         /* Sensor ID, 0x8100 LM70.  */
    148                         s->shiftreg = 0x8100;
    149                     } else
    150                         printf("Invalid tempsens state %x\n", s->regs[0]);
    151                 }
    152             }
    153             break;
    154     }
    155 }
    156 
    157 
    158 #define RW_PA_DOUT    0x00
    159 #define R_PA_DIN      0x01
    160 #define RW_PA_OE      0x02
    161 #define RW_PD_DOUT    0x10
    162 #define R_PD_DIN      0x11
    163 #define RW_PD_OE      0x12
    164 
    165 static struct gpio_state_t
    166 {
    167     MemoryRegion iomem;
    168     struct nand_state_t *nand;
    169     struct tempsensor_t tempsensor;
    170     uint32_t regs[0x5c / 4];
    171 } gpio_state;
    172 
    173 static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size)
    174 {
    175     struct gpio_state_t *s = opaque;
    176     uint32_t r = 0;
    177 
    178     addr >>= 2;
    179     switch (addr)
    180     {
    181         case R_PA_DIN:
    182             r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
    183 
    184             /* Encode pins from the nand.  */
    185             r |= s->nand->rdy << 7;
    186             break;
    187         case R_PD_DIN:
    188             r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
    189 
    190             /* Encode temp sensor pins.  */
    191             r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
    192             break;
    193 
    194         default:
    195             r = s->regs[addr];
    196             break;
    197     }
    198     return r;
    199     D(printf("%s %x=%x\n", __func__, addr, r));
    200 }
    201 
    202 static void gpio_write(void *opaque, hwaddr addr, uint64_t value,
    203                        unsigned size)
    204 {
    205     struct gpio_state_t *s = opaque;
    206     D(printf("%s %x=%x\n", __func__, addr, (unsigned)value));
    207 
    208     addr >>= 2;
    209     switch (addr)
    210     {
    211         case RW_PA_DOUT:
    212             /* Decode nand pins.  */
    213             s->nand->ale = !!(value & (1 << 6));
    214             s->nand->cle = !!(value & (1 << 5));
    215             s->nand->ce  = !!(value & (1 << 4));
    216 
    217             s->regs[addr] = value;
    218             break;
    219 
    220         case RW_PD_DOUT:
    221             /* Temp sensor clk.  */
    222             if ((s->regs[addr] ^ value) & 2)
    223                 tempsensor_clkedge(&s->tempsensor, !!(value & 2),
    224                                    !!(value & 16));
    225             s->regs[addr] = value;
    226             break;
    227 
    228         default:
    229             s->regs[addr] = value;
    230             break;
    231     }
    232 }
    233 
    234 static const MemoryRegionOps gpio_ops = {
    235     .read = gpio_read,
    236     .write = gpio_write,
    237     .endianness = DEVICE_NATIVE_ENDIAN,
    238     .valid = {
    239         .min_access_size = 4,
    240         .max_access_size = 4,
    241     },
    242 };
    243 
    244 #define INTMEM_SIZE (128 * KiB)
    245 
    246 static struct cris_load_info li;
    247 
    248 static
    249 void axisdev88_init(MachineState *machine)
    250 {
    251     const char *kernel_filename = machine->kernel_filename;
    252     const char *kernel_cmdline = machine->kernel_cmdline;
    253     CRISCPU *cpu;
    254     DeviceState *dev;
    255     SysBusDevice *s;
    256     DriveInfo *nand;
    257     qemu_irq irq[30], nmi[2];
    258     void *etraxfs_dmac;
    259     struct etraxfs_dma_client *dma_eth;
    260     int i;
    261     MemoryRegion *address_space_mem = get_system_memory();
    262     MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
    263 
    264     /* init CPUs */
    265     cpu = CRIS_CPU(cpu_create(machine->cpu_type));
    266 
    267     memory_region_add_subregion(address_space_mem, 0x40000000, machine->ram);
    268 
    269     /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
    270        internal memory.  */
    271     memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram",
    272                            INTMEM_SIZE, &error_fatal);
    273     memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
    274 
    275       /* Attach a NAND flash to CS1.  */
    276     nand = drive_get(IF_MTD, 0, 0);
    277     nand_state.nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
    278                                 NAND_MFR_STMICRO, 0x39);
    279     memory_region_init_io(&nand_state.iomem, NULL, &nand_ops, &nand_state,
    280                           "nand", 0x05000000);
    281     memory_region_add_subregion(address_space_mem, 0x10000000,
    282                                 &nand_state.iomem);
    283 
    284     gpio_state.nand = &nand_state;
    285     memory_region_init_io(&gpio_state.iomem, NULL, &gpio_ops, &gpio_state,
    286                           "gpio", 0x5c);
    287     memory_region_add_subregion(address_space_mem, 0x3001a000,
    288                                 &gpio_state.iomem);
    289 
    290 
    291     dev = qdev_new("etraxfs-pic");
    292     s = SYS_BUS_DEVICE(dev);
    293     sysbus_realize_and_unref(s, &error_fatal);
    294     sysbus_mmio_map(s, 0, 0x3001c000);
    295     sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ));
    296     sysbus_connect_irq(s, 1, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_NMI));
    297     for (i = 0; i < 30; i++) {
    298         irq[i] = qdev_get_gpio_in(dev, i);
    299     }
    300     nmi[0] = qdev_get_gpio_in(dev, 30);
    301     nmi[1] = qdev_get_gpio_in(dev, 31);
    302 
    303     etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
    304     for (i = 0; i < 10; i++) {
    305         /* On ETRAX, odd numbered channels are inputs.  */
    306         etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
    307     }
    308 
    309     /* Add the two ethernet blocks.  */
    310     dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels.  */
    311     etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]);
    312     if (nb_nics > 1) {
    313         etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]);
    314     }
    315 
    316     /* The DMA Connector block is missing, hardwire things for now.  */
    317     etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
    318     etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
    319     if (nb_nics > 1) {
    320         etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
    321         etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
    322     }
    323 
    324     /* 2 timers.  */
    325     sysbus_create_varargs("etraxfs-timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
    326     sysbus_create_varargs("etraxfs-timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
    327 
    328     for (i = 0; i < 4; i++) {
    329         etraxfs_ser_create(0x30026000 + i * 0x2000, irq[0x14 + i], serial_hd(i));
    330     }
    331 
    332     if (kernel_filename) {
    333         li.image_filename = kernel_filename;
    334         li.cmdline = kernel_cmdline;
    335         li.ram_size = machine->ram_size;
    336         cris_load_image(cpu, &li);
    337     } else if (!qtest_enabled()) {
    338         fprintf(stderr, "Kernel image must be specified\n");
    339         exit(1);
    340     }
    341 }
    342 
    343 static void axisdev88_machine_init(MachineClass *mc)
    344 {
    345     mc->desc = "AXIS devboard 88";
    346     mc->init = axisdev88_init;
    347     mc->is_default = true;
    348     mc->default_cpu_type = CRIS_CPU_TYPE_NAME("crisv32");
    349     mc->default_ram_id = "axisdev88.ram";
    350 }
    351 
    352 DEFINE_MACHINE("axis-dev88", axisdev88_machine_init)