/*
 * 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_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;

	uint_t			sc_ndmac;	/* # DMA cookies */
	ddi_dma_cookie_t	*sc_dmacs;	/* 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 */
};

_NOTE(SCHEME_PROTECTS_DATA("unshared request", sda_cmd))

/*
 * 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_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 */