axis_dev88.c 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * QEMU model for the AXIS devboard 88.
 *
 * Copyright (c) 2009 Edgar E. Iglesias, Axis Communications AB.
 *
 * 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.
 */
E
Edgar E. Iglesias 已提交
24

P
Peter Maydell 已提交
25
#include "qemu/osdep.h"
26
#include "qapi/error.h"
27 28
#include "qemu-common.h"
#include "cpu.h"
29
#include "hw/sysbus.h"
P
Paolo Bonzini 已提交
30
#include "net/net.h"
P
Paolo Bonzini 已提交
31
#include "hw/block/flash.h"
32
#include "hw/boards.h"
P
Paolo Bonzini 已提交
33
#include "hw/cris/etraxfs.h"
34
#include "hw/loader.h"
B
Blue Swirl 已提交
35
#include "elf.h"
36
#include "boot.h"
37
#include "sysemu/block-backend.h"
38
#include "exec/address-spaces.h"
39
#include "sysemu/qtest.h"
X
xiaoqiang zhao 已提交
40
#include "sysemu/sysemu.h"
41 42 43 44 45 46

#define D(x)
#define DNAND(x)

struct nand_state_t
{
J
Juha Riihimäki 已提交
47
    DeviceState *nand;
A
Avi Kivity 已提交
48
    MemoryRegion iomem;
49 50 51 52 53 54 55
    unsigned int rdy:1;
    unsigned int ale:1;
    unsigned int cle:1;
    unsigned int ce:1;
};

static struct nand_state_t nand_state;
A
Avi Kivity 已提交
56
static uint64_t nand_read(void *opaque, hwaddr addr, unsigned size)
57 58 59 60 61 62 63 64 65 66 67 68 69 70
{
    struct nand_state_t *s = opaque;
    uint32_t r;
    int rdy;

    r = nand_getio(s->nand);
    nand_getpins(s->nand, &rdy);
    s->rdy = rdy;

    DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r));
    return r;
}

static void
A
Avi Kivity 已提交
71
nand_write(void *opaque, hwaddr addr, uint64_t value,
A
Avi Kivity 已提交
72
           unsigned size)
73 74 75 76
{
    struct nand_state_t *s = opaque;
    int rdy;

A
Avi Kivity 已提交
77
    DNAND(printf("%s addr=%x v=%x\n", __func__, addr, (unsigned)value));
78 79 80 81 82 83
    nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
    nand_setio(s->nand, value);
    nand_getpins(s->nand, &rdy);
    s->rdy = rdy;
}

A
Avi Kivity 已提交
84 85 86 87
static const MemoryRegionOps nand_ops = {
    .read = nand_read,
    .write = nand_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
88 89
};

90 91 92 93 94 95 96 97 98 99 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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
struct tempsensor_t
{
    unsigned int shiftreg;
    unsigned int count;
    enum {
        ST_OUT, ST_IN, ST_Z
    } state;

    uint16_t regs[3];
};

static void tempsensor_clkedge(struct tempsensor_t *s,
                               unsigned int clk, unsigned int data_in)
{
    D(printf("%s clk=%d state=%d sr=%x\n", __func__,
             clk, s->state, s->shiftreg));
    if (s->count == 0) {
        s->count = 16;
        s->state = ST_OUT;
    }
    switch (s->state) {
        case ST_OUT:
            /* Output reg is clocked at negedge.  */
            if (!clk) {
                s->count--;
                s->shiftreg <<= 1;
                if (s->count == 0) {
                    s->shiftreg = 0;
                    s->state = ST_IN;
                    s->count = 16;
                }
            }
            break;
        case ST_Z:
            if (clk) {
                s->count--;
                if (s->count == 0) {
                    s->shiftreg = 0;
                    s->state = ST_OUT;
                    s->count = 16;
                }
            }
            break;
        case ST_IN:
            /* Indata is sampled at posedge.  */
            if (clk) {
                s->count--;
                s->shiftreg <<= 1;
                s->shiftreg |= data_in & 1;
                if (s->count == 0) {
                    D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
                    s->regs[0] = s->shiftreg;
                    s->state = ST_OUT;
                    s->count = 16;

                    if ((s->regs[0] & 0xff) == 0) {
V
Veres Lajos 已提交
146
                        /* 25 degrees celsius.  */
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
                        s->shiftreg = 0x0b9f;
                    } else if ((s->regs[0] & 0xff) == 0xff) {
                        /* Sensor ID, 0x8100 LM70.  */
                        s->shiftreg = 0x8100;
                    } else
                        printf("Invalid tempsens state %x\n", s->regs[0]);
                }
            }
            break;
    }
}


#define RW_PA_DOUT    0x00
#define R_PA_DIN      0x01
#define RW_PA_OE      0x02
#define RW_PD_DOUT    0x10
#define R_PD_DIN      0x11
#define RW_PD_OE      0x12

static struct gpio_state_t
168
{
A
Avi Kivity 已提交
169
    MemoryRegion iomem;
170
    struct nand_state_t *nand;
171
    struct tempsensor_t tempsensor;
172 173 174
    uint32_t regs[0x5c / 4];
} gpio_state;

A
Avi Kivity 已提交
175
static uint64_t gpio_read(void *opaque, hwaddr addr, unsigned size)
176 177 178 179 180 181 182 183 184 185 186 187 188
{
    struct gpio_state_t *s = opaque;
    uint32_t r = 0;

    addr >>= 2;
    switch (addr)
    {
        case R_PA_DIN:
            r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];

            /* Encode pins from the nand.  */
            r |= s->nand->rdy << 7;
            break;
189 190 191 192 193 194 195
        case R_PD_DIN:
            r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];

            /* Encode temp sensor pins.  */
            r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4;
            break;

196 197 198 199 200 201 202 203
        default:
            r = s->regs[addr];
            break;
    }
    return r;
    D(printf("%s %x=%x\n", __func__, addr, r));
}

A
Avi Kivity 已提交
204
static void gpio_write(void *opaque, hwaddr addr, uint64_t value,
A
Avi Kivity 已提交
205
                       unsigned size)
206 207
{
    struct gpio_state_t *s = opaque;
A
Avi Kivity 已提交
208
    D(printf("%s %x=%x\n", __func__, addr, (unsigned)value));
209 210 211 212 213 214 215 216 217 218 219 220

    addr >>= 2;
    switch (addr)
    {
        case RW_PA_DOUT:
            /* Decode nand pins.  */
            s->nand->ale = !!(value & (1 << 6));
            s->nand->cle = !!(value & (1 << 5));
            s->nand->ce  = !!(value & (1 << 4));

            s->regs[addr] = value;
            break;
221 222 223 224 225 226 227 228 229

        case RW_PD_DOUT:
            /* Temp sensor clk.  */
            if ((s->regs[addr] ^ value) & 2)
                tempsensor_clkedge(&s->tempsensor, !!(value & 2),
                                   !!(value & 16));
            s->regs[addr] = value;
            break;

230 231 232 233 234 235
        default:
            s->regs[addr] = value;
            break;
    }
}

A
Avi Kivity 已提交
236 237 238 239 240 241 242 243
static const MemoryRegionOps gpio_ops = {
    .read = gpio_read,
    .write = gpio_write,
    .endianness = DEVICE_NATIVE_ENDIAN,
    .valid = {
        .min_access_size = 4,
        .max_access_size = 4,
    },
244 245 246 247
};

#define INTMEM_SIZE (128 * 1024)

248
static struct cris_load_info li;
249

250
static
251
void axisdev88_init(MachineState *machine)
252
{
253 254 255 256
    ram_addr_t ram_size = machine->ram_size;
    const char *cpu_model = machine->cpu_model;
    const char *kernel_filename = machine->kernel_filename;
    const char *kernel_cmdline = machine->kernel_cmdline;
257
    CRISCPU *cpu;
A
Andreas Färber 已提交
258
    CPUCRISState *env;
259 260
    DeviceState *dev;
    SysBusDevice *s;
261
    DriveInfo *nand;
262
    qemu_irq irq[30], nmi[2];
263
    void *etraxfs_dmac;
264
    struct etraxfs_dma_client *dma_eth;
265
    int i;
266 267 268
    MemoryRegion *address_space_mem = get_system_memory();
    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
    MemoryRegion *phys_intmem = g_new(MemoryRegion, 1);
269 270 271 272 273

    /* init CPUs */
    if (cpu_model == NULL) {
        cpu_model = "crisv32";
    }
274 275
    cpu = cpu_cris_init(cpu_model);
    env = &cpu->env;
276 277

    /* allocate RAM */
278 279
    memory_region_allocate_system_memory(phys_ram, NULL, "axisdev88.ram",
                                         ram_size);
280
    memory_region_add_subregion(address_space_mem, 0x40000000, phys_ram);
281 282 283

    /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
       internal memory.  */
284
    memory_region_init_ram(phys_intmem, NULL, "axisdev88.chipram", INTMEM_SIZE,
285
                           &error_fatal);
286
    vmstate_register_ram_global(phys_intmem);
287
    memory_region_add_subregion(address_space_mem, 0x38000000, phys_intmem);
288 289

      /* Attach a NAND flash to CS1.  */
290
    nand = drive_get(IF_MTD, 0, 0);
291
    nand_state.nand = nand_init(nand ? blk_by_legacy_dinfo(nand) : NULL,
292
                                NAND_MFR_STMICRO, 0x39);
293
    memory_region_init_io(&nand_state.iomem, NULL, &nand_ops, &nand_state,
A
Avi Kivity 已提交
294 295 296
                          "nand", 0x05000000);
    memory_region_add_subregion(address_space_mem, 0x10000000,
                                &nand_state.iomem);
297 298

    gpio_state.nand = &nand_state;
299
    memory_region_init_io(&gpio_state.iomem, NULL, &gpio_ops, &gpio_state,
A
Avi Kivity 已提交
300 301 302
                          "gpio", 0x5c);
    memory_region_add_subregion(address_space_mem, 0x3001a000,
                                &gpio_state.iomem);
303 304


305 306
    dev = qdev_create(NULL, "etraxfs,pic");
    /* FIXME: Is there a proper way to signal vectors to the CPU core?  */
G
Gerd Hoffmann 已提交
307
    qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
M
Markus Armbruster 已提交
308
    qdev_init_nofail(dev);
309
    s = SYS_BUS_DEVICE(dev);
310
    sysbus_mmio_map(s, 0, 0x3001c000);
311 312
    sysbus_connect_irq(s, 0, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_IRQ));
    sysbus_connect_irq(s, 1, qdev_get_gpio_in(DEVICE(cpu), CRIS_CPU_NMI));
313
    for (i = 0; i < 30; i++) {
P
Paul Brook 已提交
314
        irq[i] = qdev_get_gpio_in(dev, i);
315
    }
P
Paul Brook 已提交
316 317
    nmi[0] = qdev_get_gpio_in(dev, 30);
    nmi[1] = qdev_get_gpio_in(dev, 31);
318

319
    etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
320 321
    for (i = 0; i < 10; i++) {
        /* On ETRAX, odd numbered channels are inputs.  */
322
        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
323 324 325
    }

    /* Add the two ethernet blocks.  */
326
    dma_eth = g_malloc0(sizeof dma_eth[0] * 4); /* Allocate 4 channels.  */
327 328 329 330
    etraxfs_eth_init(&nd_table[0], 0x30034000, 1, &dma_eth[0], &dma_eth[1]);
    if (nb_nics > 1) {
        etraxfs_eth_init(&nd_table[1], 0x30036000, 2, &dma_eth[2], &dma_eth[3]);
    }
331 332

    /* The DMA Connector block is missing, hardwire things for now.  */
333 334 335 336 337
    etraxfs_dmac_connect_client(etraxfs_dmac, 0, &dma_eth[0]);
    etraxfs_dmac_connect_client(etraxfs_dmac, 1, &dma_eth[1]);
    if (nb_nics > 1) {
        etraxfs_dmac_connect_client(etraxfs_dmac, 6, &dma_eth[2]);
        etraxfs_dmac_connect_client(etraxfs_dmac, 7, &dma_eth[3]);
338 339 340
    }

    /* 2 timers.  */
E
Edgar E. Iglesias 已提交
341 342
    sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
    sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
343 344

    for (i = 0; i < 4; i++) {
X
xiaoqiang zhao 已提交
345
        etraxfs_ser_create(0x30026000 + i * 0x2000, irq[0x14 + i], serial_hds[i]);
346 347
    }

348 349 350 351 352
    if (kernel_filename) {
        li.image_filename = kernel_filename;
        li.cmdline = kernel_cmdline;
        cris_load_image(cpu, &li);
    } else if (!qtest_enabled()) {
353 354
        fprintf(stderr, "Kernel image must be specified\n");
        exit(1);
355 356 357
    }
}

358
static void axisdev88_machine_init(MachineClass *mc)
359
{
360 361 362
    mc->desc = "AXIS devboard 88";
    mc->init = axisdev88_init;
    mc->is_default = 1;
363 364
}

365
DEFINE_MACHINE("axis-dev88", axisdev88_machine_init)