|
|
1.1 ! root 1: /* ! 2: * TI OMAP general purpose memory controller emulation. ! 3: * ! 4: * Copyright (C) 2007-2009 Nokia Corporation ! 5: * Original code written by Andrzej Zaborowski <[email protected]> ! 6: * Enhancements for OMAP3 and NAND support written by Juha Riihimäki ! 7: * ! 8: * This program is free software; you can redistribute it and/or ! 9: * modify it under the terms of the GNU General Public License as ! 10: * published by the Free Software Foundation; either version 2 or ! 11: * (at your option) any later version of the License. ! 12: * ! 13: * This program is distributed in the hope that it will be useful, ! 14: * but WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ! 16: * GNU General Public License for more details. ! 17: * ! 18: * You should have received a copy of the GNU General Public License along ! 19: * with this program; if not, see <http://www.gnu.org/licenses/>. ! 20: */ ! 21: #include "hw.h" ! 22: #include "flash.h" ! 23: #include "omap.h" ! 24: ! 25: /* General-Purpose Memory Controller */ ! 26: struct omap_gpmc_s { ! 27: qemu_irq irq; ! 28: ! 29: uint8_t sysconfig; ! 30: uint16_t irqst; ! 31: uint16_t irqen; ! 32: uint16_t timeout; ! 33: uint16_t config; ! 34: uint32_t prefconfig[2]; ! 35: int prefcontrol; ! 36: int preffifo; ! 37: int prefcount; ! 38: struct omap_gpmc_cs_file_s { ! 39: uint32_t config[7]; ! 40: target_phys_addr_t base; ! 41: size_t size; ! 42: int iomemtype; ! 43: void (*base_update)(void *opaque, target_phys_addr_t new); ! 44: void (*unmap)(void *opaque); ! 45: void *opaque; ! 46: } cs_file[8]; ! 47: int ecc_cs; ! 48: int ecc_ptr; ! 49: uint32_t ecc_cfg; ! 50: ECCState ecc[9]; ! 51: }; ! 52: ! 53: static void omap_gpmc_int_update(struct omap_gpmc_s *s) ! 54: { ! 55: qemu_set_irq(s->irq, s->irqen & s->irqst); ! 56: } ! 57: ! 58: static void omap_gpmc_cs_map(struct omap_gpmc_cs_file_s *f, int base, int mask) ! 59: { ! 60: /* TODO: check for overlapping regions and report access errors */ ! 61: if ((mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf) || ! 62: (base < 0 || base >= 0x40) || ! 63: (base & 0x0f & ~mask)) { ! 64: fprintf(stderr, "%s: wrong cs address mapping/decoding!\n", ! 65: __FUNCTION__); ! 66: return; ! 67: } ! 68: ! 69: if (!f->opaque) ! 70: return; ! 71: ! 72: f->base = base << 24; ! 73: f->size = (0x0fffffff & ~(mask << 24)) + 1; ! 74: /* TODO: rather than setting the size of the mapping (which should be ! 75: * constant), the mask should cause wrapping of the address space, so ! 76: * that the same memory becomes accessible at every <i>size</i> bytes ! 77: * starting from <i>base</i>. */ ! 78: if (f->iomemtype) ! 79: cpu_register_physical_memory(f->base, f->size, f->iomemtype); ! 80: ! 81: if (f->base_update) ! 82: f->base_update(f->opaque, f->base); ! 83: } ! 84: ! 85: static void omap_gpmc_cs_unmap(struct omap_gpmc_cs_file_s *f) ! 86: { ! 87: if (f->size) { ! 88: if (f->unmap) ! 89: f->unmap(f->opaque); ! 90: if (f->iomemtype) ! 91: cpu_register_physical_memory(f->base, f->size, IO_MEM_UNASSIGNED); ! 92: f->base = 0; ! 93: f->size = 0; ! 94: } ! 95: } ! 96: ! 97: void omap_gpmc_reset(struct omap_gpmc_s *s) ! 98: { ! 99: int i; ! 100: ! 101: s->sysconfig = 0; ! 102: s->irqst = 0; ! 103: s->irqen = 0; ! 104: omap_gpmc_int_update(s); ! 105: s->timeout = 0; ! 106: s->config = 0xa00; ! 107: s->prefconfig[0] = 0x00004000; ! 108: s->prefconfig[1] = 0x00000000; ! 109: s->prefcontrol = 0; ! 110: s->preffifo = 0; ! 111: s->prefcount = 0; ! 112: for (i = 0; i < 8; i ++) { ! 113: if (s->cs_file[i].config[6] & (1 << 6)) /* CSVALID */ ! 114: omap_gpmc_cs_unmap(s->cs_file + i); ! 115: s->cs_file[i].config[0] = i ? 1 << 12 : 0; ! 116: s->cs_file[i].config[1] = 0x101001; ! 117: s->cs_file[i].config[2] = 0x020201; ! 118: s->cs_file[i].config[3] = 0x10031003; ! 119: s->cs_file[i].config[4] = 0x10f1111; ! 120: s->cs_file[i].config[5] = 0; ! 121: s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6); ! 122: if (s->cs_file[i].config[6] & (1 << 6)) /* CSVALID */ ! 123: omap_gpmc_cs_map(&s->cs_file[i], ! 124: s->cs_file[i].config[6] & 0x1f, /* MASKADDR */ ! 125: (s->cs_file[i].config[6] >> 8 & 0xf)); /* BASEADDR */ ! 126: } ! 127: omap_gpmc_cs_map(s->cs_file, 0, 0xf); ! 128: s->ecc_cs = 0; ! 129: s->ecc_ptr = 0; ! 130: s->ecc_cfg = 0x3fcff000; ! 131: for (i = 0; i < 9; i ++) ! 132: ecc_reset(&s->ecc[i]); ! 133: } ! 134: ! 135: static uint32_t omap_gpmc_read(void *opaque, target_phys_addr_t addr) ! 136: { ! 137: struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; ! 138: int cs; ! 139: struct omap_gpmc_cs_file_s *f; ! 140: ! 141: switch (addr) { ! 142: case 0x000: /* GPMC_REVISION */ ! 143: return 0x20; ! 144: ! 145: case 0x010: /* GPMC_SYSCONFIG */ ! 146: return s->sysconfig; ! 147: ! 148: case 0x014: /* GPMC_SYSSTATUS */ ! 149: return 1; /* RESETDONE */ ! 150: ! 151: case 0x018: /* GPMC_IRQSTATUS */ ! 152: return s->irqst; ! 153: ! 154: case 0x01c: /* GPMC_IRQENABLE */ ! 155: return s->irqen; ! 156: ! 157: case 0x040: /* GPMC_TIMEOUT_CONTROL */ ! 158: return s->timeout; ! 159: ! 160: case 0x044: /* GPMC_ERR_ADDRESS */ ! 161: case 0x048: /* GPMC_ERR_TYPE */ ! 162: return 0; ! 163: ! 164: case 0x050: /* GPMC_CONFIG */ ! 165: return s->config; ! 166: ! 167: case 0x054: /* GPMC_STATUS */ ! 168: return 0x001; ! 169: ! 170: case 0x060 ... 0x1d4: ! 171: cs = (addr - 0x060) / 0x30; ! 172: addr -= cs * 0x30; ! 173: f = s->cs_file + cs; ! 174: switch (addr) { ! 175: case 0x60: /* GPMC_CONFIG1 */ ! 176: return f->config[0]; ! 177: case 0x64: /* GPMC_CONFIG2 */ ! 178: return f->config[1]; ! 179: case 0x68: /* GPMC_CONFIG3 */ ! 180: return f->config[2]; ! 181: case 0x6c: /* GPMC_CONFIG4 */ ! 182: return f->config[3]; ! 183: case 0x70: /* GPMC_CONFIG5 */ ! 184: return f->config[4]; ! 185: case 0x74: /* GPMC_CONFIG6 */ ! 186: return f->config[5]; ! 187: case 0x78: /* GPMC_CONFIG7 */ ! 188: return f->config[6]; ! 189: case 0x84: /* GPMC_NAND_DATA */ ! 190: return 0; ! 191: } ! 192: break; ! 193: ! 194: case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ ! 195: return s->prefconfig[0]; ! 196: case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ ! 197: return s->prefconfig[1]; ! 198: case 0x1ec: /* GPMC_PREFETCH_CONTROL */ ! 199: return s->prefcontrol; ! 200: case 0x1f0: /* GPMC_PREFETCH_STATUS */ ! 201: return (s->preffifo << 24) | ! 202: ((s->preffifo > ! 203: ((s->prefconfig[0] >> 8) & 0x7f) ? 1 : 0) << 16) | ! 204: s->prefcount; ! 205: ! 206: case 0x1f4: /* GPMC_ECC_CONFIG */ ! 207: return s->ecc_cs; ! 208: case 0x1f8: /* GPMC_ECC_CONTROL */ ! 209: return s->ecc_ptr; ! 210: case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ ! 211: return s->ecc_cfg; ! 212: case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ ! 213: cs = (addr & 0x1f) >> 2; ! 214: /* TODO: check correctness */ ! 215: return ! 216: ((s->ecc[cs].cp & 0x07) << 0) | ! 217: ((s->ecc[cs].cp & 0x38) << 13) | ! 218: ((s->ecc[cs].lp[0] & 0x1ff) << 3) | ! 219: ((s->ecc[cs].lp[1] & 0x1ff) << 19); ! 220: ! 221: case 0x230: /* GPMC_TESTMODE_CTRL */ ! 222: return 0; ! 223: case 0x234: /* GPMC_PSA_LSB */ ! 224: case 0x238: /* GPMC_PSA_MSB */ ! 225: return 0x00000000; ! 226: } ! 227: ! 228: OMAP_BAD_REG(addr); ! 229: return 0; ! 230: } ! 231: ! 232: static void omap_gpmc_write(void *opaque, target_phys_addr_t addr, ! 233: uint32_t value) ! 234: { ! 235: struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque; ! 236: int cs; ! 237: struct omap_gpmc_cs_file_s *f; ! 238: ! 239: switch (addr) { ! 240: case 0x000: /* GPMC_REVISION */ ! 241: case 0x014: /* GPMC_SYSSTATUS */ ! 242: case 0x054: /* GPMC_STATUS */ ! 243: case 0x1f0: /* GPMC_PREFETCH_STATUS */ ! 244: case 0x200 ... 0x220: /* GPMC_ECC_RESULT */ ! 245: case 0x234: /* GPMC_PSA_LSB */ ! 246: case 0x238: /* GPMC_PSA_MSB */ ! 247: OMAP_RO_REG(addr); ! 248: break; ! 249: ! 250: case 0x010: /* GPMC_SYSCONFIG */ ! 251: if ((value >> 3) == 0x3) ! 252: fprintf(stderr, "%s: bad SDRAM idle mode %i\n", ! 253: __FUNCTION__, value >> 3); ! 254: if (value & 2) ! 255: omap_gpmc_reset(s); ! 256: s->sysconfig = value & 0x19; ! 257: break; ! 258: ! 259: case 0x018: /* GPMC_IRQSTATUS */ ! 260: s->irqen = ~value; ! 261: omap_gpmc_int_update(s); ! 262: break; ! 263: ! 264: case 0x01c: /* GPMC_IRQENABLE */ ! 265: s->irqen = value & 0xf03; ! 266: omap_gpmc_int_update(s); ! 267: break; ! 268: ! 269: case 0x040: /* GPMC_TIMEOUT_CONTROL */ ! 270: s->timeout = value & 0x1ff1; ! 271: break; ! 272: ! 273: case 0x044: /* GPMC_ERR_ADDRESS */ ! 274: case 0x048: /* GPMC_ERR_TYPE */ ! 275: break; ! 276: ! 277: case 0x050: /* GPMC_CONFIG */ ! 278: s->config = value & 0xf13; ! 279: break; ! 280: ! 281: case 0x060 ... 0x1d4: ! 282: cs = (addr - 0x060) / 0x30; ! 283: addr -= cs * 0x30; ! 284: f = s->cs_file + cs; ! 285: switch (addr) { ! 286: case 0x60: /* GPMC_CONFIG1 */ ! 287: f->config[0] = value & 0xffef3e13; ! 288: break; ! 289: case 0x64: /* GPMC_CONFIG2 */ ! 290: f->config[1] = value & 0x001f1f8f; ! 291: break; ! 292: case 0x68: /* GPMC_CONFIG3 */ ! 293: f->config[2] = value & 0x001f1f8f; ! 294: break; ! 295: case 0x6c: /* GPMC_CONFIG4 */ ! 296: f->config[3] = value & 0x1f8f1f8f; ! 297: break; ! 298: case 0x70: /* GPMC_CONFIG5 */ ! 299: f->config[4] = value & 0x0f1f1f1f; ! 300: break; ! 301: case 0x74: /* GPMC_CONFIG6 */ ! 302: f->config[5] = value & 0x00000fcf; ! 303: break; ! 304: case 0x78: /* GPMC_CONFIG7 */ ! 305: if ((f->config[6] ^ value) & 0xf7f) { ! 306: if (f->config[6] & (1 << 6)) /* CSVALID */ ! 307: omap_gpmc_cs_unmap(f); ! 308: if (value & (1 << 6)) /* CSVALID */ ! 309: omap_gpmc_cs_map(f, value & 0x1f, /* MASKADDR */ ! 310: (value >> 8 & 0xf)); /* BASEADDR */ ! 311: } ! 312: f->config[6] = value & 0x00000f7f; ! 313: break; ! 314: case 0x7c: /* GPMC_NAND_COMMAND */ ! 315: case 0x80: /* GPMC_NAND_ADDRESS */ ! 316: case 0x84: /* GPMC_NAND_DATA */ ! 317: break; ! 318: ! 319: default: ! 320: goto bad_reg; ! 321: } ! 322: break; ! 323: ! 324: case 0x1e0: /* GPMC_PREFETCH_CONFIG1 */ ! 325: s->prefconfig[0] = value & 0x7f8f7fbf; ! 326: /* TODO: update interrupts, fifos, dmas */ ! 327: break; ! 328: ! 329: case 0x1e4: /* GPMC_PREFETCH_CONFIG2 */ ! 330: s->prefconfig[1] = value & 0x3fff; ! 331: break; ! 332: ! 333: case 0x1ec: /* GPMC_PREFETCH_CONTROL */ ! 334: s->prefcontrol = value & 1; ! 335: if (s->prefcontrol) { ! 336: if (s->prefconfig[0] & 1) ! 337: s->preffifo = 0x40; ! 338: else ! 339: s->preffifo = 0x00; ! 340: } ! 341: /* TODO: start */ ! 342: break; ! 343: ! 344: case 0x1f4: /* GPMC_ECC_CONFIG */ ! 345: s->ecc_cs = 0x8f; ! 346: break; ! 347: case 0x1f8: /* GPMC_ECC_CONTROL */ ! 348: if (value & (1 << 8)) ! 349: for (cs = 0; cs < 9; cs ++) ! 350: ecc_reset(&s->ecc[cs]); ! 351: s->ecc_ptr = value & 0xf; ! 352: if (s->ecc_ptr == 0 || s->ecc_ptr > 9) { ! 353: s->ecc_ptr = 0; ! 354: s->ecc_cs &= ~1; ! 355: } ! 356: break; ! 357: case 0x1fc: /* GPMC_ECC_SIZE_CONFIG */ ! 358: s->ecc_cfg = value & 0x3fcff1ff; ! 359: break; ! 360: case 0x230: /* GPMC_TESTMODE_CTRL */ ! 361: if (value & 7) ! 362: fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__); ! 363: break; ! 364: ! 365: default: ! 366: bad_reg: ! 367: OMAP_BAD_REG(addr); ! 368: return; ! 369: } ! 370: } ! 371: ! 372: static CPUReadMemoryFunc * const omap_gpmc_readfn[] = { ! 373: omap_badwidth_read32, /* TODO */ ! 374: omap_badwidth_read32, /* TODO */ ! 375: omap_gpmc_read, ! 376: }; ! 377: ! 378: static CPUWriteMemoryFunc * const omap_gpmc_writefn[] = { ! 379: omap_badwidth_write32, /* TODO */ ! 380: omap_badwidth_write32, /* TODO */ ! 381: omap_gpmc_write, ! 382: }; ! 383: ! 384: struct omap_gpmc_s *omap_gpmc_init(target_phys_addr_t base, qemu_irq irq) ! 385: { ! 386: int iomemtype; ! 387: struct omap_gpmc_s *s = (struct omap_gpmc_s *) ! 388: qemu_mallocz(sizeof(struct omap_gpmc_s)); ! 389: ! 390: omap_gpmc_reset(s); ! 391: ! 392: iomemtype = cpu_register_io_memory(omap_gpmc_readfn, ! 393: omap_gpmc_writefn, s); ! 394: cpu_register_physical_memory(base, 0x1000, iomemtype); ! 395: ! 396: return s; ! 397: } ! 398: ! 399: void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, int iomemtype, ! 400: void (*base_upd)(void *opaque, target_phys_addr_t new), ! 401: void (*unmap)(void *opaque), void *opaque) ! 402: { ! 403: struct omap_gpmc_cs_file_s *f; ! 404: ! 405: if (cs < 0 || cs >= 8) { ! 406: fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs); ! 407: exit(-1); ! 408: } ! 409: f = &s->cs_file[cs]; ! 410: ! 411: f->iomemtype = iomemtype; ! 412: f->base_update = base_upd; ! 413: f->unmap = unmap; ! 414: f->opaque = opaque; ! 415: ! 416: if (f->config[6] & (1 << 6)) /* CSVALID */ ! 417: omap_gpmc_cs_map(f, f->config[6] & 0x1f, /* MASKADDR */ ! 418: (f->config[6] >> 8 & 0xf)); /* BASEADDR */ ! 419: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.