(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/omap_mmc.c

    1: /*
    2:  * OMAP on-chip MMC/SD host emulation.
    3:  *
    4:  * Copyright (C) 2006-2007 Andrzej Zaborowski  <balrog@zabor.org>
    5:  *
    6:  * This program is free software; you can redistribute it and/or
    7:  * modify it under the terms of the GNU General Public License as
    8:  * published by the Free Software Foundation; either version 2 of
    9:  * the License, or (at your option) any later version.
   10:  *
   11:  * This program is distributed in the hope that it will be useful,
   12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:  * GNU General Public License for more details.
   15:  *
   16:  * You should have received a copy of the GNU General Public License
   17:  * along with this program; if not, write to the Free Software
   18:  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
   19:  * MA 02111-1307 USA
   20:  */
   21: #include "hw.h"
   22: #include "omap.h"
   23: #include "sd.h"
   24: 
   25: struct omap_mmc_s {
   26:     target_phys_addr_t base;
   27:     qemu_irq irq;
   28:     qemu_irq *dma;
   29:     omap_clk clk;
   30:     SDState *card;
   31:     uint16_t last_cmd;
   32:     uint16_t sdio;
   33:     uint16_t rsp[8];
   34:     uint32_t arg;
   35:     int dw;
   36:     int mode;
   37:     int enable;
   38:     uint16_t status;
   39:     uint16_t mask;
   40:     uint8_t cto;
   41:     uint16_t dto;
   42:     uint16_t fifo[32];
   43:     int fifo_start;
   44:     int fifo_len;
   45:     uint16_t blen;
   46:     uint16_t blen_counter;
   47:     uint16_t nblk;
   48:     uint16_t nblk_counter;
   49:     int tx_dma;
   50:     int rx_dma;
   51:     int af_level;
   52:     int ae_level;
   53: 
   54:     int ddir;
   55:     int transfer;
   56: };
   57: 
   58: static void omap_mmc_interrupts_update(struct omap_mmc_s *s)
   59: {
   60:     qemu_set_irq(s->irq, !!(s->status & s->mask));
   61: }
   62: 
   63: static void omap_mmc_fifolevel_update(struct omap_mmc_s *host)
   64: {
   65:     if (!host->transfer && !host->fifo_len) {
   66:         host->status &= 0xf3ff;
   67:         return;
   68:     }
   69: 
   70:     if (host->fifo_len > host->af_level && host->ddir) {
   71:         if (host->rx_dma) {
   72:             host->status &= 0xfbff;
   73:             qemu_irq_raise(host->dma[1]);
   74:         } else
   75:             host->status |= 0x0400;
   76:     } else {
   77:         host->status &= 0xfbff;
   78:         qemu_irq_lower(host->dma[1]);
   79:     }
   80: 
   81:     if (host->fifo_len < host->ae_level && !host->ddir) {
   82:         if (host->tx_dma) {
   83:             host->status &= 0xf7ff;
   84:             qemu_irq_raise(host->dma[0]);
   85:         } else
   86:             host->status |= 0x0800;
   87:     } else {
   88:         qemu_irq_lower(host->dma[0]);
   89:         host->status &= 0xf7ff;
   90:     }
   91: }
   92: 
   93: typedef enum {
   94:     sd_nore = 0,        /* no response */
   95:     sd_r1,              /* normal response command */
   96:     sd_r2,              /* CID, CSD registers */
   97:     sd_r3,              /* OCR register */
   98:     sd_r6 = 6,          /* Published RCA response */
   99:     sd_r1b = -1,
  100: } sd_rsp_type_t;
  101: 
  102: static void omap_mmc_command(struct omap_mmc_s *host, int cmd, int dir,
  103:                 sd_cmd_type_t type, int busy, sd_rsp_type_t resptype, int init)
  104: {
  105:     uint32_t rspstatus, mask;
  106:     int rsplen, timeout;
  107:     struct sd_request_s request;
  108:     uint8_t response[16];
  109: 
  110:     if (resptype == sd_r1 && busy)
  111:         resptype = sd_r1b;
  112: 
  113:     if (type == sd_adtc) {
  114:         host->fifo_start = 0;
  115:         host->fifo_len = 0;
  116:         host->transfer = 1;
  117:         host->ddir = dir;
  118:     } else
  119:         host->transfer = 0;
  120:     timeout = 0;
  121:     mask = 0;
  122:     rspstatus = 0;
  123: 
  124:     request.cmd = cmd;
  125:     request.arg = host->arg;
  126:     request.crc = 0; /* FIXME */
  127: 
  128:     rsplen = sd_do_command(host->card, &request, response);
  129: 
  130:     /* TODO: validate CRCs */
  131:     switch (resptype) {
  132:     case sd_nore:
  133:         rsplen = 0;
  134:         break;
  135: 
  136:     case sd_r1:
  137:     case sd_r1b:
  138:         if (rsplen < 4) {
  139:             timeout = 1;
  140:             break;
  141:         }
  142:         rsplen = 4;
  143: 
  144:         mask = OUT_OF_RANGE | ADDRESS_ERROR | BLOCK_LEN_ERROR |
  145:                 ERASE_SEQ_ERROR | ERASE_PARAM | WP_VIOLATION |
  146:                 LOCK_UNLOCK_FAILED | COM_CRC_ERROR | ILLEGAL_COMMAND |
  147:                 CARD_ECC_FAILED | CC_ERROR | SD_ERROR |
  148:                 CID_CSD_OVERWRITE;
  149:         if (host->sdio & (1 << 13))
  150:             mask |= AKE_SEQ_ERROR;
  151:         rspstatus = (response[0] << 24) | (response[1] << 16) |
  152:                 (response[2] << 8) | (response[3] << 0);
  153:         break;
  154: 
  155:     case sd_r2:
  156:         if (rsplen < 16) {
  157:             timeout = 1;
  158:             break;
  159:         }
  160:         rsplen = 16;
  161:         break;
  162: 
  163:     case sd_r3:
  164:         if (rsplen < 4) {
  165:             timeout = 1;
  166:             break;
  167:         }
  168:         rsplen = 4;
  169: 
  170:         rspstatus = (response[0] << 24) | (response[1] << 16) |
  171:                 (response[2] << 8) | (response[3] << 0);
  172:         if (rspstatus & 0x80000000)
  173:             host->status &= 0xe000;
  174:         else
  175:             host->status |= 0x1000;
  176:         break;
  177: 
  178:     case sd_r6:
  179:         if (rsplen < 4) {
  180:             timeout = 1;
  181:             break;
  182:         }
  183:         rsplen = 4;
  184: 
  185:         mask = 0xe000 | AKE_SEQ_ERROR;
  186:         rspstatus = (response[2] << 8) | (response[3] << 0);
  187:     }
  188: 
  189:     if (rspstatus & mask)
  190:         host->status |= 0x4000;
  191:     else
  192:         host->status &= 0xb000;
  193: 
  194:     if (rsplen)
  195:         for (rsplen = 0; rsplen < 8; rsplen ++)
  196:             host->rsp[~rsplen & 7] = response[(rsplen << 1) | 1] |
  197:                     (response[(rsplen << 1) | 0] << 8);
  198: 
  199:     if (timeout)
  200:         host->status |= 0x0080;
  201:     else if (cmd == 12)
  202:         host->status |= 0x0005; /* Makes it more real */
  203:     else
  204:         host->status |= 0x0001;
  205: }
  206: 
  207: static void omap_mmc_transfer(struct omap_mmc_s *host)
  208: {
  209:     uint8_t value;
  210: 
  211:     if (!host->transfer)
  212:         return;
  213: 
  214:     while (1) {
  215:         if (host->ddir) {
  216:             if (host->fifo_len > host->af_level)
  217:                 break;
  218: 
  219:             value = sd_read_data(host->card);
  220:             host->fifo[(host->fifo_start + host->fifo_len) & 31] = value;
  221:             if (-- host->blen_counter) {
  222:                 value = sd_read_data(host->card);
  223:                 host->fifo[(host->fifo_start + host->fifo_len) & 31] |=
  224:                         value << 8;
  225:                 host->blen_counter --;
  226:             }
  227: 
  228:             host->fifo_len ++;
  229:         } else {
  230:             if (!host->fifo_len)
  231:                 break;
  232: 
  233:             value = host->fifo[host->fifo_start] & 0xff;
  234:             sd_write_data(host->card, value);
  235:             if (-- host->blen_counter) {
  236:                 value = host->fifo[host->fifo_start] >> 8;
  237:                 sd_write_data(host->card, value);
  238:                 host->blen_counter --;
  239:             }
  240: 
  241:             host->fifo_start ++;
  242:             host->fifo_len --;
  243:             host->fifo_start &= 31;
  244:         }
  245: 
  246:         if (host->blen_counter == 0) {
  247:             host->nblk_counter --;
  248:             host->blen_counter = host->blen;
  249: 
  250:             if (host->nblk_counter == 0) {
  251:                 host->nblk_counter = host->nblk;
  252:                 host->transfer = 0;
  253:                 host->status |= 0x0008;
  254:                 break;
  255:             }
  256:         }
  257:     }
  258: }
  259: 
  260: static void omap_mmc_update(void *opaque)
  261: {
  262:     struct omap_mmc_s *s = opaque;
  263:     omap_mmc_transfer(s);
  264:     omap_mmc_fifolevel_update(s);
  265:     omap_mmc_interrupts_update(s);
  266: }
  267: 
  268: static uint32_t omap_mmc_read(void *opaque, target_phys_addr_t offset)
  269: {
  270:     uint16_t i;
  271:     struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
  272:     offset &= OMAP_MPUI_REG_MASK;
  273: 
  274:     switch (offset) {
  275:     case 0x00:  /* MMC_CMD */
  276:         return s->last_cmd;
  277: 
  278:     case 0x04:  /* MMC_ARGL */
  279:         return s->arg & 0x0000ffff;
  280: 
  281:     case 0x08:  /* MMC_ARGH */
  282:         return s->arg >> 16;
  283: 
  284:     case 0x0c:  /* MMC_CON */
  285:         return (s->dw << 15) | (s->mode << 12) | (s->enable << 11);
  286: 
  287:     case 0x10:  /* MMC_STAT */
  288:         return s->status;
  289: 
  290:     case 0x14:  /* MMC_IE */
  291:         return s->mask;
  292: 
  293:     case 0x18:  /* MMC_CTO */
  294:         return s->cto;
  295: 
  296:     case 0x1c:  /* MMC_DTO */
  297:         return s->dto;
  298: 
  299:     case 0x20:  /* MMC_DATA */
  300:         /* TODO: support 8-bit access */
  301:         i = s->fifo[s->fifo_start];
  302:         if (s->fifo_len == 0) {
  303:             printf("MMC: FIFO underrun\n");
  304:             return i;
  305:         }
  306:         s->fifo_start ++;
  307:         s->fifo_len --;
  308:         s->fifo_start &= 31;
  309:         omap_mmc_transfer(s);
  310:         omap_mmc_fifolevel_update(s);
  311:         omap_mmc_interrupts_update(s);
  312:         return i;
  313: 
  314:     case 0x24:  /* MMC_BLEN */
  315:         return s->blen_counter;
  316: 
  317:     case 0x28:  /* MMC_NBLK */
  318:         return s->nblk_counter;
  319: 
  320:     case 0x2c:  /* MMC_BUF */
  321:         return (s->rx_dma << 15) | (s->af_level << 8) |
  322:             (s->tx_dma << 7) | s->ae_level;
  323: 
  324:     case 0x30:  /* MMC_SPI */
  325:         return 0x0000;
  326:     case 0x34:  /* MMC_SDIO */
  327:         return s->sdio;
  328:     case 0x38:  /* MMC_SYST */
  329:         return 0x0000;
  330: 
  331:     case 0x3c:  /* MMC_REV */
  332:         return 0x0001;
  333: 
  334:     case 0x40:  /* MMC_RSP0 */
  335:     case 0x44:  /* MMC_RSP1 */
  336:     case 0x48:  /* MMC_RSP2 */
  337:     case 0x4c:  /* MMC_RSP3 */
  338:     case 0x50:  /* MMC_RSP4 */
  339:     case 0x54:  /* MMC_RSP5 */
  340:     case 0x58:  /* MMC_RSP6 */
  341:     case 0x5c:  /* MMC_RSP7 */
  342:         return s->rsp[(offset - 0x40) >> 2];
  343:     }
  344: 
  345:     OMAP_BAD_REG(offset);
  346:     return 0;
  347: }
  348: 
  349: static void omap_mmc_write(void *opaque, target_phys_addr_t offset,
  350:                 uint32_t value)
  351: {
  352:     int i;
  353:     struct omap_mmc_s *s = (struct omap_mmc_s *) opaque;
  354:     offset &= OMAP_MPUI_REG_MASK;
  355: 
  356:     switch (offset) {
  357:     case 0x00:  /* MMC_CMD */
  358:         if (!s->enable)
  359:             break;
  360: 
  361:         s->last_cmd = value;
  362:         for (i = 0; i < 8; i ++)
  363:             s->rsp[i] = 0x0000;
  364:         omap_mmc_command(s, value & 63, (value >> 15) & 1,
  365:                 (sd_cmd_type_t) ((value >> 12) & 3),
  366:                 (value >> 11) & 1,
  367:                 (sd_rsp_type_t) ((value >> 8) & 7),
  368:                 (value >> 7) & 1);
  369:         omap_mmc_update(s);
  370:         break;
  371: 
  372:     case 0x04:  /* MMC_ARGL */
  373:         s->arg &= 0xffff0000;
  374:         s->arg |= 0x0000ffff & value;
  375:         break;
  376: 
  377:     case 0x08:  /* MMC_ARGH */
  378:         s->arg &= 0x0000ffff;
  379:         s->arg |= value << 16;
  380:         break;
  381: 
  382:     case 0x0c:  /* MMC_CON */
  383:         s->dw = (value >> 15) & 1;
  384:         s->mode = (value >> 12) & 3;
  385:         s->enable = (value >> 11) & 1;
  386:         if (s->mode != 0)
  387:             printf("SD mode %i unimplemented!\n", s->mode);
  388:         if (s->dw != 0)
  389:             printf("4-bit SD bus enabled\n");
  390:         break;
  391: 
  392:     case 0x10:  /* MMC_STAT */
  393:         s->status &= ~value;
  394:         omap_mmc_interrupts_update(s);
  395:         break;
  396: 
  397:     case 0x14:  /* MMC_IE */
  398:         s->mask = value;
  399:         omap_mmc_interrupts_update(s);
  400:         break;
  401: 
  402:     case 0x18:  /* MMC_CTO */
  403:         s->cto = value & 0xff;
  404:         if (s->cto > 0xfd)
  405:             printf("MMC: CTO of 0xff and 0xfe cannot be used!\n");
  406:         break;
  407: 
  408:     case 0x1c:  /* MMC_DTO */
  409:         s->dto = value & 0xffff;
  410:         break;
  411: 
  412:     case 0x20:  /* MMC_DATA */
  413:         /* TODO: support 8-bit access */
  414:         if (s->fifo_len == 32)
  415:             break;
  416:         s->fifo[(s->fifo_start + s->fifo_len) & 31] = value;
  417:         s->fifo_len ++;
  418:         omap_mmc_transfer(s);
  419:         omap_mmc_fifolevel_update(s);
  420:         omap_mmc_interrupts_update(s);
  421:         break;
  422: 
  423:     case 0x24:  /* MMC_BLEN */
  424:         s->blen = (value & 0x07ff) + 1;
  425:         s->blen_counter = s->blen;
  426:         break;
  427: 
  428:     case 0x28:  /* MMC_NBLK */
  429:         s->nblk = (value & 0x07ff) + 1;
  430:         s->nblk_counter = s->nblk;
  431:         s->blen_counter = s->blen;
  432:         break;
  433: 
  434:     case 0x2c:  /* MMC_BUF */
  435:         s->rx_dma = (value >> 15) & 1;
  436:         s->af_level = (value >> 8) & 0x1f;
  437:         s->tx_dma = (value >> 7) & 1;
  438:         s->ae_level = value & 0x1f;
  439: 
  440:         if (s->rx_dma)
  441:             s->status &= 0xfbff;
  442:         if (s->tx_dma)
  443:             s->status &= 0xf7ff;
  444:         omap_mmc_fifolevel_update(s);
  445:         omap_mmc_interrupts_update(s);
  446:         break;
  447: 
  448:     /* SPI, SDIO and TEST modes unimplemented */
  449:     case 0x30:  /* MMC_SPI */
  450:         break;
  451:     case 0x34:  /* MMC_SDIO */
  452:         s->sdio = value & 0x2020;
  453:         break;
  454:     case 0x38:  /* MMC_SYST */
  455:         break;
  456: 
  457:     case 0x3c:  /* MMC_REV */
  458:     case 0x40:  /* MMC_RSP0 */
  459:     case 0x44:  /* MMC_RSP1 */
  460:     case 0x48:  /* MMC_RSP2 */
  461:     case 0x4c:  /* MMC_RSP3 */
  462:     case 0x50:  /* MMC_RSP4 */
  463:     case 0x54:  /* MMC_RSP5 */
  464:     case 0x58:  /* MMC_RSP6 */
  465:     case 0x5c:  /* MMC_RSP7 */
  466:         OMAP_RO_REG(offset);
  467:         break;
  468: 
  469:     default:
  470:         OMAP_BAD_REG(offset);
  471:     }
  472: }
  473: 
  474: static CPUReadMemoryFunc *omap_mmc_readfn[] = {
  475:     omap_badwidth_read16,
  476:     omap_mmc_read,
  477:     omap_badwidth_read16,
  478: };
  479: 
  480: static CPUWriteMemoryFunc *omap_mmc_writefn[] = {
  481:     omap_badwidth_write16,
  482:     omap_mmc_write,
  483:     omap_badwidth_write16,
  484: };
  485: 
  486: void omap_mmc_reset(struct omap_mmc_s *host)
  487: {
  488:     host->last_cmd = 0;
  489:     memset(host->rsp, 0, sizeof(host->rsp));
  490:     host->arg = 0;
  491:     host->dw = 0;
  492:     host->mode = 0;
  493:     host->enable = 0;
  494:     host->status = 0;
  495:     host->mask = 0;
  496:     host->cto = 0;
  497:     host->dto = 0;
  498:     host->fifo_len = 0;
  499:     host->blen = 0;
  500:     host->blen_counter = 0;
  501:     host->nblk = 0;
  502:     host->nblk_counter = 0;
  503:     host->tx_dma = 0;
  504:     host->rx_dma = 0;
  505:     host->ae_level = 0x00;
  506:     host->af_level = 0x1f;
  507:     host->transfer = 0;
  508: }
  509: 
  510: struct omap_mmc_s *omap_mmc_init(target_phys_addr_t base,
  511:                 BlockDriverState *bd,
  512:                 qemu_irq irq, qemu_irq dma[], omap_clk clk)
  513: {
  514:     int iomemtype;
  515:     struct omap_mmc_s *s = (struct omap_mmc_s *)
  516:             qemu_mallocz(sizeof(struct omap_mmc_s));
  517: 
  518:     s->irq = irq;
  519:     s->base = base;
  520:     s->dma = dma;
  521:     s->clk = clk;
  522: 
  523:     iomemtype = cpu_register_io_memory(0, omap_mmc_readfn,
  524:                     omap_mmc_writefn, s);
  525:     cpu_register_physical_memory(s->base, 0x800, iomemtype);
  526: 
  527:     /* Instantiate the storage */
  528:     s->card = sd_init(bd, 0);
  529: 
  530:     return s;
  531: }
  532: 
  533: void omap_mmc_handlers(struct omap_mmc_s *s, qemu_irq ro, qemu_irq cover)
  534: {
  535:     sd_set_cb(s->card, ro, cover);
  536: }
1
Syntax (Markdown)