/* * 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 #include #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 */ /* * 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_IMPL_H #define _SYS_SDCARD_SDA_IMPL_H #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /* * Type and structure definitions. */ typedef struct sda_slot sda_slot_t; /* * Per slot state. */ struct sda_slot { sda_host_t *s_hostp; void *s_prv; /* bus private data */ dev_info_t *s_dip; /* devinfo node for child */ int s_slot_num; boolean_t s_inserted; boolean_t s_failed; uint8_t s_num_io; uint32_t s_cur_ocr; /* current ocr */ uint16_t s_rca; uint32_t s_maxclk; /* maximum freq for card */ sda_cmd_t *s_xfrp; /* pending transfer cmd */ hrtime_t s_xfrtmo; /* transfer timeout */ boolean_t s_reap; boolean_t s_warn; boolean_t s_ready; /* target node ready */ boolean_t s_init; /* slot initializing */ /* these are protected by the evlock */ boolean_t s_wake; /* wake up thread */ boolean_t s_detach; /* detach in progress */ boolean_t s_suspend; /* host has DDI_SUSPENDed */ boolean_t s_detect; /* detect event occurred */ sda_fault_t s_fault; boolean_t s_xfrdone; /* transfer event occurred */ sda_err_t s_errno; uint16_t s_flags; #define SLOTF_WRITABLE 0x0004 #define SLOTF_4BITS 0x0008 #define SLOTF_IFCOND 0x0010 #define SLOTF_MMC 0x0020 #define SLOTF_SDMEM 0x0040 #define SLOTF_SDIO 0x0080 #define SLOTF_SDHC 0x0100 #define SLOTF_MEMORY (SLOTF_MMC | SLOTF_SDMEM) #define SLOTF_SD (SLOTF_SDMEM | SLOTF_SDIO) uint16_t s_caps; #define SLOT_CAP_NOPIO 0x0002 #define SLOT_CAP_HISPEED 0x0004 #define SLOT_CAP_4BITS 0x0008 list_t s_cmdlist; list_t s_abortlist; /* * Slot operations. Slot local copy for performance. */ sda_ops_t s_ops; /* * Recursive locking of slot. */ kmutex_t s_lock; kcondvar_t s_cv; kt_did_t s_owner; /* owner holding the slot */ uint32_t s_circular; /* circular sda_slot_enter() calls */ /* * Event notification/thread wakeup. */ kmutex_t s_evlock; kcondvar_t s_evcv; /* * Asynch. threads. */ ddi_taskq_t *s_hp_tq; /* insert taskq */ ddi_taskq_t *s_main_tq; /* main processing taskq */ /* * Timestamping for cfgadm benefit. */ uint8_t s_intransit; time_t s_stamp; /* * Memory card-specific. */ uint32_t s_rcsd[4]; /* raw csd */ uint32_t s_rcid[4]; /* raw cid */ uint32_t s_nblks; /* total blocks on device */ uint16_t s_blksz; /* device block size (typ. 512) */ uint16_t s_bshift; /* block address shift factor */ uint32_t s_speed; /* max memory clock in hz */ /* Other CID and CSD values */ uint32_t s_mfg; /* mfg id */ char s_prod[8]; /* product id */ char s_oem[2]; /* oem id */ uint32_t s_serial; uint8_t s_majver; uint8_t s_minver; uint16_t s_year; uint8_t s_month; uint16_t s_ccc; /* card command classes */ uint8_t s_r2w; /* read/write factor */ uint8_t s_dsr; /* DSR implemented? */ uint8_t s_perm_wp; /* permanent write protect set? */ uint8_t s_temp_wp; /* temporary write protect set? */ bd_handle_t s_bdh; /* block dev handle */ }; /* * Per host state. One per devinfo node. There could be multiple * slots per devinfo node. */ struct sda_host { dev_info_t *h_dip; int h_nslot; sda_slot_t *h_slots; ddi_dma_attr_t *h_dma; /* dma attr, needed for mem */ list_node_t h_node; /* nexus node linkage */ uint32_t h_flags; #define HOST_ATTACH (1U << 0) /* host attach completed */ #define HOST_XOPEN (1U << 2) /* exclusive open */ #define HOST_SOPEN (1U << 3) /* shared open */ }; /* * Useful function-like macros. */ #define sda_setprop(s, p, v) s->s_ops.so_setprop(s->s_prv, p, v) #define sda_getprop(s, p, v) s->s_ops.so_getprop(s->s_prv, p, v) /* * sda_cmd.c */ void sda_cmd_init(void); void sda_cmd_fini(void); void sda_cmd_list_init(list_t *); void sda_cmd_list_fini(list_t *); sda_cmd_t *sda_cmd_alloc(sda_slot_t *, sda_index_t, uint32_t, sda_rtype_t, void *, int); sda_cmd_t *sda_cmd_alloc_acmd(sda_slot_t *, sda_index_t, uint32_t, sda_rtype_t, void *, int); void sda_cmd_free(sda_cmd_t *); sda_err_t sda_cmd_errno(sda_cmd_t *); void *sda_cmd_data(sda_cmd_t *); void sda_cmd_submit(sda_slot_t *, sda_cmd_t *, void (*)(sda_cmd_t *)); void sda_cmd_resubmit_acmd(sda_slot_t *, sda_cmd_t *); void sda_cmd_notify(sda_cmd_t *, uint16_t, sda_err_t); sda_err_t sda_cmd_exec(sda_slot_t *, sda_cmd_t *, uint32_t *); /* * sda_init.c */ sda_err_t sda_init_card(sda_slot_t *); /* * sda_mem.c */ void sda_mem_init(struct modlinkage *); void sda_mem_fini(struct modlinkage *); uint32_t sda_mem_maxclk(sda_slot_t *); uint32_t sda_mem_getbits(uint32_t *, int, int); int sda_mem_parse_cid_csd(sda_slot_t *); int sda_mem_bd_read(void *, bd_xfer_t *); int sda_mem_bd_write(void *, bd_xfer_t *); void sda_mem_bd_driveinfo(void *, bd_drive_t *); int sda_mem_bd_mediainfo(void *, bd_media_t *); /* * sda_nexus.c */ void sda_nexus_init(void); void sda_nexus_fini(void); void sda_nexus_register(sda_host_t *); void sda_nexus_unregister(sda_host_t *); int sda_nexus_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **); int sda_nexus_open(dev_t *, int, int, cred_t *); int sda_nexus_close(dev_t, int, int, cred_t *); int sda_nexus_ioctl(dev_t, int, intptr_t, int, cred_t *, int *); int sda_nexus_bus_ctl(dev_info_t *, dev_info_t *, ddi_ctl_enum_t, void *, void *); void sda_nexus_remove(sda_slot_t *); void sda_nexus_insert(sda_slot_t *); void sda_nexus_reap(void *); /* * sda_slot.c */ void sda_slot_init(sda_slot_t *); void sda_slot_fini(sda_slot_t *); void sda_slot_enter(sda_slot_t *); void sda_slot_exit(sda_slot_t *); boolean_t sda_slot_owned(sda_slot_t *); void sda_slot_attach(sda_slot_t *); void sda_slot_detach(sda_slot_t *); void sda_slot_suspend(sda_slot_t *); void sda_slot_resume(sda_slot_t *); void sda_slot_reset(sda_slot_t *); void sda_slot_wakeup(sda_slot_t *); void sda_slot_detect(sda_slot_t *); int sda_slot_power_on(sda_slot_t *); void sda_slot_power_off(sda_slot_t *); void sda_slot_reset(sda_slot_t *); void sda_slot_shutdown(sda_slot_t *); void sda_slot_transfer(sda_slot_t *, sda_err_t); void sda_slot_fault(sda_slot_t *, sda_fault_t); /*PRINTFLIKE2*/ void sda_slot_err(sda_slot_t *, const char *, ...); /*PRINTFLIKE2*/ void sda_slot_log(sda_slot_t *, const char *, ...); #ifdef DEBUG #define sda_slot_debug(...) sda_slot_log(__VA_ARGS__) #else #define sda_slot_debug(...) #endif #ifdef __cplusplus } #endif #endif /* _SYS_SDCARD_SDA_IMPL_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 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _SYS_SDCARD_SDA_IOCTL_H #define _SYS_SDCARD_SDA_IOCTL_H #include #ifdef __cplusplus extern "C" { #endif /* * These IOCTLs are private between the sdcard cfgadm plugin, and the sda * framework. */ typedef enum { SDA_CT_UNKNOWN, SDA_CT_MMC, SDA_CT_SDMEM, SDA_CT_SDHC, SDA_CT_SDCOMBO, SDA_CT_SDIO /* expand on this later */ } sda_card_type_t; typedef struct { sda_card_type_t ci_type; /* these are only valid for memory cards */ uint32_t ci_mfg; char ci_oem[16]; /* mfg id */ char ci_pid[16]; /* ASCIIZ product */ uint32_t ci_serial; uint8_t ci_month; uint8_t ci_year; uint8_t ci_major; uint8_t ci_minor; } sda_card_info_t; struct sda_ap_control { unsigned cmd; size_t size; void *data; }; #ifdef _KERNEL struct sda_ap_control32 { unsigned cmd; size32_t size; caddr32_t data; }; #endif /* AP_CONTROL commands */ #define SDA_CFGA_GET_CARD_INFO 1 #define SDA_CFGA_GET_DEVICE_PATH 2 #define SDA_CFGA_RESET_SLOT 3 #ifdef __cplusplus } #endif #endif /* _SYS_SDCARD_SDA_IOCTL_H */