14d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/*
24d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * Broadcom BCMSDH to SPI Protocol Conversion Layer
34d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
407770aa679cd45674eaac3d8fb2e01a995068838Greg Goldman * Copyright (C) 1999-2010, Broadcom Corporation
54d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
64d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *      Unless you and Broadcom execute a separate written software license
74d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * agreement governing use of this software, this software is licensed to you
84d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * under the terms of the GNU General Public License version 2 (the "GPL"),
94d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * available at http://www.broadcom.com/licenses/GPLv2.php, with the
104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * following added to such license:
114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *      As a special exception, the copyright holders of this software give you
134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * permission to link this software with independent modules, and to copy and
144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * distribute the resulting executable under terms of your choice, provided that
154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * you also meet, for each linked independent module, the terms and conditions of
164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * the license of that module.  An independent module is a module which is not
174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * derived from this software.  The special exception does not apply to any
184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * modifications of the software.
194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *      Notwithstanding the above, under no circumstances may you combine this
214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * software in any way with any other Broadcom software provided under a license
224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * other than the GPL, without Broadcom's express prior written consent.
234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *
2407770aa679cd45674eaac3d8fb2e01a995068838Greg Goldman * $Id: bcmsdspi.c,v 1.14.4.2.4.4.6.5 2010/03/10 03:09:48 Exp $
254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt */
264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <typedefs.h>
284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmdevs.h>
304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmendian.h>
314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmutils.h>
324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <osl.h>
334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <siutils.h>
344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <sdio.h>		/* SDIO Device and Protocol Specs */
354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <sdioh.h>		/* SDIO Host Controller Specification */
364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmsdbus.h>		/* bcmsdh to/from specific controller APIs */
374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <sdiovar.h>		/* ioctl/iovars */
384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <pcicfg.h>
404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmsdspi.h>
434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <bcmspi.h>
444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#include <proto/sdspi.h>
464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define SD_PAGE 4096
484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* Globals */
504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_msglevel = SDH_ERROR_VAL;
524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_hiok = FALSE;		/* Use hi-speed mode if available? */
534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_sdmode = SDIOH_MODE_SPI;		/* Use SD4 mode by default */
544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_f2_blocksize = 512;	/* Default blocksize */
554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_divisor = 2;		/* Default 33MHz/2 = 16MHz for dongle */
574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_power = 1;		/* Default to SD Slot powered ON */
584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_clock = 1;		/* Default to SD Clock turned ON */
594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_crc = 0;		/* Default to SPI CRC Check turned OFF */
6007770aa679cd45674eaac3d8fb2e01a995068838Greg Goldmanuint sd_pci_slot = 0xFFFFffff; /* Used to force selection of a particular PCI slot */
614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint sd_toctl = 7;
634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* Prototypes */
654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic bool sdspi_start_power(sdioh_info_t *sd);
664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode);
674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_card_enablefuncs(sdioh_info_t *sd);
684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic void sdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count);
694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt                           uint32 *data, uint32 datalen);
714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr,
724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt                              int regsize, uint32 *data);
734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr,
744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt                               int regsize, uint32 data);
754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_driver_init(sdioh_info_t *sd);
764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic bool sdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset);
774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo,
784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt                          uint32 addr, int nbytes, uint32 *data);
794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_abort(sdioh_info_t *sd, uint func);
804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int set_client_block_size(sdioh_info_t *sd, int func, int blocksize);
824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic uint8 sdspi_crc7(unsigned char* p, uint32 len);
844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic uint16 sdspi_crc16(unsigned char* p, uint32 len);
854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int sdspi_crc_onoff(sdioh_info_t *sd, bool use_crc);
864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/*
884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt *  Public entry points & extern's
894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt */
904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern sdioh_info_t *
914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_attach(osl_t *osh, void *bar0, uint irq)
924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdioh_info_t *sd;
944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s\n", __FUNCTION__));
964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((sd = (sdioh_info_t *)MALLOC(osh, sizeof(sdioh_info_t))) == NULL) {
974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("sdioh_attach: out of memory, malloced %d bytes\n", MALLOCED(osh)));
984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return NULL;
994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bzero((char *)sd, sizeof(sdioh_info_t));
1014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->osh = osh;
1024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (spi_osinit(sd) != 0) {
1044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: spi_osinit() failed\n", __FUNCTION__));
1054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		MFREE(sd->osh, sd, sizeof(sdioh_info_t));
1064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return NULL;
1074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->bar0 = (uintptr)bar0;
1104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->irq = irq;
1114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler = NULL;
1124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler_arg = NULL;
1134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler_valid = FALSE;
1144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Set defaults */
1164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->sd_blockmode = FALSE;
1174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->use_client_ints = TRUE;
1184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->sd_use_dma = FALSE;	/* DMA Not supported */
1194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Haven't figured out how to make bytemode work with dma */
1214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!sd->sd_blockmode)
1224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->sd_use_dma = 0;
1234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!spi_hw_attach(sd)) {
1254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: spi_hw_attach() failed\n", __FUNCTION__));
1264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_osfree(sd);
1274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		MFREE(sd->osh, sd, sizeof(sdioh_info_t));
1284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return NULL;
1294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (sdspi_driver_init(sd) != SUCCESS) {
1324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sdspi_driver_init(sd) != SUCCESS) {
1334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s:sdspi_driver_init() failed()\n", __FUNCTION__));
1344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_hw_detach(sd);
1354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_osfree(sd);
1364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			MFREE(sd->osh, sd, sizeof(sdioh_info_t));
1374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return (NULL);
1384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
1394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (spi_register_irq(sd, irq) != SUCCESS) {
1424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: spi_register_irq() failed for irq = %d\n", __FUNCTION__, irq));
1434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_hw_detach(sd);
1444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_osfree(sd);
1454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		MFREE(sd->osh, sd, sizeof(sdioh_info_t));
1464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return (NULL);
1474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: Done\n", __FUNCTION__));
1504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return sd;
1514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
1524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
1544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_detach(osl_t *osh, sdioh_info_t *sd)
1554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
1564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s\n", __FUNCTION__));
1574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (sd) {
1594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sd->card_init_done)
1604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sdspi_reset(sd, 1, 1);
1614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_info(("%s: detaching from hardware\n", __FUNCTION__));
1634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_free_irq(sd->irq, sd);
1644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_hw_detach(sd);
1654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_osfree(sd);
1664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		MFREE(sd->osh, sd, sizeof(sdioh_info_t));
1674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
1684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SDIOH_API_RC_SUCCESS;
1704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
1714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* Configure callback to client when we recieve client interrupt */
1734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
1744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_interrupt_register(sdioh_info_t *sd, sdioh_cb_fn_t fn, void *argh)
1754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
1764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: Entering\n", __FUNCTION__));
1774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler = fn;
1794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler_arg = argh;
1804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler_valid = TRUE;
1814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SDIOH_API_RC_SUCCESS;
1834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
1844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
1864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_interrupt_deregister(sdioh_info_t *sd)
1874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
1884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: Entering\n", __FUNCTION__));
1894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler_valid = FALSE;
1914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler = NULL;
1924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->intr_handler_arg = NULL;
1934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SDIOH_API_RC_SUCCESS;
1954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
1964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
1974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
1984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_interrupt_query(sdioh_info_t *sd, bool *onoff)
1994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
2004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: Entering\n", __FUNCTION__));
2014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	*onoff = sd->client_intr_enabled;
2034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SDIOH_API_RC_SUCCESS;
2054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
2064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#if defined(DHD_DEBUG)
2084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern bool
2094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_interrupt_pending(sdioh_info_t *sd)
2104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
2114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return 0;
2124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
2134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#endif
2144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint
2164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_query_iofnum(sdioh_info_t *sd)
2174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
2184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return sd->num_funcs;
2194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
2204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* IOVar table */
2224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtenum {
2234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_MSGLEVEL = 1,
2244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_BLOCKMODE,
2254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_BLOCKSIZE,
2264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_DMA,
2274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_USEINTS,
2284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_NUMINTS,
2294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_NUMLOCALINTS,
2304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_HOSTREG,
2314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_DEVREG,
2324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_DIVISOR,
2334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_SDMODE,
2344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_HISPEED,
2354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_HCIREGS,
2364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_POWER,
2374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_CLOCK,
2384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	IOV_CRC
2394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt};
2404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtconst bcm_iovar_t sdioh_iovars[] = {
2424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_msglevel",	IOV_MSGLEVEL, 	0,	IOVT_UINT32,	0 },
2434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_blockmode", IOV_BLOCKMODE,	0,	IOVT_BOOL,	0 },
2444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_blocksize", IOV_BLOCKSIZE, 0,	IOVT_UINT32,	0 }, /* ((fn << 16) | size) */
2454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_dma",	IOV_DMA,	0,	IOVT_BOOL,	0 },
2464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_ints",	IOV_USEINTS,	0,	IOVT_BOOL,	0 },
2474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_numints",	IOV_NUMINTS,	0,	IOVT_UINT32,	0 },
2484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_numlocalints", IOV_NUMLOCALINTS, 0, IOVT_UINT32,	0 },
2494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_hostreg",	IOV_HOSTREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t) },
2504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_devreg",	IOV_DEVREG,	0,	IOVT_BUFFER,	sizeof(sdreg_t)	},
2514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_divisor",	IOV_DIVISOR,	0,	IOVT_UINT32,	0 },
2524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_power",	IOV_POWER,	0,	IOVT_UINT32,	0 },
2534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_clock",	IOV_CLOCK,	0,	IOVT_UINT32,	0 },
2544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_crc",	IOV_CRC,	0,	IOVT_UINT32,	0 },
2554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_mode",	IOV_SDMODE,	0,	IOVT_UINT32,	100},
2564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{"sd_highspeed",	IOV_HISPEED,	0,	IOVT_UINT32,	0},
2574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{NULL, 0, 0, 0, 0 }
2584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt};
2594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtint
2614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_iovar_op(sdioh_info_t *si, const char *name,
2624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt               void *params, int plen, void *arg, int len, bool set)
2634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
2644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	const bcm_iovar_t *vi = NULL;
2654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int bcmerror = 0;
2664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int val_size;
2674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int32 int_val = 0;
2684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bool bool_val;
2694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 actionid;
2704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(name);
2724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(len >= 0);
2734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Get must have return space; Set does not take qualifiers */
2754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(set || (arg && len));
2764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(!set || (!params && !plen));
2774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: Enter (%s %s)\n", __FUNCTION__, (set ? "set" : "get"), name));
2794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((vi = bcm_iovar_lookup(sdioh_iovars, name)) == NULL) {
2814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcmerror = BCME_UNSUPPORTED;
2824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		goto exit;
2834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
2844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((bcmerror = bcm_iovar_lencheck(vi, arg, len, set)) != 0)
2864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		goto exit;
2874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Set up params so get and set can share the convenience variables */
2894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (params == NULL) {
2904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		params = arg;
2914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		plen = len;
2924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
2934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
2944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (vi->type == IOVT_VOID)
2954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		val_size = 0;
2964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	else if (vi->type == IOVT_BUFFER)
2974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		val_size = len;
2984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	else
2994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		val_size = sizeof(int);
3004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (plen >= (int)sizeof(int_val))
3024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(params, &int_val, sizeof(int_val));
3034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bool_val = (int_val != 0) ? TRUE : FALSE;
3054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	actionid = set ? IOV_SVAL(vi->varid) : IOV_GVAL(vi->varid);
3074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	switch (actionid) {
3084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_MSGLEVEL):
3094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int32)sd_msglevel;
3104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
3114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_MSGLEVEL):
3144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_msglevel = int_val;
3154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_BLOCKMODE):
3184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int32)si->sd_blockmode;
3194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
3204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_BLOCKMODE):
3234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		si->sd_blockmode = (bool)int_val;
3244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* Haven't figured out how to make non-block mode with DMA */
3254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (!si->sd_blockmode)
3264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			si->sd_use_dma = 0;
3274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_BLOCKSIZE):
3304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((uint32)int_val > si->num_funcs) {
3314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bcmerror = BCME_BADARG;
3324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
3334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
3344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int32)si->client_block_size[int_val];
3354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
3364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_BLOCKSIZE):
3394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{
3404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		uint func = ((uint32)int_val >> 16);
3414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		uint blksize = (uint16)int_val;
3424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		uint maxsize;
3434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (func > si->num_funcs) {
3454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bcmerror = BCME_BADARG;
3464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
3474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
3484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		switch (func) {
3504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		case 0: maxsize = 32; break;
3514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		case 1: maxsize = BLOCK_SIZE_4318; break;
3524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		case 2: maxsize = BLOCK_SIZE_4328; break;
3534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		default: maxsize = 0;
3544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
3554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (blksize > maxsize) {
3564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bcmerror = BCME_BADARG;
3574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
3584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
3594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (!blksize) {
3604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			blksize = maxsize;
3614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
3624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* Now set it */
3644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_lock(si);
3654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcmerror = set_client_block_size(si, func, blksize);
3664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_unlock(si);
3674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
3694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_DMA):
3714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int32)si->sd_use_dma;
3724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
3734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_DMA):
3764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		si->sd_use_dma = (bool)int_val;
3774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_USEINTS):
3804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int32)si->use_client_ints;
3814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
3824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_USEINTS):
3854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_DIVISOR):
3884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (uint32)sd_divisor;
3894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
3904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
3924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_DIVISOR):
3934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_divisor = int_val;
3944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (!spi_start_clock(si, (uint16)sd_divisor)) {
3954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("set clock failed!\n"));
3964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bcmerror = BCME_ERROR;
3974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
3984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
3994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_POWER):
4014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (uint32)sd_power;
4024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
4034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_POWER):
4064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_power = int_val;
4074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_CLOCK):
4104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (uint32)sd_clock;
4114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
4124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_CLOCK):
4154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_clock = int_val;
4164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_CRC):
4194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (uint32)sd_crc;
4204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
4214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_CRC):
4244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* Apply new setting, but don't change sd_crc until
4254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 * after the CRC-mode is selected in the device.  This
4264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 * is required because the software must generate a
4274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 * correct CRC for the CMD59 in order to be able to
4284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 * turn OFF the CRC.
4294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 */
4304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdspi_crc_onoff(si, int_val ? 1 : 0);
4314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_crc = int_val;
4324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_SDMODE):
4354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (uint32)sd_sdmode;
4364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
4374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_SDMODE):
4404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_sdmode = int_val;
4414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_HISPEED):
4444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (uint32)sd_hiok;
4454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
4464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_HISPEED):
4494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_hiok = int_val;
4504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (!sdspi_set_highspeed_mode(si, (bool)sd_hiok)) {
4524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("Failed changing highspeed mode to %d.\n", sd_hiok));
4534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bcmerror = BCME_ERROR;
4544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return ERROR;
4554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
4564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_NUMINTS):
4594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int32)si->intrcount;
4604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
4614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_NUMLOCALINTS):
4644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int32)si->local_intrcount;
4654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, val_size);
4664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_HOSTREG):
4694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{
4704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
4724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_HOSTREG):
4744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{
4754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("IOV_HOSTREG unsupported\n"));
4764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
4784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_GVAL(IOV_DEVREG):
4804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{
4814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdreg_t *sd_ptr = (sdreg_t *)params;
4824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		uint8 data;
4834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sdioh_cfg_read(si, sd_ptr->func, sd_ptr->offset, &data)) {
4854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bcmerror = BCME_SDIO_ERROR;
4864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
4874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
4884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		int_val = (int)data;
4904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcopy(&int_val, arg, sizeof(int_val));
4914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
4924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
4934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case IOV_SVAL(IOV_DEVREG):
4954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	{
4964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdreg_t *sd_ptr = (sdreg_t *)params;
4974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		uint8 data = (uint8)sd_ptr->value;
4984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
4994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sdioh_cfg_write(si, sd_ptr->func, sd_ptr->offset, &data)) {
5004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bcmerror = BCME_SDIO_ERROR;
5014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
5024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
5034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
5044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
5054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	default:
5084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bcmerror = BCME_UNSUPPORTED;
5094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
5104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
5114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtexit:
5124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return bcmerror;
5144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
5154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
5174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_cfg_read(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
5184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
5194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	SDIOH_API_RC status;
5204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* No lock needed since sdioh_request_byte does locking */
5214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	status = sdioh_request_byte(sd, SDIOH_READ, fnc_num, addr, data);
5224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return status;
5234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
5244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
5264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_cfg_write(sdioh_info_t *sd, uint fnc_num, uint32 addr, uint8 *data)
5274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
5284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* No lock needed since sdioh_request_byte does locking */
5294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	SDIOH_API_RC status;
5304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	status = sdioh_request_byte(sd, SDIOH_WRITE, fnc_num, addr, data);
5314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return status;
5324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
5334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
5354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_cis_read(sdioh_info_t *sd, uint func, uint8 *cisd, uint32 length)
5364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
5374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 count;
5384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int offset;
5394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 foo;
5404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 *cis = cisd;
5414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: Func = %d\n", __FUNCTION__, func));
5434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!sd->func_cis_ptr[func]) {
5454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		bzero(cis, length);
5464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return SDIOH_API_RC_FAIL;
5474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
5484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_lock(sd);
5504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	*cis = 0;
5514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (count = 0; count < length; count++) {
5524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		offset =  sd->func_cis_ptr[func] + count;
5534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sdspi_card_regread (sd, 0, offset, 1, &foo) < 0) {
5544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: regread failed: Can't read CIS\n", __FUNCTION__));
5554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_unlock(sd);
5564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return SDIOH_API_RC_FAIL;
5574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
5584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		*cis = (uint8)(foo & 0xff);
5594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cis++;
5604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
5614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_unlock(sd);
5624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SDIOH_API_RC_SUCCESS;
5634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
5644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
5664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_request_byte(sdioh_info_t *sd, uint rw, uint func, uint regaddr, uint8 *byte)
5674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
5684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
5694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_arg;
5704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 rsp5;
5714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_lock(sd);
5734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = 0;
5754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
5764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
5774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, rw == SDIOH_READ ? 0 : 1);
5784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
5794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = SFIELD(cmd_arg, CMD52_DATA, rw == SDIOH_READ ? 0 : *byte);
5804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: rw=%d, func=%d, regaddr=0x%08x\n", __FUNCTION__, rw, func, regaddr));
5824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
5844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	                              SDIOH_CMD_52, cmd_arg, NULL, 0)) != SUCCESS) {
5854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_unlock(sd);
5864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return status;
5874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
5884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdspi_cmd_getrsp(sd, &rsp5, 1);
5904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (rsp5 != 0x00) {
5914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: rsp5 flags is 0x%x func=%d\n",
5924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		        __FUNCTION__, rsp5, func));
5934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* ASSERT(0); */
5944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_unlock(sd);
5954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return SDIOH_API_RC_FAIL;
5964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
5974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
5984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (rw == SDIOH_READ)
5994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		*byte = sd->card_rsp_data >> 24;
6004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_unlock(sd);
6024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SDIOH_API_RC_SUCCESS;
6034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
6044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
6064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_request_word(sdioh_info_t *sd, uint cmd_type, uint rw, uint func, uint addr,
6074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt                   uint32 *word, uint nbytes)
6084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
6094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
6104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_lock(sd);
6124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (rw == SDIOH_READ)
6144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		status = sdspi_card_regread(sd, func, addr, nbytes, word);
6154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	else
6164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		status = sdspi_card_regwrite(sd, func, addr, nbytes, *word);
6174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_unlock(sd);
6194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (status == SUCCESS ?  SDIOH_API_RC_SUCCESS : SDIOH_API_RC_FAIL);
6204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
6214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern SDIOH_API_RC
6234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_request_buffer(sdioh_info_t *sd, uint pio_dma, uint fix_inc, uint rw, uint func,
6244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt                     uint addr, uint reg_width, uint buflen_u, uint8 *buffer, void *pkt)
6254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
6264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int len;
6274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int buflen = (int)buflen_u;
6284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bool fifo = (fix_inc == SDIOH_DATA_FIX);
6294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_lock(sd);
6314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(reg_width == 4);
6334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(buflen_u < (1 << 30));
6344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(sd->client_block_size[func]);
6354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_data(("%s: %c len %d r_cnt %d t_cnt %d, pkt @0x%p\n",
6374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	         __FUNCTION__, rw == SDIOH_READ ? 'R' : 'W',
6384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	         buflen_u, sd->r_cnt, sd->t_cnt, pkt));
6394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Break buffer down into blocksize chunks:
6414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * Bytemode: 1 block at a time.
6424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 */
6434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	while (buflen > 0) {
6444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sd->sd_blockmode) {
6454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			/* Max xfer is Page size */
6464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			len = MIN(SD_PAGE, buflen);
6474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			/* Round down to a block boundry */
6494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (buflen > sd->client_block_size[func])
6504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				len = (len/sd->client_block_size[func]) *
6514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				        sd->client_block_size[func];
6524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		} else {
6534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			/* Byte mode: One block at a time */
6544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			len = MIN(sd->client_block_size[func], buflen);
6554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
6564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sdspi_card_buf(sd, rw, func, fifo, addr, len, (uint32 *)buffer) != SUCCESS) {
6584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_unlock(sd);
6594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return SDIOH_API_RC_FAIL;
6604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
6614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		buffer += len;
6624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		buflen -= len;
6634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (!fifo)
6644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			addr += len;
6654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
6664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_unlock(sd);
6674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SDIOH_API_RC_SUCCESS;
6684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
6694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
6714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_abort(sdioh_info_t *sd, uint func)
6724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
6734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 spi_databuf[] = { 0x74, 0x80, 0x00, 0x0C, 0xFF, 0x95, 0xFF, 0xFF,
6744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	                        0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
6754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 spi_rspbuf[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
6764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	                       0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
6774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int err = 0;
6784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_err(("Sending SPI Abort to F%d\n", func));
6804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_databuf[4] = func & 0x7;
6814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* write to function 0, addr 6 (IOABORT) func # in 3 LSBs. */
6824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_sendrecv(sd, spi_databuf, spi_rspbuf, sizeof(spi_databuf));
6834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return err;
6854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
6864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtextern int
6884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_abort(sdioh_info_t *sd, uint fnum)
6894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
6904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int ret;
6914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_lock(sd);
6934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ret = sdspi_abort(sd, fnum);
6944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_unlock(sd);
6954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return ret;
6974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
6984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
6994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtint
7004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_start(sdioh_info_t *sd, int stage)
7014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
7024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
7034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
7044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtint
7064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_stop(sdioh_info_t *sd)
7074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
7084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
7094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
7104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/*
7134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * Private/Static work routines
7144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt */
7154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic bool
7164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_reset(sdioh_info_t *sd, bool host_reset, bool client_reset)
7174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
7184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!sd)
7194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return TRUE;
7204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_lock(sd);
7224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Reset client card */
7234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (client_reset && (sd->adapter_slot != -1)) {
7244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOABORT, 1, 0x8) != SUCCESS)
7254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: Cannot write to card reg 0x%x\n",
7264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			        __FUNCTION__, SDIOD_CCCR_IOABORT));
7274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		else
7284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd->card_rca = 0;
7294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
7304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* The host reset is a NOP in the sd-spi case. */
7324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (host_reset) {
7334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->sd_mode = SDIOH_MODE_SPI;
7344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
7354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_unlock(sd);
7364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return TRUE;
7374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
7384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
7404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_host_init(sdioh_info_t *sd)
7414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
7424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdspi_reset(sd, 1, 0);
7434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Default power on mode is SD1 */
7454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->sd_mode = SDIOH_MODE_SPI;
7464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->polled_mode = TRUE;
7474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->host_init_done = TRUE;
7484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->card_init_done = FALSE;
7494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->adapter_slot = 1;
7504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (SUCCESS);
7524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
7534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define CMD0_RETRIES 3
7554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define CMD5_RETRIES 10
7564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
7584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtget_ocr(sdioh_info_t *sd, uint32 *cmd_arg, uint32 *cmd_rsp)
7594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
7604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 rsp5;
7614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int retries, status;
7624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* First issue a CMD0 to get the card into SPI mode. */
7644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (retries = 0; retries <= CMD0_RETRIES; retries++) {
7654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
7664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		                              SDIOH_CMD_0, *cmd_arg, NULL, 0)) != SUCCESS) {
7674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: No response to CMD0\n", __FUNCTION__));
7684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			continue;
7694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
7704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdspi_cmd_getrsp(sd, &rsp5, 1);
7724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (GFIELD(rsp5, SPI_RSP_ILL_CMD)) {
7744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			printf("%s: Card already initialized (continuing)\n", __FUNCTION__);
7754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
7764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
7774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (GFIELD(rsp5, SPI_RSP_IDLE)) {
7794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			printf("%s: Card in SPI mode\n", __FUNCTION__);
7804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
7814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
7824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
7834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (retries > CMD0_RETRIES) {
7854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: Too many retries for CMD0\n", __FUNCTION__));
7864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
7874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
7884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Get the Card's Operation Condition. */
7904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Occasionally the board takes a while to become ready. */
7914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (retries = 0; retries <= CMD5_RETRIES; retries++) {
7924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
7934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		                              SDIOH_CMD_5, *cmd_arg, NULL, 0)) != SUCCESS) {
7944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: No response to CMD5\n", __FUNCTION__));
7954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			continue;
7964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
7974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
7984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		printf("CMD5 response data was: 0x%08x\n", sd->card_rsp_data);
7994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (GFIELD(sd->card_rsp_data, RSP4_CARD_READY)) {
8014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			printf("%s: Card ready\n", __FUNCTION__);
8024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
8034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
8044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (retries > CMD5_RETRIES) {
8074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: Too many retries for CMD5\n", __FUNCTION__));
8084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
8094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	*cmd_rsp = sd->card_rsp_data;
8124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdspi_crc_onoff(sd, sd_crc ? 1 : 0);
8144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (SUCCESS);
8164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
8174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
8194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_crc_onoff(sdioh_info_t *sd, bool use_crc)
8204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
8214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 args;
8224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
8234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	args = use_crc ? 1 : 0;
8254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma,
8264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	                              SDIOH_CMD_59, args, NULL, 0)) != SUCCESS) {
8274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: No response to CMD59\n", __FUNCTION__));
8284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_info(("CMD59 response data was: 0x%08x\n", sd->card_rsp_data));
8314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_err(("SD-SPI CRC turned %s\n", use_crc ? "ON" : "OFF"));
8334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (SUCCESS);
8344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
8354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
8374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_client_init(sdioh_info_t *sd)
8384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
8394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 fn_ints;
8404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s: Powering up slot %d\n", __FUNCTION__, sd->adapter_slot));
8424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Start at ~400KHz clock rate for initialization */
8444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!spi_start_clock(sd, 128)) {
8454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("spi_start_clock failed\n"));
8464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
8474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!sdspi_start_power(sd)) {
8504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("sdspi_start_power failed\n"));
8514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
8524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (sd->num_funcs == 0) {
8554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: No IO funcs!\n", __FUNCTION__));
8564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
8574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdspi_card_enablefuncs(sd);
8604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	set_client_block_size(sd, 1, BLOCK_SIZE_4318);
8624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	fn_ints = INTR_CTL_FUNC1_EN;
8634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (sd->num_funcs >= 2) {
8654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		set_client_block_size(sd, 2, sd_f2_blocksize /* BLOCK_SIZE_4328 */);
8664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		fn_ints |= INTR_CTL_FUNC2_EN;
8674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Enable/Disable Client interrupts */
8704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Turn on here but disable at host controller */
8714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (sdspi_card_regwrite(sd, 0, SDIOD_CCCR_INTEN, 1,
8724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	                        (fn_ints | INTR_CTL_MASTER_EN)) != SUCCESS) {
8734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: Could not enable ints in CCCR\n", __FUNCTION__));
8744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
8754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Switch to High-speed clocking mode if both host and device support it */
8784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdspi_set_highspeed_mode(sd, (bool)sd_hiok);
8794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* After configuring for High-Speed mode, set the desired clock rate. */
8814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!spi_start_clock(sd, (uint16)sd_divisor)) {
8824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("spi_start_clock failed\n"));
8834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
8844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
8854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->card_init_done = TRUE;
8874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
8894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
8904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
8924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_set_highspeed_mode(sdioh_info_t *sd, bool HSMode)
8934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
8944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 regdata;
8954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
8964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bool hsmode;
8974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
8984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (HSMode == TRUE) {
8994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("Attempting to enable High-Speed mode.\n"));
9014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
9034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		                                 1, &regdata)) != SUCCESS) {
9044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
9054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
9064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (regdata & SDIO_SPEED_SHS) {
9074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("Device supports High-Speed mode.\n"));
9084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			regdata |= SDIO_SPEED_EHS;
9104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("Writing %08x to Card at %08x\n",
9124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			         regdata, SDIOD_CCCR_SPEED_CONTROL));
9134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
9144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			                                  1, regdata)) != BCME_OK) {
9154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				return status;
9164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
9174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			hsmode = 1;
9194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("High-speed clocking mode enabled.\n"));
9214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
9224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		else {
9234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("Device does not support High-Speed Mode.\n"));
9244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			hsmode = 0;
9254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
9264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	} else {
9274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_card_regread(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
9284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		                                 1, &regdata)) != SUCCESS) {
9294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
9304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
9314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		regdata = ~SDIO_SPEED_EHS;
9334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("Writing %08x to Card at %08x\n",
9354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		         regdata, SDIOD_CCCR_SPEED_CONTROL));
9364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_SPEED_CONTROL,
9374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		                                  1, regdata)) != BCME_OK) {
9384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
9394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
9404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("Low-speed clocking mode enabled.\n"));
9424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		hsmode = 0;
9434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
9444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_controller_highspeed_mode(sd, hsmode);
9464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return TRUE;
9484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
9494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtbool
9514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_start_power(sdioh_info_t *sd)
9524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
9534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_arg;
9544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_rsp;
9554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s\n", __FUNCTION__));
9574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Get the Card's Operation Condition.  Occasionally the board
9594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * takes a while to become ready
9604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 */
9614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = 0;
9634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (get_ocr(sd, &cmd_arg, &cmd_rsp) != SUCCESS) {
9644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: Failed to get OCR; bailing\n", __FUNCTION__));
9654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return FALSE;
9664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
9674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_err(("mem_present = %d\n", GFIELD(cmd_rsp, RSP4_MEM_PRESENT)));
9694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_err(("num_funcs = %d\n", GFIELD(cmd_rsp, RSP4_NUM_FUNCS)));
9704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_err(("card_ready = %d\n", GFIELD(cmd_rsp, RSP4_CARD_READY)));
9714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_err(("OCR = 0x%x\n", GFIELD(cmd_rsp, RSP4_IO_OCR)));
9724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Verify that the card supports I/O mode */
9744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (GFIELD(cmd_rsp, RSP4_NUM_FUNCS) == 0) {
9754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: Card does not support I/O\n", __FUNCTION__));
9764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
9774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
9784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->num_funcs = GFIELD(cmd_rsp, RSP4_NUM_FUNCS);
9804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Examine voltage: Arasan only supports 3.3 volts,
9824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * so look for 3.2-3.3 Volts and also 3.3-3.4 volts.
9834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 */
9844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((GFIELD(cmd_rsp, RSP4_IO_OCR) & (0x3 << 20)) == 0) {
9864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("This client does not support 3.3 volts!\n"));
9874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
9884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
9894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return TRUE;
9924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
9934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
9954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_driver_init(sdioh_info_t *sd)
9964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
9974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s\n", __FUNCTION__));
9984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
9994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((sdspi_host_init(sd)) != SUCCESS) {
10004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
10014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
10024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (sdspi_client_init(sd) != SUCCESS) {
10044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
10054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
10064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
10084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
10094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
10114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_card_enablefuncs(sdioh_info_t *sd)
10124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
10134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
10144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 regdata;
10154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 regaddr, fbraddr;
10164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 func;
10174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 *ptr;
10184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_trace(("%s\n", __FUNCTION__));
10204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Get the Card's common CIS address */
10214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ptr = (uint8 *) &sd->com_cis_ptr;
10224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (regaddr = SDIOD_CCCR_CISPTR_0; regaddr <= SDIOD_CCCR_CISPTR_2; regaddr++) {
10234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_card_regread (sd, 0, regaddr, 1, &regdata)) != SUCCESS)
10244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
10254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		*ptr++ = (uint8) regdata;
10274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
10284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Only the lower 17-bits are valid */
10304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->com_cis_ptr &= 0x0001FFFF;
10314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->func_cis_ptr[0] = sd->com_cis_ptr;
10324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_info(("%s: Card's Common CIS Ptr = 0x%x\n", __FUNCTION__, sd->com_cis_ptr));
10334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Get the Card's function CIS (for each function) */
10354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (fbraddr = SDIOD_FBR_STARTADDR, func = 1;
10364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	     func <= sd->num_funcs; func++, fbraddr += SDIOD_FBR_SIZE) {
10374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		ptr = (uint8 *) &sd->func_cis_ptr[func];
10384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		for (regaddr = SDIOD_FBR_CISPTR_0; regaddr <= SDIOD_FBR_CISPTR_2; regaddr++) {
10394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if ((status = sdspi_card_regread (sd, 0, regaddr + fbraddr, 1, &regdata))
10404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			    != SUCCESS)
10414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				return status;
10424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			*ptr++ = (uint8) regdata;
10444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
10454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* Only the lower 17-bits are valid */
10474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->func_cis_ptr[func] &= 0x0001FFFF;
10484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_info(("%s: Function %d CIS Ptr = 0x%x\n",
10494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		         __FUNCTION__, func, sd->func_cis_ptr[func]));
10504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
10514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_info(("%s: write ESCI bit\n", __FUNCTION__));
10534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Enable continuous SPI interrupt (ESCI bit) */
10544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdspi_card_regwrite(sd, 0, SDIOD_CCCR_BICTRL, 1, 0x60);
10554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_info(("%s: enable f1\n", __FUNCTION__));
10574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Enable function 1 on the card */
10584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	regdata = SDIO_FUNC_ENABLE_1;
10594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((status = sdspi_card_regwrite(sd, 0, SDIOD_CCCR_IOEN, 1, regdata)) != SUCCESS)
10604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return status;
10614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_info(("%s: done\n", __FUNCTION__));
10634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
10644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
10654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* Read client card reg */
10674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
10684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_card_regread(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 *data)
10694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
10704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
10714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_arg;
10724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 rsp5;
10734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = 0;
10754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((func == 0) || (regsize == 1)) {
10774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
10784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
10794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_READ);
10804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
10814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_DATA, 0);
10824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0))
10844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		    != SUCCESS)
10854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
10864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdspi_cmd_getrsp(sd, &rsp5, 1);
10884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (rsp5 != 0x00)
10904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
10914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			        __FUNCTION__, rsp5, func));
10924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
10934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		*data = sd->card_rsp_data >> 24;
10944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	} else {
10954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
10964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
10974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
10984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
10994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
11004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
11014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->data_xfer_count = regsize;
11034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* sdspi_cmd_issue() returns with the command complete bit
11054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 * in the ISR already cleared
11064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 */
11074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0))
11084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		    != SUCCESS)
11094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
11104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdspi_cmd_getrsp(sd, &rsp5, 1);
11124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (rsp5 != 0x00)
11144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: rsp5 flags is 0x%x\t %d\n",
11154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			        __FUNCTION__, rsp5, func));
11164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		*data = sd->card_rsp_data;
11184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (regsize == 2) {
11194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			*data &= 0xffff;
11204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
11214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n",
11234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		         __FUNCTION__, func, regaddr, regsize, *data));
11244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
11274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
11294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
11304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* write a client register */
11324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
11334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_card_regwrite(sdioh_info_t *sd, int func, uint32 regaddr, int regsize, uint32 data)
11344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
11354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
11364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_arg, rsp5, flags;
11374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = 0;
11394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((func == 0) || (regsize == 1)) {
11414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_FUNCTION, func);
11424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_REG_ADDR, regaddr);
11434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
11444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_RAW, 0);
11454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD52_DATA, data & 0xff);
11464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_52, cmd_arg, NULL, 0))
11474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		    != SUCCESS)
11484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
11494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdspi_cmd_getrsp(sd, &rsp5, 1);
11514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		flags = GFIELD(rsp5, RSP5_FLAGS);
11524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (flags && (flags != 0x10))
11534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: rsp5.rsp5.flags = 0x%x, expecting 0x10\n",
11544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			        __FUNCTION__,  flags));
11554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
11564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	else {
11574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, regsize);
11584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
11594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
11604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
11614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, regaddr);
11624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
11634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->data_xfer_count = regsize;
11654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->cmd53_wr_data = data;
11664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_info(("%s: CMD53 func %d, addr 0x%x, size %d, data 0x%08x\n",
11684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		         __FUNCTION__, func, regaddr, regsize, data));
11694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* sdspi_cmd_issue() returns with the command complete bit
11714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 * in the ISR already cleared
11724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		 */
11734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((status = sdspi_cmd_issue(sd, sd->sd_use_dma, SDIOH_CMD_53, cmd_arg, NULL, 0))
11744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		    != SUCCESS)
11754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			return status;
11764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sdspi_cmd_getrsp(sd, &rsp5, 1);
11784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (rsp5 != 0x00)
11804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n",
11814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			        __FUNCTION__,  rsp5));
11824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
11844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
11854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
11864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtvoid
11884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_cmd_getrsp(sdioh_info_t *sd, uint32 *rsp_buffer, int count /* num 32 bit words */)
11894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
11904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	*rsp_buffer = sd->card_response;
11914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
11924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtint max_errors = 0;
11944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define SPI_MAX_PKT_LEN		768
11964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint8	spi_databuf[SPI_MAX_PKT_LEN];
11974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtuint8	spi_rspbuf[SPI_MAX_PKT_LEN];
11984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
11994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* datalen is used for CMD53 length only (0 for sd->data_xfer_count) */
12004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
12014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_cmd_issue(sdioh_info_t *sd, bool use_dma, uint32 cmd, uint32 arg,
12024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt                uint32 *data, uint32 datalen)
12034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
12044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_reg;
12054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_arg = arg;
12064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 cmd_crc = 0x95;		/* correct CRC for CMD0 and don't care for others. */
12074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint16 dat_crc;
12084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 cmd52data = 0;
12094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 i, j;
12104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 spi_datalen = 0;
12114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 spi_pre_cmd_pad	= 0;
12124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 spi_max_response_pad = 128;
12134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_reg = 0;
12154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_reg = SFIELD(cmd_reg, SPI_DIR, 1);
12164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_reg = SFIELD(cmd_reg, SPI_CMD_INDEX, cmd);
12174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) {	/* Same for CMD52 and CMD53 */
12194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_RW, 1);
12204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
12214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	switch (cmd) {
12234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_59:	/* CRC_ON_OFF (SPI Mode Only) - Response R1 */
12244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd52data = arg & 0x1;
12254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_0:	/* Set Card to Idle State - No Response */
12264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_5:	/* Send Operation condition - Response R4 */
12274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_trace(("%s: CMD%d\n", __FUNCTION__, cmd));
12284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_datalen = 44;
12294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_pre_cmd_pad = 12;
12304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_max_response_pad = 28;
12314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
12324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_3:	/* Ask card to send RCA - Response R6 */
12344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_7:	/* Select card - Response R1 */
12354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_15:	/* Set card to inactive state - Response None */
12364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: CMD%d is invalid for SPI Mode.\n", __FUNCTION__, cmd));
12374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
12384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
12394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_52:	/* IO R/W Direct (single byte) - Response R5 */
12414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd52data = GFIELD(cmd_arg, CMD52_DATA);
12424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = arg;
12434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD52_FUNCTION));
12444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD52_REG_ADDR));
12454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* Display trace for byte write */
12464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (GFIELD(cmd_arg, CMD52_RW_FLAG) == 1) {
12474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sd_trace(("%s: CMD52: Wr F:%d @0x%04x=%02x\n",
12484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			          __FUNCTION__,
12494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			          GFIELD(cmd_arg, CMD52_FUNCTION),
12504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			          GFIELD(cmd_arg, CMD52_REG_ADDR),
12514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			          cmd52data));
12524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
12534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_datalen = 32;
12554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		spi_max_response_pad = 28;
12564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
12584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	case SDIOH_CMD_53:	/* IO R/W Extended (multiple bytes/blocks) */
12594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = arg;
12604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_FUNC, GFIELD(cmd_arg, CMD53_FUNCTION));
12614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_ADDR, GFIELD(cmd_arg, CMD53_REG_ADDR));
12624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_BLKMODE, 0);
12634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_OPCODE, GFIELD(cmd_arg, CMD53_OP_CODE));
12644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_reg = SFIELD(cmd_reg, SPI_STUFF0, (sd->data_xfer_count>>8));
12654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd52data = (uint8)sd->data_xfer_count;
12664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		/* Set upper bit in byte count if necessary, but don't set it for 512 bytes. */
12684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((sd->data_xfer_count > 255) && (sd->data_xfer_count < 512)) {
12694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			cmd_reg |= 1;
12704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
12714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (GFIELD(cmd_reg, SPI_RW) == 1) { /* Write */
12734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_max_response_pad = 32;
12744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC;
12754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		} else { /* Read */
12764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_max_response_pad = 32;
12784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_datalen = (sd->data_xfer_count + spi_max_response_pad) & 0xFFFC;
12794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
12804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_trace(("%s: CMD53: %s F:%d @0x%04x len=0x%02x\n",
12814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          __FUNCTION__,
12824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          (GFIELD(cmd_reg, SPI_RW) == 1 ? "Wr" : "Rd"),
12834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          GFIELD(cmd_arg, CMD53_FUNCTION),
12844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          GFIELD(cmd_arg, CMD53_REG_ADDR),
12854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          cmd52data));
12864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		break;
12874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	default:
12894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: Unknown command %d\n", __FUNCTION__, cmd));
12904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
12914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
12924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
12934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Set up and issue the SDIO command */
12944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	memset(spi_databuf, SDSPI_IDLE_PAD, spi_datalen);
12954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_databuf[spi_pre_cmd_pad + 0] = (cmd_reg & 0xFF000000) >> 24;
12964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_databuf[spi_pre_cmd_pad + 1] = (cmd_reg & 0x00FF0000) >> 16;
12974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_databuf[spi_pre_cmd_pad + 2] = (cmd_reg & 0x0000FF00) >> 8;
12984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_databuf[spi_pre_cmd_pad + 3] = (cmd_reg & 0x000000FF);
12994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_databuf[spi_pre_cmd_pad + 4] = cmd52data;
13004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Generate CRC7 for command, if CRC is enabled, otherwise, a
13024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * default CRC7 of 0x95, which is correct for CMD0, is used.
13034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 */
13044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (sd_crc) {
13054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_crc = sdspi_crc7(&spi_databuf[spi_pre_cmd_pad], 5);
13064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
13074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_databuf[spi_pre_cmd_pad + 5] = cmd_crc;
13084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define SPI_STOP_TRAN		0xFD
13094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* for CMD53 Write, put the data into the output buffer  */
13114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD53_RW_FLAG) == 1)) {
13124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (datalen != 0) {
13134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
13144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
13154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			for (i = 0; i < sd->data_xfer_count; i++) {
13174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				spi_databuf[i + 11 + spi_pre_cmd_pad] = ((uint8 *)data)[i];
13184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
13194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (sd_crc) {
13204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], i);
13214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			} else {
13224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				dat_crc = 0xAAAA;
13234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
13244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[i + 11 + spi_pre_cmd_pad] = (dat_crc >> 8) & 0xFF;
13254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[i + 12 + spi_pre_cmd_pad] = dat_crc & 0xFF;
13264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		} else if (sd->data_xfer_count == 2) {
13274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
13284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
13294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 11]  = sd->cmd53_wr_data & 0xFF;
13304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8;
13314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (sd_crc) {
13324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 2);
13334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			} else {
13344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				dat_crc = 0x22AA;
13354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
13364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 13] = (dat_crc >> 8) & 0xFF;
13374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 14] = (dat_crc & 0xFF);
13384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		} else if (sd->data_xfer_count == 4) {
13394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 9] = SDSPI_IDLE_PAD;
13404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 10] = SDSPI_START_BLOCK;
13414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 11]  = sd->cmd53_wr_data & 0xFF;
13424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 12] = (sd->cmd53_wr_data & 0x0000FF00) >> 8;
13434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 13] = (sd->cmd53_wr_data & 0x00FF0000) >> 16;
13444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 14] = (sd->cmd53_wr_data & 0xFF000000) >> 24;
13454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (sd_crc) {
13464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				dat_crc = sdspi_crc16(&spi_databuf[spi_pre_cmd_pad+11], 4);
13474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			} else {
13484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				dat_crc = 0x44AA;
13494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
13504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 15] = (dat_crc >> 8) & 0xFF;
13514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			spi_databuf[spi_pre_cmd_pad + 16] = (dat_crc & 0xFF);
13524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		} else {
13534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			printf("CMD53 Write: size %d unsupported\n", sd->data_xfer_count);
13544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
13554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
13564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	spi_sendrecv(sd, spi_databuf, spi_rspbuf, spi_datalen);
13584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (i = spi_pre_cmd_pad + SDSPI_COMMAND_LEN; i < spi_max_response_pad; i++) {
13604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if ((spi_rspbuf[i] & SDSPI_START_BIT_MASK) == 0) {
13614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			break;
13624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
13634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
13644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (i == spi_max_response_pad) {
13664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: Did not get a response for CMD%d\n", __FUNCTION__, cmd));
13674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
13684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
13694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Extract the response. */
13714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->card_response = spi_rspbuf[i];
13724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* for CMD53 Read, find the start of the response data... */
13744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((cmd == SDIOH_CMD_53) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) {
13754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		for (; i < spi_max_response_pad; i++) {
13764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (spi_rspbuf[i] == SDSPI_START_BLOCK) {
13774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				break;
13784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
13794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
13804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (i == spi_max_response_pad) {
13824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			printf("Did not get a start of data phase for CMD%d\n", cmd);
13834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			max_errors++;
13844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			sdspi_abort(sd, GFIELD(cmd_arg, CMD53_FUNCTION));
13854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
13864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->card_rsp_data = spi_rspbuf[i+1];
13874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->card_rsp_data |= spi_rspbuf[i+2] << 8;
13884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->card_rsp_data |= spi_rspbuf[i+3] << 16;
13894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd->card_rsp_data |= spi_rspbuf[i+4] << 24;
13904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		if (datalen != 0) {
13924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			i++;
13934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			for (j = 0; j < sd->data_xfer_count; j++) {
13944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				((uint8 *)data)[j] = spi_rspbuf[i+j];
13954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
13964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (sd_crc) {
13974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				uint16 recv_crc;
13984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
13994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				recv_crc = spi_rspbuf[i+j] << 8 | spi_rspbuf[i+j+1];
14004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				dat_crc = sdspi_crc16((uint8 *)data, datalen);
14014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				if (dat_crc != recv_crc) {
14024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt					sd_err(("%s: Incorrect data CRC: expected 0x%04x, "
14034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt					        "received 0x%04x\n",
14044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt					        __FUNCTION__, dat_crc, recv_crc));
14054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt				}
14064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			}
14074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
14084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return SUCCESS;
14094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
14104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->card_rsp_data = spi_rspbuf[i+4];
14124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->card_rsp_data |= spi_rspbuf[i+3] << 8;
14134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->card_rsp_data |= spi_rspbuf[i+2] << 16;
14144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->card_rsp_data |= spi_rspbuf[i+1] << 24;
14154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Display trace for byte read */
14174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((cmd == SDIOH_CMD_52) && (GFIELD(cmd_arg, CMD52_RW_FLAG) == 0)) {
14184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_trace(("%s: CMD52: Rd F:%d @0x%04x=%02x\n",
14194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          __FUNCTION__,
14204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          GFIELD(cmd_arg, CMD53_FUNCTION),
14214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          GFIELD(cmd_arg, CMD53_REG_ADDR),
14224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		          sd->card_rsp_data >> 24));
14234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
14244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
14264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
14274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/*
14294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * On entry: if single-block or non-block, buffer size <= block size.
14304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * If multi-block, buffer size is unlimited.
14314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * Question is how to handle the left-overs in either single- or multi-block.
14324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * I think the caller should break the buffer up so this routine will always
14334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt * use block size == buffer size to handle the end piece of the buffer
14344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt */
14354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
14374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdspi_card_buf(sdioh_info_t *sd, int rw, int func, bool fifo, uint32 addr, int nbytes, uint32 *data)
14384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
14394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int status;
14404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 cmd_arg;
14414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 rsp5;
14424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int num_blocks, blocksize;
14434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bool local_blockmode, local_dma;
14444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	bool read = rw == SDIOH_READ ? 1 : 0;
14454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	ASSERT(nbytes);
14474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = 0;
14494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
14504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	         __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR",
14514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	         addr, nbytes, sd->r_cnt, sd->t_cnt));
14524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (read) sd->r_cnt++; else sd->t_cnt++;
14544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	local_blockmode = sd->sd_blockmode;
14564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	local_dma = sd->sd_use_dma;
14574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Don't bother with block mode on small xfers */
14594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (nbytes < sd->client_block_size[func]) {
14604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_info(("setting local blockmode to false: nbytes (%d) != block_size (%d)\n",
14614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		         nbytes, sd->client_block_size[func]));
14624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		local_blockmode = FALSE;
14634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		local_dma = FALSE;
14644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
14654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (local_blockmode) {
14674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		blocksize = MIN(sd->client_block_size[func], nbytes);
14684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		num_blocks = nbytes/blocksize;
14694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, num_blocks);
14704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 1);
14714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	} else {
14724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		num_blocks =  1;
14734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		blocksize = nbytes;
14744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BYTE_BLK_CNT, nbytes);
14754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_BLK_MODE, 0);
14764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
14774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (fifo)
14794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 0);
14804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	else
14814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_OP_CODE, 1);
14824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = SFIELD(cmd_arg, CMD53_FUNCTION, func);
14844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	cmd_arg = SFIELD(cmd_arg, CMD53_REG_ADDR, addr);
14854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (read)
14864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_READ);
14874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	else
14884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		cmd_arg = SFIELD(cmd_arg, CMD53_RW_FLAG, SDIOH_XFER_TYPE_WRITE);
14894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->data_xfer_count = nbytes;
14914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((func == 2) && (fifo == 1)) {
14924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_data(("%s: %s 53 func %d, %s, addr 0x%x, len %d bytes, r_cnt %d t_cnt %d\n",
14934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		         __FUNCTION__, read ? "Rd" : "Wr", func, fifo ? "FIXED" : "INCR",
14944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		         addr, nbytes, sd->r_cnt, sd->t_cnt));
14954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
14964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
14974d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* sdspi_cmd_issue() returns with the command complete bit
14984d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * in the ISR already cleared
14994d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 */
15004d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if ((status = sdspi_cmd_issue(sd, local_dma,
15014d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	                              SDIOH_CMD_53, cmd_arg,
15024d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	                              data, nbytes)) != SUCCESS) {
15034d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: cmd_issue failed for %s\n", __FUNCTION__, (read ? "read" : "write")));
15044d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return status;
15054d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
15064d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15074d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sdspi_cmd_getrsp(sd, &rsp5, 1);
15084d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15094d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (rsp5 != 0x00) {
15104d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		sd_err(("%s: rsp5 flags = 0x%x, expecting 0x00\n",
15114d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		        __FUNCTION__,  rsp5));
15124d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		return ERROR;
15134d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
15144d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15154d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return SUCCESS;
15164d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
15174d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15184d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic int
15194d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtset_client_block_size(sdioh_info_t *sd, int func, int block_size)
15204d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
15214d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int base;
15224d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	int err = 0;
15234d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15244d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd_err(("%s: Setting block size %d, func %d\n", __FUNCTION__, block_size, func));
15254d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	sd->client_block_size[func] = block_size;
15264d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15274d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Set the block size in the SDIO Card register */
15284d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	base = func * SDIOD_FBR_SIZE;
15294d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_0, 1, block_size & 0xff);
15304d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	if (!err) {
15314d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		err = sdspi_card_regwrite(sd, 0, base + SDIOD_CCCR_BLKSIZE_1, 1,
15324d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		                          (block_size >> 8) & 0xff);
15334d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
15344d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15354d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/*
15364d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * Do not set the block size in the SDIO Host register; that
15374d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * is func dependent and will get done on an individual
15384d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 * transaction basis.
15394d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	 */
15404d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15414d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (err ? BCME_SDIO_ERROR : 0);
15424d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
15434d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15444d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt/* Reset and re-initialize the device */
15454d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtint
15464d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtsdioh_sdio_reset(sdioh_info_t *si)
15474d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
15484d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	si->card_init_done = FALSE;
15494d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return sdspi_client_init(si);
15504d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
15514d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15524d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define CRC7_POLYNOM	0x09
15534d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define CRC7_CRCHIGHBIT	0x40
15544d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15554d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic uint8 sdspi_crc7(unsigned char* p, uint32 len)
15564d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
15574d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint8 c, j, bit, crc = 0;
15584d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 i;
15594d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15604d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (i = 0; i < len; i++) {
15614d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		c = *p++;
15624d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		for (j = 0x80; j; j >>= 1) {
15634d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bit = crc & CRC7_CRCHIGHBIT;
15644d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			crc <<= 1;
15654d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (c & j) bit ^= CRC7_CRCHIGHBIT;
15664d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (bit) crc ^= CRC7_POLYNOM;
15674d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
15684d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
15694d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15704d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	/* Convert the CRC7 to an 8-bit SD CRC */
15714d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	crc = (crc << 1) | 1;
15724d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15734d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (crc);
15744d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
15754d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15764d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define CRC16_POLYNOM	0x1021
15774d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt#define CRC16_CRCHIGHBIT	0x8000
15784d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15794d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidtstatic uint16 sdspi_crc16(unsigned char* p, uint32 len)
15804d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt{
15814d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint32 i;
15824d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint16 j, c, bit;
15834d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	uint16 crc = 0;
15844d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15854d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	for (i = 0; i < len; i++) {
15864d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		c = *p++;
15874d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		for (j = 0x80; j; j >>= 1) {
15884d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			bit = crc & CRC16_CRCHIGHBIT;
15894d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			crc <<= 1;
15904d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (c & j) bit ^= CRC16_CRCHIGHBIT;
15914d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt			if (bit) crc ^= CRC16_POLYNOM;
15924d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt		}
15934d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	}
15944d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt
15954d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt	return (crc);
15964d92e4c7da35860a39214c8fdb794ce0243dfabbDmitry Shmidt}
1597