Annotation of qemu/hw/omap_gpmc.c, revision 1.1.1.2

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,
1.1.1.2 ! root      393:                     omap_gpmc_writefn, s, DEVICE_NATIVE_ENDIAN);
1.1       root      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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.