root/usr/src/uts/common/sys/sdcard/sda.h
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
 */

#ifndef _SYS_SDCARD_SDA_H
#define _SYS_SDCARD_SDA_H

#include <sys/types.h>
#include <sys/note.h>

#ifdef  __cplusplus
extern "C" {
#endif

/*
 * SD card common framework.  This module provides most of the common
 * functionality so that SecureDigital host adapters and client devices
 * (such as the sdmem driver) can share common code.
 */

/*
 * SD Commands.  Commmand format is 48-bits as follows:
 *
 * bits         value           desc
 * -------------------------------------------
 * 47           0               start bit
 * 46           1               transmission bit
 * 45:40        cmd             command index (see values listed below)
 * 39:8         arg             32-bit command argument
 * 7:1          crc7            crc7 check value
 * 0            1               end bit
 * -------------------------------------------
 */
typedef enum {
        CMD_GO_IDLE = 0,
        CMD_SEND_OCR = 1,               /* MMC only */
        CMD_BCAST_CID = 2,
        CMD_SEND_RCA = 3,
        CMD_SET_DSR = 4,
        CMD_IO_SEND_OCR = 5,            /* SDIO only */
        CMD_SWITCH_FUNC = 6,
        CMD_SELECT_CARD = 7,
        CMD_SEND_IF_COND = 8,
        CMD_SEND_CSD = 9,
        CMD_SEND_CID = 10,
        CMD_STOP_TRANSMIT = 12,
        CMD_SEND_STATUS = 13,
        CMD_GO_INACTIVE = 15,
        CMD_SET_BLOCKLEN = 16,
        CMD_READ_SINGLE = 17,
        CMD_READ_MULTI = 18,
        CMD_WRITE_SINGLE = 24,
        CMD_WRITE_MULTI = 25,
        CMD_PROGRAM_CSD = 27,
        CMD_SET_WRITE_PROT = 28,
        CMD_CLR_WRITE_PROT = 29,
        CMD_SEND_WRITE_PROT = 30,
        CMD_ERASE_START = 32,
        CMD_ERASE_END = 33,
        CMD_ERASE = 38,
        CMD_LOCK = 42,
        CMD_IO_RW_DIRECT = 52,
        CMD_IO_RW_EXTENDED = 53,
        CMD_APP_CMD = 55,
        CMD_GEN_CMD = 56,
        /* APP CMD values, send ACMD first */
        ACMD_SET_BUS_WIDTH = 6,
        ACMD_SD_STATUS = 13,
        ACMD_SEND_NUM_WR_BLKS = 22,
        ACMD_SET_WR_BLK_ERASE_COUNT = 23,
        ACMD_SD_SEND_OCR = 41,
        ACMD_SET_CLR_CARD_DETECT = 42,
        ACMD_SEND_SCR = 51
} sda_index_t;

/*
 * Classes of response type.  Note that we encode the "busy bit" as
 * value 0x10.
 */
typedef enum {
        R0 = 0,
        R1 = 1,
        R2 = 2,
        R3 = 3,
        R4 = 4,
        R5 = 5,
        R6 = 6,
        R7 = 7,
        Rb = 0x10,
        R1b = 0x11,
        R5b = 0x15
} sda_rtype_t;

/*
 * R1 status bits.
 */
#define R1_OUT_OF_RANGE         (1U << 31)
#define R1_ADDRESS_ERROR        (1U << 30)
#define R1_BLOCK_LEN_ERROR      (1U << 29)
#define R1_ERASE_SEQ_ERROR      (1U << 28)
#define R1_ERASE_PARAM          (1U << 27)
#define R1_WP_VIOLATION         (1U << 26)
#define R1_CARD_IS_LOCKED       (1U << 25)
#define R1_LOCK_FAILED          (1U << 24)
#define R1_COM_CRC_ERROR        (1U << 23)
#define R1_ILLEGAL_COMMAND      (1U << 22)
#define R1_CARD_ECC_FAILED      (1U << 21)
#define R1_CC_ERROR             (1U << 20)
#define R1_ERROR                (1U << 19)
#define R1_CSD_OVERWRITE        (1U << 16)
#define R1_WP_ERASE_SKIP        (1U << 15)
#define R1_CARD_ECC_DIS         (1U << 14)
#define R1_ERASE_RESET          (1U << 13)
#define R1_READY_FOR_DATA       (1U << 8)
#define R1_APP_CMD              (1U << 5)
#define R1_AKE_SEQ_ERROR        (1U << 3)

/*
 * Note that R1_COM_CRC_ERR, R1_ILLEGAL_COMMAND, R1_ERASE_SEQ_ERROR, and
 * R1_AKE_SEQ_ERROR errors are delayed error bits reported on the next
 * command.  So we don't list them here.
 */
#define R1_ERRS (\
        R1_ERROR | R1_OUT_OF_RANGE | R1_ADDRESS_ERROR | R1_BLOCK_LEN_ERROR | \
        R1_ERASE_PARAM | R1_WP_VIOLATION | R1_LOCK_FAILED | \
        R1_CARD_ECC_FAILED | R1_CC_ERROR | R1_CSD_OVERWRITE | \
        R1_WP_ERASE_SKIP)

#define R1_STATE(x)     (((x) & 0xf) >> 9)

/*
 * R5 status bits.
 */
#define R5_COM_CRC_ERROR        (1U << 7)
#define R5_ILLEGAL_COMMAND      (1U << 6)
#define R5_ERROR                (1U << 3)
#define R5_RFU                  (1U << 2)
#define R5_FUNCTION_NUMBER      (1U << 1)
#define R5_OUT_OF_RANGE         (1U << 0)

#define R5_ERRS (R5_ERROR | R5_FUNCTION_NUMBER | R5_OUT_OF_RANGE)

#define R5_IO_STATE(x)  (((x) & 0x3) >> 4)

/*
 * R7 bits (CMD8).
 */
#define R7_VHS_27_36V           (1U << 8)
#define R7_PATTERN              (0xAA)

/*
 * OCR bits.
 */
#define OCR_POWER_UP            (1U << 31)
#define OCR_CCS                 (1U << 30)
#define OCR_FUNCS(x)            (((x) & 7) >> 28)       /* SDIO only */
#define OCR_MEM_PRESENT         (1U << 27)              /* SDIO only */
#define OCR_VOLTAGE_MASK        (0xffffffU)             /* (bits 0-23 */
#define OCR_HI_MASK             (0xff8000U)             /* 2.7-3.6V */
#define OCR_35_36V              (1U << 23)
#define OCR_34_35V              (1U << 22)
#define OCR_33_34V              (1U << 21)
#define OCR_32_33V              (1U << 20)
#define OCR_31_32V              (1U << 19)
#define OCR_30_31V              (1U << 18)
#define OCR_29_30V              (1U << 17)
#define OCR_28_29V              (1U << 16)
#define OCR_27_28V              (1U << 15)
#define OCR_26_27V              (1U << 14)
#define OCR_25_26V              (1U << 14)
#define OCR_24_25V              (1U << 13)
#define OCR_23_24V              (1U << 12)
#define OCR_22_23V              (1U << 11)
#define OCR_21_22V              (1U << 10)
#define OCR_20_21V              (1U << 9)
#define OCR_19_20V              (1U << 8)
#define OCR_18_19V              (1U << 7)
#define OCR_17_18V              (1U << 6)


/*
 * Command structure.  Used internally by the framework, and by host
 * drivers.  Note that it is forbidden to depend on the size of this
 * structure.
 */
typedef struct sda_cmd sda_cmd_t;

struct sda_cmd {
        /*
         * The ordering of these is done to maximize packing.
         */
        sda_index_t             sc_index;       /* command name */
        sda_rtype_t             sc_rtype;       /* response type expected */
        uint16_t                sc_flags;
        uint32_t                sc_argument;    /* command argument */

        uint32_t                sc_response[4];

        uint16_t                sc_nblks;
        uint16_t                sc_blksz;

        uint32_t                sc_resid;

        ddi_dma_handle_t        sc_dmah;
        uint_t                  sc_ndmac;       /* # DMA cookies */
        ddi_dma_cookie_t        sc_dmac;        /* actual DMA cookies */
        caddr_t                 sc_kvaddr;      /* kernel virtual address */

#define SDA_CMDF_READ           0x0001          /* transfer direction */
#define SDA_CMDF_WRITE          0x0002          /* transfer direction */
#define SDA_CMDF_AUTO_CMD12     0x0004          /* cmd12 requested */
/* private flags .. not for driver consumption */
#define SDA_CMDF_DAT            0x0100          /* data phase pending */
#define SDA_CMDF_BUSY           0x0200          /* cmd in-flight or queued */
#define SDA_CMDF_INIT           0x0400          /* initialization command */
#define SDA_CMDF_MEM            0x0800          /* memory target command */
};

/*
 * The framework has two APIs.  The first API is for host controllers,
 * and is referred to as SDHOST.  The second API is for target devices,
 * and is referred to as SDCLIENT.  Please don't mix and match usage outside
 * of the framework implementation itself!
 */

typedef struct sda_host sda_host_t;

typedef enum {
        SDA_PROP_INSERTED =     1,      /* R: is card inserted? */
        SDA_PROP_WPROTECT =     2,      /* R: is card write protected */
        SDA_PROP_LED =          3,      /* W: LED */
        SDA_PROP_CLOCK =        4,      /* R: frequency, Hz */
        SDA_PROP_BUSWIDTH =     5,      /* W: bus width */
        SDA_PROP_OCR =          6,      /* RW: ocr R: supported, W: set curr */
        SDA_PROP_CAP_4BITS =    7,      /* R: 4 bit data bus? */
        SDA_PROP_CAP_8BITS =    8,      /* R: MMC future expansion */
        SDA_PROP_CAP_HISPEED =  9,      /* R: fast bus rates (> 25MHz) */
        SDA_PROP_CAP_INTR =     10,     /* R: SDIO interrupt support */
        SDA_PROP_CAP_NOPIO =    11,     /* R: Never needs bp_mapin */
        SDA_PROP_HISPEED =      12      /* W: high speed (>25MHz) */
} sda_prop_t;

typedef enum {
        SDA_FAULT_NONE =        0,      /* No failure */
        SDA_FAULT_ACMD12 =      1,      /* Auto CMD12 failure */
        SDA_FAULT_CRC7 =        2,      /* CRC7 failure on CMD/DAT line */
        SDA_FAULT_PROTO =       3,      /* SD/MMC protocol error */
        SDA_FAULT_CURRENT =     4,      /* Current overlimit detected */
        SDA_FAULT_INIT =        5,      /* Card initialization failure */
        SDA_FAULT_TIMEOUT =     6,      /* Unexpected timeout failure */
        SDA_FAULT_HOST =        7,      /* Internal host or slot failure */
        SDA_FAULT_RESET =       8,      /* Slot failed to reset */
} sda_fault_t;

typedef enum {
        SDA_EOK =               0,      /* Success */
        SDA_ECRC7 =             1,      /* CRC7 failure */
        SDA_EPROTO =            2,      /* SD/MMC protocol error */
        SDA_EINVAL =            3,      /* Invalid argument */
        SDA_ETIME =             4,      /* Timeout */
        SDA_ECMD12 =            5,      /* Failed during stop cmd */
        SDA_ENOTSUP =           6,      /* Setting/property not supported */
        SDA_ERESID =            7,      /* Incomplete transfer */
        SDA_EFAULT =            8,      /* Previous fault condition present */
        SDA_ENOMEM =            9,      /* Memory exhausted */
        SDA_EWPROTECT =         10,     /* Media is write protected */
        SDA_ENODEV =            11,     /* Card removed */
        SDA_ERESET =            12,     /* Memory card reset */
        SDA_EABORT =            13,     /* Memory command aborted */
        SDA_EIO =               14,     /* Other generic error */
        SDA_ESUSPENDED =        15,     /* Slot has been suspended */
} sda_err_t;

typedef struct sda_ops {
        int     so_version;
#define SDA_OPS_VERSION 1
        sda_err_t       (*so_cmd)(void *, sda_cmd_t *);
        sda_err_t       (*so_getprop)(void *, sda_prop_t, uint32_t *);
        sda_err_t       (*so_setprop)(void *, sda_prop_t, uint32_t);
        sda_err_t       (*so_poll)(void *);
        sda_err_t       (*so_reset)(void *);
        sda_err_t       (*so_halt)(void *);
} sda_ops_t;

/*
 * Host operations.
 */
void sda_host_init_ops(struct dev_ops *);
void sda_host_fini_ops(struct dev_ops *);
sda_host_t *sda_host_alloc(dev_info_t *, int, sda_ops_t *, ddi_dma_attr_t *);
void sda_host_free(sda_host_t *);
void sda_host_set_private(sda_host_t *, int, void *);
int sda_host_attach(sda_host_t *);
void sda_host_detach(sda_host_t *);
void sda_host_suspend(sda_host_t *);
void sda_host_resume(sda_host_t *);
void sda_host_detect(sda_host_t *, int);
void sda_host_fault(sda_host_t *, int, sda_fault_t);
void sda_host_transfer(sda_host_t *, int, sda_err_t);
/*PRINTFLIKE3*/
void sda_host_log(sda_host_t *, int, const char *, ...);

#ifdef  __cplusplus
}
#endif

#endif  /* _SYS_SDCARD_SDA_H */