r3726 - in trunk/src/host/qemu-neo1973: . hw

andrew at sita.openmoko.org andrew at sita.openmoko.org
Sat Dec 22 04:01:34 CET 2007


Author: andrew
Date: 2007-12-22 04:01:31 +0100 (Sat, 22 Dec 2007)
New Revision: 3726

Added:
   trunk/src/host/qemu-neo1973/hw/ar6000.c
Modified:
   trunk/src/host/qemu-neo1973/Makefile
   trunk/src/host/qemu-neo1973/hw/neo1973.c
   trunk/src/host/qemu-neo1973/hw/pcmcia.h
   trunk/src/host/qemu-neo1973/hw/sd.c
   trunk/src/host/qemu-neo1973/hw/sd.h
Log:
Initial version of Atheros AR6001 files.  Currently it's a dummy SDIO with the
correct Manufacturer/Card ID.  SDIO FBR I/O not yet support.
Attach the AR6k to the SD slot of gta02fake.
Add missing CISTPL IDs to pcmcia.h as they're now shared with SDIO.


Modified: trunk/src/host/qemu-neo1973/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile	2007-12-22 02:30:17 UTC (rev 3725)
+++ trunk/src/host/qemu-neo1973/Makefile	2007-12-22 03:01:31 UTC (rev 3726)
@@ -59,7 +59,7 @@
 OBJS+=scsi-disk.o cdrom.o
 OBJS+=usb.o usb-hub.o usb-linux.o usb-linux-gadget.o
 OBJS+=usb-hid.o usb-msd.o usb-wacom.o usb-net.o usb-bt.o
-OBJS+=sd.o ssi-sd.o
+OBJS+=sd.o ssi-sd.o ar6000.o
 
 ifdef CONFIG_WIN32
 OBJS+=tap-win32.o

Added: trunk/src/host/qemu-neo1973/hw/ar6000.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ar6000.c	2007-12-22 02:30:17 UTC (rev 3725)
+++ trunk/src/host/qemu-neo1973/hw/ar6000.c	2007-12-22 03:01:31 UTC (rev 3726)
@@ -0,0 +1,880 @@
+/*
+ * Atheros AR600X Wireless Ethernet SDIO cards.  Firmware 1.3.
+ *
+ * Copyright (c) 2007 OpenMoko, Inc.
+ * Author: Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ * BIG TODO: Merge all the generic SDIO emulation back into sd.c and
+ * allow hooks for card specific functions to be registered.  This file
+ * then would solely provide callbacks for these hooks.
+ */
+
+#include "hw.h"
+#include "net.h"
+#include "sd.h"
+#include "pcmcia.h"
+
+typedef enum {
+    sd_r0 = 0,	/* no response */
+    sd_r1,	/* normal response command */
+    sd_r2_i,	/* CID register */
+    sd_r2_s,	/* CSD register */
+    sd_r3,	/* OCR register */
+    sd_r4,	/* SDIO OCR register */
+    sd_r5,	/* SDIO direct I/O */
+    sd_r6,	/* Published RCA response */
+    sd_r7,	/* Operating voltage */
+    sd_r1b = -1,
+} sd_rsp_type_t;
+
+struct sdio_s {
+    enum sd_state_e state;
+    uint32_t ioocr;
+    uint16_t rca;
+    uint32_t card_status;
+
+    struct {
+        uint8_t io_enable;
+        uint8_t intr_enable;
+        uint8_t intr;
+        uint8_t bus;
+        uint8_t e4mi;
+        uint8_t power;
+        uint8_t speed;
+    } cccr;
+    struct {
+    } fbr[7];
+    const uint8_t *cis;
+    int cislen;
+
+    qemu_irq *func_irq;
+
+    int spi;
+    int sdio_ok;
+    int current_cmd;
+    uint16_t blk_len[8];
+    struct {
+        uint8_t func;
+        int dir;
+        int blk_len;
+        int blk_num;
+        int step;
+        uint32_t data_start;
+        uint32_t data_offset;
+        uint8_t data[2048];
+    } transfer;		/* TODO Move to per function struct to support sspnd */
+
+    void (*write[8])(struct sdio_s *sd, uint32_t addr, uint8_t *data, int len);
+    void (*read[8])(struct sdio_s *sd, uint32_t addr, uint8_t *data, int len);
+    void (*reset)(struct sdio_s *sd);
+
+    struct sd_card_s card;
+};
+
+#define SDIO_SIZE	0x20000
+#define SDIO_ADDR_MASK	(SDIO_SIZE - 1)
+
+static const sd_cmd_type_t sd_cmd_type[64] = {
+    sd_bc,   sd_none, sd_bcr,  sd_bcr,  sd_none, sd_none, sd_none, sd_ac,
+    sd_bcr,  sd_ac,   sd_ac,   sd_adtc, sd_ac,   sd_ac,   sd_none, sd_ac,
+    sd_ac,   sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac,   sd_ac,   sd_adtc, sd_none,
+    sd_ac,   sd_ac,   sd_none, sd_none, sd_none, sd_none, sd_ac,   sd_none,
+    sd_none, sd_none, sd_bc,   sd_none, sd_none, sd_none, sd_none, sd_none,
+    sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
+    sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+};
+
+static const int sd_cmd_class[64] = {
+    0,  0,  0,  0,  0,  9, 10,  0,  0,  0,  0,  1,  0,  0,  0,  0,
+    2,  2,  2,  2,  3,  3,  3,  3,  4,  4,  4,  4,  6,  6,  6,  6,
+    5,  5, 10, 10, 10, 10,  5,  9,  9,  9,  7,  7,  7,  7,  7,  7,
+    7,  7, 10,  7,  9,  9,  9,  8,  8, 10,  8,  8,  8,  8,  8,  8,
+};
+
+static void sd_set_ioocr(struct sdio_s *sd)
+{
+    /* 2.0 - 3.6 V, No memory present, One function only */
+    sd->ioocr = 0x00ffff00;
+}
+
+static void sd_set_rca(struct sdio_s *sd)
+{
+    sd->rca += 0x4567;
+}
+
+static void sd_set_cardstatus(struct sdio_s *sd)
+{
+    sd->card_status = 0x00001e00;
+}
+
+static int sd_req_crc_validate(struct sd_request_s *req)
+{
+    uint8_t buffer[5];
+    buffer[0] = 0x40 | req->cmd;
+    buffer[1] = (req->arg >> 24) & 0xff;
+    buffer[2] = (req->arg >> 16) & 0xff;
+    buffer[3] = (req->arg >> 8) & 0xff;
+    buffer[4] = (req->arg >> 0) & 0xff;
+    return 0;
+    return sd_crc7(buffer, 5) != req->crc;	/* TODO */
+}
+
+static void sd_response_r1_make(struct sdio_s *sd,
+                                uint8_t *response, uint32_t last_status)
+{
+    uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND;
+    uint32_t status;
+
+    status = (sd->card_status & ~mask) | (last_status & mask);
+    sd->card_status &= ~CARD_STATUS_C;
+
+    response[0] = (status >> 24) & 0xff;
+    response[1] = (status >> 16) & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = (status >> 0) & 0xff;
+}
+
+static void sd_response_r4_make(struct sdio_s *sd, uint8_t *response)
+{
+    response[0] = (sd->ioocr >> 24) & 0xff;
+    response[1] = (sd->ioocr >> 16) & 0xff;
+    response[2] = (sd->ioocr >> 8) & 0xff;
+    response[3] = (sd->ioocr >> 0) & 0xff;
+}
+
+static void sd_response_r5_make(struct sdio_s *sd, uint8_t *response)
+{
+    int byte = 0;
+    uint8_t status, state;
+
+    switch (sd->state) {
+    case sd_initialization_state:
+    case sd_standby_state:
+    case sd_inactive_state:
+    default:
+        state = 0x00;
+        break;
+    case sd_command_state:
+        state = 0x01;
+        break;
+    case sd_transfer_state:
+        state = 0x02;
+        break;
+    }
+
+    if (sd->spi) {
+        status = ((sd->card_status & 0xb7380003) ? (1 << 6) : 0) |
+                ((sd->card_status & ADDRESS_ERROR) ? (1 << 4) : 0) |
+                ((sd->card_status & COM_CRC_ERROR) ? (1 << 3) : 0) |
+                ((sd->card_status & ILLEGAL_COMMAND) ? (1 << 2) : 0) |
+                ((state == 0x00) ? (1 << 0) : 0);
+    } else {
+        status = ((sd->card_status & COM_CRC_ERROR) ? (1 << 7) : 0) |
+                ((sd->card_status & ILLEGAL_COMMAND) ? (1 << 6) : 0) |
+                (state << 4) |
+                ((sd->card_status & 0x37380003) ? (1 << 3) : 0) |
+                ((sd->card_status & ADDRESS_ERROR) ? (1 << 1) : 0) |
+                ((sd->card_status & OUT_OF_RANGE) ? (1 << 0) : 0);
+
+        response[byte ++] = 0;
+        response[byte ++] = 0;
+    }
+    sd->card_status &= ~0xf7f80003;			/* TODO check */
+
+    response[byte ++] = status;
+    response[byte ++] = sd->transfer.data[sd->transfer.data_offset];
+}
+
+static void sd_response_r6_make(struct sdio_s *sd, uint8_t *response)
+{
+    uint16_t arg;
+    uint16_t status;
+
+    arg = sd->rca;
+    status =
+            ((sd->card_status & SD_ERROR)        ? (1 << 13) : 0) |
+            ((sd->card_status & ILLEGAL_COMMAND) ? (1 << 14) : 0) |
+            ((sd->card_status & COM_CRC_ERROR)   ? (1 << 15) : 0);
+
+    response[0] = (arg >> 8) & 0xff;
+    response[1] = arg & 0xff;
+    response[2] = (status >> 8) & 0xff;
+    response[3] = 0;
+}
+
+static void sdio_intr_update(struct sdio_s *sd)
+{
+    int level;
+
+    if (!(sd->cccr.intr_enable & 1) ||				/* IENM */
+                    ((sd->cccr.bus & 3) == 2 &&			/* BusWidth */
+                     !sd->cccr.e4mi && sd->state == sd_transfer_state) ||
+                    (sd->spi && !((sd->cccr.bus & (1 << 6)) &&	/* SCSI */
+                                  (sd->cccr.bus & (1 << 5)))))	/* ECSI */
+        level = 0;
+    else
+        level = !!((sd->cccr.intr << 1) & sd->cccr.intr_enable);
+
+    qemu_set_irq(sd->card.irq, level);
+}
+
+static void sdio_reset(struct sdio_s *sd)
+{
+    int i;
+
+    sd->state = sd_initialization_state;
+    sd->rca = 0x0000;
+    sd->sdio_ok = 0;
+    sd_set_ioocr(sd);
+    sd_set_cardstatus(sd);
+
+    memset(&sd->cccr, 0, sizeof(sd->cccr));
+    memset(&sd->fbr,  0, sizeof(sd->fbr));
+    for (i = 0; i < 8; i ++)
+        sd->blk_len[i] = 0;
+    if (sd->reset)
+        sd->reset(sd);
+
+    /* TODO: should preserve CDDisable (sd->cccr.bus & (1 << 7)) */
+}
+
+static void sdio_transfer_done(struct sdio_s *sd)
+{
+    sd->state = sd_command_state;
+
+    /* Must check interrupts because of 4-wire mode Interrupt Period.  */
+    if ((sd->cccr.bus & 3) == 2)			/* BusWidth */
+        sdio_intr_update(sd);
+}
+
+static sd_rsp_type_t sdio_normal_command(struct sdio_s *sd,
+                struct sd_request_s req)
+{
+    uint32_t rca = 0x0000;
+    uint32_t addr;
+    uint8_t fun;
+
+    if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
+        rca = req.arg >> 16;
+
+    switch (req.cmd) {
+    /* Basic commands (Class 0) */
+    case 0:	/* CMD0:   GO_IDLE_STATE */
+        /* XXX: Used to switch to SPI mode and back */
+        printf("%s: Bus mode switch attempt\n", __FUNCTION__);
+        break;
+
+    case 3:	/* CMD3:   SEND_RELATIVE_ADDR */
+        if (sd->spi || !sd->sdio_ok)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_initialization_state:
+        case sd_standby_state:
+            sd->state = sd_standby_state;
+            sd_set_rca(sd);
+            return sd_r6;
+
+        default:
+            break;
+        }
+        break;
+
+    /* I/O mode commands (Class 9) */
+    case 5:	/* CMD5:   IO_SEND_OP_COND */
+        switch (sd->state) {
+        case sd_initialization_state:
+            /* We accept any voltage.  10000 V is nothing.  */
+            if (req.arg) {
+                sd->state = sd_ready_state;
+                sd->sdio_ok = 1;
+            }
+
+            return sd_r4;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Basic commands (Class 0) */
+    case 7:	/* CMD7:   SELECT/DESELECT_CARD */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_standby_state:
+            if (sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_command_state;
+            return sd_r1b;
+
+        case sd_command_state:
+            if (sd->rca != rca)
+                sd->state = sd_standby_state;
+
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    case 15:	/* CMD15:  GO_INACTIVE_STATE */
+        if (sd->spi)
+            goto bad_cmd;
+        switch (sd->state) {
+        case sd_initialization_state:
+        case sd_standby_state:
+        case sd_command_state:
+            if (sd->rca && sd->rca != rca)
+                return sd_r0;
+
+            sd->state = sd_inactive_state;
+            return sd_r0;
+
+        default:
+            break;
+        }
+        break;
+
+    /* I/O mode commands (Class 9) */
+    case 52:	/* CMD52:  IO_RW_DIRECT */
+        /* XXX In some situations this must preserve cmdNo and restore later */
+        switch (sd->state) {
+        case sd_command_state:
+        case sd_transfer_state:
+            fun = (req.arg >> 28) & 7;
+            addr = (req.arg >> 9) & SDIO_ADDR_MASK;
+            sd->transfer.data_offset = 0;
+            sd->transfer.step = 1;
+
+            if (unlikely(fun > ((sd->ioocr >> 28) & 7))) {
+                sd->card_status |= ADDRESS_ERROR;
+                sd->transfer.data[sd->transfer.data_offset] = req.arg & 0xff;
+                return sd_r5;
+            }
+
+            if ((req.arg >> 31) & 1) {				/* R/W */
+                sd->transfer.data[sd->transfer.data_offset] = req.arg & 0xff;
+                sd->write[fun](sd, addr, sd->transfer.data +
+                                sd->transfer.data_offset, 1);
+            }
+
+            if (((~req.arg >> 31) & 1) ||			/* !R/W */
+                            ((req.arg >> 27) & 1))		/* RAW */
+                sd->read[fun](sd, addr, sd->transfer.data +
+                                sd->transfer.data_offset, 1);
+
+            return sd_r5;
+
+        default:
+            break;
+        }
+        break;
+
+    case 53:	/* CMD53:  IO_RW_EXTENDED */
+        switch (sd->state) {
+        case sd_command_state:
+            fun = (req.arg >> 28) & 7;
+            addr = (req.arg >> 9) & SDIO_ADDR_MASK;
+
+            if (unlikely(fun > ((sd->ioocr >> 28) & 7))) {
+                sd->card_status |= ADDRESS_ERROR;
+                return sd_r1b;
+            }
+
+            sd->transfer.dir = (req.arg >> 31) & 1;		/* R/W */
+            sd->transfer.step = (req.arg >> 27) & 1;		/* OPCode */
+            sd->transfer.func = fun;
+            sd->transfer.data_start = addr;
+            sd->transfer.data_offset = 0;
+            if ((req.arg >> 28) & 1) {				/* BlockMode */
+                if (sd->blk_len[fun] < 1 || sd->blk_len[fun] > 2048)
+                    return sd_r1b;
+
+                sd->transfer.blk_len = sd->blk_len[fun];
+            } else
+                sd->transfer.blk_len = 1;
+            sd->transfer.blk_num = ((req.arg >> 0) & 0x1ff) ?:
+                    ((req.arg >> 28) & 1) ? -1 : 0x200;		/* BlockMode */
+
+            sd->state = sd_transfer_state;
+            return sd_r1b;
+
+        default:
+            break;
+        }
+        break;
+
+    /* Basic commands (Class 0) */
+    case 59:	/* CMD59:  CRC_ON_OFF */
+        if (!sd->spi)
+            goto bad_cmd;
+        /* TODO */
+        return sd_r1;
+
+    default:
+    bad_cmd:
+        sd->card_status |= ILLEGAL_COMMAND;
+
+        printf("%s: Unknown CMD%i\n", __FUNCTION__, req.cmd);
+        return sd->spi ? sd_r1 : sd_r0;
+    }
+
+    sd->card_status |= ILLEGAL_COMMAND;
+    printf("%s: CMD%i in a wrong state\n", __FUNCTION__, req.cmd);
+    return sd->spi ? sd_r1 : sd_r0;
+}
+
+static int sdio_do_command(struct sdio_s *sd, struct sd_request_s *req,
+                uint8_t *response)
+{
+    uint32_t last_status = sd->card_status;
+    sd_rsp_type_t rtype;
+    int rsplen;
+
+    if (sd_req_crc_validate(req)) {
+        sd->card_status &= ~COM_CRC_ERROR;
+        return 0;
+    }
+
+    sd->card_status &= ~CARD_STATUS_B;
+
+    rtype = sdio_normal_command(sd, *req);
+
+    sd->current_cmd = req->cmd;
+
+    switch (rtype) {
+    case sd_r1:
+    case sd_r1b:
+        sd_response_r1_make(sd, response, last_status);
+        rsplen = 4;
+        break;
+
+    case sd_r4:
+        sd_response_r4_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r5:
+        sd_response_r5_make(sd, response);
+        rsplen = sd->spi ? 2 : 4;
+        break;
+
+    case sd_r6:
+        sd_response_r6_make(sd, response);
+        rsplen = 4;
+        break;
+
+    case sd_r0:
+    default:
+        rsplen = 0;
+        break;
+    }
+
+    if (sd->card_status & ILLEGAL_COMMAND)
+        rsplen = 0;
+
+    return rsplen;
+}
+
+static void sdio_write_data(struct sdio_s *sd, uint8_t value)
+{
+    if (sd->state != sd_transfer_state) {
+        printf("%s: not in Transfer state\n", __FUNCTION__);
+        return;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | OUT_OF_RANGE | SD_ERROR))
+        return;
+
+    switch (sd->current_cmd) {
+    case 53:	/* CMD53:  IO_RW_EXTENDED */
+        if (!sd->transfer.dir)
+            goto bad_cmd;
+
+        sd->transfer.data[sd->transfer.data_offset ++] = value;
+        if (sd->transfer.data_offset >= sd->transfer.blk_len) {
+            /* TODO: Check CRC before committing */
+            sd->write[sd->transfer.func](sd, sd->transfer.data_start,
+                            sd->transfer.data, sd->transfer.blk_len);
+
+            if (sd->transfer.blk_num >= 0)
+                if (!-- sd->transfer.blk_num) {
+                    sdio_transfer_done(sd);
+                    break;
+                }
+
+            sd->transfer.data_start +=
+                    sd->transfer.blk_len * sd->transfer.step;
+            sd->transfer.data_offset = 0;
+        }
+        break;
+
+    default:
+    bad_cmd:
+        printf("%s: unknown command\n", __FUNCTION__);
+        break;
+    }
+}
+
+static uint8_t sdio_read_data(struct sdio_s *sd)
+{
+    /* TODO: Append CRCs */
+    uint8_t ret;
+
+    if (sd->state != sd_receivingdata_state) {
+        printf("%s: not in Transfer state\n", __FUNCTION__);
+        return 0x00;
+    }
+
+    if (sd->card_status & (ADDRESS_ERROR | OUT_OF_RANGE | SD_ERROR))
+        return 0x00;
+
+    switch (sd->current_cmd) {
+    case 53:	/* CMD53:  IO_RW_EXTENDED */
+        if (sd->transfer.dir)
+            goto bad_cmd;
+
+        if (!sd->transfer.data_offset)
+            sd->read[sd->transfer.func](sd, sd->transfer.data_start,
+                            sd->transfer.data, sd->transfer.blk_len);
+
+        ret = sd->transfer.data[sd->transfer.data_offset ++];
+
+        if (sd->transfer.data_offset >= sd->transfer.blk_len) {
+            if (sd->transfer.blk_num >= 0)
+                if (!-- sd->transfer.blk_num) {
+                    sdio_transfer_done(sd);
+                    break;
+                }
+
+            sd->transfer.data_start +=
+                    sd->transfer.blk_len * sd->transfer.step;
+            sd->transfer.data_offset = 0;
+        }
+        break;
+
+    default:
+    bad_cmd:
+        printf("%s: unknown command\n", __FUNCTION__);
+        return 0x00;
+    }
+
+    return ret;
+}
+
+static int sdio_data_ready(struct sdio_s *sd)
+{
+    return sd->state == sd_transfer_state;
+}
+
+static void sdio_cccr_write(struct sdio_s *sd, uint32_t offset, uint8_t value)
+{
+    switch (offset) {
+    case 0x02:	/* I/O Enable */
+        sd->cccr.io_enable =
+                value & (((1 << ((sd->ioocr >> 28) & 7)) - 1) << 1);
+        /* TODO: reset the disabled functions */
+        break;
+
+    case 0x04:	/* Int Enable */
+        sd->cccr.intr_enable = value;
+        sdio_intr_update(sd);
+        break;
+
+    case 0x06:	/* I/O Abort */
+        if ((value >> 3) & 1)				/* RES */
+            sdio_reset(sd);
+        else if ((value >> 0) & 7) {			/* ASx */
+            if (sd->state == sd_transfer_state &&
+                            sd->transfer.func == (value & 7) && !sd->spi)
+                sdio_transfer_done(sd);
+            else
+                fprintf(stderr, "%s: no transfer to abort for function %i\n",
+                                __FUNCTION__, value & 7);
+        }
+
+        break;
+
+    case 0x07:	/* Bus Interface Control */
+        sd->cccr.bus = (value & 0xe3) | 0x40;
+        if (value & 1)
+            fprintf(stderr, "%s: wrong bus-width selected\n", __FUNCTION__);
+        if (sd->spi)
+            sdio_intr_update(sd);
+        /* XXX Possibly toggle some SD_DETECT gpio on CDDisable change */
+        break;
+
+    case 0x08:	/* Card Capability */
+        sd->cccr.e4mi = value & 0x20;
+        break;
+
+    /* Since SBS == 0, Function Select and Bus Suspend are R/O.  */
+
+    case 0x0f:	/* Ready Flags */
+        break;
+
+    case 0x10:	/* Fn0 Block Size LSB */
+        sd->blk_len[0] &= 0xff << 8;
+        sd->blk_len[0] |= value;
+        break;
+
+    case 0x11:	/* Fn0 Block Size MSB */
+        sd->blk_len[0] &= 0xff;
+        sd->blk_len[0] |= value << 8;
+        break;
+
+    case 0x12:	/* Power Control */
+        sd->cccr.power |= value & 0x02;				/* EMPC */
+        break;
+
+    case 0x13:	/* High-Speed */
+        sd->cccr.speed |= value & 0x02;				/* EHS */
+        break;
+
+    default:
+        printf("%s: unknown register %02x\n", __FUNCTION__, offset);
+    }
+}
+
+static uint8_t sdio_cccr_read(struct sdio_s *sd, uint32_t offset)
+{
+    switch (offset) {
+    case 0x00:	/* CCCR/SDIO Revison */
+        return 0x32;
+
+    case 0x01:	/* SD Specification Revision */
+        return 0x02;	/* SD Physical Specification Version 2.00 (May 2006) */
+
+    case 0x02:	/* I/O Enable */
+        return sd->cccr.io_enable;
+
+    case 0x03:	/* I/O Ready */
+        return sd->cccr.io_enable;
+
+    case 0x04:	/* Int Enable */
+        return sd->cccr.intr_enable;
+
+    case 0x05:	/* Int Pending */
+        return sd->cccr.intr << 1;
+
+    case 0x07:	/* Bus Interface Control */
+        return sd->cccr.bus;
+
+    case 0x08:	/* Card Capability */
+        /* XXX: set SDC (01) when CMD52 learns to preserve current_cmd */
+        return 0x12 | sd->cccr.e4mi;	/* SMB | S4MI | E4MI | Full-Speed */
+
+    case 0x09:	/* Common CIS Pointer */
+    case 0x0a:	/* Common CIS Pointer */
+    case 0x0b:	/* Common CIS Pointer */
+        return 0x00;	/* Starts at 0x1000 */
+
+    case 0x1c:	/* Bus Suspend */
+        return 0x00;
+
+    case 0x1d:	/* Function Select */
+        return sd->transfer.func;
+
+    case 0x0e:	/* Exec Flags */
+        return 0x00;
+
+    case 0x0f:	/* Ready Flags */
+        return 0x00;
+
+    case 0x10:	/* Fn0 Block Size LSB */
+        return (sd->blk_len[0] >> 0) & 0xff;
+
+    case 0x11:	/* Fn0 Block Size MSB */
+        return (sd->blk_len[0] >> 8) & 0xff;
+
+    case 0x12:	/* Power Control */
+        return sd->cccr.power | 0x01;
+
+    case 0x13:	/* High-Speed */
+        return sd->cccr.speed | 0x01;
+
+    default:
+        printf("%s: unknown register %02x\n", __FUNCTION__, offset);
+        return 0;
+    }
+}
+
+static void sdio_fbr_write(struct sdio_s *sd,
+                int fn, uint32_t offset, uint8_t value)
+{
+    switch (offset) {
+    default:
+        printf("%s: unknown register %02x\n", __FUNCTION__, offset);
+    }
+}
+
+static uint8_t sdio_fbr_read(struct sdio_s *sd,
+                int fn, uint32_t offset)
+{
+    switch (offset) {
+    default:
+        printf("%s: unknown register %02x\n", __FUNCTION__, offset);
+        return 0;
+    }
+}
+
+static void sdio_cia_write(struct sdio_s *sd,
+                uint32_t addr, uint8_t *data, int len)
+{
+    /* CCCR */
+    for (; len && addr < 0x100; len --, addr += sd->transfer.step)
+        sdio_cccr_write(sd, addr, *data ++);
+
+    /* FBR */
+    for (; len && addr < 0x800; len --, addr += sd->transfer.step)
+        sdio_fbr_write(sd, addr >> 8, addr & 0xff, *data ++);
+
+    if (len)
+        fprintf(stderr, "%s: bad write at %x (%i bytes)\n",
+                        __FUNCTION__, addr, len);
+}
+
+static void sdio_cia_read(struct sdio_s *sd,
+                uint32_t addr, uint8_t *data, int len)
+{
+    int llen;
+
+    /* CCCR */
+    for (; len && addr < 0x100; len --, addr += sd->transfer.step)
+        *data ++ = sdio_cccr_read(sd, addr);
+
+    /* FBR */
+    for (; len && addr < 0x800; len --, addr += sd->transfer.step)
+        *data ++ = sdio_fbr_read(sd, addr >> 8, addr & 0xff);
+
+    /* RFU */
+    if (len && unlikely(addr < 0x1000)) {
+        llen = sd->transfer.step ? MIN(len, 0x1000 - addr) : len;
+        memset(data, 0, llen);
+        data += llen;
+        len -= llen;
+        addr = 0x1000;
+    }
+
+    /* CIS */
+    addr -= 0x1000;
+    if (len && addr < sd->cislen) {
+        llen = MIN(len, sd->cislen - addr);
+        memcpy(data, sd->cis + addr, llen);
+        data += llen;
+        len -= llen;
+    }
+
+    /* RFU */
+    if (len)
+        memset(data, 0, len);
+}
+
+static void sdio_dummy_write(struct sdio_s *sd,
+                uint32_t addr, uint8_t *data, int len)
+{
+    fprintf(stderr, "%s: writing %i bytes at %x\n", __FUNCTION__, len, addr);
+}
+
+static void sdio_dummy_read(struct sdio_s *sd,
+                uint32_t addr, uint8_t *data, int len)
+{
+    fprintf(stderr, "%s: reading %i bytes at %x\n", __FUNCTION__, len, addr);
+    memset(data, 0, sd->transfer.step ? len : 1);
+}
+
+static void sdio_set_irq(void *opaque, int line, int level)
+{
+    struct sdio_s *s = opaque;
+
+    if (level)
+        s->cccr.intr |= 1 << line;
+    else
+        s->cccr.intr &= ~(1 << line);
+
+    sdio_intr_update(s);
+}
+
+struct sd_card_s *sdio_init(struct sdio_s *s)
+{
+    int i;
+
+    for (i = 0; i < 8; i ++) {
+        s->write[i] = i ? sdio_dummy_write : sdio_cia_write;
+        s->read[i]  = i ? sdio_dummy_read  : sdio_cia_read;
+    }
+
+    s->func_irq = qemu_allocate_irqs(sdio_set_irq, s, 7);
+
+    s->card.opaque = s;
+    s->card.do_command = (void *) sdio_do_command;
+    s->card.write_data = (void *) sdio_write_data;
+    s->card.read_data  = (void *) sdio_read_data;
+    s->card.data_ready = (void *) sdio_data_ready;
+
+    sdio_reset(s);
+
+    return &s->card;
+}
+
+struct ar6k_s {
+    struct sdio_s sd;
+    NICInfo *nd;
+};
+
+static void ar6k_set_ioocr(struct sdio_s *sd)
+{
+    /* 2.9 - 3.6 V, No memory present, Two functions only */
+    sd->ioocr = 0x10fe0000;
+}
+
+static void ar6k_reset(struct ar6k_s *s)
+{
+    ar6k_set_ioocr(&s->sd);
+}
+
+/* TODO: dump real values from an Atheros AR6001 - need hw access! */
+const static uint8_t ar6k_cis[] = {
+    CISTPL_MANFID, 4,
+    0x0a, 0x01,			/* SDIO Card manufacturer code */
+    0x71, 0x02,			/* Manufacturer information (Part No, Rev) */
+
+    CISTPL_FUNCID, 2,
+    0x0c,			/* Card funcion code: SDIO */
+    0x00,			/* System initialization mask */
+
+    CISTPL_END, 0xff,
+};
+
+struct sd_card_s *ar6k_init(NICInfo *nd)
+{
+    struct ar6k_s *s = (struct ar6k_s *) qemu_mallocz(sizeof(struct ar6k_s));
+    struct sd_card_s *ret = sdio_init(&s->sd);
+
+    s->nd = nd;
+    s->sd.reset = (void *) ar6k_reset;
+    s->sd.cis = ar6k_cis;
+    s->sd.cislen = sizeof(ar6k_cis);
+
+    ar6k_reset(s);
+
+    return ret;
+}

Modified: trunk/src/host/qemu-neo1973/hw/neo1973.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/neo1973.c	2007-12-22 02:30:17 UTC (rev 3725)
+++ trunk/src/host/qemu-neo1973/hw/neo1973.c	2007-12-22 03:01:31 UTC (rev 3726)
@@ -27,6 +27,12 @@
 
 #define GTA01Bv4		1
 
+enum {
+    NEO1973_GTA01	= 1182,
+    NEO1973_GTA02	= 1304,
+    NEO1973_GTA02F	= 1555,
+};
+
 /* Wiring common to all revisions */
 #define GTA01_GPIO_BACKLIGHT	S3C_GPB(0)
 #define GTA01_GPIO_GPS_PWRON	S3C_GPB(1)
@@ -261,7 +267,9 @@
 
     s3c_timers_cmp_handler_set(s->cpu->timers, 0, neo_bl_intensity, s);
 
-    sd_set_cb(s->mmc, 0, s3c_gpio_in_get(s->cpu->io)[GTA01_IRQ_nSD_DETECT]);
+    if (s->id == NEO1973_GTA01)
+        sd_set_cb(s->mmc, 0,
+                        s3c_gpio_in_get(s->cpu->io)[GTA01_IRQ_nSD_DETECT]);
 }
 
 /* PMB 2520 Hammerhead A-GPS chip */
@@ -524,7 +532,7 @@
         sd = sd_init(drives_table[sd_idx].bdrv, 0);
 
     neo1973_init_common(ram_size, ds,
-                    kernel_filename, cpu_model, sd, 1304);
+                    kernel_filename, cpu_model, sd, NEO1973_GTA01);
 }
 
 static void gta02f_init(int ram_size, int vga_ram_size,
@@ -533,9 +541,10 @@
                 const char *initrd_filename, const char *cpu_model)
 {
     struct neo_board_s *neo;
+    struct sd_card_s *sd = ar6k_init(&nd_table[0]);
 
     neo = neo1973_init_common(ram_size, ds,
-                    kernel_filename, cpu_model, 0, 1555);
+                    kernel_filename, cpu_model, sd, NEO1973_GTA02F);
 
     neo_gps_setup(neo);
     neo_machid_init(neo);

Modified: trunk/src/host/qemu-neo1973/hw/pcmcia.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pcmcia.h	2007-12-22 02:30:17 UTC (rev 3725)
+++ trunk/src/host/qemu-neo1973/hw/pcmcia.h	2007-12-22 03:01:31 UTC (rev 3726)
@@ -28,9 +28,12 @@
     void (*io_write)(void *state, uint32_t address, uint16_t value);
 };
 
+#define CISTPL_NULL		0x00	/* Null Tuple */
 #define CISTPL_DEVICE		0x01	/* 5V Device Information Tuple */
+#define CISTPL_CHECKSUM		0x10	/* Checksum Control Tuple */
 #define CISTPL_NO_LINK		0x14	/* No Link Tuple */
 #define CISTPL_VERS_1		0x15	/* Level 1 Version Tuple */
+#define CISTPL_ALTSTR		0x16	/* The Alternate Language String */
 #define CISTPL_JEDEC_C		0x18	/* JEDEC ID Tuple */
 #define CISTPL_JEDEC_A		0x19	/* JEDEC ID Tuple */
 #define CISTPL_CONFIG		0x1a	/* Configuration Tuple */
@@ -39,12 +42,16 @@
 #define CISTPL_DEVICE_OA	0x1d	/* Additional Device Information */
 #define CISTPL_DEVICE_GEO	0x1e	/* Additional Device Information */
 #define CISTPL_DEVICE_GEO_A	0x1f	/* Additional Device Information */
-#define CISTPL_MANFID		0x20	/* Manufacture ID Tuple */
+#define CISTPL_MANFID		0x20	/* Manufacture ID String Tuple */
 #define CISTPL_FUNCID		0x21	/* Function ID Tuple */
 #define CISTPL_FUNCE		0x22	/* Function Extension Tuple */
-#define CISTPL_END		0xff	/* Tuple End */
+#define CISTPL_END		0xff	/* End-of-chain Tuple */
 #define CISTPL_ENDMARK		0xff
 
+/* SDIO Unique Tuples */
+#define CISTPL_SDIO_STD		0x91	/* Application Spec. Support Info */
+#define CISTPL_SDIO_EXT		0x92	/* SDIO Future-Use Reserved */
+
 /* dscm1xxxx.c */
 struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv);
 

Modified: trunk/src/host/qemu-neo1973/hw/sd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sd.c	2007-12-22 02:30:17 UTC (rev 3725)
+++ trunk/src/host/qemu-neo1973/hw/sd.c	2007-12-22 03:01:31 UTC (rev 3726)
@@ -149,39 +149,6 @@
     7,  7, 10,  7,  9,  9,  9,  8,  8, 10,  8,  8,  8,  8,  8,  8,
 };
 
-static uint8_t sd_crc7(void *message, size_t width)
-{
-    int i, bit;
-    uint8_t shift_reg = 0x00;
-    uint8_t *msg = (uint8_t *) message;
-
-    for (i = 0; i < width; i ++, msg ++)
-        for (bit = 7; bit >= 0; bit --) {
-            shift_reg <<= 1;
-            if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
-                shift_reg ^= 0x89;
-        }
-
-    return shift_reg;
-}
-
-static uint16_t sd_crc16(void *message, size_t width)
-{
-    int i, bit;
-    uint16_t shift_reg = 0x0000;
-    uint16_t *msg = (uint16_t *) message;
-    width <<= 1;
-
-    for (i = 0; i < width; i ++, msg ++)
-        for (bit = 15; bit >= 0; bit --) {
-            shift_reg <<= 1;
-            if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
-                shift_reg ^= 0x1011;
-        }
-
-    return shift_reg;
-}
-
 static void sd_set_ocr(SDState *sd)
 {
     /* All voltages OK, card power-up OK, Standard Capacity SD Memory Card */

Modified: trunk/src/host/qemu-neo1973/hw/sd.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sd.h	2007-12-22 02:30:17 UTC (rev 3725)
+++ trunk/src/host/qemu-neo1973/hw/sd.h	2007-12-22 03:01:31 UTC (rev 3726)
@@ -118,6 +118,39 @@
     return sd->data_ready(sd->opaque);
 }
 
+static inline uint8_t sd_crc7(void *message, size_t width)
+{
+    int i, bit;
+    uint8_t shift_reg = 0x00;
+    uint8_t *msg = (uint8_t *) message;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 7; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x89;
+        }
+
+    return shift_reg;
+}
+
+static inline uint16_t sd_crc16(void *message, size_t width)
+{
+    int i, bit;
+    uint16_t shift_reg = 0x0000;
+    uint16_t *msg = (uint16_t *) message;
+    width <<= 1;
+
+    for (i = 0; i < width; i ++, msg ++)
+        for (bit = 15; bit >= 0; bit --) {
+            shift_reg <<= 1;
+            if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
+                shift_reg ^= 0x1011;
+        }
+
+    return shift_reg;
+}
+
 /* sd.c */
 struct sd_card_s *sd_init(BlockDriverState *bs, int is_spi);
 void sd_set_cb(struct sd_card_s *sd, qemu_irq readonly, qemu_irq insert);





More information about the commitlog mailing list