Statistics
| Branch: | Revision:

root / hw / axis_dev88.c @ 4b816985

History | View | Annotate | Download (10.4 kB)

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 "sysbus.h"
26
#include "net.h"
27
#include "flash.h"
28
#include "boards.h"
29
#include "sysemu.h"
30
#include "etraxfs.h"
31

    
32
#define D(x)
33
#define DNAND(x)
34

    
35
struct nand_state_t
36
{
37
    NANDFlashState *nand;
38
    unsigned int rdy:1;
39
    unsigned int ale:1;
40
    unsigned int cle:1;
41
    unsigned int ce:1;
42
};
43

    
44
static struct nand_state_t nand_state;
45
static uint32_t nand_readl (void *opaque, target_phys_addr_t addr)
46
{
47
    struct nand_state_t *s = opaque;
48
    uint32_t r;
49
    int rdy;
50

    
51
    r = nand_getio(s->nand);
52
    nand_getpins(s->nand, &rdy);
53
    s->rdy = rdy;
54

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

    
59
static void
60
nand_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
61
{
62
    struct nand_state_t *s = opaque;
63
    int rdy;
64

    
65
    DNAND(printf("%s addr=%x v=%x\n", __func__, addr, value));
66
    nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0);
67
    nand_setio(s->nand, value);
68
    nand_getpins(s->nand, &rdy);
69
    s->rdy = rdy;
70
}
71

    
72
static CPUReadMemoryFunc *nand_read[] = {
73
    &nand_readl,
74
    &nand_readl,
75
    &nand_readl,
76
};
77

    
78
static CPUWriteMemoryFunc *nand_write[] = {
79
    &nand_writel,
80
    &nand_writel,
81
    &nand_writel,
82
};
83

    
84

    
85
struct tempsensor_t
86
{
87
    unsigned int shiftreg;
88
    unsigned int count;
89
    enum {
90
        ST_OUT, ST_IN, ST_Z
91
    } state;
92

    
93
    uint16_t regs[3];
94
};
95

    
96
static void tempsensor_clkedge(struct tempsensor_t *s,
97
                               unsigned int clk, unsigned int data_in)
98
{
99
    D(printf("%s clk=%d state=%d sr=%x\n", __func__,
100
             clk, s->state, s->shiftreg));
101
    if (s->count == 0) {
102
        s->count = 16;
103
        s->state = ST_OUT;
104
    }
105
    switch (s->state) {
106
        case ST_OUT:
107
            /* Output reg is clocked at negedge.  */
108
            if (!clk) {
109
                s->count--;
110
                s->shiftreg <<= 1;
111
                if (s->count == 0) {
112
                    s->shiftreg = 0;
113
                    s->state = ST_IN;
114
                    s->count = 16;
115
                }
116
            }
117
            break;
118
        case ST_Z:
119
            if (clk) {
120
                s->count--;
121
                if (s->count == 0) {
122
                    s->shiftreg = 0;
123
                    s->state = ST_OUT;
124
                    s->count = 16;
125
                }
126
            }
127
            break;
128
        case ST_IN:
129
            /* Indata is sampled at posedge.  */
130
            if (clk) {
131
                s->count--;
132
                s->shiftreg <<= 1;
133
                s->shiftreg |= data_in & 1;
134
                if (s->count == 0) {
135
                    D(printf("%s cfgreg=%x\n", __func__, s->shiftreg));
136
                    s->regs[0] = s->shiftreg;
137
                    s->state = ST_OUT;
138
                    s->count = 16;
139

    
140
                    if ((s->regs[0] & 0xff) == 0) {
141
                        /* 25 degrees celcius.  */
142
                        s->shiftreg = 0x0b9f;
143
                    } else if ((s->regs[0] & 0xff) == 0xff) {
144
                        /* Sensor ID, 0x8100 LM70.  */
145
                        s->shiftreg = 0x8100;
146
                    } else
147
                        printf("Invalid tempsens state %x\n", s->regs[0]);
148
                }
149
            }
150
            break;
151
    }
152
}
153

    
154

    
155
#define RW_PA_DOUT    0x00
156
#define R_PA_DIN      0x01
157
#define RW_PA_OE      0x02
158
#define RW_PD_DOUT    0x10
159
#define R_PD_DIN      0x11
160
#define RW_PD_OE      0x12
161

    
162
static struct gpio_state_t
163
{
164
    struct nand_state_t *nand;
165
    struct tempsensor_t tempsensor;
166
    uint32_t regs[0x5c / 4];
167
} gpio_state;
168

    
169
static uint32_t gpio_readl (void *opaque, target_phys_addr_t addr)
170
{
171
    struct gpio_state_t *s = opaque;
172
    uint32_t r = 0;
173

    
174
    addr >>= 2;
175
    switch (addr)
176
    {
177
        case R_PA_DIN:
178
            r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE];
179

    
180
            /* Encode pins from the nand.  */
181
            r |= s->nand->rdy << 7;
182
            break;
183
        case R_PD_DIN:
184
            r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE];
185

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

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

    
198
static void gpio_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
199
{
200
    struct gpio_state_t *s = opaque;
201
    D(printf("%s %x=%x\n", __func__, addr, value));
202

    
203
    addr >>= 2;
204
    switch (addr)
205
    {
206
        case RW_PA_DOUT:
207
            /* Decode nand pins.  */
208
            s->nand->ale = !!(value & (1 << 6));
209
            s->nand->cle = !!(value & (1 << 5));
210
            s->nand->ce  = !!(value & (1 << 4));
211

    
212
            s->regs[addr] = value;
213
            break;
214

    
215
        case RW_PD_DOUT:
216
            /* Temp sensor clk.  */
217
            if ((s->regs[addr] ^ value) & 2)
218
                tempsensor_clkedge(&s->tempsensor, !!(value & 2),
219
                                   !!(value & 16));
220
            s->regs[addr] = value;
221
            break;
222

    
223
        default:
224
            s->regs[addr] = value;
225
            break;
226
    }
227
}
228

    
229
static CPUReadMemoryFunc *gpio_read[] = {
230
    NULL, NULL,
231
    &gpio_readl,
232
};
233

    
234
static CPUWriteMemoryFunc *gpio_write[] = {
235
    NULL, NULL,
236
    &gpio_writel,
237
};
238

    
239
#define INTMEM_SIZE (128 * 1024)
240

    
241
static uint32_t bootstrap_pc;
242
static void main_cpu_reset(void *opaque)
243
{
244
    CPUState *env = opaque;
245
    cpu_reset(env);
246

    
247
    env->pc = bootstrap_pc;
248
}
249

    
250
static
251
void axisdev88_init (ram_addr_t ram_size,
252
                     const char *boot_device,
253
                     const char *kernel_filename, const char *kernel_cmdline,
254
                     const char *initrd_filename, const char *cpu_model)
255
{
256
    CPUState *env;
257
    qemu_irq *irq, *nmi;
258
    void *etraxfs_dmac;
259
    struct etraxfs_dma_client *eth[2] = {NULL, NULL};
260
    int kernel_size;
261
    int i;
262
    int nand_regs;
263
    int gpio_regs;
264
    ram_addr_t phys_ram;
265
    ram_addr_t phys_intmem;
266

    
267
    /* init CPUs */
268
    if (cpu_model == NULL) {
269
        cpu_model = "crisv32";
270
    }
271
    env = cpu_init(cpu_model);
272
    qemu_register_reset(main_cpu_reset, env);
273

    
274
    /* allocate RAM */
275
    phys_ram = qemu_ram_alloc(ram_size);
276
    cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM);
277

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

    
284

    
285
      /* Attach a NAND flash to CS1.  */
286
    nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39);
287
    nand_regs = cpu_register_io_memory(0, nand_read, nand_write, &nand_state);
288
    cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs);
289

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

    
294

    
295
    irq = etraxfs_pic_init(env, 0x3001c000);
296
    nmi = irq + 30;
297

    
298
    etraxfs_dmac = etraxfs_dmac_init(env, 0x30000000, 10);
299
    for (i = 0; i < 10; i++) {
300
        /* On ETRAX, odd numbered channels are inputs.  */
301
        etraxfs_dmac_connect(etraxfs_dmac, i, irq + 7 + i, i & 1);
302
    }
303

    
304
    /* Add the two ethernet blocks.  */
305
    eth[0] = etraxfs_eth_init(&nd_table[0], env, irq + 25, 0x30034000, 1);
306
    if (nb_nics > 1)
307
        eth[1] = etraxfs_eth_init(&nd_table[1], env,
308
                                  irq + 26, 0x30036000, 2);
309

    
310
    /* The DMA Connector block is missing, hardwire things for now.  */
311
    etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]);
312
    etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1);
313
    if (eth[1]) {
314
        etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]);
315
        etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1);
316
    }
317

    
318
    /* 2 timers.  */
319
    etraxfs_timer_init(env, irq + 0x1b, nmi + 1, 0x3001e000);
320
    etraxfs_timer_init(env, irq + 0x1b, nmi + 1, 0x3005e000);
321

    
322
    for (i = 0; i < 4; i++) {
323
        sysbus_create_simple("etraxfs,serial", 0x30026000 + i * 0x2000,
324
                             irq[0x14 + i]); 
325
    }
326

    
327
    if (kernel_filename) {
328
        uint64_t entry, high;
329
        int kcmdline_len;
330

    
331
        /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis 
332
           devboard SDK.  */
333
        kernel_size = load_elf(kernel_filename, -0x80000000LL,
334
                               &entry, NULL, &high);
335
        bootstrap_pc = entry;
336
        if (kernel_size < 0) {
337
            /* Takes a kimage from the axis devboard SDK.  */
338
            kernel_size = load_image_targphys(kernel_filename, 0x40004000,
339
                                              ram_size);
340
            bootstrap_pc = 0x40004000;
341
            env->regs[9] = 0x40004000 + kernel_size;
342
        }
343
        env->regs[8] = 0x56902387; /* RAM init magic.  */
344

    
345
        if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) {
346
            if (kcmdline_len > 256) {
347
                fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n");
348
                exit(1);
349
            }
350
            /* Let the kernel know we are modifying the cmdline.  */
351
            env->regs[10] = 0x87109563;
352
            env->regs[11] = 0x40000000;
353
            pstrcpy_targphys(env->regs[11], 256, kernel_cmdline);
354
        }
355
    }
356
    env->pc = bootstrap_pc;
357

    
358
    printf ("pc =%x\n", env->pc);
359
    printf ("ram size =%ld\n", ram_size);
360
}
361

    
362
QEMUMachine axisdev88_machine = {
363
    .name = "axis-dev88",
364
    .desc = "AXIS devboard 88",
365
    .init = axisdev88_init,
366
};