4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * CDDL HEADER START
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * The contents of this file are subject to the terms of the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Common Development and Distribution License (the "License").
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * You may not use this file except in compliance with the License.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * or http://www.opensolaris.org/os/licensing.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * See the License for the specific language governing permissions
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * and limitations under the License.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner]
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * CDDL HEADER END
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#include "sdhost.h"
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amoretypedef struct sdstats sdstats_t;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoretypedef struct sdslot sdslot_t;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoretypedef struct sdhost sdhost_t;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amorestruct sdstats {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_ncmd;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_ixfr;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_oxfr;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_ibytes;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_obytes;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_npio;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_ndma;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_nmulti;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_baseclk;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_cardclk;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_tmusecs;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_width;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_flags;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_t ks_capab;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore};
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define SDFLAG_FORCE_PIO (1U << 0)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define SDFLAG_FORCE_DMA (1U << 1)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Per slot state.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestruct sdslot {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_t *ss_host;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int ss_num;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_acc_handle_t ss_acch;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore caddr_t ss_regva;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore kmutex_t ss_lock;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint8_t ss_tmoutclk;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint32_t ss_ocr; /* OCR formatted voltages */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t ss_mode;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore boolean_t ss_suspended;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore sdstats_t ss_stats;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_ncmd ss_stats.ks_ncmd.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_ixfr ss_stats.ks_ixfr.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_oxfr ss_stats.ks_oxfr.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_ibytes ss_stats.ks_ibytes.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_obytes ss_stats.ks_obytes.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_ndma ss_stats.ks_ndma.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_npio ss_stats.ks_npio.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_nmulti ss_stats.ks_nmulti.value.ui64
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_baseclk ss_stats.ks_baseclk.value.ui32
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_cardclk ss_stats.ks_cardclk.value.ui32
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_tmusecs ss_stats.ks_tmusecs.value.ui32
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_width ss_stats.ks_width.value.ui32
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_flags ss_stats.ks_flags.value.ui32
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define ss_capab ss_stats.ks_capab.value.ui32
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_t *ss_ksp;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Command in progress
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint8_t *ss_kvaddr;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int ss_blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t ss_resid; /* in blocks */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore int ss_rcnt;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* scratch buffer, to receive extra PIO data */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore caddr_t ss_bounce;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ddi_dma_handle_t ss_bufdmah;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ddi_acc_handle_t ss_bufacch;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ddi_dma_cookie_t ss_bufdmac;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore};
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore/*
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * This allocates a rather large chunk of contiguous memory for DMA.
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * But doing so means that we'll almost never have to resort to PIO.
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define SDHOST_BOUNCESZ 65536
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Per controller state.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestruct sdhost {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int sh_numslots;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_dma_attr_t sh_dmaattr;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t sh_slots[SDHOST_MAXSLOTS];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_t *sh_host;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Interrupt related information.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_intr_handle_t sh_ihandle;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int sh_icap;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint_t sh_ipri;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore};
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore#define PROPSET(x) \
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore (ddi_prop_get_int(DDI_DEV_T_ANY, dip, \
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, x, 0) != 0)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic int sdhost_attach(dev_info_t *, ddi_attach_cmd_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic int sdhost_detach(dev_info_t *, ddi_detach_cmd_t);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amorestatic int sdhost_quiesce(dev_info_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic int sdhost_suspend(dev_info_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic int sdhost_resume(dev_info_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sdhost_enable_interrupts(sdslot_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sdhost_disable_interrupts(sdslot_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic int sdhost_setup_intr(dev_info_t *, sdhost_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic uint_t sdhost_intr(caddr_t, caddr_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic int sdhost_init_slot(dev_info_t *, sdhost_t *, int, int);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sdhost_uninit_slot(sdhost_t *, int);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_soft_reset(sdslot_t *, uint8_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_set_clock(sdslot_t *, uint32_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic void sdhost_xfer_done(sdslot_t *, sda_err_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_wait_cmd(sdslot_t *, sda_cmd_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic uint_t sdhost_slot_intr(sdslot_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_cmd(void *, sda_cmd_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_getprop(void *, sda_prop_t, uint32_t *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_setprop(void *, sda_prop_t, uint32_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_poll(void *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_reset(void *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic sda_err_t sdhost_halt(void *);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic struct dev_ops sdhost_dev_ops = {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DEVO_REV, /* devo_rev */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore 0, /* devo_refcnt */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_no_info, /* devo_getinfo */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore nulldev, /* devo_identify */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore nulldev, /* devo_probe */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_attach, /* devo_attach */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_detach, /* devo_detach */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore nodev, /* devo_reset */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore NULL, /* devo_cb_ops */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore NULL, /* devo_bus_ops */
193974072f41a843678abf5f61979c748687e66bSherry Moore NULL, /* devo_power */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sdhost_quiesce, /* devo_quiesce */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore};
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic struct modldrv sdhost_modldrv = {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore &mod_driverops, /* drv_modops */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore "Standard SD Host Controller", /* drv_linkinfo */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore &sdhost_dev_ops /* drv_dev_ops */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore};
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic struct modlinkage modlinkage = {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore MODREV_1, /* ml_rev */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore { &sdhost_modldrv, NULL } /* ml_linkage */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore};
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic struct sda_ops sdhost_ops = {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore SDA_OPS_VERSION,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_cmd, /* so_cmd */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_getprop, /* so_getprop */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_setprop, /* so_setprop */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_poll, /* so_poll */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_reset, /* so_reset */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_halt, /* so_halt */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore};
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorestatic ddi_device_acc_attr_t sdhost_regattr = {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_STRUCTURE_LE_ACC, /* devacc_attr_endian_flags */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_STRICTORDER_ACC, /* devacc_attr_dataorder */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_DEFAULT_ACC, /* devacc_attr_access */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore};
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amorestatic ddi_device_acc_attr_t sdhost_bufattr = {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_DEVICE_ATTR_V0, /* devacc_attr_version */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_NEVERSWAP_ACC, /* devacc_attr_endian_flags */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_STRICTORDER_ACC, /* devacc_attr_dataorder */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_DEFAULT_ACC, /* devacc_attr_access */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore};
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define GET16(ss, reg) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_get16(ss->ss_acch, (void *)(ss->ss_regva + reg))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define PUT16(ss, reg, val) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_put16(ss->ss_acch, (void *)(ss->ss_regva + reg), val)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define GET32(ss, reg) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_get32(ss->ss_acch, (void *)(ss->ss_regva + reg))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define PUT32(ss, reg, val) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_put32(ss->ss_acch, (void *)(ss->ss_regva + reg), val)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define GET64(ss, reg) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_get64(ss->ss_acch, (void *)(ss->ss_regva + reg))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define GET8(ss, reg) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_get8(ss->ss_acch, (void *)(ss->ss_regva + reg))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define PUT8(ss, reg, val) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_put8(ss->ss_acch, (void *)(ss->ss_regva + reg), val)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define CLR8(ss, reg, mask) PUT8(ss, reg, GET8(ss, reg) & ~(mask))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define SET8(ss, reg, mask) PUT8(ss, reg, GET8(ss, reg) | (mask))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * If ever anyone uses PIO on SPARC, we have to endian-swap. But we
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * think that SD Host Controllers are likely to be uncommon on SPARC,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * and hopefully when they exist at all they will be able to use DMA.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#ifdef _BIG_ENDIAN
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define sw32(x) ddi_swap32(x)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define sw16(x) ddi_swap16(x)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#else
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define sw32(x) (x)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define sw16(x) (x)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#endif
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define GETDATA32(ss) sw32(GET32(ss, REG_DATA))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define GETDATA16(ss) sw16(GET16(ss, REG_DATA))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define GETDATA8(ss) GET8(ss, REG_DATA)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define PUTDATA32(ss, val) PUT32(ss, REG_DATA, sw32(val))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define PUTDATA16(ss, val) PUT16(ss, REG_DATA, sw16(val))
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define PUTDATA8(ss, val) PUT8(ss, REG_DATA, val)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore#define CHECK_STATE(ss, nm) \
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ((GET32(ss, REG_PRS) & PRS_ ## nm) != 0)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore_init(void)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int rv;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_init_ops(&sdhost_dev_ops);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((rv = mod_install(&modlinkage)) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_fini_ops(&sdhost_dev_ops);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore_fini(void)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int rv;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((rv = mod_remove(&modlinkage)) == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_fini_ops(&sdhost_dev_ops);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore_info(struct modinfo *modinfop)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (mod_info(&modlinkage, modinfop));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_t *shp;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_acc_handle_t pcih;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint8_t slotinfo;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint8_t bar;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int i;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore int rv;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore switch (cmd) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case DDI_ATTACH:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case DDI_RESUME:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (sdhost_resume(dip));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore default:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Soft state allocation.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp = kmem_zalloc(sizeof (*shp), KM_SLEEP);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_set_driver_private(dip, shp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore /*
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore * Reset the "slot number", so uninit slot works properly.
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore */
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore for (i = 0; i < SDHOST_MAXSLOTS; i++) {
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore shp->sh_slots[i].ss_num = -1;
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore }
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Initialize DMA attributes. For now we initialize as for
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * SDMA. If we add ADMA support we can improve this.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_version = DMA_ATTR_V0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_addr_lo = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_addr_hi = 0xffffffffU;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_count_max = 0xffffffffU;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore shp->sh_dmaattr.dma_attr_align = 4096; /* Ricoh needs it */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_burstsizes = 0; /* for now! */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_minxfer = 1;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore shp->sh_dmaattr.dma_attr_maxxfer = 0x7ffffU;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore shp->sh_dmaattr.dma_attr_sgllen = 1; /* no scatter/gather */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore shp->sh_dmaattr.dma_attr_seg = 0x7ffffU; /* not to cross 512K */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_granular = 1;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_dmaattr.dma_attr_flags = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * PCI configuration access to figure out number of slots present.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (pci_config_setup(dip, &pcih) != DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "pci_config_setup failed");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore goto failed;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore slotinfo = pci_config_get8(pcih, SLOTINFO);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_numslots = SLOTINFO_NSLOT(slotinfo);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (shp->sh_numslots > SDHOST_MAXSLOTS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Host reports to have too many slots: %d",
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_numslots);
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore pci_config_teardown(&pcih);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore goto failed;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Enable master accesses and DMA.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore pci_config_put16(pcih, PCI_CONF_COMM,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore pci_config_get16(pcih, PCI_CONF_COMM) |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PCI_COMM_MAE | PCI_COMM_ME);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Figure out which BAR to use. Note that we number BARs from
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * 1, although PCI and SD Host numbers from 0. (We number
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * from 1, because register number 0 means PCI configuration
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * space in Solaris.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore bar = SLOTINFO_BAR(slotinfo) + 1;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore pci_config_teardown(&pcih);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Setup interrupts ... supports the new DDI interrupt API. This
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * will support MSI or MSI-X interrupts if a device is found to
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * support it.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (sdhost_setup_intr(dip, shp) != DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Failed to setup interrupts");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore goto failed;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_host = sda_host_alloc(dip, shp->sh_numslots, &sdhost_ops,
3f7d54a6b84904c8f4d8daa4c7b577bede7df8b9Garrett D'Amore NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (shp->sh_host == NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Failed allocating SD host structure");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore goto failed;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Configure slots, this also maps registers, enables
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * interrupts, etc. Most of the hardware setup is done here.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 0; i < shp->sh_numslots; i++) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (sdhost_init_slot(dip, shp, i, bar + i) != DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Failed initializing slot %d", i);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore goto failed;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ddi_report_dev(dip);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Enable device interrupts at the DDI layer.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if (shp->sh_icap & DDI_INTR_FLAG_BLOCK) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore rv = ddi_intr_block_enable(&shp->sh_ihandle, 1);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore } else {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore rv = ddi_intr_enable(shp->sh_ihandle);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore }
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if (rv != DDI_SUCCESS) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore cmn_err(CE_WARN, "Failed enabling interrupts");
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore goto failed;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Mark the slots online with the framework. This will cause
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * the framework to probe them for the presence of cards.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (sda_host_attach(shp->sh_host) != DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Failed attaching to SDA framework");
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if (shp->sh_icap & DDI_INTR_FLAG_BLOCK) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) ddi_intr_block_disable(&shp->sh_ihandle, 1);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore } else {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) ddi_intr_disable(shp->sh_ihandle);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore goto failed;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_SUCCESS);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorefailed:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (shp->sh_ihandle != NULL) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_remove_handler(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_free(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 0; i < shp->sh_numslots; i++)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_uninit_slot(shp, i);
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (shp->sh_host != NULL)
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore sda_host_free(shp->sh_host);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore kmem_free(shp, sizeof (*shp));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_t *shp;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int i;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore switch (cmd) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case DDI_DETACH:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case DDI_SUSPEND:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (sdhost_suspend(dip));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore default:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp = ddi_get_driver_private(dip);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Take host offline with the framework.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_detach(shp->sh_host);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Tear down interrupts.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (shp->sh_ihandle != NULL) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if (shp->sh_icap & DDI_INTR_FLAG_BLOCK) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) ddi_intr_block_disable(&shp->sh_ihandle, 1);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore } else {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) ddi_intr_disable(shp->sh_ihandle);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_remove_handler(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_free(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Tear down register mappings, etc.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 0; i < shp->sh_numslots; i++)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_uninit_slot(shp, i);
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore sda_host_free(shp->sh_host);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore kmem_free(shp, sizeof (*shp));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_SUCCESS);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amoreint
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amoresdhost_quiesce(dev_info_t *dip)
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore{
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sdhost_t *shp;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sdslot_t *ss;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore shp = ddi_get_driver_private(dip);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore /* reset each slot separately */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore for (int i = 0; i < shp->sh_numslots; i++) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore ss = &shp->sh_slots[i];
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore if (ss->ss_acch == NULL)
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore continue;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_ALL);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore }
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore return (DDI_SUCCESS);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore}
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_suspend(dev_info_t *dip)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_t *shp;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int i;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp = ddi_get_driver_private(dip);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sda_host_suspend(shp->sh_host);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 0; i < shp->sh_numslots; i++) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss = &shp->sh_slots[i];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_suspended = B_TRUE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_disable_interrupts(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_ALL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_SUCCESS);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_resume(dev_info_t *dip)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_t *shp;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int i;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp = ddi_get_driver_private(dip);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 0; i < shp->sh_numslots; i++) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss = &shp->sh_slots[i];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_suspended = B_FALSE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_ALL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_enable_interrupts(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sda_host_resume(shp->sh_host);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_SUCCESS);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_set_clock(sdslot_t *ss, uint32_t hz)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t div;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint32_t val;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint32_t clk;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int count;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Shut off the clock to begin.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_cardclk = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_CLOCK_CONTROL, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (hz == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ss->ss_baseclk == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_log(ss->ss_host, ss->ss_num,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore "Base clock frequency not established.");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EINVAL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((hz > 25000000) && ((ss->ss_capab & CAPAB_HIGH_SPEED) != 0)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* this clock requires high speed timings! */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore SET8(ss, REG_HOST_CONTROL, HOST_CONTROL_HIGH_SPEED_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* don't allow clock to run faster than 25MHz */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore hz = min(hz, 25000000);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore CLR8(ss, REG_HOST_CONTROL, HOST_CONTROL_HIGH_SPEED_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* figure out the divider */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore clk = ss->ss_baseclk;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore div = 1;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while (clk > hz) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (div > 0x80)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore clk >>= 1; /* divide clock by two */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore div <<= 1; /* divider goes up by one */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore div >>= 1; /* 0 == divide by 1, 1 = divide by 2 */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Set the internal clock divider first, without enabling the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * card clock yet.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_CLOCK_CONTROL,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (div << CLOCK_CONTROL_FREQ_SHIFT) | CLOCK_CONTROL_INT_CLOCK_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Wait up to 100 msec for the internal clock to stabilize.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * (The spec does not seem to indicate a maximum timeout, but
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * it also suggests that an infinite loop be used, which is
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * not appropriate for hardened Solaris drivers.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (count = 100000; count; count -= 10) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore val = GET16(ss, REG_CLOCK_CONTROL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (val & CLOCK_CONTROL_INT_CLOCK_STABLE) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* if clock is stable, enable the SD clock pin */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_CLOCK_CONTROL, val |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore CLOCK_CONTROL_SD_CLOCK_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_cardclk = clk;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore drv_usecwait(10);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_ETIME);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_soft_reset(sdslot_t *ss, uint8_t bits)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int count;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * There appears to be a bug where Ricoh hosts might have a
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * problem if the host frequency is not set. If the card
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * isn't present, or we are doing a master reset, just enable
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * the internal clock at its native speed. (No dividers, and
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * not exposed to card.).
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((bits == SOFT_RESET_ALL) || !(CHECK_STATE(ss, CARD_INSERTED))) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_CLOCK_CONTROL, CLOCK_CONTROL_INT_CLOCK_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* simple 1msec wait, don't wait for clock to stabilize */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore drv_usecwait(1000);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /*
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * reset the card clock & width -- master reset also
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * resets these
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_cardclk = 0;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_width = 1;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_SOFT_RESET, bits);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (count = 100000; count != 0; count -= 10) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((GET8(ss, REG_SOFT_RESET) & bits) == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore drv_usecwait(10);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_ETIME);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_disable_interrupts(sdslot_t *ss)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* disable slot interrupts for card insert and remove */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_MASK, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_EN, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* disable error interrupts */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_ERR_MASK, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_ERR_EN, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_enable_interrupts(sdslot_t *ss)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Note that we want to enable reading of the CMD related
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bits, but we do not want them to generate an interrupt.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * (The busy wait for typical CMD stuff will normally be less
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * than 10usec, so its simpler/easier to just poll. Even in
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * the worst case of 100 kHz, the poll is at worst 2 msec.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* enable slot interrupts for card insert and remove */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_MASK, INT_MASK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_EN, INT_ENAB);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* enable error interrupts */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_ERR_MASK, ERR_MASK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_ERR_EN, ERR_ENAB);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_setup_intr(dev_info_t *dip, sdhost_t *shp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int itypes;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int itype;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Set up interrupt handler.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ddi_intr_get_supported_types(dip, &itypes) != DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "ddi_intr_get_supported_types failed");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore /*
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * It turns out that some controllers don't properly implement MSI,
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * but advertise MSI capability in their PCI config space.
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore *
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * While this is really a chip-specific bug, the simplest solution
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * is to just suppress MSI for now by default -- every device seen
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * so far can use FIXED interrupts.
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore *
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * We offer an override property, though, just in case someone really
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * wants to force it.
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore *
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore * We don't do this if the FIXED type isn't supported though!
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (itypes & DDI_INTR_TYPE_FIXED) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (!PROPSET(SDHOST_PROP_ENABLE_MSI)) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore itypes &= ~DDI_INTR_TYPE_MSI;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (!PROPSET(SDHOST_PROP_ENABLE_MSIX)) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore itypes &= ~DDI_INTR_TYPE_MSIX;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore }
28e612309dbb020942b5b5327a5385f9bf217e48Garrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Interrupt types are bits in a mask. We know about these ones:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * FIXED = 1
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * MSI = 2
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * MSIX = 4
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (itype = DDI_INTR_TYPE_MSIX; itype != 0; itype >>= 1) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int count;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((itypes & itype) == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* this type is not supported on this device! */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((ddi_intr_get_nintrs(dip, itype, &count) != DDI_SUCCESS) ||
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (count == 0)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "ddi_intr_get_nintrs failed");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * We have not seen a host device with multiple
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * interrupts (one per slot?), and the spec does not
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * indicate that they exist. But if one ever occurs,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * we spew a warning to help future debugging/support
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * efforts.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (count > 1) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Controller offers %d interrupts, "
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore "but driver only supports one", count);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((ddi_intr_alloc(dip, &shp->sh_ihandle, itype, 0, 1,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore &count, DDI_INTR_ALLOC_NORMAL) != DDI_SUCCESS) ||
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (count != 1)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "ddi_intr_alloc failed");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ddi_intr_get_pri(shp->sh_ihandle, &shp->sh_ipri) !=
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "ddi_intr_get_pri failed");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_free(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_ihandle = NULL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (shp->sh_ipri >= ddi_intr_get_hilevel_pri()) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Hi level interrupt not supported");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_free(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_ihandle = NULL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ddi_intr_get_cap(shp->sh_ihandle, &shp->sh_icap) !=
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "ddi_intr_get_cap failed");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_free(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_ihandle = NULL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ddi_intr_add_handler(shp->sh_ihandle, sdhost_intr,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp, NULL) != DDI_SUCCESS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "ddi_intr_add_handler failed");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) ddi_intr_free(shp->sh_ihandle);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore shp->sh_ihandle = NULL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore continue;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_SUCCESS);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_xfer_done(sdslot_t *ss, sda_err_t errno)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((errno == SDA_EOK) && (ss->ss_resid != 0)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* an unexpected partial transfer was found */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore errno = SDA_ERESID;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_blksz = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_resid = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (errno != SDA_EOK) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_CMD);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_DAT);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* send a STOP command if necessary */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ss->ss_mode & XFR_MODE_AUTO_CMD12) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT32(ss, REG_ARGUMENT, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_COMMAND,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (CMD_STOP_TRANSMIT << 8) |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore COMMAND_TYPE_NORM | COMMAND_INDEX_CHECK_EN |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore COMMAND_CRC_CHECK_EN | COMMAND_RESP_48_BUSY);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_transfer(ss->ss_host, ss->ss_num, errno);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreuint_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_slot_intr(sdslot_t *ss)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t intr;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t errs;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore caddr_t data;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int count;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ss->ss_suspended) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_INTR_UNCLAIMED);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore intr = GET16(ss, REG_INT_STAT);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (intr == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_INTR_UNCLAIMED);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore errs = GET16(ss, REG_ERR_STAT);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (intr & (INT_REM | INT_INS)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_STAT, intr);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_detect(ss->ss_host, ss->ss_num);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* no further interrupt processing this cycle */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_INTR_CLAIMED);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (intr & INT_DMA) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * We have crossed a DMA/page boundary. Cope with it.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /*
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * Apparently some sdhost controllers issue a final
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * DMA interrupt if the DMA completes on a boundary,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * even though there is no further data to transfer.
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore *
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * There might be a risk here of the controller
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * continuing to access the same data over and over
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * again, but we accept the risk.
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore PUT16(ss, REG_INT_STAT, INT_DMA);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (intr & INT_RD) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * PIO read! PIO is quite suboptimal, but we expect
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * performance critical applications to use DMA
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * whenever possible. We have to stage this through
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * the bounce buffer to meet alignment considerations.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_STAT, INT_RD);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while ((ss->ss_resid > 0) && CHECK_STATE(ss, BUF_RD_EN)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore data = ss->ss_bounce;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count = ss->ss_blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ASSERT(count > 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ASSERT(ss->ss_kvaddr != NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while (count >= sizeof (uint32_t)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *(uint32_t *)(void *)data = GETDATA32(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore data += sizeof (uint32_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count -= sizeof (uint32_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while (count >= sizeof (uint16_t)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *(uint16_t *)(void *)data = GETDATA16(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore data += sizeof (uint16_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count -= sizeof (uint16_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while (count >= sizeof (uint8_t)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *(uint8_t *)data = GETDATA8(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore data += sizeof (uint8_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count -= sizeof (uint8_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore bcopy(ss->ss_bounce, ss->ss_kvaddr, ss->ss_blksz);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_kvaddr += ss->ss_blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_resid--;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (intr & INT_WR) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * PIO write! PIO is quite suboptimal, but we expect
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * performance critical applications to use DMA
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * whenever possible. We have to stage this through
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * the bounce buffer to meet alignment considerations.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_STAT, INT_WR);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while ((ss->ss_resid > 0) && CHECK_STATE(ss, BUF_WR_EN)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore data = ss->ss_bounce;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count = ss->ss_blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ASSERT(count > 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ASSERT(ss->ss_kvaddr != NULL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore bcopy(ss->ss_kvaddr, data, count);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while (count >= sizeof (uint32_t)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUTDATA32(ss, *(uint32_t *)(void *)data);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore data += sizeof (uint32_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count -= sizeof (uint32_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while (count >= sizeof (uint16_t)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUTDATA16(ss, *(uint16_t *)(void *)data);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore data += sizeof (uint16_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count -= sizeof (uint16_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore while (count >= sizeof (uint8_t)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUTDATA8(ss, *(uint8_t *)data);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore data += sizeof (uint8_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore count -= sizeof (uint8_t);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_kvaddr += ss->ss_blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_resid--;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (intr & INT_XFR) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if ((ss->ss_mode & (XFR_MODE_READ | XFR_MODE_DMA_EN)) ==
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore (XFR_MODE_READ | XFR_MODE_DMA_EN)) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore (void) ddi_dma_sync(ss->ss_bufdmah, 0, 0,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_DMA_SYNC_FORKERNEL);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore bcopy(ss->ss_bounce, ss->ss_kvaddr, ss->ss_rcnt);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_rcnt = 0;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_STAT, INT_XFR);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_xfer_done(ss, SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (intr & INT_ERR) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_ERR_STAT, errs);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_STAT, INT_ERR);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (errs & ERR_DAT) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((errs & ERR_DAT_END) == ERR_DAT_END) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_xfer_done(ss, SDA_EPROTO);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else if ((errs & ERR_DAT_CRC) == ERR_DAT_CRC) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_xfer_done(ss, SDA_ECRC7);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_xfer_done(ss, SDA_ETIME);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else if (errs & ERR_ACMD12) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Generally, this is bad news. we need a full
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * reset to recover properly.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_xfer_done(ss, SDA_ECMD12);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * This asynchronous error leaves the slot more or less
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * useless. Report it to the framework.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (errs & ERR_CURRENT) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_fault(ss->ss_host, ss->ss_num,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore SDA_FAULT_CURRENT);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_INTR_CLAIMED);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore/*ARGSUSED1*/
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreuint_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_intr(caddr_t arg1, caddr_t arg2)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_t *shp = (void *)arg1;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int rv = DDI_INTR_UNCLAIMED;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int num;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* interrupt for each of the slots present in the system */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (num = 0; num < shp->sh_numslots; num++) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (sdhost_slot_intr(&shp->sh_slots[num]) ==
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_INTR_CLAIMED) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore rv = DDI_INTR_CLAIMED;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoreint
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_init_slot(dev_info_t *dip, sdhost_t *shp, int num, int bar)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint32_t capab;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint32_t clk;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore char ksname[16];
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore size_t blen;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore unsigned ndmac;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore int rv;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Register the private state.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss = &shp->sh_slots[num];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_host = shp->sh_host;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_num = num;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_host_set_private(shp->sh_host, num, ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Initialize core data structure, locks, etc.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_init(&ss->ss_lock, NULL, MUTEX_DRIVER,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore DDI_INTR_PRI(shp->sh_ipri));
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /*
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * Set up DMA.
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore rv = ddi_dma_alloc_handle(dip, &shp->sh_dmaattr,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_DMA_SLEEP, NULL, &ss->ss_bufdmah);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (rv != DDI_SUCCESS) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore cmn_err(CE_WARN, "Failed to alloc dma handle (%d)!", rv);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore return (DDI_FAILURE);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore rv = ddi_dma_mem_alloc(ss->ss_bufdmah, SDHOST_BOUNCESZ,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore &sdhost_bufattr, DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore &ss->ss_bounce, &blen, &ss->ss_bufacch);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (rv != DDI_SUCCESS) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore cmn_err(CE_WARN, "Failed to alloc bounce buffer (%d)!", rv);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore return (DDI_FAILURE);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore rv = ddi_dma_addr_bind_handle(ss->ss_bufdmah, NULL, ss->ss_bounce,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore blen, DDI_DMA_RDWR | DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, NULL,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore &ss->ss_bufdmac, &ndmac);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if ((rv != DDI_DMA_MAPPED) || (ndmac != 1)) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore cmn_err(CE_WARN, "Failed to bind DMA bounce buffer (%d, %u)!",
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore rv, ndmac);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore return (DDI_FAILURE);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /*
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * Set up virtual kstats.
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore (void) snprintf(ksname, sizeof (ksname), "slot%d", num);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ksp = kstat_create(ddi_driver_name(dip), ddi_get_instance(dip),
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ksname, "misc", KSTAT_TYPE_NAMED,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore sizeof (sdstats_t) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (ss->ss_ksp != NULL) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore sdstats_t *sp = &ss->ss_stats;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ksp->ks_data = sp;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ksp->ks_private = ss;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ksp->ks_lock = &ss->ss_lock;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /* counters are 64 bits wide */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_ncmd, "ncmd", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_ixfr, "ixfr", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_oxfr, "oxfr", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_ibytes, "ibytes", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_obytes, "obytes", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_npio, "npio", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_ndma, "ndma", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_nmulti, "nmulti", KSTAT_DATA_UINT64);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /* these aren't counters -- leave them at 32 bits */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_baseclk, "baseclk", KSTAT_DATA_UINT32);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_cardclk, "cardclk", KSTAT_DATA_UINT32);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_tmusecs, "tmusecs", KSTAT_DATA_UINT32);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_width, "width", KSTAT_DATA_UINT32);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_flags, "flags", KSTAT_DATA_UINT32);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_named_init(&sp->ks_capab, "capab", KSTAT_DATA_UINT32);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_install(ss->ss_ksp);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (PROPSET(SDHOST_PROP_FORCE_PIO)) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_flags |= SDFLAG_FORCE_PIO;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (PROPSET(SDHOST_PROP_FORCE_DMA)) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_flags |= SDFLAG_FORCE_DMA;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ddi_regs_map_setup(dip, bar, &ss->ss_regva, 0, 0, &sdhost_regattr,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore &ss->ss_acch) != DDI_SUCCESS) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore cmn_err(CE_WARN, "Failed to map registers!");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* reset before reading capabilities */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (sdhost_soft_reset(ss, SOFT_RESET_ALL) != SDA_EOK)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore capab = GET64(ss, REG_CAPAB) & 0xffffffffU; /* upper bits reserved */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_capab = capab;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* host voltages in OCR format */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_ocr = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (capab & CAPAB_18V)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_ocr |= OCR_18_19V; /* 1.8V */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (capab & CAPAB_30V)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_ocr |= OCR_30_31V;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (capab & CAPAB_33V)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_ocr |= OCR_32_33V;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* base clock */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_baseclk =
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ((capab & CAPAB_BASE_FREQ_MASK) >> CAPAB_BASE_FREQ_SHIFT);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_baseclk *= 1000000;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Timeout clock. We can calculate this using the following
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * formula:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * (1000000 usec/1sec) * (1sec/tmoutclk) * base factor = clock time
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Clock time is the length of the base clock in usecs.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Our base factor is 2^13, which is the shortest clock we
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * can count.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * To simplify the math and avoid overflow, we cancel out the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * zeros for kHz or MHz. Since we want to wait more clocks, not
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * less, on error, we truncate the result rather than rounding
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * up.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore clk = ((capab & CAPAB_TIMEOUT_FREQ_MASK) >> CAPAB_TIMEOUT_FREQ_SHIFT);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((ss->ss_baseclk == 0) || (clk == 0)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore cmn_err(CE_WARN, "Unable to determine clock frequencies");
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_FAILURE);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (capab & CAPAB_TIMEOUT_UNITS) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* MHz */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_tmusecs = (1 << 13) / clk;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore clk *= 1000000;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* kHz */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_tmusecs = (1000 * (1 << 13)) / clk;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore clk *= 1000;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Calculation of the timeout.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * SDIO cards use a 1sec timeout, and SDHC cards use fixed
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * 100msec for read and 250 msec for write.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Legacy cards running at 375kHz have a worst case of about
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * 15 seconds. Running at 25MHz (the standard speed) it is
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * about 100msec for read, and about 3.2 sec for write.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Typical values are 1/100th that, or about 1msec for read,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * and 32 msec for write.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * No transaction at full speed should ever take more than 4
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * seconds. (Some slow legacy cards might have trouble, but
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * we'll worry about them if they ever are seen. Nobody wants
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * to wait 4 seconds to access a single block anyway!)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * To get to 4 seconds, we continuously double usec until we
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * get to the maximum value, or a timeout greater than 4
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * seconds.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Note that for high-speed timeout clocks, we might not be
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * able to get to the full 4 seconds. E.g. with a 48MHz
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * timeout clock, we can only get to about 2.8 seconds. Its
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * possible that there could be some slow MMC cards that will
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * timeout at this clock rate, but it seems unlikely. (The
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * device would have to be pressing the very worst times,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * against the 100-fold "permissive" window allowed, and
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * running at only 12.5MHz.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * XXX: this could easily be a tunable. Someone dealing with only
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * reasonable cards could set this to just 1 second.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (ss->ss_tmoutclk = 0; ss->ss_tmoutclk < 14; ss->ss_tmoutclk++) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((ss->ss_tmusecs * (1 << ss->ss_tmoutclk)) >= 4000000) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Enable slot interrupts.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_enable_interrupts(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (DDI_SUCCESS);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_uninit_slot(sdhost_t *shp, int num)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss = &shp->sh_slots[num];
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (ss->ss_acch != NULL)
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_ALL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (ss->ss_bufdmac.dmac_address)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore (void) ddi_dma_unbind_handle(ss->ss_bufdmah);
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (ss->ss_bufacch != NULL)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ddi_dma_mem_free(&ss->ss_bufacch);
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (ss->ss_bufdmah != NULL)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ddi_dma_free_handle(&ss->ss_bufdmah);
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (ss->ss_ksp != NULL)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore kstat_delete(ss->ss_ksp);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (ss->ss_acch != NULL)
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore ddi_regs_map_free(&ss->ss_acch);
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore if (ss->ss_num != -1)
c8ca7eb82dbd1de2747ac78a9ad7822cee2820f1Garrett D'Amore mutex_destroy(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amorevoid
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_get_response(sdslot_t *ss, sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint32_t *resp = cmdp->sc_response;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int i;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[0] = GET32(ss, REG_RESP1);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[1] = GET32(ss, REG_RESP2);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[2] = GET32(ss, REG_RESP3);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[3] = GET32(ss, REG_RESP4);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Response 2 is goofy because the host drops the low
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * order CRC bits. This makes it a bit awkward, so we
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * have to shift the bits to make it work out right.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Note that the framework expects the 32 bit
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * words to be ordered in LE fashion. (The
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bits within the words are in native order).
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (cmdp->sc_rtype == R2) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 3; i > 0; i--) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[i] <<= 8;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[i] |= (resp[i - 1] >> 24);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore resp[0] <<= 8;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_wait_cmd(sdslot_t *ss, sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore int i;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t errs;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore sda_err_t rv;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Worst case for 100kHz timeout is 2msec (200 clocks), we add
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * a tiny bit for safety. (Generally timeout will be far, far
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * less than that.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Note that at more typical 12MHz (and normally it will be
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * even faster than that!) that the device timeout is only
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * 16.67 usec. We could be smarter and reduce the delay time,
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * but that would require putting more intelligence into the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * code, and we don't expect CMD timeout to normally occur
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * except during initialization. (At which time we need the
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * full timeout anyway.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Checking the ERR_STAT will normally cause the timeout to
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * terminate to finish early if the device is healthy, anyway.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore for (i = 3000; i > 0; i -= 5) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (GET16(ss, REG_INT_STAT) & INT_CMD) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_INT_STAT, INT_CMD);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* command completed */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_get_response(ss, cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((errs = (GET16(ss, REG_ERR_STAT) & ERR_CMD)) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_ERR_STAT, errs);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* command timeout isn't a host failure */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((errs & ERR_CMD_TMO) == ERR_CMD_TMO) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore rv = SDA_ETIME;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore } else if ((errs & ERR_CMD_CRC) == ERR_CMD_CRC) {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore rv = SDA_ECRC7;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore rv = SDA_EPROTO;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore goto error;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore drv_usecwait(5);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore rv = SDA_ETIME;
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amoreerror:
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore /*
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * NB: We need to soft reset the CMD and DAT
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore * lines after a failure of this sort.
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore */
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_CMD);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_DAT);
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore
f2b90c3c415ff04d4adb3a54242822b41d74bfd9Garrett D'Amore return (rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_poll(void *arg)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss = arg;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) sdhost_slot_intr(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_cmd(void *arg, sda_cmd_t *cmdp)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss = arg;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t command;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t mode;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_err_t rv;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Command register:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bit 13-8 = command index
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bit 7-6 = command type (always zero for us!)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bit 5 = data present select
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bit 4 = command index check (always on!)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bit 3 = command CRC check enable
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bit 2 = reserved
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * bit 1-0 = response type
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command = ((uint16_t)cmdp->sc_index << 8);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command |= COMMAND_TYPE_NORM |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore COMMAND_INDEX_CHECK_EN | COMMAND_CRC_CHECK_EN;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore switch (cmdp->sc_rtype) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R0:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command |= COMMAND_RESP_NONE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R1:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R5:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R6:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R7:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command |= COMMAND_RESP_48;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R1b:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R5b:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command |= COMMAND_RESP_48_BUSY;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R2:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command |= COMMAND_RESP_136;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command &= ~(COMMAND_INDEX_CHECK_EN | COMMAND_CRC_CHECK_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R3:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case R4:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command |= COMMAND_RESP_48;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command &= ~COMMAND_CRC_CHECK_EN;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command &= ~COMMAND_INDEX_CHECK_EN;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore default:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EINVAL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ss->ss_suspended) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_ESUSPENDED);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (cmdp->sc_nblks != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore uint16_t nblks;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore blksz = cmdp->sc_blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore nblks = cmdp->sc_nblks;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Ensure that we have good data.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((blksz < 1) || (blksz > 2048)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EINVAL);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore command |= COMMAND_DATA_PRESENT;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_blksz = blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_kvaddr = (void *)cmdp->sc_kvaddr;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_rcnt = 0;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_resid = 0;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Only SDMA for now. We can investigate ADMA2 later.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * (Right now we don't have ADMA2 capable hardware.)
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * We always use a bounce buffer, which solves weird
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * problems with certain controllers. Doing this with
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * a large contiguous buffer may be faster than
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * servicing all the little per-page interrupts
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * anyway. (Bcopy of 64 K vs. 16 interrupts.)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (((ss->ss_capab & CAPAB_SDMA) != 0) &&
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ((ss->ss_flags & SDFLAG_FORCE_PIO) == 0) &&
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ((blksz * nblks) <= SDHOST_BOUNCESZ)) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore if (cmdp->sc_flags & SDA_CMDF_WRITE) {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /*
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * if we're writing, prepare initial round
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * of data
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore bcopy(cmdp->sc_kvaddr, ss->ss_bounce,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore nblks * blksz);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore (void) ddi_dma_sync(ss->ss_bufdmah, 0, 0,
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore DDI_DMA_SYNC_FORDEV);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore } else {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_rcnt = nblks * blksz;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore }
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore PUT32(ss, REG_SDMA_ADDR, ss->ss_bufdmac.dmac_address);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mode = XFR_MODE_DMA_EN;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore PUT16(ss, REG_BLKSZ, BLKSZ_BOUNDARY_512K | blksz);
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ndma++;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mode = 0;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_npio++;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_resid = nblks;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_BLKSZ, blksz);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (nblks > 1) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mode |= XFR_MODE_MULTI | XFR_MODE_COUNT;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (cmdp->sc_flags & SDA_CMDF_AUTO_CMD12)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mode |= XFR_MODE_AUTO_CMD12;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_nmulti++;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((cmdp->sc_flags & SDA_CMDF_READ) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mode |= XFR_MODE_READ;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ixfr++;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ibytes += nblks * blksz;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore } else {
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_oxfr++;
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_obytes += nblks * blksz;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore ss->ss_mode = mode;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_TIMEOUT_CONTROL, ss->ss_tmoutclk);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_BLOCK_COUNT, nblks);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_XFR_MODE, mode);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT32(ss, REG_ARGUMENT, cmdp->sc_argument);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT16(ss, REG_COMMAND, command);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_ncmd++;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore rv = sdhost_wait_cmd(ss, cmdp);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_getprop(void *arg, sda_prop_t prop, uint32_t *val)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss = arg;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_err_t rv = 0;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ss->ss_suspended) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_ESUSPENDED);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore switch (prop) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_INSERTED:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (CHECK_STATE(ss, CARD_INSERTED)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_TRUE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_FALSE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_WPROTECT:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (CHECK_STATE(ss, WRITE_ENABLE)) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_FALSE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_TRUE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_OCR:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = ss->ss_ocr;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_CLOCK:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = ss->ss_cardclk;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_CAP_HISPEED:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if ((ss->ss_capab & CAPAB_HIGH_SPEED) != 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_TRUE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_FALSE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_CAP_4BITS:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_TRUE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_CAP_NOPIO:
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore /*
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * We might have to use PIO for buffers that don't
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * have reasonable alignments. A few controllers seem
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * not to deal with granularity or alignments of
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore * something other 32-bits.
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore */
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore *val = B_FALSE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_CAP_INTR:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_CAP_8BITS:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore *val = B_FALSE;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore default:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore rv = SDA_ENOTSUP;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_setprop(void *arg, sda_prop_t prop, uint32_t val)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss = arg;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sda_err_t rv = SDA_EOK;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (ss->ss_suspended) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_ESUSPENDED);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore switch (prop) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_LED:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (val) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore SET8(ss, REG_HOST_CONTROL, HOST_CONTROL_LED_ON);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore CLR8(ss, REG_HOST_CONTROL, HOST_CONTROL_LED_ON);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_CLOCK:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore rv = sdhost_set_clock(arg, val);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_BUSWIDTH:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore switch (val) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case 1:
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_width = val;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore CLR8(ss, REG_HOST_CONTROL, HOST_CONTROL_DATA_WIDTH);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case 4:
9a5113a6958e1e7b93b09e74189ebc16d2a68affGarrett D'Amore ss->ss_width = val;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore SET8(ss, REG_HOST_CONTROL, HOST_CONTROL_DATA_WIDTH);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore default:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore rv = SDA_EINVAL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_OCR:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore val &= ss->ss_ocr;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (val & OCR_17_18V) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_POWER_CONTROL, POWER_CONTROL_18V);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_POWER_CONTROL, POWER_CONTROL_18V |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore POWER_CONTROL_BUS_POWER);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else if (val & OCR_29_30V) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_POWER_CONTROL, POWER_CONTROL_30V);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_POWER_CONTROL, POWER_CONTROL_30V |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore POWER_CONTROL_BUS_POWER);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else if (val & OCR_32_33V) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_POWER_CONTROL, POWER_CONTROL_33V);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_POWER_CONTROL, POWER_CONTROL_33V |
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore POWER_CONTROL_BUS_POWER);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else if (val == 0) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* turn off power */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore PUT8(ss, REG_POWER_CONTROL, 0);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore rv = SDA_EINVAL;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore case SDA_PROP_HISPEED:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (val) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore SET8(ss, REG_HOST_CONTROL, HOST_CONTROL_HIGH_SPEED_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore } else {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore CLR8(ss, REG_HOST_CONTROL, HOST_CONTROL_HIGH_SPEED_EN);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* give clocks time to settle */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore drv_usecwait(10);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore default:
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore rv = SDA_ENOTSUP;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore break;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /*
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * Apparently some controllers (ENE) have issues with changing
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * certain parameters (bus width seems to be one), requiring
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore * a reset of the DAT and CMD lines.
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (rv == SDA_EOK) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_CMD);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore (void) sdhost_soft_reset(ss, SOFT_RESET_DAT);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (rv);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_reset(void *arg)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss = arg;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (!ss->ss_suspended) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (sdhost_soft_reset(ss, SOFT_RESET_ALL) != SDA_EOK) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_ETIME);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_enable_interrupts(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresda_err_t
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amoresdhost_halt(void *arg)
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore{
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdslot_t *ss = arg;
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_enter(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (!ss->ss_suspended) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore sdhost_disable_interrupts(ss);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore /* this has the side effect of removing power from the card */
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore if (sdhost_soft_reset(ss, SOFT_RESET_ALL) != SDA_EOK) {
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_ETIME);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore }
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore mutex_exit(&ss->ss_lock);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore return (SDA_EOK);
4bb7efa72ed531c10f097919636e67724ec4c25aGarrett D'Amore}