|
|
1.1 ! root 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: #include <time.h> ! 25: #include <sys/time.h> ! 26: #include "hw.h" ! 27: #include "net.h" ! 28: #include "flash.h" ! 29: #include "sysemu.h" ! 30: #include "devices.h" ! 31: #include "boards.h" ! 32: ! 33: #include "etraxfs.h" ! 34: ! 35: #define D(x) ! 36: #define DNAND(x) ! 37: ! 38: struct nand_state_t ! 39: { ! 40: struct nand_flash_s *nand; ! 41: unsigned int rdy:1; ! 42: unsigned int ale:1; ! 43: unsigned int cle:1; ! 44: unsigned int ce:1; ! 45: }; ! 46: ! 47: static struct nand_state_t nand_state; ! 48: static uint32_t nand_readl (void *opaque, target_phys_addr_t addr) ! 49: { ! 50: struct nand_state_t *s = opaque; ! 51: uint32_t r; ! 52: int rdy; ! 53: ! 54: r = nand_getio(s->nand); ! 55: nand_getpins(s->nand, &rdy); ! 56: s->rdy = rdy; ! 57: ! 58: DNAND(printf("%s addr=%x r=%x\n", __func__, addr, r)); ! 59: return r; ! 60: } ! 61: ! 62: static void ! 63: nand_writel (void *opaque, target_phys_addr_t addr, uint32_t value) ! 64: { ! 65: struct nand_state_t *s = opaque; ! 66: int rdy; ! 67: ! 68: DNAND(printf("%s addr=%x v=%x\n", __func__, addr, value)); ! 69: nand_setpins(s->nand, s->cle, s->ale, s->ce, 1, 0); ! 70: nand_setio(s->nand, value); ! 71: nand_getpins(s->nand, &rdy); ! 72: s->rdy = rdy; ! 73: } ! 74: ! 75: static CPUReadMemoryFunc *nand_read[] = { ! 76: &nand_readl, ! 77: &nand_readl, ! 78: &nand_readl, ! 79: }; ! 80: ! 81: static CPUWriteMemoryFunc *nand_write[] = { ! 82: &nand_writel, ! 83: &nand_writel, ! 84: &nand_writel, ! 85: }; ! 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 celcius. */ ! 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: struct nand_state_t *nand; ! 168: struct tempsensor_t tempsensor; ! 169: uint32_t regs[0x5c / 4]; ! 170: } gpio_state; ! 171: ! 172: static uint32_t gpio_readl (void *opaque, target_phys_addr_t addr) ! 173: { ! 174: struct gpio_state_t *s = opaque; ! 175: uint32_t r = 0; ! 176: ! 177: addr >>= 2; ! 178: switch (addr) ! 179: { ! 180: case R_PA_DIN: ! 181: r = s->regs[RW_PA_DOUT] & s->regs[RW_PA_OE]; ! 182: ! 183: /* Encode pins from the nand. */ ! 184: r |= s->nand->rdy << 7; ! 185: break; ! 186: case R_PD_DIN: ! 187: r = s->regs[RW_PD_DOUT] & s->regs[RW_PD_OE]; ! 188: ! 189: /* Encode temp sensor pins. */ ! 190: r |= (!!(s->tempsensor.shiftreg & 0x10000)) << 4; ! 191: break; ! 192: ! 193: default: ! 194: r = s->regs[addr]; ! 195: break; ! 196: } ! 197: return r; ! 198: D(printf("%s %x=%x\n", __func__, addr, r)); ! 199: } ! 200: ! 201: static void gpio_writel (void *opaque, target_phys_addr_t addr, uint32_t value) ! 202: { ! 203: struct gpio_state_t *s = opaque; ! 204: D(printf("%s %x=%x\n", __func__, addr, value)); ! 205: ! 206: addr >>= 2; ! 207: switch (addr) ! 208: { ! 209: case RW_PA_DOUT: ! 210: /* Decode nand pins. */ ! 211: s->nand->ale = !!(value & (1 << 6)); ! 212: s->nand->cle = !!(value & (1 << 5)); ! 213: s->nand->ce = !!(value & (1 << 4)); ! 214: ! 215: s->regs[addr] = value; ! 216: break; ! 217: ! 218: case RW_PD_DOUT: ! 219: /* Temp sensor clk. */ ! 220: if ((s->regs[addr] ^ value) & 2) ! 221: tempsensor_clkedge(&s->tempsensor, !!(value & 2), ! 222: !!(value & 16)); ! 223: s->regs[addr] = value; ! 224: break; ! 225: ! 226: default: ! 227: s->regs[addr] = value; ! 228: break; ! 229: } ! 230: } ! 231: ! 232: static CPUReadMemoryFunc *gpio_read[] = { ! 233: NULL, NULL, ! 234: &gpio_readl, ! 235: }; ! 236: ! 237: static CPUWriteMemoryFunc *gpio_write[] = { ! 238: NULL, NULL, ! 239: &gpio_writel, ! 240: }; ! 241: ! 242: #define INTMEM_SIZE (128 * 1024) ! 243: ! 244: static uint32_t bootstrap_pc; ! 245: static void main_cpu_reset(void *opaque) ! 246: { ! 247: CPUState *env = opaque; ! 248: cpu_reset(env); ! 249: ! 250: env->pc = bootstrap_pc; ! 251: } ! 252: ! 253: static ! 254: void axisdev88_init (ram_addr_t ram_size, int vga_ram_size, ! 255: const char *boot_device, ! 256: const char *kernel_filename, const char *kernel_cmdline, ! 257: const char *initrd_filename, const char *cpu_model) ! 258: { ! 259: CPUState *env; ! 260: struct etraxfs_pic *pic; ! 261: void *etraxfs_dmac; ! 262: struct etraxfs_dma_client *eth[2] = {NULL, NULL}; ! 263: int kernel_size; ! 264: int i; ! 265: int nand_regs; ! 266: int gpio_regs; ! 267: ram_addr_t phys_ram; ! 268: ram_addr_t phys_intmem; ! 269: ! 270: /* init CPUs */ ! 271: if (cpu_model == NULL) { ! 272: cpu_model = "crisv32"; ! 273: } ! 274: env = cpu_init(cpu_model); ! 275: qemu_register_reset(main_cpu_reset, env); ! 276: ! 277: /* allocate RAM */ ! 278: phys_ram = qemu_ram_alloc(ram_size); ! 279: cpu_register_physical_memory(0x40000000, ram_size, phys_ram | IO_MEM_RAM); ! 280: ! 281: /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the ! 282: internal memory. */ ! 283: phys_intmem = qemu_ram_alloc(INTMEM_SIZE); ! 284: cpu_register_physical_memory(0x38000000, INTMEM_SIZE, ! 285: phys_intmem | IO_MEM_RAM); ! 286: ! 287: ! 288: /* Attach a NAND flash to CS1. */ ! 289: nand_state.nand = nand_init(NAND_MFR_STMICRO, 0x39); ! 290: nand_regs = cpu_register_io_memory(0, nand_read, nand_write, &nand_state); ! 291: cpu_register_physical_memory(0x10000000, 0x05000000, nand_regs); ! 292: ! 293: gpio_state.nand = &nand_state; ! 294: gpio_regs = cpu_register_io_memory(0, gpio_read, gpio_write, &gpio_state); ! 295: cpu_register_physical_memory(0x3001a000, 0x5c, gpio_regs); ! 296: ! 297: ! 298: pic = etraxfs_pic_init(env, 0x3001c000); ! 299: etraxfs_dmac = etraxfs_dmac_init(env, 0x30000000, 10); ! 300: for (i = 0; i < 10; i++) { ! 301: /* On ETRAX, odd numbered channels are inputs. */ ! 302: etraxfs_dmac_connect(etraxfs_dmac, i, pic->irq + 7 + i, i & 1); ! 303: } ! 304: ! 305: /* Add the two ethernet blocks. */ ! 306: eth[0] = etraxfs_eth_init(&nd_table[0], env, pic->irq + 25, 0x30034000, 1); ! 307: if (nb_nics > 1) ! 308: eth[1] = etraxfs_eth_init(&nd_table[1], env, ! 309: pic->irq + 26, 0x30036000, 2); ! 310: ! 311: /* The DMA Connector block is missing, hardwire things for now. */ ! 312: etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]); ! 313: etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1); ! 314: if (eth[1]) { ! 315: etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]); ! 316: etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1); ! 317: } ! 318: ! 319: /* 2 timers. */ ! 320: etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0x3001e000); ! 321: etraxfs_timer_init(env, pic->irq + 0x1b, pic->nmi + 1, 0x3005e000); ! 322: ! 323: for (i = 0; i < 4; i++) { ! 324: if (serial_hds[i]) { ! 325: etraxfs_ser_init(env, pic->irq + 0x14 + i, ! 326: serial_hds[i], 0x30026000 + i * 0x2000); ! 327: } ! 328: } ! 329: ! 330: if (kernel_filename) { ! 331: uint64_t entry, high; ! 332: int kcmdline_len; ! 333: ! 334: /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis ! 335: devboard SDK. */ ! 336: kernel_size = load_elf(kernel_filename, -0x80000000LL, ! 337: &entry, NULL, &high); ! 338: bootstrap_pc = entry; ! 339: if (kernel_size < 0) { ! 340: /* Takes a kimage from the axis devboard SDK. */ ! 341: kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000); ! 342: bootstrap_pc = 0x40004000; ! 343: env->regs[9] = 0x40004000 + kernel_size; ! 344: } ! 345: env->regs[8] = 0x56902387; /* RAM init magic. */ ! 346: ! 347: if (kernel_cmdline && (kcmdline_len = strlen(kernel_cmdline))) { ! 348: if (kcmdline_len > 256) { ! 349: fprintf(stderr, "Too long CRIS kernel cmdline (max 256)\n"); ! 350: exit(1); ! 351: } ! 352: pstrcpy_targphys(high, 256, kernel_cmdline); ! 353: /* Let the kernel know we are modifying the cmdline. */ ! 354: env->regs[10] = 0x87109563; ! 355: env->regs[11] = high; ! 356: } ! 357: } ! 358: env->pc = bootstrap_pc; ! 359: ! 360: printf ("pc =%x\n", env->pc); ! 361: printf ("ram size =%ld\n", ram_size); ! 362: } ! 363: ! 364: QEMUMachine axisdev88_machine = { ! 365: .name = "axis-dev88", ! 366: .desc = "AXIS devboard 88", ! 367: .init = axisdev88_init, ! 368: .ram_require = 0x8000000, ! 369: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.