/*
* Shared part of driver for MMC/SDHC controller on Cavium OCTEON and
* ThunderX SOCs.
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 2012-2017 Cavium Inc.
* Authors:
* David Daney <david.daney@cavium.com>
* Peter Swain <pswain@cavium.com>
* Steven J. Hill <steven.hill@cavium.com>
* Jan Glauber <jglauber@cavium.com>
*/
#include <linux/bitfield.h>
#include <linux/delay.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/slot-gpio.h>
#include <linux/module.h>
#include <linux/regulator/consumer.h>
#include <linux/scatterlist.h>
#include <linux/time.h>
#include "cavium.h"
const char *cvm_mmc_irq_names[] = {
"MMC Buffer",
"MMC Command",
"MMC DMA",
"MMC Command Error",
"MMC DMA Error",
"MMC Switch",
"MMC Switch Error",
"MMC DMA int Fifo",
"MMC DMA int",
};
/*
* The Cavium MMC host hardware assumes that all commands have fixed
* command and response types. These are correct if MMC devices are
* being used. However, non-MMC devices like SD use command and
* response types that are unexpected by the host hardware.
*
* The command and response types can be overridden by supplying an
* XOR value that is applied to the type. We calculate the XOR value
* from the values in this table and the flags passed from the MMC
* core.
*/
static struct cvm_mmc_cr_type cvm_mmc_cr_types[] = {
{0, 0}, /* CMD0 */
{0, 3}, /* CMD1 */
{0, 2}, /* CMD2 */
{0, 1}, /* CMD3 */
{0, 0}, /* CMD4 */
{0, 1}, /* CMD5 */
{0, 1}, /* CMD6 */
{0, 1}, /* CMD7 */
{1, 1}, /* CMD8 */
{0, 2}, /* CMD9 */
{0, 2}, /* CMD10 */
{1, 1}, /* CMD11 */
{0, 1}, /* CMD12 */
{0, 1}, /* CMD13 */
{1, 1}, /* CMD14 */
{0, 0}, /* CMD15 */
{0, 1}, /* CMD16 */
{1, 1}, /* CMD17 */
{1, 1}, /* CMD18 */
{3, 1}, /* CMD19 */
{2, 1}, /* CMD20 */
{0, 0}, /* CMD21 */
{0, 0}, /* CMD22 */
{0, 1}, /* CMD23 */
{2, 1}, /* CMD24 */
{2, 1}, /* CMD25 */
{2, 1}, /* CMD26 */
{2, 1}, /* CMD27 */
{0, 1}, /* CMD28 */
{0, 1}, /* CMD29 */
{1, 1}, /* CMD30 */
{1, 1}, /* CMD31 */
{0, 0}, /* CMD32 */
{0, 0}, /* CMD33 */
{0, 0}, /* CMD34 */
{0, 1}, /* CMD35 */
{0, 1}, /* CMD36 */
{0, 0}, /* CMD37 */
{0, 1}, /* CMD38 */
{0, 4}, /* CMD39 */
{0, 5}, /* CMD40 */
{0, 0}, /* CMD41 */
{2, 1}, /* CMD42 */
{0, 0}, /* CMD43 */
{0, 0}, /* CMD44 */
{0, 0}, /* CMD45 */
{0, 0}, /* CMD46 */
{0, 0}, /* CMD47 */
{0, 0}, /* CMD48 */
{0, 0}, /* CMD49 */
{0, 0}, /* CMD50 */
{0, 0}, /* CMD51 */
{0, 0}, /* CMD52 */
{0, 0}, /* CMD53 */
{0, 0}, /* CMD54 */
{0, 1}, /* CMD55 */
{0xff, 0xff}, /* CMD56 */
{0, 0}, /* CMD57 */
{0, 0}, /* CMD58 */
{0, 0}, /* CMD59 */
{0, 0}, /* CMD60 */
{0, 0}, /* CMD61 */
{0, 0}, /* CMD62 */
{0, 0} /* CMD63 */
};
static struct cvm_mmc_cr_mods cvm_mmc_get_cr_mods(struct mmc_command *cmd)
{
struct cvm_mmc_cr_type *cr;
u8 hardware_ctype, hardware_rtype;
u8 desired_ctype = 0, desired_rtype = 0;
struct cvm_mmc_cr_mods r;
cr = cvm_mmc_cr_types + (cmd->opcode & 0x3f);
hardware_ctype = cr->ctype;
hardware_rtype = cr->rtype;
if (cmd->opcode == MMC_GEN_CMD)
hardware_ctype = (cmd->arg & 1) ? 1 : 2;
switch (mmc_cmd_type(cmd)) {
case MMC_CMD_ADTC:
desired_ctype = (cmd->data->flags & MMC_DATA_WRITE) ? 2 : 1;
break;
case MMC_CMD_AC:
case MMC_CMD_BC:
case MMC_CMD_BCR:
desired_ctype = 0;
break;
}
switch (mmc_resp_type(cmd)) {
case MMC_RSP_NONE:
desired_rtype = 0;
break;
case MMC_RSP_R1:/* MMC_RSP_R5, MMC_RSP_R6, MMC_RSP_R7 */
case MMC_RSP_R1B:
desired_rtype = 1;
break;
case MMC_RSP_R2:
desired_rtype = 2;
break;
case MMC_RSP_R3: /* MMC_RSP_R4 */
desired_rtype = 3;
break;
}
r.ctype_xor =