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

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"
1.1.1.3 ! root       24: #include "memory.h"
        !            25: #include "exec-memory.h"
1.1       root       26: 
                     27: /* General-Purpose Memory Controller */
                     28: struct omap_gpmc_s {
                     29:     qemu_irq irq;
1.1.1.3 ! root       30:     qemu_irq drq;
        !            31:     MemoryRegion iomem;
        !            32:     int accept_256;
1.1       root       33: 
1.1.1.3 ! root       34:     uint8_t revision;
1.1       root       35:     uint8_t sysconfig;
                     36:     uint16_t irqst;
                     37:     uint16_t irqen;
1.1.1.3 ! root       38:     uint16_t lastirq;
1.1       root       39:     uint16_t timeout;
                     40:     uint16_t config;
                     41:     struct omap_gpmc_cs_file_s {
                     42:         uint32_t config[7];
1.1.1.3 ! root       43:         MemoryRegion *iomem;
        !            44:         MemoryRegion container;
        !            45:         MemoryRegion nandiomem;
        !            46:         DeviceState *dev;
1.1       root       47:     } cs_file[8];
                     48:     int ecc_cs;
                     49:     int ecc_ptr;
                     50:     uint32_t ecc_cfg;
                     51:     ECCState ecc[9];
1.1.1.3 ! root       52:     struct prefetch {
        !            53:         uint32_t config1; /* GPMC_PREFETCH_CONFIG1 */
        !            54:         uint32_t transfercount; /* GPMC_PREFETCH_CONFIG2:TRANSFERCOUNT */
        !            55:         int startengine; /* GPMC_PREFETCH_CONTROL:STARTENGINE */
        !            56:         int fifopointer; /* GPMC_PREFETCH_STATUS:FIFOPOINTER */
        !            57:         int count; /* GPMC_PREFETCH_STATUS:COUNTVALUE */
        !            58:         MemoryRegion iomem;
        !            59:         uint8_t fifo[64];
        !            60:     } prefetch;
1.1       root       61: };
                     62: 
1.1.1.3 ! root       63: #define OMAP_GPMC_8BIT 0
        !            64: #define OMAP_GPMC_16BIT 1
        !            65: #define OMAP_GPMC_NOR 0
        !            66: #define OMAP_GPMC_NAND 2
        !            67: 
        !            68: static int omap_gpmc_devtype(struct omap_gpmc_cs_file_s *f)
        !            69: {
        !            70:     return (f->config[0] >> 10) & 3;
        !            71: }
        !            72: 
        !            73: static int omap_gpmc_devsize(struct omap_gpmc_cs_file_s *f)
        !            74: {
        !            75:     /* devsize field is really 2 bits but we ignore the high
        !            76:      * bit to ensure consistent behaviour if the guest sets
        !            77:      * it (values 2 and 3 are reserved in the TRM)
        !            78:      */
        !            79:     return (f->config[0] >> 12) & 1;
        !            80: }
        !            81: 
        !            82: /* Extract the chip-select value from the prefetch config1 register */
        !            83: static int prefetch_cs(uint32_t config1)
        !            84: {
        !            85:     return (config1 >> 24) & 7;
        !            86: }
        !            87: 
        !            88: static int prefetch_threshold(uint32_t config1)
        !            89: {
        !            90:     return (config1 >> 8) & 0x7f;
        !            91: }
        !            92: 
1.1       root       93: static void omap_gpmc_int_update(struct omap_gpmc_s *s)
                     94: {
1.1.1.3 ! root       95:     /* The TRM is a bit unclear, but it seems to say that
        !            96:      * the TERMINALCOUNTSTATUS bit is set only on the
        !            97:      * transition when the prefetch engine goes from
        !            98:      * active to inactive, whereas the FIFOEVENTSTATUS
        !            99:      * bit is held high as long as the fifo has at
        !           100:      * least THRESHOLD bytes available.
        !           101:      * So we do the latter here, but TERMINALCOUNTSTATUS
        !           102:      * is set elsewhere.
        !           103:      */
        !           104:     if (s->prefetch.fifopointer >= prefetch_threshold(s->prefetch.config1)) {
        !           105:         s->irqst |= 1;
        !           106:     }
        !           107:     if ((s->irqen & s->irqst) != s->lastirq) {
        !           108:         s->lastirq = s->irqen & s->irqst;
        !           109:         qemu_set_irq(s->irq, s->lastirq);
        !           110:     }
1.1       root      111: }
                    112: 
1.1.1.3 ! root      113: static void omap_gpmc_dma_update(struct omap_gpmc_s *s, int value)
1.1       root      114: {
1.1.1.3 ! root      115:     if (s->prefetch.config1 & 4) {
        !           116:         qemu_set_irq(s->drq, value);
        !           117:     }
        !           118: }
        !           119: 
        !           120: /* Access functions for when a NAND-like device is mapped into memory:
        !           121:  * all addresses in the region behave like accesses to the relevant
        !           122:  * GPMC_NAND_DATA_i register (which is actually implemented to call these)
        !           123:  */
        !           124: static uint64_t omap_nand_read(void *opaque, target_phys_addr_t addr,
        !           125:                                unsigned size)
        !           126: {
        !           127:     struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
        !           128:     uint64_t v;
        !           129:     nand_setpins(f->dev, 0, 0, 0, 1, 0);
        !           130:     switch (omap_gpmc_devsize(f)) {
        !           131:     case OMAP_GPMC_8BIT:
        !           132:         v = nand_getio(f->dev);
        !           133:         if (size == 1) {
        !           134:             return v;
        !           135:         }
        !           136:         v |= (nand_getio(f->dev) << 8);
        !           137:         if (size == 2) {
        !           138:             return v;
        !           139:         }
        !           140:         v |= (nand_getio(f->dev) << 16);
        !           141:         v |= (nand_getio(f->dev) << 24);
        !           142:         return v;
        !           143:     case OMAP_GPMC_16BIT:
        !           144:         v = nand_getio(f->dev);
        !           145:         if (size == 1) {
        !           146:             /* 8 bit read from 16 bit device : probably a guest bug */
        !           147:             return v & 0xff;
        !           148:         }
        !           149:         if (size == 2) {
        !           150:             return v;
        !           151:         }
        !           152:         v |= (nand_getio(f->dev) << 16);
        !           153:         return v;
        !           154:     default:
        !           155:         abort();
        !           156:     }
        !           157: }
        !           158: 
        !           159: static void omap_nand_setio(DeviceState *dev, uint64_t value,
        !           160:                             int nandsize, int size)
        !           161: {
        !           162:     /* Write the specified value to the NAND device, respecting
        !           163:      * both size of the NAND device and size of the write access.
        !           164:      */
        !           165:     switch (nandsize) {
        !           166:     case OMAP_GPMC_8BIT:
        !           167:         switch (size) {
        !           168:         case 1:
        !           169:             nand_setio(dev, value & 0xff);
        !           170:             break;
        !           171:         case 2:
        !           172:             nand_setio(dev, value & 0xff);
        !           173:             nand_setio(dev, (value >> 8) & 0xff);
        !           174:             break;
        !           175:         case 4:
        !           176:         default:
        !           177:             nand_setio(dev, value & 0xff);
        !           178:             nand_setio(dev, (value >> 8) & 0xff);
        !           179:             nand_setio(dev, (value >> 16) & 0xff);
        !           180:             nand_setio(dev, (value >> 24) & 0xff);
        !           181:             break;
        !           182:         }
        !           183:         break;
        !           184:     case OMAP_GPMC_16BIT:
        !           185:         switch (size) {
        !           186:         case 1:
        !           187:             /* writing to a 16bit device with 8bit access is probably a guest
        !           188:              * bug; pass the value through anyway.
        !           189:              */
        !           190:         case 2:
        !           191:             nand_setio(dev, value & 0xffff);
        !           192:             break;
        !           193:         case 4:
        !           194:         default:
        !           195:             nand_setio(dev, value & 0xffff);
        !           196:             nand_setio(dev, (value >> 16) & 0xffff);
        !           197:             break;
        !           198:         }
        !           199:         break;
        !           200:     }
        !           201: }
        !           202: 
        !           203: static void omap_nand_write(void *opaque, target_phys_addr_t addr,
        !           204:                             uint64_t value, unsigned size)
        !           205: {
        !           206:     struct omap_gpmc_cs_file_s *f = (struct omap_gpmc_cs_file_s *)opaque;
        !           207:     nand_setpins(f->dev, 0, 0, 0, 1, 0);
        !           208:     omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
        !           209: }
        !           210: 
        !           211: static const MemoryRegionOps omap_nand_ops = {
        !           212:     .read = omap_nand_read,
        !           213:     .write = omap_nand_write,
        !           214:     .endianness = DEVICE_NATIVE_ENDIAN,
        !           215: };
        !           216: 
        !           217: static void fill_prefetch_fifo(struct omap_gpmc_s *s)
        !           218: {
        !           219:     /* Fill the prefetch FIFO by reading data from NAND.
        !           220:      * We do this synchronously, unlike the hardware which
        !           221:      * will do this asynchronously. We refill when the
        !           222:      * FIFO has THRESHOLD bytes free, and we always refill
        !           223:      * as much data as possible starting at the top end
        !           224:      * of the FIFO.
        !           225:      * (We have to refill at THRESHOLD rather than waiting
        !           226:      * for the FIFO to empty to allow for the case where
        !           227:      * the FIFO size isn't an exact multiple of THRESHOLD
        !           228:      * and we're doing DMA transfers.)
        !           229:      * This means we never need to handle wrap-around in
        !           230:      * the fifo-reading code, and the next byte of data
        !           231:      * to read is always fifo[63 - fifopointer].
        !           232:      */
        !           233:     int fptr;
        !           234:     int cs = prefetch_cs(s->prefetch.config1);
        !           235:     int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
        !           236:     int bytes;
        !           237:     /* Don't believe the bit of the OMAP TRM that says that COUNTVALUE
        !           238:      * and TRANSFERCOUNT are in units of 16 bit words for 16 bit NAND.
        !           239:      * Instead believe the bit that says it is always a byte count.
        !           240:      */
        !           241:     bytes = 64 - s->prefetch.fifopointer;
        !           242:     if (bytes > s->prefetch.count) {
        !           243:         bytes = s->prefetch.count;
        !           244:     }
        !           245:     s->prefetch.count -= bytes;
        !           246:     s->prefetch.fifopointer += bytes;
        !           247:     fptr = 64 - s->prefetch.fifopointer;
        !           248:     /* Move the existing data in the FIFO so it sits just
        !           249:      * before what we're about to read in
        !           250:      */
        !           251:     while (fptr < (64 - bytes)) {
        !           252:         s->prefetch.fifo[fptr] = s->prefetch.fifo[fptr + bytes];
        !           253:         fptr++;
        !           254:     }
        !           255:     while (fptr < 64) {
        !           256:         if (is16bit) {
        !           257:             uint32_t v = omap_nand_read(&s->cs_file[cs], 0, 2);
        !           258:             s->prefetch.fifo[fptr++] = v & 0xff;
        !           259:             s->prefetch.fifo[fptr++] = (v >> 8) & 0xff;
        !           260:         } else {
        !           261:             s->prefetch.fifo[fptr++] = omap_nand_read(&s->cs_file[cs], 0, 1);
        !           262:         }
        !           263:     }
        !           264:     if (s->prefetch.startengine && (s->prefetch.count == 0)) {
        !           265:         /* This was the final transfer: raise TERMINALCOUNTSTATUS */
        !           266:         s->irqst |= 2;
        !           267:         s->prefetch.startengine = 0;
        !           268:     }
        !           269:     /* If there are any bytes in the FIFO at this point then
        !           270:      * we must raise a DMA request (either this is a final part
        !           271:      * transfer, or we filled the FIFO in which case we certainly
        !           272:      * have THRESHOLD bytes available)
        !           273:      */
        !           274:     if (s->prefetch.fifopointer != 0) {
        !           275:         omap_gpmc_dma_update(s, 1);
        !           276:     }
        !           277:     omap_gpmc_int_update(s);
        !           278: }
        !           279: 
        !           280: /* Access functions for a NAND-like device when the prefetch/postwrite
        !           281:  * engine is enabled -- all addresses in the region behave alike:
        !           282:  * data is read or written to the FIFO.
        !           283:  */
        !           284: static uint64_t omap_gpmc_prefetch_read(void *opaque, target_phys_addr_t addr,
        !           285:                                         unsigned size)
        !           286: {
        !           287:     struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
        !           288:     uint32_t data;
        !           289:     if (s->prefetch.config1 & 1) {
        !           290:         /* The TRM doesn't define the behaviour if you read from the
        !           291:          * FIFO when the prefetch engine is in write mode. We choose
        !           292:          * to always return zero.
        !           293:          */
        !           294:         return 0;
        !           295:     }
        !           296:     /* Note that trying to read an empty fifo repeats the last byte */
        !           297:     if (s->prefetch.fifopointer) {
        !           298:         s->prefetch.fifopointer--;
        !           299:     }
        !           300:     data = s->prefetch.fifo[63 - s->prefetch.fifopointer];
        !           301:     if (s->prefetch.fifopointer ==
        !           302:         (64 - prefetch_threshold(s->prefetch.config1))) {
        !           303:         /* We've drained THRESHOLD bytes now. So deassert the
        !           304:          * DMA request, then refill the FIFO (which will probably
        !           305:          * assert it again.)
        !           306:          */
        !           307:         omap_gpmc_dma_update(s, 0);
        !           308:         fill_prefetch_fifo(s);
        !           309:     }
        !           310:     omap_gpmc_int_update(s);
        !           311:     return data;
        !           312: }
        !           313: 
        !           314: static void omap_gpmc_prefetch_write(void *opaque, target_phys_addr_t addr,
        !           315:                                      uint64_t value, unsigned size)
        !           316: {
        !           317:     struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
        !           318:     int cs = prefetch_cs(s->prefetch.config1);
        !           319:     if ((s->prefetch.config1 & 1) == 0) {
        !           320:         /* The TRM doesn't define the behaviour of writing to the
        !           321:          * FIFO when the prefetch engine is in read mode. We
        !           322:          * choose to ignore the write.
        !           323:          */
1.1       root      324:         return;
                    325:     }
1.1.1.3 ! root      326:     if (s->prefetch.count == 0) {
        !           327:         /* The TRM doesn't define the behaviour of writing to the
        !           328:          * FIFO if the transfer is complete. We choose to ignore.
        !           329:          */
        !           330:         return;
        !           331:     }
        !           332:     /* The only reason we do any data buffering in postwrite
        !           333:      * mode is if we are talking to a 16 bit NAND device, in
        !           334:      * which case we need to buffer the first byte of the
        !           335:      * 16 bit word until the other byte arrives.
        !           336:      */
        !           337:     int is16bit = (((s->cs_file[cs].config[0] >> 12) & 3) != 0);
        !           338:     if (is16bit) {
        !           339:         /* fifopointer alternates between 64 (waiting for first
        !           340:          * byte of word) and 63 (waiting for second byte)
        !           341:          */
        !           342:         if (s->prefetch.fifopointer == 64) {
        !           343:             s->prefetch.fifo[0] = value;
        !           344:             s->prefetch.fifopointer--;
        !           345:         } else {
        !           346:             value = (value << 8) | s->prefetch.fifo[0];
        !           347:             omap_nand_write(&s->cs_file[cs], 0, value, 2);
        !           348:             s->prefetch.count--;
        !           349:             s->prefetch.fifopointer = 64;
        !           350:         }
        !           351:     } else {
        !           352:         /* Just write the byte : fifopointer remains 64 at all times */
        !           353:         omap_nand_write(&s->cs_file[cs], 0, value, 1);
        !           354:         s->prefetch.count--;
        !           355:     }
        !           356:     if (s->prefetch.count == 0) {
        !           357:         /* Final transfer: raise TERMINALCOUNTSTATUS */
        !           358:         s->irqst |= 2;
        !           359:         s->prefetch.startengine = 0;
        !           360:     }
        !           361:     omap_gpmc_int_update(s);
        !           362: }
        !           363: 
        !           364: static const MemoryRegionOps omap_prefetch_ops = {
        !           365:     .read = omap_gpmc_prefetch_read,
        !           366:     .write = omap_gpmc_prefetch_write,
        !           367:     .endianness = DEVICE_NATIVE_ENDIAN,
        !           368:     .impl.min_access_size = 1,
        !           369:     .impl.max_access_size = 1,
        !           370: };
        !           371: 
        !           372: static MemoryRegion *omap_gpmc_cs_memregion(struct omap_gpmc_s *s, int cs)
        !           373: {
        !           374:     /* Return the MemoryRegion* to map/unmap for this chipselect */
        !           375:     struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
        !           376:     if (omap_gpmc_devtype(f) == OMAP_GPMC_NOR) {
        !           377:         return f->iomem;
        !           378:     }
        !           379:     if ((s->prefetch.config1 & 0x80) &&
        !           380:         (prefetch_cs(s->prefetch.config1) == cs)) {
        !           381:         /* The prefetch engine is enabled for this CS: map the FIFO */
        !           382:         return &s->prefetch.iomem;
        !           383:     }
        !           384:     return &f->nandiomem;
        !           385: }
        !           386: 
        !           387: static void omap_gpmc_cs_map(struct omap_gpmc_s *s, int cs)
        !           388: {
        !           389:     struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
        !           390:     uint32_t mask = (f->config[6] >> 8) & 0xf;
        !           391:     uint32_t base = f->config[6] & 0x3f;
        !           392:     uint32_t size;
1.1       root      393: 
1.1.1.3 ! root      394:     if (!f->iomem && !f->dev) {
1.1       root      395:         return;
1.1.1.3 ! root      396:     }
        !           397: 
        !           398:     if (!(f->config[6] & (1 << 6))) {
        !           399:         /* Do nothing unless CSVALID */
        !           400:         return;
        !           401:     }
1.1       root      402: 
1.1.1.3 ! root      403:     /* TODO: check for overlapping regions and report access errors */
        !           404:     if (mask != 0x8 && mask != 0xc && mask != 0xe && mask != 0xf
        !           405:          && !(s->accept_256 && !mask)) {
        !           406:         fprintf(stderr, "%s: invalid chip-select mask address (0x%x)\n",
        !           407:                  __func__, mask);
        !           408:     }
        !           409: 
        !           410:     base <<= 24;
        !           411:     size = (0x0fffffff & ~(mask << 24)) + 1;
1.1       root      412:     /* TODO: rather than setting the size of the mapping (which should be
                    413:      * constant), the mask should cause wrapping of the address space, so
                    414:      * that the same memory becomes accessible at every <i>size</i> bytes
                    415:      * starting from <i>base</i>.  */
1.1.1.3 ! root      416:     memory_region_init(&f->container, "omap-gpmc-file", size);
        !           417:     memory_region_add_subregion(&f->container, 0,
        !           418:                                 omap_gpmc_cs_memregion(s, cs));
        !           419:     memory_region_add_subregion(get_system_memory(), base,
        !           420:                                 &f->container);
1.1       root      421: }
                    422: 
1.1.1.3 ! root      423: static void omap_gpmc_cs_unmap(struct omap_gpmc_s *s, int cs)
1.1       root      424: {
1.1.1.3 ! root      425:     struct omap_gpmc_cs_file_s *f = &s->cs_file[cs];
        !           426:     if (!(f->config[6] & (1 << 6))) {
        !           427:         /* Do nothing unless CSVALID */
        !           428:         return;
        !           429:     }
        !           430:     if (!f->iomem && !f->dev) {
        !           431:         return;
1.1       root      432:     }
1.1.1.3 ! root      433:     memory_region_del_subregion(get_system_memory(), &f->container);
        !           434:     memory_region_del_subregion(&f->container, omap_gpmc_cs_memregion(s, cs));
        !           435:     memory_region_destroy(&f->container);
1.1       root      436: }
                    437: 
                    438: void omap_gpmc_reset(struct omap_gpmc_s *s)
                    439: {
                    440:     int i;
                    441: 
                    442:     s->sysconfig = 0;
                    443:     s->irqst = 0;
                    444:     s->irqen = 0;
                    445:     omap_gpmc_int_update(s);
                    446:     s->timeout = 0;
                    447:     s->config = 0xa00;
1.1.1.3 ! root      448:     s->prefetch.config1 = 0x00004000;
        !           449:     s->prefetch.transfercount = 0x00000000;
        !           450:     s->prefetch.startengine = 0;
        !           451:     s->prefetch.fifopointer = 0;
        !           452:     s->prefetch.count = 0;
1.1       root      453:     for (i = 0; i < 8; i ++) {
1.1.1.3 ! root      454:         omap_gpmc_cs_unmap(s, i);
1.1       root      455:         s->cs_file[i].config[1] = 0x101001;
                    456:         s->cs_file[i].config[2] = 0x020201;
                    457:         s->cs_file[i].config[3] = 0x10031003;
                    458:         s->cs_file[i].config[4] = 0x10f1111;
                    459:         s->cs_file[i].config[5] = 0;
                    460:         s->cs_file[i].config[6] = 0xf00 | (i ? 0 : 1 << 6);
1.1.1.3 ! root      461: 
        !           462:         s->cs_file[i].config[6] = 0xf00;
        !           463:         /* In theory we could probe attached devices for some CFG1
        !           464:          * bits here, but we just retain them across resets as they
        !           465:          * were set initially by omap_gpmc_attach().
        !           466:          */
        !           467:         if (i == 0) {
        !           468:             s->cs_file[i].config[0] &= 0x00433e00;
        !           469:             s->cs_file[i].config[6] |= 1 << 6; /* CSVALID */
        !           470:             omap_gpmc_cs_map(s, i);
        !           471:         } else {
        !           472:             s->cs_file[i].config[0] &= 0x00403c00;
        !           473:         }
1.1       root      474:     }
                    475:     s->ecc_cs = 0;
                    476:     s->ecc_ptr = 0;
                    477:     s->ecc_cfg = 0x3fcff000;
                    478:     for (i = 0; i < 9; i ++)
                    479:         ecc_reset(&s->ecc[i]);
                    480: }
                    481: 
1.1.1.3 ! root      482: static int gpmc_wordaccess_only(target_phys_addr_t addr)
        !           483: {
        !           484:     /* Return true if the register offset is to a register that
        !           485:      * only permits word width accesses.
        !           486:      * Non-word accesses are only OK for GPMC_NAND_DATA/ADDRESS/COMMAND
        !           487:      * for any chipselect.
        !           488:      */
        !           489:     if (addr >= 0x60 && addr <= 0x1d4) {
        !           490:         int cs = (addr - 0x60) / 0x30;
        !           491:         addr -= cs * 0x30;
        !           492:         if (addr >= 0x7c && addr < 0x88) {
        !           493:             /* GPMC_NAND_COMMAND, GPMC_NAND_ADDRESS, GPMC_NAND_DATA */
        !           494:             return 0;
        !           495:         }
        !           496:     }
        !           497:     return 1;
        !           498: }
        !           499: 
        !           500: static uint64_t omap_gpmc_read(void *opaque, target_phys_addr_t addr,
        !           501:                                unsigned size)
1.1       root      502: {
                    503:     struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
                    504:     int cs;
                    505:     struct omap_gpmc_cs_file_s *f;
                    506: 
1.1.1.3 ! root      507:     if (size != 4 && gpmc_wordaccess_only(addr)) {
        !           508:         return omap_badwidth_read32(opaque, addr);
        !           509:     }
        !           510: 
1.1       root      511:     switch (addr) {
                    512:     case 0x000:        /* GPMC_REVISION */
1.1.1.3 ! root      513:         return s->revision;
1.1       root      514: 
                    515:     case 0x010:        /* GPMC_SYSCONFIG */
                    516:         return s->sysconfig;
                    517: 
                    518:     case 0x014:        /* GPMC_SYSSTATUS */
                    519:         return 1;                                              /* RESETDONE */
                    520: 
                    521:     case 0x018:        /* GPMC_IRQSTATUS */
                    522:         return s->irqst;
                    523: 
                    524:     case 0x01c:        /* GPMC_IRQENABLE */
                    525:         return s->irqen;
                    526: 
                    527:     case 0x040:        /* GPMC_TIMEOUT_CONTROL */
                    528:         return s->timeout;
                    529: 
                    530:     case 0x044:        /* GPMC_ERR_ADDRESS */
                    531:     case 0x048:        /* GPMC_ERR_TYPE */
                    532:         return 0;
                    533: 
                    534:     case 0x050:        /* GPMC_CONFIG */
                    535:         return s->config;
                    536: 
                    537:     case 0x054:        /* GPMC_STATUS */
                    538:         return 0x001;
                    539: 
                    540:     case 0x060 ... 0x1d4:
                    541:         cs = (addr - 0x060) / 0x30;
                    542:         addr -= cs * 0x30;
                    543:         f = s->cs_file + cs;
                    544:         switch (addr) {
1.1.1.3 ! root      545:         case 0x60:      /* GPMC_CONFIG1 */
        !           546:             return f->config[0];
        !           547:         case 0x64:      /* GPMC_CONFIG2 */
        !           548:             return f->config[1];
        !           549:         case 0x68:      /* GPMC_CONFIG3 */
        !           550:             return f->config[2];
        !           551:         case 0x6c:      /* GPMC_CONFIG4 */
        !           552:             return f->config[3];
        !           553:         case 0x70:      /* GPMC_CONFIG5 */
        !           554:             return f->config[4];
        !           555:         case 0x74:      /* GPMC_CONFIG6 */
        !           556:             return f->config[5];
        !           557:         case 0x78:      /* GPMC_CONFIG7 */
        !           558:             return f->config[6];
        !           559:         case 0x84 ... 0x87: /* GPMC_NAND_DATA */
        !           560:             if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
        !           561:                 return omap_nand_read(f, 0, size);
        !           562:             }
        !           563:             return 0;
1.1       root      564:         }
                    565:         break;
                    566: 
                    567:     case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
1.1.1.3 ! root      568:         return s->prefetch.config1;
1.1       root      569:     case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
1.1.1.3 ! root      570:         return s->prefetch.transfercount;
1.1       root      571:     case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
1.1.1.3 ! root      572:         return s->prefetch.startengine;
1.1       root      573:     case 0x1f0:        /* GPMC_PREFETCH_STATUS */
1.1.1.3 ! root      574:         /* NB: The OMAP3 TRM is inconsistent about whether the GPMC
        !           575:          * FIFOTHRESHOLDSTATUS bit should be set when
        !           576:          * FIFOPOINTER > FIFOTHRESHOLD or when it is >= FIFOTHRESHOLD.
        !           577:          * Apparently the underlying functional spec from which the TRM was
        !           578:          * created states that the behaviour is ">=", and this also
        !           579:          * makes more conceptual sense.
        !           580:          */
        !           581:         return (s->prefetch.fifopointer << 24) |
        !           582:                 ((s->prefetch.fifopointer >=
        !           583:                   ((s->prefetch.config1 >> 8) & 0x7f) ? 1 : 0) << 16) |
        !           584:                 s->prefetch.count;
1.1       root      585: 
                    586:     case 0x1f4:        /* GPMC_ECC_CONFIG */
                    587:         return s->ecc_cs;
                    588:     case 0x1f8:        /* GPMC_ECC_CONTROL */
                    589:         return s->ecc_ptr;
                    590:     case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
                    591:         return s->ecc_cfg;
                    592:     case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
                    593:         cs = (addr & 0x1f) >> 2;
                    594:         /* TODO: check correctness */
                    595:         return
                    596:                 ((s->ecc[cs].cp    &  0x07) <<  0) |
                    597:                 ((s->ecc[cs].cp    &  0x38) << 13) |
                    598:                 ((s->ecc[cs].lp[0] & 0x1ff) <<  3) |
                    599:                 ((s->ecc[cs].lp[1] & 0x1ff) << 19);
                    600: 
                    601:     case 0x230:        /* GPMC_TESTMODE_CTRL */
                    602:         return 0;
                    603:     case 0x234:        /* GPMC_PSA_LSB */
                    604:     case 0x238:        /* GPMC_PSA_MSB */
                    605:         return 0x00000000;
                    606:     }
                    607: 
                    608:     OMAP_BAD_REG(addr);
                    609:     return 0;
                    610: }
                    611: 
                    612: static void omap_gpmc_write(void *opaque, target_phys_addr_t addr,
1.1.1.3 ! root      613:                             uint64_t value, unsigned size)
1.1       root      614: {
                    615:     struct omap_gpmc_s *s = (struct omap_gpmc_s *) opaque;
                    616:     int cs;
                    617:     struct omap_gpmc_cs_file_s *f;
                    618: 
1.1.1.3 ! root      619:     if (size != 4 && gpmc_wordaccess_only(addr)) {
        !           620:         return omap_badwidth_write32(opaque, addr, value);
        !           621:     }
        !           622: 
1.1       root      623:     switch (addr) {
                    624:     case 0x000:        /* GPMC_REVISION */
                    625:     case 0x014:        /* GPMC_SYSSTATUS */
                    626:     case 0x054:        /* GPMC_STATUS */
                    627:     case 0x1f0:        /* GPMC_PREFETCH_STATUS */
                    628:     case 0x200 ... 0x220:      /* GPMC_ECC_RESULT */
                    629:     case 0x234:        /* GPMC_PSA_LSB */
                    630:     case 0x238:        /* GPMC_PSA_MSB */
                    631:         OMAP_RO_REG(addr);
                    632:         break;
                    633: 
                    634:     case 0x010:        /* GPMC_SYSCONFIG */
                    635:         if ((value >> 3) == 0x3)
1.1.1.3 ! root      636:             fprintf(stderr, "%s: bad SDRAM idle mode %"PRIi64"\n",
1.1       root      637:                             __FUNCTION__, value >> 3);
                    638:         if (value & 2)
                    639:             omap_gpmc_reset(s);
                    640:         s->sysconfig = value & 0x19;
                    641:         break;
                    642: 
                    643:     case 0x018:        /* GPMC_IRQSTATUS */
1.1.1.3 ! root      644:         s->irqst &= ~value;
1.1       root      645:         omap_gpmc_int_update(s);
                    646:         break;
                    647: 
                    648:     case 0x01c:        /* GPMC_IRQENABLE */
                    649:         s->irqen = value & 0xf03;
                    650:         omap_gpmc_int_update(s);
                    651:         break;
                    652: 
                    653:     case 0x040:        /* GPMC_TIMEOUT_CONTROL */
                    654:         s->timeout = value & 0x1ff1;
                    655:         break;
                    656: 
                    657:     case 0x044:        /* GPMC_ERR_ADDRESS */
                    658:     case 0x048:        /* GPMC_ERR_TYPE */
                    659:         break;
                    660: 
                    661:     case 0x050:        /* GPMC_CONFIG */
                    662:         s->config = value & 0xf13;
                    663:         break;
                    664: 
                    665:     case 0x060 ... 0x1d4:
                    666:         cs = (addr - 0x060) / 0x30;
                    667:         addr -= cs * 0x30;
                    668:         f = s->cs_file + cs;
                    669:         switch (addr) {
1.1.1.3 ! root      670:         case 0x60:      /* GPMC_CONFIG1 */
        !           671:             f->config[0] = value & 0xffef3e13;
        !           672:             break;
        !           673:         case 0x64:      /* GPMC_CONFIG2 */
        !           674:             f->config[1] = value & 0x001f1f8f;
        !           675:             break;
        !           676:         case 0x68:      /* GPMC_CONFIG3 */
        !           677:             f->config[2] = value & 0x001f1f8f;
        !           678:             break;
        !           679:         case 0x6c:      /* GPMC_CONFIG4 */
        !           680:             f->config[3] = value & 0x1f8f1f8f;
        !           681:             break;
        !           682:         case 0x70:      /* GPMC_CONFIG5 */
        !           683:             f->config[4] = value & 0x0f1f1f1f;
        !           684:             break;
        !           685:         case 0x74:      /* GPMC_CONFIG6 */
        !           686:             f->config[5] = value & 0x00000fcf;
        !           687:             break;
        !           688:         case 0x78:      /* GPMC_CONFIG7 */
        !           689:             if ((f->config[6] ^ value) & 0xf7f) {
        !           690:                 omap_gpmc_cs_unmap(s, cs);
1.1       root      691:                 f->config[6] = value & 0x00000f7f;
1.1.1.3 ! root      692:                 omap_gpmc_cs_map(s, cs);
        !           693:             }
        !           694:             break;
        !           695:         case 0x7c ... 0x7f: /* GPMC_NAND_COMMAND */
        !           696:             if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
        !           697:                 nand_setpins(f->dev, 1, 0, 0, 1, 0); /* CLE */
        !           698:                 omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
        !           699:             }
        !           700:             break;
        !           701:         case 0x80 ... 0x83: /* GPMC_NAND_ADDRESS */
        !           702:             if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
        !           703:                 nand_setpins(f->dev, 0, 1, 0, 1, 0); /* ALE */
        !           704:                 omap_nand_setio(f->dev, value, omap_gpmc_devsize(f), size);
        !           705:             }
        !           706:             break;
        !           707:         case 0x84 ... 0x87: /* GPMC_NAND_DATA */
        !           708:             if (omap_gpmc_devtype(f) == OMAP_GPMC_NAND) {
        !           709:                 omap_nand_write(f, 0, value, size);
        !           710:             }
        !           711:             break;
        !           712:         default:
        !           713:             goto bad_reg;
1.1       root      714:         }
                    715:         break;
                    716: 
                    717:     case 0x1e0:        /* GPMC_PREFETCH_CONFIG1 */
1.1.1.3 ! root      718:         if (!s->prefetch.startengine) {
        !           719:             uint32_t oldconfig1 = s->prefetch.config1;
        !           720:             uint32_t changed;
        !           721:             s->prefetch.config1 = value & 0x7f8f7fbf;
        !           722:             changed = oldconfig1 ^ s->prefetch.config1;
        !           723:             if (changed & (0x80 | 0x7000000)) {
        !           724:                 /* Turning the engine on or off, or mapping it somewhere else.
        !           725:                  * cs_map() and cs_unmap() check the prefetch config and
        !           726:                  * overall CSVALID bits, so it is sufficient to unmap-and-map
        !           727:                  * both the old cs and the new one.
        !           728:                  */
        !           729:                 int oldcs = prefetch_cs(oldconfig1);
        !           730:                 int newcs = prefetch_cs(s->prefetch.config1);
        !           731:                 omap_gpmc_cs_unmap(s, oldcs);
        !           732:                 omap_gpmc_cs_map(s, oldcs);
        !           733:                 if (newcs != oldcs) {
        !           734:                     omap_gpmc_cs_unmap(s, newcs);
        !           735:                     omap_gpmc_cs_map(s, newcs);
        !           736:                 }
        !           737:             }
        !           738:         }
1.1       root      739:         break;
                    740: 
                    741:     case 0x1e4:        /* GPMC_PREFETCH_CONFIG2 */
1.1.1.3 ! root      742:         if (!s->prefetch.startengine) {
        !           743:             s->prefetch.transfercount = value & 0x3fff;
        !           744:         }
1.1       root      745:         break;
                    746: 
                    747:     case 0x1ec:        /* GPMC_PREFETCH_CONTROL */
1.1.1.3 ! root      748:         if (s->prefetch.startengine != (value & 1)) {
        !           749:             s->prefetch.startengine = value & 1;
        !           750:             if (s->prefetch.startengine) {
        !           751:                 /* Prefetch engine start */
        !           752:                 s->prefetch.count = s->prefetch.transfercount;
        !           753:                 if (s->prefetch.config1 & 1) {
        !           754:                     /* Write */
        !           755:                     s->prefetch.fifopointer = 64;
        !           756:                 } else {
        !           757:                     /* Read */
        !           758:                     s->prefetch.fifopointer = 0;
        !           759:                     fill_prefetch_fifo(s);
        !           760:                 }
        !           761:             } else {
        !           762:                 /* Prefetch engine forcibly stopped. The TRM
        !           763:                  * doesn't define the behaviour if you do this.
        !           764:                  * We clear the prefetch count, which means that
        !           765:                  * we permit no more writes, and don't read any
        !           766:                  * more data from NAND. The CPU can still drain
        !           767:                  * the FIFO of unread data.
        !           768:                  */
        !           769:                 s->prefetch.count = 0;
        !           770:             }
        !           771:             omap_gpmc_int_update(s);
1.1       root      772:         }
                    773:         break;
                    774: 
                    775:     case 0x1f4:        /* GPMC_ECC_CONFIG */
                    776:         s->ecc_cs = 0x8f;
                    777:         break;
                    778:     case 0x1f8:        /* GPMC_ECC_CONTROL */
                    779:         if (value & (1 << 8))
                    780:             for (cs = 0; cs < 9; cs ++)
                    781:                 ecc_reset(&s->ecc[cs]);
                    782:         s->ecc_ptr = value & 0xf;
                    783:         if (s->ecc_ptr == 0 || s->ecc_ptr > 9) {
                    784:             s->ecc_ptr = 0;
                    785:             s->ecc_cs &= ~1;
                    786:         }
                    787:         break;
                    788:     case 0x1fc:        /* GPMC_ECC_SIZE_CONFIG */
                    789:         s->ecc_cfg = value & 0x3fcff1ff;
                    790:         break;
                    791:     case 0x230:        /* GPMC_TESTMODE_CTRL */
                    792:         if (value & 7)
                    793:             fprintf(stderr, "%s: test mode enable attempt\n", __FUNCTION__);
                    794:         break;
                    795: 
                    796:     default:
                    797:     bad_reg:
                    798:         OMAP_BAD_REG(addr);
                    799:         return;
                    800:     }
                    801: }
                    802: 
1.1.1.3 ! root      803: static const MemoryRegionOps omap_gpmc_ops = {
        !           804:     .read = omap_gpmc_read,
        !           805:     .write = omap_gpmc_write,
        !           806:     .endianness = DEVICE_NATIVE_ENDIAN,
1.1       root      807: };
                    808: 
1.1.1.3 ! root      809: struct omap_gpmc_s *omap_gpmc_init(struct omap_mpu_state_s *mpu,
        !           810:                                    target_phys_addr_t base,
        !           811:                                    qemu_irq irq, qemu_irq drq)
1.1       root      812: {
1.1.1.3 ! root      813:     int cs;
1.1       root      814:     struct omap_gpmc_s *s = (struct omap_gpmc_s *)
1.1.1.3 ! root      815:             g_malloc0(sizeof(struct omap_gpmc_s));
1.1       root      816: 
1.1.1.3 ! root      817:     memory_region_init_io(&s->iomem, &omap_gpmc_ops, s, "omap-gpmc", 0x1000);
        !           818:     memory_region_add_subregion(get_system_memory(), base, &s->iomem);
        !           819: 
        !           820:     s->irq = irq;
        !           821:     s->drq = drq;
        !           822:     s->accept_256 = cpu_is_omap3630(mpu);
        !           823:     s->revision = cpu_class_omap3(mpu) ? 0x50 : 0x20;
        !           824:     s->lastirq = 0;
1.1       root      825:     omap_gpmc_reset(s);
                    826: 
1.1.1.3 ! root      827:     /* We have to register a different IO memory handler for each
        !           828:      * chip select region in case a NAND device is mapped there. We
        !           829:      * make the region the worst-case size of 256MB and rely on the
        !           830:      * container memory region in cs_map to chop it down to the actual
        !           831:      * guest-requested size.
        !           832:      */
        !           833:     for (cs = 0; cs < 8; cs++) {
        !           834:         memory_region_init_io(&s->cs_file[cs].nandiomem,
        !           835:                               &omap_nand_ops,
        !           836:                               &s->cs_file[cs],
        !           837:                               "omap-nand",
        !           838:                               256 * 1024 * 1024);
        !           839:     }
1.1       root      840: 
1.1.1.3 ! root      841:     memory_region_init_io(&s->prefetch.iomem, &omap_prefetch_ops, s,
        !           842:                           "omap-gpmc-prefetch", 256 * 1024 * 1024);
1.1       root      843:     return s;
                    844: }
                    845: 
1.1.1.3 ! root      846: void omap_gpmc_attach(struct omap_gpmc_s *s, int cs, MemoryRegion *iomem)
1.1       root      847: {
                    848:     struct omap_gpmc_cs_file_s *f;
1.1.1.3 ! root      849:     assert(iomem);
1.1       root      850: 
                    851:     if (cs < 0 || cs >= 8) {
                    852:         fprintf(stderr, "%s: bad chip-select %i\n", __FUNCTION__, cs);
                    853:         exit(-1);
                    854:     }
                    855:     f = &s->cs_file[cs];
                    856: 
1.1.1.3 ! root      857:     omap_gpmc_cs_unmap(s, cs);
        !           858:     f->config[0] &= ~(0xf << 10);
        !           859:     f->iomem = iomem;
        !           860:     omap_gpmc_cs_map(s, cs);
        !           861: }
        !           862: 
        !           863: void omap_gpmc_attach_nand(struct omap_gpmc_s *s, int cs, DeviceState *nand)
        !           864: {
        !           865:     struct omap_gpmc_cs_file_s *f;
        !           866:     assert(nand);
        !           867: 
        !           868:     if (cs < 0 || cs >= 8) {
        !           869:         fprintf(stderr, "%s: bad chip-select %i\n", __func__, cs);
        !           870:         exit(-1);
        !           871:     }
        !           872:     f = &s->cs_file[cs];
        !           873: 
        !           874:     omap_gpmc_cs_unmap(s, cs);
        !           875:     f->config[0] &= ~(0xf << 10);
        !           876:     f->config[0] |= (OMAP_GPMC_NAND << 10);
        !           877:     f->dev = nand;
        !           878:     if (nand_getbuswidth(f->dev) == 16) {
        !           879:         f->config[0] |= OMAP_GPMC_16BIT << 12;
        !           880:     }
        !           881:     omap_gpmc_cs_map(s, cs);
1.1       root      882: }

unix.superglobalmegacorp.com

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