1da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman/* 270f10482c668301c483acded13bf68780ad352b9Pierre Ossman * linux/drivers/mmc/core/sd_ops.h 3da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * 4da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * Copyright 2006-2007 Pierre Ossman 5da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * 6da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * This program is free software; you can redistribute it and/or modify 7da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * it under the terms of the GNU General Public License as published by 8da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * the Free Software Foundation; either version 2 of the License, or (at 9da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * your option) any later version. 10da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman */ 11da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 124f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda#include <linux/slab.h> 13da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/types.h> 143ef77af154b03776c6c662c68c6332719e9eecacPaul Gortmaker#include <linux/export.h> 15da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/scatterlist.h> 16da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 17da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/host.h> 18da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/card.h> 19da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/mmc.h> 20da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include <linux/mmc/sd.h> 21da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 22da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include "core.h" 23da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman#include "sd_ops.h" 24da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 25cb87ea28ed9e75a41eb456bfcb547b4e6f10e750John Calixtoint mmc_app_cmd(struct mmc_host *host, struct mmc_card *card) 26393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk{ 27393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk int err; 281278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 29393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 30393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk BUG_ON(!host); 31393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk BUG_ON(card && (card->host != host)); 32393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 33393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk cmd.opcode = MMC_APP_CMD; 34393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 35393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk if (card) { 36393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk cmd.arg = card->rca << 16; 37af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_AC; 38393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk } else { 39393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk cmd.arg = 0; 40af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_BCR; 41393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk } 42393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 43393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk err = mmc_wait_for_cmd(host, &cmd, 0); 4417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (err) 45393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk return err; 46393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 47393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk /* Check that card supported application commands */ 48af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (!mmc_host_is_spi(host) && !(cmd.resp[0] & R1_APP_CMD)) 4917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return -EOPNOTSUPP; 50393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 5117b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return 0; 52393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk} 53cb87ea28ed9e75a41eb456bfcb547b4e6f10e750John CalixtoEXPORT_SYMBOL_GPL(mmc_app_cmd); 54393618510d5349e07d71dc28fb6fc49baf0d96a0Adrian Bunk 55da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman/** 56da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * mmc_wait_for_app_cmd - start an application command and wait for 57da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman completion 58da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * @host: MMC host to start command 5967a61c484735de9bf4f099830ecb4ef2eca95c38Pierre Ossman * @card: Card to send MMC_APP_CMD to 60da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * @cmd: MMC command to start 61da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * @retries: maximum number of retries 62da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * 63da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * Sends a MMC_APP_CMD, checks the card response, sends the command 64da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * in the parameter and waits for it to complete. Return any error 65da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * that occurred while the command was executing. Do not attempt to 66da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * parse the response. 67da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman */ 68da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanint mmc_wait_for_app_cmd(struct mmc_host *host, struct mmc_card *card, 69da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman struct mmc_command *cmd, int retries) 70da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman{ 71ad5fd97288655b5628052c1fa906419417c86100Venkatraman S struct mmc_request mrq = {NULL}; 72da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 73da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman int i, err; 74da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 75da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!cmd); 76da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(retries < 0); 77da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 7817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman err = -EIO; 79da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 80da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman /* 81da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * We have to resend MMC_APP_CMD for each attempt so 82da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * we cannot use the retries field in mmc_command. 83da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman */ 84da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman for (i = 0;i <= retries;i++) { 85da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman err = mmc_app_cmd(host, card); 86af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (err) { 87af51715079e7fb6b290e1881d63d815dc4de5011David Brownell /* no point in retrying; no APP commands allowed */ 88af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (mmc_host_is_spi(host)) { 89af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) 90af51715079e7fb6b290e1881d63d815dc4de5011David Brownell break; 91af51715079e7fb6b290e1881d63d815dc4de5011David Brownell } 92da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman continue; 93af51715079e7fb6b290e1881d63d815dc4de5011David Brownell } 94da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 95da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman memset(&mrq, 0, sizeof(struct mmc_request)); 96da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 97da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman memset(cmd->resp, 0, sizeof(cmd->resp)); 98da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd->retries = 0; 99da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 100da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mrq.cmd = cmd; 101da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd->data = NULL; 102da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 103da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mmc_wait_for_req(host, &mrq); 104da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 105da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman err = cmd->error; 10617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (!cmd->error) 107da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman break; 108af51715079e7fb6b290e1881d63d815dc4de5011David Brownell 109af51715079e7fb6b290e1881d63d815dc4de5011David Brownell /* no point in retrying illegal APP commands */ 110af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (mmc_host_is_spi(host)) { 111af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (cmd->resp[0] & R1_SPI_ILLEGAL_COMMAND) 112af51715079e7fb6b290e1881d63d815dc4de5011David Brownell break; 113af51715079e7fb6b290e1881d63d815dc4de5011David Brownell } 114da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman } 115da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 116da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return err; 117da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman} 118da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 119da7fbe58d2d347e95af699ddf04d885be6362bbePierre OssmanEXPORT_SYMBOL(mmc_wait_for_app_cmd); 120da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 121da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanint mmc_app_set_bus_width(struct mmc_card *card, int width) 122da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman{ 123da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman int err; 1241278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 125da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 126da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!card); 127da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!card->host); 128da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 129da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.opcode = SD_APP_SET_BUS_WIDTH; 130da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.flags = MMC_RSP_R1 | MMC_CMD_AC; 131da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 132da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman switch (width) { 133da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman case MMC_BUS_WIDTH_1: 134da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg = SD_BUS_WIDTH_1; 135da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman break; 136da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman case MMC_BUS_WIDTH_4: 137da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg = SD_BUS_WIDTH_4; 138da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman break; 139da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman default: 14017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return -EINVAL; 141da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman } 142da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 143da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman err = mmc_wait_for_app_cmd(card->host, card, &cmd, MMC_CMD_RETRIES); 14417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (err) 145da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return err; 146da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 14717b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return 0; 148da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman} 149da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 150da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanint mmc_send_app_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr) 151da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman{ 1521278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 153da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman int i, err = 0; 154da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 155da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!host); 156da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 157da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.opcode = SD_APP_OP_COND; 158af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (mmc_host_is_spi(host)) 159af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.arg = ocr & (1 << 30); /* SPI only defines one bit */ 160af51715079e7fb6b290e1881d63d815dc4de5011David Brownell else 161af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.arg = ocr; 162af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R3 | MMC_CMD_BCR; 163da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 164da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman for (i = 100; i; i--) { 165da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman err = mmc_wait_for_app_cmd(host, NULL, &cmd, MMC_CMD_RETRIES); 16617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (err) 167da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman break; 168da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 169af51715079e7fb6b290e1881d63d815dc4de5011David Brownell /* if we're just probing, do a single pass */ 170af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (ocr == 0) 171da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman break; 172da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 173af51715079e7fb6b290e1881d63d815dc4de5011David Brownell /* otherwise wait until reset completes */ 174af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (mmc_host_is_spi(host)) { 175af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (!(cmd.resp[0] & R1_SPI_IDLE)) 176af51715079e7fb6b290e1881d63d815dc4de5011David Brownell break; 177af51715079e7fb6b290e1881d63d815dc4de5011David Brownell } else { 178af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (cmd.resp[0] & MMC_CARD_BUSY) 179af51715079e7fb6b290e1881d63d815dc4de5011David Brownell break; 180af51715079e7fb6b290e1881d63d815dc4de5011David Brownell } 181af51715079e7fb6b290e1881d63d815dc4de5011David Brownell 18217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman err = -ETIMEDOUT; 183da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 184da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mmc_delay(10); 185da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman } 186da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 1875e863662add1fc00bf088dc381b787edc0a0de5bJohan Rudholm if (!i) 1885e863662add1fc00bf088dc381b787edc0a0de5bJohan Rudholm pr_err("%s: card never left busy state\n", mmc_hostname(host)); 1895e863662add1fc00bf088dc381b787edc0a0de5bJohan Rudholm 190af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (rocr && !mmc_host_is_spi(host)) 191da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman *rocr = cmd.resp[0]; 192da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 193da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return err; 194da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman} 195da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 196da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanint mmc_send_if_cond(struct mmc_host *host, u32 ocr) 197da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman{ 1981278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 199da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman int err; 200da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman static const u8 test_pattern = 0xAA; 201af51715079e7fb6b290e1881d63d815dc4de5011David Brownell u8 result_pattern; 202da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 203da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman /* 204da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * To support SD 2.0 cards, we must always invoke SD_SEND_IF_COND 205da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * before SD_APP_OP_COND. This command will harmlessly fail for 206da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman * SD 1.0 cards. 207da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman */ 208da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.opcode = SD_SEND_IF_COND; 209da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg = ((ocr & 0xFF8000) != 0) << 8 | test_pattern; 210af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.flags = MMC_RSP_SPI_R7 | MMC_RSP_R7 | MMC_CMD_BCR; 211da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 212da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman err = mmc_wait_for_cmd(host, &cmd, 0); 21317b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (err) 214da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return err; 215da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 216af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (mmc_host_is_spi(host)) 217af51715079e7fb6b290e1881d63d815dc4de5011David Brownell result_pattern = cmd.resp[1] & 0xFF; 218af51715079e7fb6b290e1881d63d815dc4de5011David Brownell else 219af51715079e7fb6b290e1881d63d815dc4de5011David Brownell result_pattern = cmd.resp[0] & 0xFF; 220af51715079e7fb6b290e1881d63d815dc4de5011David Brownell 221af51715079e7fb6b290e1881d63d815dc4de5011David Brownell if (result_pattern != test_pattern) 22217b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return -EIO; 223da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 22417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return 0; 225da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman} 226da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 227da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanint mmc_send_relative_addr(struct mmc_host *host, unsigned int *rca) 228da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman{ 229da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman int err; 2301278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 231da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 232da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!host); 233da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!rca); 234da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 235da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.opcode = SD_SEND_RELATIVE_ADDR; 236da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg = 0; 237da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.flags = MMC_RSP_R6 | MMC_CMD_BCR; 238da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 239da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES); 24017b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (err) 241da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return err; 242da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 243da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman *rca = cmd.resp[0] >> 16; 244da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 24517b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return 0; 246da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman} 247da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 248da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanint mmc_app_send_scr(struct mmc_card *card, u32 *scr) 249da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman{ 250da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman int err; 251ad5fd97288655b5628052c1fa906419417c86100Venkatraman S struct mmc_request mrq = {NULL}; 2521278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 253a61ad2b49bfce94dfddce828cd9222e4b9e7825bChris Ball struct mmc_data data = {0}; 254da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman struct scatterlist sg; 2554f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda void *data_buf; 256da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 257da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!card); 258da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!card->host); 259da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!scr); 260da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 261af51715079e7fb6b290e1881d63d815dc4de5011David Brownell /* NOTE: caller guarantees scr is heap-allocated */ 262af51715079e7fb6b290e1881d63d815dc4de5011David Brownell 263da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman err = mmc_app_cmd(card->host, card); 26417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (err) 265da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return err; 266da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 2674f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda /* dma onto stack is unsafe/nonportable, but callers to this 2684f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda * routine normally provide temporary on-stack buffers ... 2694f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda */ 2704f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda data_buf = kmalloc(sizeof(card->raw_scr), GFP_KERNEL); 2714f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda if (data_buf == NULL) 2724f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda return -ENOMEM; 2734f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda 274da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mrq.cmd = &cmd; 275da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mrq.data = &data; 276da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 277da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.opcode = SD_APP_SEND_SCR; 278da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg = 0; 279af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; 280da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 281da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.blksz = 8; 282da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.blocks = 1; 283da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.flags = MMC_DATA_READ; 284da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.sg = &sg; 285da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.sg_len = 1; 286da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 2874f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda sg_init_one(&sg, data_buf, 8); 288da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 289b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman mmc_set_data_timeout(&data, card); 290da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 291da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mmc_wait_for_req(card->host, &mrq); 292da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 2934f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda memcpy(scr, data_buf, sizeof(card->raw_scr)); 2944f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda kfree(data_buf); 2954f665cb614b8a258b507cc47753dd3f7dd45aac6Yoshihiro Shimoda 29617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (cmd.error) 297da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return cmd.error; 29817b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (data.error) 299da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return data.error; 300da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 3011fa8dd146f6bf57902602522c212040f8fa6fcd3Pierre Ossman scr[0] = be32_to_cpu(scr[0]); 3021fa8dd146f6bf57902602522c212040f8fa6fcd3Pierre Ossman scr[1] = be32_to_cpu(scr[1]); 303da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 30417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return 0; 305da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman} 306da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 307da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossmanint mmc_sd_switch(struct mmc_card *card, int mode, int group, 308da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman u8 value, u8 *resp) 309da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman{ 310ad5fd97288655b5628052c1fa906419417c86100Venkatraman S struct mmc_request mrq = {NULL}; 3111278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 312a61ad2b49bfce94dfddce828cd9222e4b9e7825bChris Ball struct mmc_data data = {0}; 313da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman struct scatterlist sg; 314da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 315da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!card); 316da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman BUG_ON(!card->host); 317da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 318af51715079e7fb6b290e1881d63d815dc4de5011David Brownell /* NOTE: caller guarantees resp is heap-allocated */ 319af51715079e7fb6b290e1881d63d815dc4de5011David Brownell 320da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mode = !!mode; 321da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman value &= 0xF; 322da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 323da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mrq.cmd = &cmd; 324da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mrq.data = &data; 325da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 326da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.opcode = SD_SWITCH; 327da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg = mode << 31 | 0x00FFFFFF; 328da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg &= ~(0xF << (group * 4)); 329da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman cmd.arg |= value << (group * 4); 330af51715079e7fb6b290e1881d63d815dc4de5011David Brownell cmd.flags = MMC_RSP_SPI_R1 | MMC_RSP_R1 | MMC_CMD_ADTC; 331da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 332da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.blksz = 64; 333da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.blocks = 1; 334da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.flags = MMC_DATA_READ; 335da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.sg = &sg; 336da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman data.sg_len = 1; 337da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 338da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman sg_init_one(&sg, resp, 64); 339da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 340b146d26a61e0feab2f12a98ae83fd352830899c0Pierre Ossman mmc_set_data_timeout(&data, card); 341da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 342da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman mmc_wait_for_req(card->host, &mrq); 343da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 34417b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (cmd.error) 345da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return cmd.error; 34617b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman if (data.error) 347da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman return data.error; 348da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 34917b0429dde9ab60f9cee8e07ab28c7dc6cfe6efdPierre Ossman return 0; 350da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman} 351da7fbe58d2d347e95af699ddf04d885be6362bbePierre Ossman 352dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunterint mmc_app_sd_status(struct mmc_card *card, void *ssr) 353dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter{ 354dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter int err; 355ad5fd97288655b5628052c1fa906419417c86100Venkatraman S struct mmc_request mrq = {NULL}; 3561278dba167f01bb3c6626d16450d31129d041087Chris Ball struct mmc_command cmd = {0}; 357a61ad2b49bfce94dfddce828cd9222e4b9e7825bChris Ball struct mmc_data data = {0}; 358dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter struct scatterlist sg; 359dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 360dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter BUG_ON(!card); 361dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter BUG_ON(!card->host); 362dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter BUG_ON(!ssr); 363dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 364dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter /* NOTE: caller guarantees ssr is heap-allocated */ 365dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 366dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter err = mmc_app_cmd(card->host, card); 367dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter if (err) 368dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter return err; 369dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 370dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter mrq.cmd = &cmd; 371dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter mrq.data = &data; 372dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 373dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter cmd.opcode = SD_APP_SD_STATUS; 374dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter cmd.arg = 0; 375dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_ADTC; 376dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 377dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter data.blksz = 64; 378dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter data.blocks = 1; 379dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter data.flags = MMC_DATA_READ; 380dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter data.sg = &sg; 381dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter data.sg_len = 1; 382dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 383dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter sg_init_one(&sg, ssr, 64); 384dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 385dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter mmc_set_data_timeout(&data, card); 386dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 387dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter mmc_wait_for_req(card->host, &mrq); 388dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 389dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter if (cmd.error) 390dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter return cmd.error; 391dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter if (data.error) 392dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter return data.error; 393dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter 394dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter return 0; 395dfe86cba7676d58db8de7e623f5e72f1b0d3ca35Adrian Hunter} 396