1*4bb7efa7SGarrett D'Amore /* 2*4bb7efa7SGarrett D'Amore * CDDL HEADER START 3*4bb7efa7SGarrett D'Amore * 4*4bb7efa7SGarrett D'Amore * The contents of this file are subject to the terms of the 5*4bb7efa7SGarrett D'Amore * Common Development and Distribution License (the "License"). 6*4bb7efa7SGarrett D'Amore * You may not use this file except in compliance with the License. 7*4bb7efa7SGarrett D'Amore * 8*4bb7efa7SGarrett D'Amore * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*4bb7efa7SGarrett D'Amore * or http://www.opensolaris.org/os/licensing. 10*4bb7efa7SGarrett D'Amore * See the License for the specific language governing permissions 11*4bb7efa7SGarrett D'Amore * and limitations under the License. 12*4bb7efa7SGarrett D'Amore * 13*4bb7efa7SGarrett D'Amore * When distributing Covered Code, include this CDDL HEADER in each 14*4bb7efa7SGarrett D'Amore * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*4bb7efa7SGarrett D'Amore * If applicable, add the following below this CDDL HEADER, with the 16*4bb7efa7SGarrett D'Amore * fields enclosed by brackets "[]" replaced with your own identifying 17*4bb7efa7SGarrett D'Amore * information: Portions Copyright [yyyy] [name of copyright owner] 18*4bb7efa7SGarrett D'Amore * 19*4bb7efa7SGarrett D'Amore * CDDL HEADER END 20*4bb7efa7SGarrett D'Amore */ 21*4bb7efa7SGarrett D'Amore /* 22*4bb7efa7SGarrett D'Amore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23*4bb7efa7SGarrett D'Amore * Use is subject to license terms. 24*4bb7efa7SGarrett D'Amore */ 25*4bb7efa7SGarrett D'Amore 26*4bb7efa7SGarrett D'Amore /* 27*4bb7efa7SGarrett D'Amore * SD card initialization support. 28*4bb7efa7SGarrett D'Amore */ 29*4bb7efa7SGarrett D'Amore 30*4bb7efa7SGarrett D'Amore #include <sys/types.h> 31*4bb7efa7SGarrett D'Amore #include <sys/ddi.h> 32*4bb7efa7SGarrett D'Amore #include <sys/sunddi.h> 33*4bb7efa7SGarrett D'Amore #include <sys/sdcard/sda.h> 34*4bb7efa7SGarrett D'Amore #include <sys/sdcard/sda_impl.h> 35*4bb7efa7SGarrett D'Amore 36*4bb7efa7SGarrett D'Amore 37*4bb7efa7SGarrett D'Amore /* 38*4bb7efa7SGarrett D'Amore * Local Prototypes. 39*4bb7efa7SGarrett D'Amore */ 40*4bb7efa7SGarrett D'Amore 41*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_mmc(sda_slot_t *); 42*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_sdio(sda_slot_t *); 43*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_sdmem(sda_slot_t *); 44*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_cmd(sda_slot_t *, sda_index_t, uint32_t, 45*4bb7efa7SGarrett D'Amore sda_rtype_t, uint32_t *); 46*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_acmd(sda_slot_t *, sda_index_t, uint32_t, 47*4bb7efa7SGarrett D'Amore sda_rtype_t, uint32_t *); 48*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_blocklen(sda_slot_t *); 49*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_width(sda_slot_t *); 50*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_rca(sda_slot_t *); 51*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_ifcond(sda_slot_t *); 52*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_highspeed(sda_slot_t *); 53*4bb7efa7SGarrett D'Amore static sda_err_t sda_init_switch(sda_slot_t *, uint8_t, uint8_t, uint8_t, 54*4bb7efa7SGarrett D'Amore uint8_t *); 55*4bb7efa7SGarrett D'Amore static void sda_init_clock(sda_slot_t *, uint32_t); 56*4bb7efa7SGarrett D'Amore 57*4bb7efa7SGarrett D'Amore /* 58*4bb7efa7SGarrett D'Amore * Implementation. 59*4bb7efa7SGarrett D'Amore */ 60*4bb7efa7SGarrett D'Amore sda_err_t 61*4bb7efa7SGarrett D'Amore sda_init_cmd(sda_slot_t *slot, sda_index_t cmd, uint32_t arg, 62*4bb7efa7SGarrett D'Amore sda_rtype_t rtype, uint32_t *resp) 63*4bb7efa7SGarrett D'Amore { 64*4bb7efa7SGarrett D'Amore sda_cmd_t *cmdp; 65*4bb7efa7SGarrett D'Amore sda_err_t errno; 66*4bb7efa7SGarrett D'Amore 67*4bb7efa7SGarrett D'Amore cmdp = sda_cmd_alloc(slot, cmd, arg, rtype, NULL, KM_SLEEP); 68*4bb7efa7SGarrett D'Amore 69*4bb7efa7SGarrett D'Amore cmdp->sc_flags |= SDA_CMDF_INIT; 70*4bb7efa7SGarrett D'Amore 71*4bb7efa7SGarrett D'Amore errno = sda_cmd_exec(slot, cmdp, resp); 72*4bb7efa7SGarrett D'Amore 73*4bb7efa7SGarrett D'Amore sda_cmd_free(cmdp); 74*4bb7efa7SGarrett D'Amore 75*4bb7efa7SGarrett D'Amore return (errno); 76*4bb7efa7SGarrett D'Amore } 77*4bb7efa7SGarrett D'Amore 78*4bb7efa7SGarrett D'Amore sda_err_t 79*4bb7efa7SGarrett D'Amore sda_init_acmd(sda_slot_t *slot, sda_index_t cmd, uint32_t arg, 80*4bb7efa7SGarrett D'Amore sda_rtype_t rtype, uint32_t *resp) 81*4bb7efa7SGarrett D'Amore { 82*4bb7efa7SGarrett D'Amore sda_cmd_t *cmdp; 83*4bb7efa7SGarrett D'Amore sda_err_t errno; 84*4bb7efa7SGarrett D'Amore 85*4bb7efa7SGarrett D'Amore cmdp = sda_cmd_alloc_acmd(slot, cmd, arg, rtype, NULL, KM_SLEEP); 86*4bb7efa7SGarrett D'Amore 87*4bb7efa7SGarrett D'Amore cmdp->sc_flags |= SDA_CMDF_INIT; 88*4bb7efa7SGarrett D'Amore 89*4bb7efa7SGarrett D'Amore errno = sda_cmd_exec(slot, cmdp, resp); 90*4bb7efa7SGarrett D'Amore 91*4bb7efa7SGarrett D'Amore sda_cmd_free(cmdp); 92*4bb7efa7SGarrett D'Amore 93*4bb7efa7SGarrett D'Amore return (errno); 94*4bb7efa7SGarrett D'Amore } 95*4bb7efa7SGarrett D'Amore 96*4bb7efa7SGarrett D'Amore sda_err_t 97*4bb7efa7SGarrett D'Amore sda_init_sdio(sda_slot_t *slot) 98*4bb7efa7SGarrett D'Amore { 99*4bb7efa7SGarrett D'Amore slot->s_num_io = 0; 100*4bb7efa7SGarrett D'Amore 101*4bb7efa7SGarrett D'Amore /* 102*4bb7efa7SGarrett D'Amore * TODO: SDIO: We need to initialize the SDIO OCR register using 103*4bb7efa7SGarrett D'Amore * the special CMD_IO_SEND_OCR (CMD5) command. 104*4bb7efa7SGarrett D'Amore */ 105*4bb7efa7SGarrett D'Amore return (SDA_EOK); 106*4bb7efa7SGarrett D'Amore } 107*4bb7efa7SGarrett D'Amore 108*4bb7efa7SGarrett D'Amore sda_err_t 109*4bb7efa7SGarrett D'Amore sda_init_sdmem(sda_slot_t *slot) 110*4bb7efa7SGarrett D'Amore { 111*4bb7efa7SGarrett D'Amore uint32_t ocr; 112*4bb7efa7SGarrett D'Amore int count; 113*4bb7efa7SGarrett D'Amore 114*4bb7efa7SGarrett D'Amore slot->s_flags &= ~SLOTF_SDMEM; 115*4bb7efa7SGarrett D'Amore 116*4bb7efa7SGarrett D'Amore /* 117*4bb7efa7SGarrett D'Amore * Try sending the ACMD41 to query the OCR (Op Cond Register). 118*4bb7efa7SGarrett D'Amore */ 119*4bb7efa7SGarrett D'Amore if (sda_init_acmd(slot, ACMD_SD_SEND_OCR, 0, R3, &ocr) != SDA_EOK) { 120*4bb7efa7SGarrett D'Amore /* 121*4bb7efa7SGarrett D'Amore * Card failed to respond to query, not an SD card? 122*4bb7efa7SGarrett D'Amore * We send GO_IDLE to clear any error status on the 123*4bb7efa7SGarrett D'Amore * card. 124*4bb7efa7SGarrett D'Amore */ 125*4bb7efa7SGarrett D'Amore (void) sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL); 126*4bb7efa7SGarrett D'Amore return (SDA_EOK); 127*4bb7efa7SGarrett D'Amore } 128*4bb7efa7SGarrett D'Amore 129*4bb7efa7SGarrett D'Amore /* 130*4bb7efa7SGarrett D'Amore * Now we have to send our OCR value, along with the HCS (High 131*4bb7efa7SGarrett D'Amore * Capacity Support) bit. The HCS bit is required, to 132*4bb7efa7SGarrett D'Amore * activate high capacity cards. We only set the HCS bit if 133*4bb7efa7SGarrett D'Amore * the card responded to CMD8 (SEND_IFCOND), indicating that 134*4bb7efa7SGarrett D'Amore * it supports the new protocol. 135*4bb7efa7SGarrett D'Amore * 136*4bb7efa7SGarrett D'Amore * Note that the HCS bit occupies the same location as the CCS bit 137*4bb7efa7SGarrett D'Amore * in the response. 138*4bb7efa7SGarrett D'Amore */ 139*4bb7efa7SGarrett D'Amore if ((ocr & slot->s_cur_ocr) == 0) { 140*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "SD card not compatible with host"); 141*4bb7efa7SGarrett D'Amore return (SDA_ENOTSUP); 142*4bb7efa7SGarrett D'Amore } 143*4bb7efa7SGarrett D'Amore /* set the HCS bit if its a ver 2.00 card */ 144*4bb7efa7SGarrett D'Amore if (slot->s_flags & SLOTF_IFCOND) { 145*4bb7efa7SGarrett D'Amore ocr |= OCR_CCS; 146*4bb7efa7SGarrett D'Amore } 147*4bb7efa7SGarrett D'Amore 148*4bb7efa7SGarrett D'Amore /* make sure card is powered up */ 149*4bb7efa7SGarrett D'Amore for (count = 1000000; count != 0; count -= 10000) { 150*4bb7efa7SGarrett D'Amore uint32_t r3; 151*4bb7efa7SGarrett D'Amore 152*4bb7efa7SGarrett D'Amore if (sda_init_acmd(slot, ACMD_SD_SEND_OCR, ocr, R3, &r3) != 0) { 153*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "SD card failed to power up"); 154*4bb7efa7SGarrett D'Amore return (SDA_ENOTSUP); 155*4bb7efa7SGarrett D'Amore } 156*4bb7efa7SGarrett D'Amore 157*4bb7efa7SGarrett D'Amore /* Now check the busy bit */ 158*4bb7efa7SGarrett D'Amore if (r3 & OCR_POWER_UP) { 159*4bb7efa7SGarrett D'Amore slot->s_flags |= SLOTF_SDMEM; 160*4bb7efa7SGarrett D'Amore if ((slot->s_flags & SLOTF_IFCOND) && 161*4bb7efa7SGarrett D'Amore (r3 & OCR_CCS)) { 162*4bb7efa7SGarrett D'Amore slot->s_flags |= SLOTF_SDHC; 163*4bb7efa7SGarrett D'Amore } else { 164*4bb7efa7SGarrett D'Amore slot->s_flags &= ~SLOTF_SDHC; 165*4bb7efa7SGarrett D'Amore } 166*4bb7efa7SGarrett D'Amore return (0); 167*4bb7efa7SGarrett D'Amore } 168*4bb7efa7SGarrett D'Amore 169*4bb7efa7SGarrett D'Amore drv_usecwait(10000); 170*4bb7efa7SGarrett D'Amore } 171*4bb7efa7SGarrett D'Amore 172*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "SD card timed out during power up"); 173*4bb7efa7SGarrett D'Amore return (SDA_ETIME); 174*4bb7efa7SGarrett D'Amore } 175*4bb7efa7SGarrett D'Amore 176*4bb7efa7SGarrett D'Amore sda_err_t 177*4bb7efa7SGarrett D'Amore sda_init_mmc(sda_slot_t *slot) 178*4bb7efa7SGarrett D'Amore { 179*4bb7efa7SGarrett D'Amore uint32_t ocr; 180*4bb7efa7SGarrett D'Amore int count; 181*4bb7efa7SGarrett D'Amore 182*4bb7efa7SGarrett D'Amore slot->s_flags &= ~SLOTF_MMC; 183*4bb7efa7SGarrett D'Amore 184*4bb7efa7SGarrett D'Amore /* 185*4bb7efa7SGarrett D'Amore * If the card has already been identified as an SD card, then 186*4bb7efa7SGarrett D'Amore * cannot also be an MMC card, so don't probe it as such. 187*4bb7efa7SGarrett D'Amore */ 188*4bb7efa7SGarrett D'Amore if (slot->s_flags & SLOTF_SD) { 189*4bb7efa7SGarrett D'Amore return (SDA_EOK); 190*4bb7efa7SGarrett D'Amore } 191*4bb7efa7SGarrett D'Amore 192*4bb7efa7SGarrett D'Amore /* 193*4bb7efa7SGarrett D'Amore * Try sending the CMD1 to query the OCR. 194*4bb7efa7SGarrett D'Amore */ 195*4bb7efa7SGarrett D'Amore if (sda_init_cmd(slot, CMD_SEND_OCR, 0, R3, &ocr) != 0) { 196*4bb7efa7SGarrett D'Amore /* 197*4bb7efa7SGarrett D'Amore * Card failed to respond to query, not an MMC card? 198*4bb7efa7SGarrett D'Amore * We send GO_IDLE to clear any error status on the 199*4bb7efa7SGarrett D'Amore * card. 200*4bb7efa7SGarrett D'Amore */ 201*4bb7efa7SGarrett D'Amore (void) sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL); 202*4bb7efa7SGarrett D'Amore return (SDA_EOK); 203*4bb7efa7SGarrett D'Amore } 204*4bb7efa7SGarrett D'Amore 205*4bb7efa7SGarrett D'Amore if ((ocr & slot->s_cur_ocr) == 0) { 206*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "MMC card not compatible with host"); 207*4bb7efa7SGarrett D'Amore return (SDA_ENOTSUP); 208*4bb7efa7SGarrett D'Amore } 209*4bb7efa7SGarrett D'Amore 210*4bb7efa7SGarrett D'Amore /* make sure card is powered up */ 211*4bb7efa7SGarrett D'Amore for (count = 1000000; count != 0; count -= 10000) { 212*4bb7efa7SGarrett D'Amore uint32_t r3; 213*4bb7efa7SGarrett D'Amore 214*4bb7efa7SGarrett D'Amore if (sda_init_cmd(slot, CMD_SEND_OCR, ocr, R3, &r3) != 0) { 215*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "MMC card failed to power up"); 216*4bb7efa7SGarrett D'Amore return (SDA_ENOTSUP); 217*4bb7efa7SGarrett D'Amore } 218*4bb7efa7SGarrett D'Amore 219*4bb7efa7SGarrett D'Amore /* Now check the busy bit */ 220*4bb7efa7SGarrett D'Amore if (r3 & OCR_POWER_UP) { 221*4bb7efa7SGarrett D'Amore slot->s_flags |= SLOTF_MMC; 222*4bb7efa7SGarrett D'Amore return (SDA_EOK); 223*4bb7efa7SGarrett D'Amore } 224*4bb7efa7SGarrett D'Amore 225*4bb7efa7SGarrett D'Amore drv_usecwait(10000); 226*4bb7efa7SGarrett D'Amore } 227*4bb7efa7SGarrett D'Amore 228*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "MMC card timed out during power up"); 229*4bb7efa7SGarrett D'Amore return (SDA_ETIME); 230*4bb7efa7SGarrett D'Amore } 231*4bb7efa7SGarrett D'Amore 232*4bb7efa7SGarrett D'Amore sda_err_t 233*4bb7efa7SGarrett D'Amore sda_init_card(sda_slot_t *slot) 234*4bb7efa7SGarrett D'Amore { 235*4bb7efa7SGarrett D'Amore int rv; 236*4bb7efa7SGarrett D'Amore uint32_t resp; 237*4bb7efa7SGarrett D'Amore uint32_t val; 238*4bb7efa7SGarrett D'Amore 239*4bb7efa7SGarrett D'Amore /* 240*4bb7efa7SGarrett D'Amore * Power off slot/card initially. 241*4bb7efa7SGarrett D'Amore */ 242*4bb7efa7SGarrett D'Amore sda_slot_power_off(slot); 243*4bb7efa7SGarrett D'Amore 244*4bb7efa7SGarrett D'Amore /* 245*4bb7efa7SGarrett D'Amore * Apply initial power to the slot. 246*4bb7efa7SGarrett D'Amore */ 247*4bb7efa7SGarrett D'Amore if ((rv = sda_slot_power_on(slot)) != 0) { 248*4bb7efa7SGarrett D'Amore return (rv); 249*4bb7efa7SGarrett D'Amore } 250*4bb7efa7SGarrett D'Amore 251*4bb7efa7SGarrett D'Amore /* 252*4bb7efa7SGarrett D'Amore * First enable the clock, but only at 400 kHz. All cards are 253*4bb7efa7SGarrett D'Amore * supposed to be able to operate between this speed and 100 254*4bb7efa7SGarrett D'Amore * kHz, and all hosts must be able to pick a speed between 100 255*4bb7efa7SGarrett D'Amore * kHz and 400 kHz. 256*4bb7efa7SGarrett D'Amore * 257*4bb7efa7SGarrett D'Amore * Once we know what the device can support, then we speed up. 258*4bb7efa7SGarrett D'Amore */ 259*4bb7efa7SGarrett D'Amore sda_init_clock(slot, 400000); 260*4bb7efa7SGarrett D'Amore 261*4bb7efa7SGarrett D'Amore if ((rv = sda_init_ifcond(slot)) != SDA_EOK) { 262*4bb7efa7SGarrett D'Amore goto done; 263*4bb7efa7SGarrett D'Amore } 264*4bb7efa7SGarrett D'Amore 265*4bb7efa7SGarrett D'Amore if (((rv = sda_init_sdio(slot)) != SDA_EOK) || 266*4bb7efa7SGarrett D'Amore ((rv = sda_init_sdmem(slot)) != SDA_EOK) || 267*4bb7efa7SGarrett D'Amore ((rv = sda_init_mmc(slot)) != SDA_EOK)) { 268*4bb7efa7SGarrett D'Amore 269*4bb7efa7SGarrett D'Amore /* message will already have been logged */ 270*4bb7efa7SGarrett D'Amore goto done; 271*4bb7efa7SGarrett D'Amore } 272*4bb7efa7SGarrett D'Amore 273*4bb7efa7SGarrett D'Amore if ((slot->s_flags & (SLOTF_MEMORY | SLOTF_SDIO)) == 0) { 274*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Unidentified card type"); 275*4bb7efa7SGarrett D'Amore rv = SDA_ENOTSUP; 276*4bb7efa7SGarrett D'Amore goto done; 277*4bb7efa7SGarrett D'Amore } 278*4bb7efa7SGarrett D'Amore 279*4bb7efa7SGarrett D'Amore /* 280*4bb7efa7SGarrett D'Amore * Memory cards need to obtain their CID before getting their RCA. 281*4bb7efa7SGarrett D'Amore * This is a requirement for the state transitions... they go thru 282*4bb7efa7SGarrett D'Amore * the ident state, unlike SDIO cards. 283*4bb7efa7SGarrett D'Amore */ 284*4bb7efa7SGarrett D'Amore if (slot->s_flags & SLOTF_MEMORY) { 285*4bb7efa7SGarrett D'Amore rv = sda_init_cmd(slot, CMD_BCAST_CID, 0, R2, slot->s_rcid); 286*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 287*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Failed getting card CID (%d)", rv); 288*4bb7efa7SGarrett D'Amore goto done; 289*4bb7efa7SGarrett D'Amore } 290*4bb7efa7SGarrett D'Amore } 291*4bb7efa7SGarrett D'Amore 292*4bb7efa7SGarrett D'Amore if ((rv = sda_init_rca(slot)) != SDA_EOK) { 293*4bb7efa7SGarrett D'Amore goto done; 294*4bb7efa7SGarrett D'Amore } 295*4bb7efa7SGarrett D'Amore 296*4bb7efa7SGarrett D'Amore slot->s_maxclk = 0xffffffffU; /* special sentinel */ 297*4bb7efa7SGarrett D'Amore 298*4bb7efa7SGarrett D'Amore /* 299*4bb7efa7SGarrett D'Amore * Figure out card supported bus width and speed. 300*4bb7efa7SGarrett D'Amore * 301*4bb7efa7SGarrett D'Amore * TODO: SDIO: For IO cards, we have to check what speed the card 302*4bb7efa7SGarrett D'Amore * supports by looking in the CCCR_CAPAB register. (SDIO cards 303*4bb7efa7SGarrett D'Amore * can go low-speed only, full-speed, or high-speed.) 304*4bb7efa7SGarrett D'Amore */ 305*4bb7efa7SGarrett D'Amore if (slot->s_flags & SLOTF_MEMORY) { 306*4bb7efa7SGarrett D'Amore 307*4bb7efa7SGarrett D'Amore /* 308*4bb7efa7SGarrett D'Amore * We need to obtain the CSD. 309*4bb7efa7SGarrett D'Amore */ 310*4bb7efa7SGarrett D'Amore rv = sda_init_cmd(slot, CMD_SEND_CSD, slot->s_rca << 16, R2, 311*4bb7efa7SGarrett D'Amore slot->s_rcsd); 312*4bb7efa7SGarrett D'Amore if (rv != 0) { 313*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Failed getting card CSD (%d)", rv); 314*4bb7efa7SGarrett D'Amore goto done; 315*4bb7efa7SGarrett D'Amore } 316*4bb7efa7SGarrett D'Amore 317*4bb7efa7SGarrett D'Amore /* 318*4bb7efa7SGarrett D'Amore * Calculate the maxclock. 319*4bb7efa7SGarrett D'Amore */ 320*4bb7efa7SGarrett D'Amore slot->s_maxclk = sda_mem_maxclk(slot); 321*4bb7efa7SGarrett D'Amore } 322*4bb7efa7SGarrett D'Amore if (((slot->s_flags & SLOTF_SDMEM) != 0) && 323*4bb7efa7SGarrett D'Amore ((slot->s_caps & SLOT_CAP_4BITS) != 0)) { 324*4bb7efa7SGarrett D'Amore slot->s_flags |= SLOTF_4BITS; 325*4bb7efa7SGarrett D'Amore } 326*4bb7efa7SGarrett D'Amore if (slot->s_flags & SLOTF_SDIO) { 327*4bb7efa7SGarrett D'Amore sda_slot_debug(slot, "Wide SDIO bus not yet supported"); 328*4bb7efa7SGarrett D'Amore slot->s_flags &= ~SLOTF_4BITS; 329*4bb7efa7SGarrett D'Amore } 330*4bb7efa7SGarrett D'Amore 331*4bb7efa7SGarrett D'Amore /* 332*4bb7efa7SGarrett D'Amore * Now select the card. 333*4bb7efa7SGarrett D'Amore */ 334*4bb7efa7SGarrett D'Amore if ((rv = sda_init_cmd(slot, CMD_SELECT_CARD, slot->s_rca << 16, 335*4bb7efa7SGarrett D'Amore R1b, &resp)) != SDA_EOK) { 336*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Failed selecting card (%d, %x)", rv, resp); 337*4bb7efa7SGarrett D'Amore goto done; 338*4bb7efa7SGarrett D'Amore } 339*4bb7efa7SGarrett D'Amore 340*4bb7efa7SGarrett D'Amore if ((rv = sda_init_highspeed(slot)) != SDA_EOK) { 341*4bb7efa7SGarrett D'Amore goto done; 342*4bb7efa7SGarrett D'Amore } 343*4bb7efa7SGarrett D'Amore 344*4bb7efa7SGarrett D'Amore sda_init_clock(slot, slot->s_maxclk); 345*4bb7efa7SGarrett D'Amore 346*4bb7efa7SGarrett D'Amore /* 347*4bb7efa7SGarrett D'Amore * Lets go to 4-bit bus mode, if possible. 348*4bb7efa7SGarrett D'Amore */ 349*4bb7efa7SGarrett D'Amore if ((rv = sda_init_width(slot)) != SDA_EOK) { 350*4bb7efa7SGarrett D'Amore goto done; 351*4bb7efa7SGarrett D'Amore } 352*4bb7efa7SGarrett D'Amore 353*4bb7efa7SGarrett D'Amore if ((rv = sda_init_blocklen(slot)) != SDA_EOK) { 354*4bb7efa7SGarrett D'Amore goto done; 355*4bb7efa7SGarrett D'Amore } 356*4bb7efa7SGarrett D'Amore 357*4bb7efa7SGarrett D'Amore /* note if a card is writable */ 358*4bb7efa7SGarrett D'Amore if ((sda_getprop(slot, SDA_PROP_WPROTECT, &val) == SDA_EOK) && 359*4bb7efa7SGarrett D'Amore (val == 0)) { 360*4bb7efa7SGarrett D'Amore slot->s_flags |= SLOTF_WRITABLE; 361*4bb7efa7SGarrett D'Amore } 362*4bb7efa7SGarrett D'Amore 363*4bb7efa7SGarrett D'Amore rv = SDA_EOK; 364*4bb7efa7SGarrett D'Amore 365*4bb7efa7SGarrett D'Amore done: 366*4bb7efa7SGarrett D'Amore 367*4bb7efa7SGarrett D'Amore sda_slot_enter(slot); 368*4bb7efa7SGarrett D'Amore slot->s_init = B_FALSE; 369*4bb7efa7SGarrett D'Amore sda_slot_exit(slot); 370*4bb7efa7SGarrett D'Amore 371*4bb7efa7SGarrett D'Amore sda_slot_wakeup(slot); 372*4bb7efa7SGarrett D'Amore 373*4bb7efa7SGarrett D'Amore return (rv); 374*4bb7efa7SGarrett D'Amore } 375*4bb7efa7SGarrett D'Amore 376*4bb7efa7SGarrett D'Amore sda_err_t 377*4bb7efa7SGarrett D'Amore sda_init_blocklen(sda_slot_t *slot) 378*4bb7efa7SGarrett D'Amore { 379*4bb7efa7SGarrett D'Amore int rv; 380*4bb7efa7SGarrett D'Amore uint32_t resp; 381*4bb7efa7SGarrett D'Amore 382*4bb7efa7SGarrett D'Amore if ((slot->s_flags & SLOTF_MEMORY) == 0) { 383*4bb7efa7SGarrett D'Amore return (SDA_EOK); 384*4bb7efa7SGarrett D'Amore } 385*4bb7efa7SGarrett D'Amore 386*4bb7efa7SGarrett D'Amore /* 387*4bb7efa7SGarrett D'Amore * All memory cards support block sizes of 512. Full stop. 388*4bb7efa7SGarrett D'Amore */ 389*4bb7efa7SGarrett D'Amore rv = sda_init_cmd(slot, CMD_SET_BLOCKLEN, 512, R1, &resp); 390*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 391*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Unable to set block length (%d, %x)", 392*4bb7efa7SGarrett D'Amore rv, resp); 393*4bb7efa7SGarrett D'Amore } 394*4bb7efa7SGarrett D'Amore return (rv); 395*4bb7efa7SGarrett D'Amore } 396*4bb7efa7SGarrett D'Amore 397*4bb7efa7SGarrett D'Amore void 398*4bb7efa7SGarrett D'Amore sda_init_clock(sda_slot_t *slot, uint32_t hz) 399*4bb7efa7SGarrett D'Amore { 400*4bb7efa7SGarrett D'Amore int rv; 401*4bb7efa7SGarrett D'Amore uint32_t act; 402*4bb7efa7SGarrett D'Amore 403*4bb7efa7SGarrett D'Amore /* 404*4bb7efa7SGarrett D'Amore * Note that at no time is a failure programming the clock 405*4bb7efa7SGarrett D'Amore * itself necessarily a fatal error. Although if the clock 406*4bb7efa7SGarrett D'Amore * wasn't programmed, other things will probably not work during 407*4bb7efa7SGarrett D'Amore * initialization. 408*4bb7efa7SGarrett D'Amore */ 409*4bb7efa7SGarrett D'Amore 410*4bb7efa7SGarrett D'Amore if ((rv = sda_setprop(slot, SDA_PROP_CLOCK, hz)) != SDA_EOK) { 411*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Failed setting clock to %u Hz (%d)", 412*4bb7efa7SGarrett D'Amore hz, rv); 413*4bb7efa7SGarrett D'Amore /* XXX: FMA fail the slot */ 414*4bb7efa7SGarrett D'Amore return; 415*4bb7efa7SGarrett D'Amore } 416*4bb7efa7SGarrett D'Amore 417*4bb7efa7SGarrett D'Amore if ((rv = sda_getprop(slot, SDA_PROP_CLOCK, &act)) == SDA_EOK) { 418*4bb7efa7SGarrett D'Amore sda_slot_debug(slot, "Clock set to %u Hz (requested %u Hz)", 419*4bb7efa7SGarrett D'Amore act, hz); 420*4bb7efa7SGarrett D'Amore } else { 421*4bb7efa7SGarrett D'Amore sda_slot_debug(slot, "Clock frequency unknown (good luck)."); 422*4bb7efa7SGarrett D'Amore } 423*4bb7efa7SGarrett D'Amore 424*4bb7efa7SGarrett D'Amore /* 425*4bb7efa7SGarrett D'Amore * For now, just wait 10msec for clocks to stabilize to the 426*4bb7efa7SGarrett D'Amore * card. (Is this really necessary?) 427*4bb7efa7SGarrett D'Amore */ 428*4bb7efa7SGarrett D'Amore delay(drv_usectohz(10000)); 429*4bb7efa7SGarrett D'Amore } 430*4bb7efa7SGarrett D'Amore 431*4bb7efa7SGarrett D'Amore sda_err_t 432*4bb7efa7SGarrett D'Amore sda_init_width(sda_slot_t *slot) 433*4bb7efa7SGarrett D'Amore { 434*4bb7efa7SGarrett D'Amore int rv; 435*4bb7efa7SGarrett D'Amore uint32_t resp; 436*4bb7efa7SGarrett D'Amore 437*4bb7efa7SGarrett D'Amore /* 438*4bb7efa7SGarrett D'Amore * Spec says we should command the card first. 439*4bb7efa7SGarrett D'Amore */ 440*4bb7efa7SGarrett D'Amore 441*4bb7efa7SGarrett D'Amore rv = sda_setprop(slot, SDA_PROP_BUSWIDTH, 1); 442*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 443*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Unable to set slot 1-bit mode (%d)", rv); 444*4bb7efa7SGarrett D'Amore return (rv); 445*4bb7efa7SGarrett D'Amore } 446*4bb7efa7SGarrett D'Amore 447*4bb7efa7SGarrett D'Amore if ((slot->s_flags & SLOTF_4BITS) == 0) { 448*4bb7efa7SGarrett D'Amore return (SDA_EOK); 449*4bb7efa7SGarrett D'Amore } 450*4bb7efa7SGarrett D'Amore 451*4bb7efa7SGarrett D'Amore /* 452*4bb7efa7SGarrett D'Amore * TODO: SDIO: SDIO cards set the CCCR_BUS_WIDTH 453*4bb7efa7SGarrett D'Amore * and CCCR_CD_DISABLE bits here. 454*4bb7efa7SGarrett D'Amore */ 455*4bb7efa7SGarrett D'Amore 456*4bb7efa7SGarrett D'Amore /* 457*4bb7efa7SGarrett D'Amore * If we're going to use all 4 pins, we really need to disconnect 458*4bb7efa7SGarrett D'Amore * the card pullup resistor. A consquence of this, is that hosts 459*4bb7efa7SGarrett D'Amore * which use that resistor for detection must not claim to support 460*4bb7efa7SGarrett D'Amore * 4-bit bus mode. This is a limitation of our implementation. 461*4bb7efa7SGarrett D'Amore */ 462*4bb7efa7SGarrett D'Amore rv = sda_init_acmd(slot, ACMD_SET_CLR_CARD_DETECT, 1, R1, &resp); 463*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 464*4bb7efa7SGarrett D'Amore sda_slot_err(slot, 465*4bb7efa7SGarrett D'Amore "Unable disconnect DAT3 resistor on card (%d, %x)", 466*4bb7efa7SGarrett D'Amore rv, resp); 467*4bb7efa7SGarrett D'Amore /* non-fatal error, muddle on */ 468*4bb7efa7SGarrett D'Amore return (SDA_EOK); 469*4bb7efa7SGarrett D'Amore } 470*4bb7efa7SGarrett D'Amore 471*4bb7efa7SGarrett D'Amore rv = sda_init_acmd(slot, ACMD_SET_BUS_WIDTH, 2, R1, &resp); 472*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 473*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Unable to set card 4-bit mode (%d, %x)", 474*4bb7efa7SGarrett D'Amore rv, resp); 475*4bb7efa7SGarrett D'Amore /* non-fatal error, muddle on */ 476*4bb7efa7SGarrett D'Amore return (SDA_EOK); 477*4bb7efa7SGarrett D'Amore } 478*4bb7efa7SGarrett D'Amore 479*4bb7efa7SGarrett D'Amore rv = sda_setprop(slot, SDA_PROP_BUSWIDTH, 4); 480*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 481*4bb7efa7SGarrett D'Amore /* 482*4bb7efa7SGarrett D'Amore * This is bad news. We've already asked for the card to 483*4bb7efa7SGarrett D'Amore * to use 4-bit mode, but the host is not complying. It 484*4bb7efa7SGarrett D'Amore * shouldn't ever happen, so we just error out. 485*4bb7efa7SGarrett D'Amore */ 486*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Unable to set slot 4-bit mode (%d)", rv); 487*4bb7efa7SGarrett D'Amore } 488*4bb7efa7SGarrett D'Amore 489*4bb7efa7SGarrett D'Amore return (rv); 490*4bb7efa7SGarrett D'Amore } 491*4bb7efa7SGarrett D'Amore 492*4bb7efa7SGarrett D'Amore sda_err_t 493*4bb7efa7SGarrett D'Amore sda_init_ifcond(sda_slot_t *slot) 494*4bb7efa7SGarrett D'Amore { 495*4bb7efa7SGarrett D'Amore int rv; 496*4bb7efa7SGarrett D'Amore int tries; 497*4bb7efa7SGarrett D'Amore uint32_t vchk; 498*4bb7efa7SGarrett D'Amore uint32_t resp; 499*4bb7efa7SGarrett D'Amore 500*4bb7efa7SGarrett D'Amore /* 501*4bb7efa7SGarrett D'Amore * Try SEND_IF_COND. Note that this assumes that the host is 502*4bb7efa7SGarrett D'Amore * supplying 2.7 - 3.6 voltage range. The standard is not 503*4bb7efa7SGarrett D'Amore * defined for any other ranges. 504*4bb7efa7SGarrett D'Amore */ 505*4bb7efa7SGarrett D'Amore vchk = R7_VHS_27_36V | R7_PATTERN; 506*4bb7efa7SGarrett D'Amore 507*4bb7efa7SGarrett D'Amore /* we try this a few times, just to be sure */ 508*4bb7efa7SGarrett D'Amore for (tries = 0; tries < 5; tries++) { 509*4bb7efa7SGarrett D'Amore rv = sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL); 510*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 511*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Failed to IDLE card"); 512*4bb7efa7SGarrett D'Amore return (rv); 513*4bb7efa7SGarrett D'Amore } 514*4bb7efa7SGarrett D'Amore 515*4bb7efa7SGarrett D'Amore rv = sda_init_cmd(slot, CMD_SEND_IF_COND, vchk, R7, &resp); 516*4bb7efa7SGarrett D'Amore if (rv == SDA_EOK) { 517*4bb7efa7SGarrett D'Amore break; 518*4bb7efa7SGarrett D'Amore } 519*4bb7efa7SGarrett D'Amore delay(drv_usectohz(10000)); 520*4bb7efa7SGarrett D'Amore } 521*4bb7efa7SGarrett D'Amore 522*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 523*4bb7efa7SGarrett D'Amore (void) sda_init_cmd(slot, CMD_GO_IDLE, 0, R0, NULL); 524*4bb7efa7SGarrett D'Amore slot->s_flags &= ~SLOTF_IFCOND; 525*4bb7efa7SGarrett D'Amore 526*4bb7efa7SGarrett D'Amore } else if (resp != vchk) { 527*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Card voltages incompatible! (%x)", resp); 528*4bb7efa7SGarrett D'Amore return (SDA_ENOTSUP); 529*4bb7efa7SGarrett D'Amore 530*4bb7efa7SGarrett D'Amore } else { 531*4bb7efa7SGarrett D'Amore /* SDHC compliant */ 532*4bb7efa7SGarrett D'Amore slot->s_flags |= SLOTF_IFCOND; 533*4bb7efa7SGarrett D'Amore } 534*4bb7efa7SGarrett D'Amore 535*4bb7efa7SGarrett D'Amore return (SDA_EOK); 536*4bb7efa7SGarrett D'Amore } 537*4bb7efa7SGarrett D'Amore 538*4bb7efa7SGarrett D'Amore sda_err_t 539*4bb7efa7SGarrett D'Amore sda_init_rca(sda_slot_t *slot) 540*4bb7efa7SGarrett D'Amore { 541*4bb7efa7SGarrett D'Amore int rv; 542*4bb7efa7SGarrett D'Amore int tries; 543*4bb7efa7SGarrett D'Amore uint32_t resp; 544*4bb7efa7SGarrett D'Amore 545*4bb7efa7SGarrett D'Amore /* 546*4bb7efa7SGarrett D'Amore * Program the RCA. Note that MMC has a different mechanism 547*4bb7efa7SGarrett D'Amore * for this. 548*4bb7efa7SGarrett D'Amore */ 549*4bb7efa7SGarrett D'Amore for (tries = 0; tries < 10; tries++) { 550*4bb7efa7SGarrett D'Amore 551*4bb7efa7SGarrett D'Amore if (slot->s_flags & SLOTF_MMC) { 552*4bb7efa7SGarrett D'Amore /* 553*4bb7efa7SGarrett D'Amore * For MMC, we push the RCA to the MMC. We 554*4bb7efa7SGarrett D'Amore * arbitrarily start at 0x100, and add from 555*4bb7efa7SGarrett D'Amore * there. 556*4bb7efa7SGarrett D'Amore */ 557*4bb7efa7SGarrett D'Amore rv = sda_init_cmd(slot, CMD_SEND_RCA, 558*4bb7efa7SGarrett D'Amore (0x100 + tries) << 16, R1, NULL); 559*4bb7efa7SGarrett D'Amore if (rv == SDA_EOK) 560*4bb7efa7SGarrett D'Amore slot->s_rca = 0x100 + tries; 561*4bb7efa7SGarrett D'Amore } else { 562*4bb7efa7SGarrett D'Amore /* 563*4bb7efa7SGarrett D'Amore * For SDcard, we are basically asking the 564*4bb7efa7SGarrett D'Amore * card to propose a value. It *may* propose 565*4bb7efa7SGarrett D'Amore * a value of zero, in which case we will have 566*4bb7efa7SGarrett D'Amore * to ask again. 567*4bb7efa7SGarrett D'Amore */ 568*4bb7efa7SGarrett D'Amore rv = sda_init_cmd(slot, CMD_SEND_RCA, 0, R6, &resp); 569*4bb7efa7SGarrett D'Amore if (rv == SDA_EOK) 570*4bb7efa7SGarrett D'Amore slot->s_rca = resp >> 16; 571*4bb7efa7SGarrett D'Amore } 572*4bb7efa7SGarrett D'Amore if ((rv == SDA_EOK) && (slot->s_rca != 0)) { 573*4bb7efa7SGarrett D'Amore sda_slot_debug(slot, "Relative address (RCA) = %d", 574*4bb7efa7SGarrett D'Amore slot->s_rca); 575*4bb7efa7SGarrett D'Amore return (SDA_EOK); 576*4bb7efa7SGarrett D'Amore } 577*4bb7efa7SGarrett D'Amore } 578*4bb7efa7SGarrett D'Amore 579*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Unable to negotiate a suitable RCA (%d)", rv); 580*4bb7efa7SGarrett D'Amore return ((rv != SDA_EOK) ? rv : SDA_EINVAL); 581*4bb7efa7SGarrett D'Amore } 582*4bb7efa7SGarrett D'Amore 583*4bb7efa7SGarrett D'Amore sda_err_t 584*4bb7efa7SGarrett D'Amore sda_init_switch(sda_slot_t *slot, uint8_t mode, uint8_t grp, uint8_t val, 585*4bb7efa7SGarrett D'Amore uint8_t *data) 586*4bb7efa7SGarrett D'Amore { 587*4bb7efa7SGarrett D'Amore sda_cmd_t *cmdp; 588*4bb7efa7SGarrett D'Amore sda_err_t errno; 589*4bb7efa7SGarrett D'Amore uint32_t arg; 590*4bb7efa7SGarrett D'Amore 591*4bb7efa7SGarrett D'Amore /* 592*4bb7efa7SGarrett D'Amore * The spec says we should leave unselected groups set to 0xf, 593*4bb7efa7SGarrett D'Amore * to prevent inadvertent changes. 594*4bb7efa7SGarrett D'Amore */ 595*4bb7efa7SGarrett D'Amore arg = (mode << 31) | 0xffffff; 596*4bb7efa7SGarrett D'Amore arg &= ~(0xf << (grp << 2)); 597*4bb7efa7SGarrett D'Amore arg |= (val << (grp << 2)); 598*4bb7efa7SGarrett D'Amore 599*4bb7efa7SGarrett D'Amore cmdp = sda_cmd_alloc(slot, CMD_SWITCH_FUNC, arg, R1, NULL, KM_SLEEP); 600*4bb7efa7SGarrett D'Amore 601*4bb7efa7SGarrett D'Amore cmdp->sc_flags |= SDA_CMDF_INIT | SDA_CMDF_DAT | SDA_CMDF_READ; 602*4bb7efa7SGarrett D'Amore cmdp->sc_blksz = 64; 603*4bb7efa7SGarrett D'Amore cmdp->sc_nblks = 1; 604*4bb7efa7SGarrett D'Amore cmdp->sc_kvaddr = (void *)data; 605*4bb7efa7SGarrett D'Amore 606*4bb7efa7SGarrett D'Amore errno = sda_cmd_exec(slot, cmdp, NULL); 607*4bb7efa7SGarrett D'Amore 608*4bb7efa7SGarrett D'Amore sda_cmd_free(cmdp); 609*4bb7efa7SGarrett D'Amore 610*4bb7efa7SGarrett D'Amore return (errno); 611*4bb7efa7SGarrett D'Amore 612*4bb7efa7SGarrett D'Amore } 613*4bb7efa7SGarrett D'Amore 614*4bb7efa7SGarrett D'Amore sda_err_t 615*4bb7efa7SGarrett D'Amore sda_init_highspeed(sda_slot_t *slot) 616*4bb7efa7SGarrett D'Amore { 617*4bb7efa7SGarrett D'Amore uint32_t ccc; 618*4bb7efa7SGarrett D'Amore uint8_t data[64]; 619*4bb7efa7SGarrett D'Amore sda_err_t rv; 620*4bb7efa7SGarrett D'Amore 621*4bb7efa7SGarrett D'Amore if ((slot->s_caps & SLOT_CAP_HISPEED) == 0) { 622*4bb7efa7SGarrett D'Amore return (SDA_EOK); 623*4bb7efa7SGarrett D'Amore } 624*4bb7efa7SGarrett D'Amore if ((slot->s_flags & SLOTF_SDMEM) == 0) { 625*4bb7efa7SGarrett D'Amore return (SDA_EOK); 626*4bb7efa7SGarrett D'Amore } 627*4bb7efa7SGarrett D'Amore ccc = sda_mem_getbits(slot->s_rcsd, 95, 12); 628*4bb7efa7SGarrett D'Amore if ((ccc & (1 << 10)) == 0) { 629*4bb7efa7SGarrett D'Amore return (SDA_EOK); 630*4bb7efa7SGarrett D'Amore } 631*4bb7efa7SGarrett D'Amore 632*4bb7efa7SGarrett D'Amore rv = sda_init_switch(slot, 0, 0, 1, data); 633*4bb7efa7SGarrett D'Amore 634*4bb7efa7SGarrett D'Amore /* these are big-endian bits, bit 401 */ 635*4bb7efa7SGarrett D'Amore if ((rv != SDA_EOK) || ((data[13] & (1 << 1)) == 0)) { 636*4bb7efa7SGarrett D'Amore return (SDA_EOK); 637*4bb7efa7SGarrett D'Amore } 638*4bb7efa7SGarrett D'Amore 639*4bb7efa7SGarrett D'Amore rv = sda_init_switch(slot, 1, 0, 1, data); 640*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 641*4bb7efa7SGarrett D'Amore return (SDA_EOK); 642*4bb7efa7SGarrett D'Amore } 643*4bb7efa7SGarrett D'Amore 644*4bb7efa7SGarrett D'Amore /* now program the card */ 645*4bb7efa7SGarrett D'Amore rv = sda_setprop(slot, SDA_PROP_HISPEED, 1); 646*4bb7efa7SGarrett D'Amore if (rv != SDA_EOK) { 647*4bb7efa7SGarrett D'Amore sda_slot_err(slot, "Failed setting slot to high speed mode"); 648*4bb7efa7SGarrett D'Amore } else { 649*4bb7efa7SGarrett D'Amore /* the card should now support 50 MHz */ 650*4bb7efa7SGarrett D'Amore slot->s_maxclk = 50000000; 651*4bb7efa7SGarrett D'Amore } 652*4bb7efa7SGarrett D'Amore 653*4bb7efa7SGarrett D'Amore return (rv); 654*4bb7efa7SGarrett D'Amore } 655