axis_dev88.c 10.2 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 25

#include "sysbus.h"
26 27 28 29
#include "net.h"
#include "flash.h"
#include "boards.h"
#include "etraxfs.h"
B
Blue Swirl 已提交
30 31
#include "loader.h"
#include "elf.h"
32
#include "cris-boot.h"
33
#include "blockdev.h"
34 35 36 37 38 39

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

struct nand_state_t
{
J
Juha Riihimäki 已提交
40
    DeviceState *nand;
41 42 43 44 45 46 47
    unsigned int rdy:1;
    unsigned int ale:1;
    unsigned int cle:1;
    unsigned int ce:1;
};

static struct nand_state_t nand_state;
A
Anthony Liguori 已提交
48
static uint32_t nand_readl (void *opaque, target_phys_addr_t addr)
49 50 51 52 53 54 55 56 57 58 59 60 61 62
{
    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
Anthony Liguori 已提交
63
nand_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
64 65 66 67 68 69 70 71 72 73 74
{
    struct nand_state_t *s = opaque;
    int rdy;

    DNAND(printf("%s addr=%x v=%x\n", __func__, addr, value));
    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;
}

75
static CPUReadMemoryFunc * const nand_read[] = {
76 77 78 79 80
    &nand_readl,
    &nand_readl,
    &nand_readl,
};

81
static CPUWriteMemoryFunc * const nand_write[] = {
82 83 84 85 86
    &nand_writel,
    &nand_writel,
    &nand_writel,
};

87 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 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165

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) {
                        /* 25 degrees celcius.  */
                        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
166 167
{
    struct nand_state_t *nand;
168
    struct tempsensor_t tempsensor;
169 170 171
    uint32_t regs[0x5c / 4];
} gpio_state;

A
Anthony Liguori 已提交
172
static uint32_t gpio_readl (void *opaque, target_phys_addr_t addr)
173 174 175 176 177 178 179 180 181 182 183 184 185
{
    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;
186 187 188 189 190 191 192
        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;

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

A
Anthony Liguori 已提交
201
static void gpio_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
{
    struct gpio_state_t *s = opaque;
    D(printf("%s %x=%x\n", __func__, addr, value));

    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;
217 218 219 220 221 222 223 224 225

        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;

226 227 228 229 230 231
        default:
            s->regs[addr] = value;
            break;
    }
}

232
static CPUReadMemoryFunc * const gpio_read[] = {
233 234 235 236
    NULL, NULL,
    &gpio_readl,
};

237
static CPUWriteMemoryFunc * const gpio_write[] = {
238 239 240 241 242 243
    NULL, NULL,
    &gpio_writel,
};

#define INTMEM_SIZE (128 * 1024)

244
static struct cris_load_info li;
245

246
static
A
Anthony Liguori 已提交
247
void axisdev88_init (ram_addr_t ram_size,
248
                     const char *boot_device,
249 250 251 252
                     const char *kernel_filename, const char *kernel_cmdline,
                     const char *initrd_filename, const char *cpu_model)
{
    CPUState *env;
253 254
    DeviceState *dev;
    SysBusDevice *s;
255
    DriveInfo *nand;
256
    qemu_irq irq[30], nmi[2], *cpu_irq;
257 258 259 260 261
    void *etraxfs_dmac;
    struct etraxfs_dma_client *eth[2] = {NULL, NULL};
    int i;
    int nand_regs;
    int gpio_regs;
A
Anthony Liguori 已提交
262 263
    ram_addr_t phys_ram;
    ram_addr_t phys_intmem;
264 265 266 267 268 269 270 271

    /* init CPUs */
    if (cpu_model == NULL) {
        cpu_model = "crisv32";
    }
    env = cpu_init(cpu_model);

    /* allocate RAM */
272
    phys_ram = qemu_ram_alloc(NULL, "axisdev88.ram", ram_size);
273 274 275 276
    cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM);

    /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the 
       internal memory.  */
277
    phys_intmem = qemu_ram_alloc(NULL, "axisdev88.chipram", INTMEM_SIZE);
278 279 280 281 282
    cpu_register_physical_memory(0x38000000, INTMEM_SIZE,
                                 phys_intmem | IO_MEM_RAM);


      /* Attach a NAND flash to CS1.  */
283 284 285
    nand = drive_get(IF_MTD, 0, 0);
    nand_state.nand = nand_init(nand ? nand->bdrv : NULL,
                                NAND_MFR_STMICRO, 0x39);
286 287
    nand_regs = cpu_register_io_memory(nand_read, nand_write, &nand_state,
                                       DEVICE_NATIVE_ENDIAN);
288 289 290
    cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);

    gpio_state.nand = &nand_state;
291 292
    gpio_regs = cpu_register_io_memory(gpio_read, gpio_write, &gpio_state,
                                       DEVICE_NATIVE_ENDIAN);
293
    cpu_register_physical_memory(0x3001a000, 0x5c, gpio_regs);
294 295


296 297 298
    cpu_irq = cris_pic_init_cpu(env);
    dev = qdev_create(NULL, "etraxfs,pic");
    /* FIXME: Is there a proper way to signal vectors to the CPU core?  */
G
Gerd Hoffmann 已提交
299
    qdev_prop_set_ptr(dev, "interrupt_vector", &env->interrupt_vector);
M
Markus Armbruster 已提交
300
    qdev_init_nofail(dev);
301 302 303 304 305
    s = sysbus_from_qdev(dev);
    sysbus_mmio_map(s, 0, 0x3001c000);
    sysbus_connect_irq(s, 0, cpu_irq[0]);
    sysbus_connect_irq(s, 1, cpu_irq[1]);
    for (i = 0; i < 30; i++) {
P
Paul Brook 已提交
306
        irq[i] = qdev_get_gpio_in(dev, i);
307
    }
P
Paul Brook 已提交
308 309
    nmi[0] = qdev_get_gpio_in(dev, 30);
    nmi[1] = qdev_get_gpio_in(dev, 31);
310

311
    etraxfs_dmac = etraxfs_dmac_init(0x30000000, 10);
312 313
    for (i = 0; i < 10; i++) {
        /* On ETRAX, odd numbered channels are inputs.  */
314
        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
315 316 317
    }

    /* Add the two ethernet blocks.  */
318
    eth[0] = etraxfs_eth_init(&nd_table[0], 0x30034000, 1);
319
    if (nb_nics > 1)
320
        eth[1] = etraxfs_eth_init(&nd_table[1], 0x30036000, 2);
321 322 323 324 325 326 327 328 329 330

    /* The DMA Connector block is missing, hardwire things for now.  */
    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
    if (eth[1]) {
        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
    }

    /* 2 timers.  */
E
Edgar E. Iglesias 已提交
331 332
    sysbus_create_varargs("etraxfs,timer", 0x3001e000, irq[0x1b], nmi[1], NULL);
    sysbus_create_varargs("etraxfs,timer", 0x3005e000, irq[0x1b], nmi[1], NULL);
333 334

    for (i = 0; i < 4; i++) {
E
Edgar E. Iglesias 已提交
335
        sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
E
Edgar E. Iglesias 已提交
336
                             irq[0x14 + i]);
337 338
    }

339 340 341
    if (!kernel_filename) {
        fprintf(stderr, "Kernel image must be specified\n");
        exit(1);
342
    }
343 344 345 346

    li.image_filename = kernel_filename;
    li.cmdline = kernel_cmdline;
    cris_load_image(env, &li);
347 348
}

349
static QEMUMachine axisdev88_machine = {
350 351 352
    .name = "axis-dev88",
    .desc = "AXIS devboard 88",
    .init = axisdev88_init,
E
Edgar E. Iglesias 已提交
353
    .is_default = 1,
354
};
355 356 357 358 359 360 361

static void axisdev88_machine_init(void)
{
    qemu_register_machine(&axisdev88_machine);
}

machine_init(axisdev88_machine_init);