Example #1
0
/*
 * Starting point for SDIO card init.
 */
int mmc_attach_sdio(void *pCard)
{
	SDM_CARD_INFO*   card;
	int err, i, funcs;

	if (pCard == NULL)
		return -EPERM;

	card = (SDM_CARD_INFO*)pCard;

	/*
	 * Detect and init the card.
	 */
	err = mmc_sdio_init_card(pCard);
	if (err)
		goto remove;

	/*
	 * The number of functions on the card is encoded inside
	 * the ocr.
	 */
	funcs = (card->ocr & 0x70000000) >> 28;
	card->sdio_funcs = 0;

	/*
	 * Initialize (but don't add) all present functions.
	 */
	for (i = 0; i < funcs; i++, card->sdio_funcs++) 
	{
		err = sdio_init_func(pCard, i + 1);
		if (err)
			goto remove;
	}
	card->type = SDIO;
	
	return 0;
	
remove:	
	return err;
}
Example #2
0
zx_status_t sdmmc_probe_sdio(sdmmc_device_t* dev) {
    zx_status_t st = sdmmc_sdio_reset(dev);

    if ((st = sdmmc_go_idle(dev)) != ZX_OK) {
      zxlogf(ERROR, "sdmmc: SDMMC_GO_IDLE_STATE failed, retcode = %d\n", st);
      return st;
    }

    uint32_t ocr;
    if ((st = sdio_send_op_cond(dev, 0, &ocr)) != ZX_OK) {
        zxlogf(TRACE, "sdmmc_probe_sdio: SDIO_SEND_OP_COND failed, retcode = %d\n", st);
        return st;
    }
    //Select voltage 3.3 V. Also request for 1.8V. Section 3.2 SDIO spec
    if (ocr & SDIO_SEND_OP_COND_IO_OCR_33V) {
        uint32_t new_ocr = SDIO_SEND_OP_COND_IO_OCR_33V | SDIO_SEND_OP_COND_CMD_S18R;
        if ((st = sdio_send_op_cond(dev, new_ocr, &ocr)) != ZX_OK) {
            zxlogf(ERROR, "sdmmc_probe_sdio: SDIO_SEND_OP_COND failed, retcode = %d\n", st);
            return st;
        }
    }
    if (ocr & SDIO_SEND_OP_COND_RESP_MEM_PRESENT) {
        //Combo cards not supported
        zxlogf(ERROR, "sdmmc_probe_sdio: Combo card not supported\n");
        return ZX_ERR_NOT_SUPPORTED;
    }
    dev->type = SDMMC_TYPE_SDIO;
    dev->signal_voltage = SDMMC_VOLTAGE_V180;
    dev->sdio_dev.hw_info.num_funcs = get_bits(ocr, SDIO_SEND_OP_COND_RESP_NUM_FUNC_MASK,
                                               SDIO_SEND_OP_COND_RESP_NUM_FUNC_LOC);
    uint16_t addr = 0;
    if ((st = sd_send_relative_addr(dev, &addr)) != ZX_OK) {
        zxlogf(ERROR, "sdmcc_probe_sdio: SD_SEND_RELATIVE_ADDR failed, retcode = %d\n", st);
        return st;
    }
    dev->rca = addr;
    if ((st = mmc_select_card(dev)) != ZX_OK) {
        zxlogf(ERROR, "sdmmc_probe_sdio: MMC_SELECT_CARD failed, retcode = %d\n", st);
        return st;
    }

    if ((st = sdio_process_cccr(dev)) != ZX_OK) {
        zxlogf(ERROR, "sdmmc_probe_sdio: Read CCCR failed, retcode = %d\n", st);
        return st;
    }

    //Read CIS to get max block size
    if ((st = sdio_process_cis(dev, 0)) != ZX_OK) {
        zxlogf(ERROR, "sdmmc_probe_sdio: Read CIS failed, retcode = %d\n", st);
        return st;
    }

    if (ocr & SDIO_SEND_OP_COND_RESP_S18A) {
        if ((st = sd_switch_uhs_voltage(dev, ocr)) != ZX_OK) {
            zxlogf(INFO, "Failed to switch voltage to 1.8V\n");
            return st;
        }
    }

    // BCM43458 includes function 0 in its OCR register. This violates the SDIO specification and
    // the assumptions made here. Check the manufacturer ID to account for this quirk.
    if (dev->sdio_dev.funcs[0].hw_info.manufacturer_id != bcm_manufacturer_id) {
        dev->sdio_dev.hw_info.num_funcs++;
    }

    //TODO(ravoorir):Re-enable ultra high speed when wifi stack is more stable.
    /* if (sdio_is_uhs_supported(dev->sdio_dev.hw_info.caps)) {
        if ((st = sdio_switch_bus_width(dev, SDIO_BW_4BIT)) != ZX_OK) {
            zxlogf(ERROR, "sdmmc_probe_sdio: Swtiching to 4-bit bus width failed, retcode = %d\n",
                   st);
            goto high_speed;
        }
        if ((st = sdio_switch_uhs(dev)) != ZX_OK) {
            zxlogf(ERROR, "sdmmc_probe_sdio: Switching to high speed failed, retcode = %d\n", st);
            goto high_speed;
        }
        uint32_t hw_caps = dev->sdio_dev.hw_info.caps;

        if ((hw_caps & SDIO_CARD_UHS_SDR104) || (hw_caps & SDIO_CARD_UHS_SDR50)) {
            st = sdmmc_perform_tuning(&dev->host, SD_SEND_TUNING_BLOCK);
            if (st != ZX_OK) {
                zxlogf(ERROR, "mmc: tuning failed %d\n", st);
                goto high_speed;
            }
        }
        goto complete;
    }

high_speed: */
    if (dev->sdio_dev.hw_info.caps & SDIO_CARD_HIGH_SPEED) {
        if ((st = sdio_switch_hs(dev)) != ZX_OK) {
            zxlogf(ERROR, "sdmmc_probe_sdio: Switching to high speed failed, retcode = %d\n", st);
            goto default_speed;
        }

        if ((st = sdio_switch_bus_width(dev, SDIO_BW_4BIT)) != ZX_OK) {
            zxlogf(ERROR, "sdmmc_probe_sdio: Swtiching to 4-bit bus width failed, retcode = %d\n",
                   st);
            goto default_speed;
        }
        goto complete;
    }

default_speed:
    if ((st = sdio_switch_freq(dev, SDIO_DEFAULT_FREQ)) != ZX_OK) {
        zxlogf(ERROR, "sdmmc_probe_sdio: Switch freq retcode = %d\n", st);
        return st;
    }

complete:
    sdio_modify_block_size(dev, 0, 0, true);
    // 0 is the common function. Already initialized
    for (size_t i = 1; i < dev->sdio_dev.hw_info.num_funcs; i++) {
        st = sdio_init_func(dev, i);
    }

    zxlogf(INFO, "sdmmc_probe_sdio: sdio device initialized successfully\n");
    zxlogf(INFO, "          Manufacturer: 0x%x\n", dev->sdio_dev.funcs[0].hw_info.manufacturer_id);
    zxlogf(INFO, "          Product: 0x%x\n", dev->sdio_dev.funcs[0].hw_info.product_id);
    zxlogf(INFO, "          cccr vsn: 0x%x\n", dev->sdio_dev.hw_info.cccr_vsn);
    zxlogf(INFO, "          SDIO vsn: 0x%x\n", dev->sdio_dev.hw_info.sdio_vsn);
    zxlogf(INFO, "          num funcs: %d\n", dev->sdio_dev.hw_info.num_funcs);
    return ZX_OK;
}