| /* | 
 |  * 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 = desired_ctype ^ hardware_ctype; | 
 | 	r.rtype_xor = desired_rtype ^ hardware_rtype; | 
 | 	return r; | 
 | } | 
 |  | 
 | static void check_switch_errors(struct cvm_mmc_host *host) | 
 | { | 
 | 	u64 emm_switch; | 
 |  | 
 | 	emm_switch = readq(host->base + MIO_EMM_SWITCH(host)); | 
 | 	if (emm_switch & MIO_EMM_SWITCH_ERR0) | 
 | 		dev_err(host->dev, "Switch power class error\n"); | 
 | 	if (emm_switch & MIO_EMM_SWITCH_ERR1) | 
 | 		dev_err(host->dev, "Switch hs timing error\n"); | 
 | 	if (emm_switch & MIO_EMM_SWITCH_ERR2) | 
 | 		dev_err(host->dev, "Switch bus width error\n"); | 
 | } | 
 |  | 
 | static void clear_bus_id(u64 *reg) | 
 | { | 
 | 	u64 bus_id_mask = GENMASK_ULL(61, 60); | 
 |  | 
 | 	*reg &= ~bus_id_mask; | 
 | } | 
 |  | 
 | static void set_bus_id(u64 *reg, int bus_id) | 
 | { | 
 | 	clear_bus_id(reg); | 
 | 	*reg |= FIELD_PREP(GENMASK(61, 60), bus_id); | 
 | } | 
 |  | 
 | static int get_bus_id(u64 reg) | 
 | { | 
 | 	return FIELD_GET(GENMASK_ULL(61, 60), reg); | 
 | } | 
 |  | 
 | /* | 
 |  * We never set the switch_exe bit since that would interfere | 
 |  * with the commands send by the MMC core. | 
 |  */ | 
 | static void do_switch(struct cvm_mmc_host *host, u64 emm_switch) | 
 | { | 
 | 	int retries = 100; | 
 | 	u64 rsp_sts; | 
 | 	int bus_id; | 
 |  | 
 | 	/* | 
 | 	 * Modes setting only taken from slot 0. Work around that hardware | 
 | 	 * issue by first switching to slot 0. | 
 | 	 */ | 
 | 	bus_id = get_bus_id(emm_switch); | 
 | 	clear_bus_id(&emm_switch); | 
 | 	writeq(emm_switch, host->base + MIO_EMM_SWITCH(host)); | 
 |  | 
 | 	set_bus_id(&emm_switch, bus_id); | 
 | 	writeq(emm_switch, host->base + MIO_EMM_SWITCH(host)); | 
 |  | 
 | 	/* wait for the switch to finish */ | 
 | 	do { | 
 | 		rsp_sts = readq(host->base + MIO_EMM_RSP_STS(host)); | 
 | 		if (!(rsp_sts & MIO_EMM_RSP_STS_SWITCH_VAL)) | 
 | 			break; | 
 | 		udelay(10); | 
 | 	} while (--retries); | 
 |  | 
 | 	check_switch_errors(host); | 
 | } | 
 |  | 
 | static bool switch_val_changed(struct cvm_mmc_slot *slot, u64 new_val) | 
 | { | 
 | 	/* Match BUS_ID, HS_TIMING, BUS_WIDTH, POWER_CLASS, CLK_HI, CLK_LO */ | 
 | 	u64 match = 0x3001070fffffffffull; | 
 |  | 
 | 	return (slot->cached_switch & match) != (new_val & match); | 
 | } | 
 |  | 
 | static void set_wdog(struct cvm_mmc_slot *slot, unsigned int ns) | 
 | { | 
 | 	u64 timeout; | 
 |  | 
 | 	if (!slot->clock) | 
 | 		return; | 
 |  | 
 | 	if (ns) | 
 | 		timeout = (slot->clock * ns) / NSEC_PER_SEC; | 
 | 	else | 
 | 		timeout = (slot->clock * 850ull) / 1000ull; | 
 | 	writeq(timeout, slot->host->base + MIO_EMM_WDOG(slot->host)); | 
 | } | 
 |  | 
 | static void cvm_mmc_reset_bus(struct cvm_mmc_slot *slot) | 
 | { | 
 | 	struct cvm_mmc_host *host = slot->host; | 
 | 	u64 emm_switch, wdog; | 
 |  | 
 | 	emm_switch = readq(slot->host->base + MIO_EMM_SWITCH(host)); | 
 | 	emm_switch &= ~(MIO_EMM_SWITCH_EXE | MIO_EMM_SWITCH_ERR0 | | 
 | 			MIO_EMM_SWITCH_ERR1 | MIO_EMM_SWITCH_ERR2); | 
 | 	set_bus_id(&emm_switch, slot->bus_id); | 
 |  | 
 | 	wdog = readq(slot->host->base + MIO_EMM_WDOG(host)); | 
 | 	do_switch(slot->host, emm_switch); | 
 |  | 
 | 	slot->cached_switch = emm_switch; | 
 |  | 
 | 	msleep(20); | 
 |  | 
 | 	writeq(wdog, slot->host->base + MIO_EMM_WDOG(host)); | 
 | } | 
 |  | 
 | /* Switch to another slot if needed */ | 
 | static void cvm_mmc_switch_to(struct cvm_mmc_slot *slot) | 
 | { | 
 | 	struct cvm_mmc_host *host = slot->host; | 
 | 	struct cvm_mmc_slot *old_slot; | 
 | 	u64 emm_sample, emm_switch; | 
 |  | 
 | 	if (slot->bus_id == host->last_slot) | 
 | 		return; | 
 |  | 
 | 	if (host->last_slot >= 0 && host->slot[host->last_slot]) { | 
 | 		old_slot = host->slot[host->last_slot]; | 
 | 		old_slot->cached_switch = readq(host->base + MIO_EMM_SWITCH(host)); | 
 | 		old_slot->cached_rca = readq(host->base + MIO_EMM_RCA(host)); | 
 | 	} | 
 |  | 
 | 	writeq(slot->cached_rca, host->base + MIO_EMM_RCA(host)); | 
 | 	emm_switch = slot->cached_switch; | 
 | 	set_bus_id(&emm_switch, slot->bus_id); | 
 | 	do_switch(host, emm_switch); | 
 |  | 
 | 	emm_sample = FIELD_PREP(MIO_EMM_SAMPLE_CMD_CNT, slot->cmd_cnt) | | 
 | 		     FIELD_PREP(MIO_EMM_SAMPLE_DAT_CNT, slot->dat_cnt); | 
 | 	writeq(emm_sample, host->base + MIO_EMM_SAMPLE(host)); | 
 |  | 
 | 	host->last_slot = slot->bus_id; | 
 | } | 
 |  | 
 | static void do_read(struct cvm_mmc_host *host, struct mmc_request *req, | 
 | 		    u64 dbuf) | 
 | { | 
 | 	struct sg_mapping_iter *smi = &host->smi; | 
 | 	int data_len = req->data->blocks * req->data->blksz; | 
 | 	int bytes_xfered, shift = -1; | 
 | 	u64 dat = 0; | 
 |  | 
 | 	/* Auto inc from offset zero */ | 
 | 	writeq((0x10000 | (dbuf << 6)), host->base + MIO_EMM_BUF_IDX(host)); | 
 |  | 
 | 	for (bytes_xfered = 0; bytes_xfered < data_len;) { | 
 | 		if (smi->consumed >= smi->length) { | 
 | 			if (!sg_miter_next(smi)) | 
 | 				break; | 
 | 			smi->consumed = 0; | 
 | 		} | 
 |  | 
 | 		if (shift < 0) { | 
 | 			dat = readq(host->base + MIO_EMM_BUF_DAT(host)); | 
 | 			shift = 56; | 
 | 		} | 
 |  | 
 | 		while (smi->consumed < smi->length && shift >= 0) { | 
 | 			((u8 *)smi->addr)[smi->consumed] = (dat >> shift) & 0xff; | 
 | 			bytes_xfered++; | 
 | 			smi->consumed++; | 
 | 			shift -= 8; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	sg_miter_stop(smi); | 
 | 	req->data->bytes_xfered = bytes_xfered; | 
 | 	req->data->error = 0; | 
 | } | 
 |  | 
 | static void do_write(struct mmc_request *req) | 
 | { | 
 | 	req->data->bytes_xfered = req->data->blocks * req->data->blksz; | 
 | 	req->data->error = 0; | 
 | } | 
 |  | 
 | static void set_cmd_response(struct cvm_mmc_host *host, struct mmc_request *req, | 
 | 			     u64 rsp_sts) | 
 | { | 
 | 	u64 rsp_hi, rsp_lo; | 
 |  | 
 | 	if (!(rsp_sts & MIO_EMM_RSP_STS_RSP_VAL)) | 
 | 		return; | 
 |  | 
 | 	rsp_lo = readq(host->base + MIO_EMM_RSP_LO(host)); | 
 |  | 
 | 	switch (FIELD_GET(MIO_EMM_RSP_STS_RSP_TYPE, rsp_sts)) { | 
 | 	case 1: | 
 | 	case 3: | 
 | 		req->cmd->resp[0] = (rsp_lo >> 8) & 0xffffffff; | 
 | 		req->cmd->resp[1] = 0; | 
 | 		req->cmd->resp[2] = 0; | 
 | 		req->cmd->resp[3] = 0; | 
 | 		break; | 
 | 	case 2: | 
 | 		req->cmd->resp[3] = rsp_lo & 0xffffffff; | 
 | 		req->cmd->resp[2] = (rsp_lo >> 32) & 0xffffffff; | 
 | 		rsp_hi = readq(host->base + MIO_EMM_RSP_HI(host)); | 
 | 		req->cmd->resp[1] = rsp_hi & 0xffffffff; | 
 | 		req->cmd->resp[0] = (rsp_hi >> 32) & 0xffffffff; | 
 | 		break; | 
 | 	} | 
 | } | 
 |  | 
 | static int get_dma_dir(struct mmc_data *data) | 
 | { | 
 | 	return (data->flags & MMC_DATA_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE; | 
 | } | 
 |  | 
 | static int finish_dma_single(struct cvm_mmc_host *host, struct mmc_data *data) | 
 | { | 
 | 	data->bytes_xfered = data->blocks * data->blksz; | 
 | 	data->error = 0; | 
 | 	dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data)); | 
 | 	return 1; | 
 | } | 
 |  | 
 | static int finish_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data) | 
 | { | 
 | 	u64 fifo_cfg; | 
 | 	int count; | 
 |  | 
 | 	/* Check if there are any pending requests left */ | 
 | 	fifo_cfg = readq(host->dma_base + MIO_EMM_DMA_FIFO_CFG(host)); | 
 | 	count = FIELD_GET(MIO_EMM_DMA_FIFO_CFG_COUNT, fifo_cfg); | 
 | 	if (count) | 
 | 		dev_err(host->dev, "%u requests still pending\n", count); | 
 |  | 
 | 	data->bytes_xfered = data->blocks * data->blksz; | 
 | 	data->error = 0; | 
 |  | 
 | 	/* Clear and disable FIFO */ | 
 | 	writeq(BIT_ULL(16), host->dma_base + MIO_EMM_DMA_FIFO_CFG(host)); | 
 | 	dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data)); | 
 | 	return 1; | 
 | } | 
 |  | 
 | static int finish_dma(struct cvm_mmc_host *host, struct mmc_data *data) | 
 | { | 
 | 	if (host->use_sg && data->sg_len > 1) | 
 | 		return finish_dma_sg(host, data); | 
 | 	else | 
 | 		return finish_dma_single(host, data); | 
 | } | 
 |  | 
 | static int check_status(u64 rsp_sts) | 
 | { | 
 | 	if (rsp_sts & MIO_EMM_RSP_STS_RSP_BAD_STS || | 
 | 	    rsp_sts & MIO_EMM_RSP_STS_RSP_CRC_ERR || | 
 | 	    rsp_sts & MIO_EMM_RSP_STS_BLK_CRC_ERR) | 
 | 		return -EILSEQ; | 
 | 	if (rsp_sts & MIO_EMM_RSP_STS_RSP_TIMEOUT || | 
 | 	    rsp_sts & MIO_EMM_RSP_STS_BLK_TIMEOUT) | 
 | 		return -ETIMEDOUT; | 
 | 	if (rsp_sts & MIO_EMM_RSP_STS_DBUF_ERR) | 
 | 		return -EIO; | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* Try to clean up failed DMA. */ | 
 | static void cleanup_dma(struct cvm_mmc_host *host, u64 rsp_sts) | 
 | { | 
 | 	u64 emm_dma; | 
 |  | 
 | 	emm_dma = readq(host->base + MIO_EMM_DMA(host)); | 
 | 	emm_dma |= FIELD_PREP(MIO_EMM_DMA_VAL, 1) | | 
 | 		   FIELD_PREP(MIO_EMM_DMA_DAT_NULL, 1); | 
 | 	set_bus_id(&emm_dma, get_bus_id(rsp_sts)); | 
 | 	writeq(emm_dma, host->base + MIO_EMM_DMA(host)); | 
 | } | 
 |  | 
 | irqreturn_t cvm_mmc_interrupt(int irq, void *dev_id) | 
 | { | 
 | 	struct cvm_mmc_host *host = dev_id; | 
 | 	struct mmc_request *req; | 
 | 	unsigned long flags = 0; | 
 | 	u64 emm_int, rsp_sts; | 
 | 	bool host_done; | 
 |  | 
 | 	if (host->need_irq_handler_lock) | 
 | 		spin_lock_irqsave(&host->irq_handler_lock, flags); | 
 | 	else | 
 | 		__acquire(&host->irq_handler_lock); | 
 |  | 
 | 	/* Clear interrupt bits (write 1 clears ). */ | 
 | 	emm_int = readq(host->base + MIO_EMM_INT(host)); | 
 | 	writeq(emm_int, host->base + MIO_EMM_INT(host)); | 
 |  | 
 | 	if (emm_int & MIO_EMM_INT_SWITCH_ERR) | 
 | 		check_switch_errors(host); | 
 |  | 
 | 	req = host->current_req; | 
 | 	if (!req) | 
 | 		goto out; | 
 |  | 
 | 	rsp_sts = readq(host->base + MIO_EMM_RSP_STS(host)); | 
 | 	/* | 
 | 	 * dma_val set means DMA is still in progress. Don't touch | 
 | 	 * the request and wait for the interrupt indicating that | 
 | 	 * the DMA is finished. | 
 | 	 */ | 
 | 	if ((rsp_sts & MIO_EMM_RSP_STS_DMA_VAL) && host->dma_active) | 
 | 		goto out; | 
 |  | 
 | 	if (!host->dma_active && req->data && | 
 | 	    (emm_int & MIO_EMM_INT_BUF_DONE)) { | 
 | 		unsigned int type = (rsp_sts >> 7) & 3; | 
 |  | 
 | 		if (type == 1) | 
 | 			do_read(host, req, rsp_sts & MIO_EMM_RSP_STS_DBUF); | 
 | 		else if (type == 2) | 
 | 			do_write(req); | 
 | 	} | 
 |  | 
 | 	host_done = emm_int & MIO_EMM_INT_CMD_DONE || | 
 | 		    emm_int & MIO_EMM_INT_DMA_DONE || | 
 | 		    emm_int & MIO_EMM_INT_CMD_ERR  || | 
 | 		    emm_int & MIO_EMM_INT_DMA_ERR; | 
 |  | 
 | 	if (!(host_done && req->done)) | 
 | 		goto no_req_done; | 
 |  | 
 | 	req->cmd->error = check_status(rsp_sts); | 
 |  | 
 | 	if (host->dma_active && req->data) | 
 | 		if (!finish_dma(host, req->data)) | 
 | 			goto no_req_done; | 
 |  | 
 | 	set_cmd_response(host, req, rsp_sts); | 
 | 	if ((emm_int & MIO_EMM_INT_DMA_ERR) && | 
 | 	    (rsp_sts & MIO_EMM_RSP_STS_DMA_PEND)) | 
 | 		cleanup_dma(host, rsp_sts); | 
 |  | 
 | 	host->current_req = NULL; | 
 | 	req->done(req); | 
 |  | 
 | no_req_done: | 
 | 	if (host->dmar_fixup_done) | 
 | 		host->dmar_fixup_done(host); | 
 | 	if (host_done) | 
 | 		host->release_bus(host); | 
 | out: | 
 | 	if (host->need_irq_handler_lock) | 
 | 		spin_unlock_irqrestore(&host->irq_handler_lock, flags); | 
 | 	else | 
 | 		__release(&host->irq_handler_lock); | 
 | 	return IRQ_RETVAL(emm_int != 0); | 
 | } | 
 |  | 
 | /* | 
 |  * Program DMA_CFG and if needed DMA_ADR. | 
 |  * Returns 0 on error, DMA address otherwise. | 
 |  */ | 
 | static u64 prepare_dma_single(struct cvm_mmc_host *host, struct mmc_data *data) | 
 | { | 
 | 	u64 dma_cfg, addr; | 
 | 	int count, rw; | 
 |  | 
 | 	count = dma_map_sg(host->dev, data->sg, data->sg_len, | 
 | 			   get_dma_dir(data)); | 
 | 	if (!count) | 
 | 		return 0; | 
 |  | 
 | 	rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; | 
 | 	dma_cfg = FIELD_PREP(MIO_EMM_DMA_CFG_EN, 1) | | 
 | 		  FIELD_PREP(MIO_EMM_DMA_CFG_RW, rw); | 
 | #ifdef __LITTLE_ENDIAN | 
 | 	dma_cfg |= FIELD_PREP(MIO_EMM_DMA_CFG_ENDIAN, 1); | 
 | #endif | 
 | 	dma_cfg |= FIELD_PREP(MIO_EMM_DMA_CFG_SIZE, | 
 | 			      (sg_dma_len(&data->sg[0]) / 8) - 1); | 
 |  | 
 | 	addr = sg_dma_address(&data->sg[0]); | 
 | 	if (!host->big_dma_addr) | 
 | 		dma_cfg |= FIELD_PREP(MIO_EMM_DMA_CFG_ADR, addr); | 
 | 	writeq(dma_cfg, host->dma_base + MIO_EMM_DMA_CFG(host)); | 
 |  | 
 | 	pr_debug("[%s] sg_dma_len: %u  total sg_elem: %d\n", | 
 | 		 (rw) ? "W" : "R", sg_dma_len(&data->sg[0]), count); | 
 |  | 
 | 	if (host->big_dma_addr) | 
 | 		writeq(addr, host->dma_base + MIO_EMM_DMA_ADR(host)); | 
 | 	return addr; | 
 | } | 
 |  | 
 | /* | 
 |  * Queue complete sg list into the FIFO. | 
 |  * Returns 0 on error, 1 otherwise. | 
 |  */ | 
 | static u64 prepare_dma_sg(struct cvm_mmc_host *host, struct mmc_data *data) | 
 | { | 
 | 	struct scatterlist *sg; | 
 | 	u64 fifo_cmd, addr; | 
 | 	int count, i, rw; | 
 |  | 
 | 	count = dma_map_sg(host->dev, data->sg, data->sg_len, | 
 | 			   get_dma_dir(data)); | 
 | 	if (!count) | 
 | 		return 0; | 
 | 	if (count > 16) | 
 | 		goto error; | 
 |  | 
 | 	/* Enable FIFO by removing CLR bit */ | 
 | 	writeq(0, host->dma_base + MIO_EMM_DMA_FIFO_CFG(host)); | 
 |  | 
 | 	for_each_sg(data->sg, sg, count, i) { | 
 | 		/* Program DMA address */ | 
 | 		addr = sg_dma_address(sg); | 
 | 		if (addr & 7) | 
 | 			goto error; | 
 | 		writeq(addr, host->dma_base + MIO_EMM_DMA_FIFO_ADR(host)); | 
 |  | 
 | 		/* | 
 | 		 * If we have scatter-gather support we also have an extra | 
 | 		 * register for the DMA addr, so no need to check | 
 | 		 * host->big_dma_addr here. | 
 | 		 */ | 
 | 		rw = (data->flags & MMC_DATA_WRITE) ? 1 : 0; | 
 | 		fifo_cmd = FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_RW, rw); | 
 |  | 
 | 		/* enable interrupts on the last element */ | 
 | 		fifo_cmd |= FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_INTDIS, | 
 | 				       (i + 1 == count) ? 0 : 1); | 
 |  | 
 | #ifdef __LITTLE_ENDIAN | 
 | 		fifo_cmd |= FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_ENDIAN, 1); | 
 | #endif | 
 | 		fifo_cmd |= FIELD_PREP(MIO_EMM_DMA_FIFO_CMD_SIZE, | 
 | 				       sg_dma_len(sg) / 8 - 1); | 
 | 		/* | 
 | 		 * The write copies the address and the command to the FIFO | 
 | 		 * and increments the FIFO's COUNT field. | 
 | 		 */ | 
 | 		writeq(fifo_cmd, host->dma_base + MIO_EMM_DMA_FIFO_CMD(host)); | 
 | 		pr_debug("[%s] sg_dma_len: %u  sg_elem: %d/%d\n", | 
 | 			 (rw) ? "W" : "R", sg_dma_len(sg), i, count); | 
 | 	} | 
 |  | 
 | 	/* | 
 | 	 * In difference to prepare_dma_single we don't return the | 
 | 	 * address here, as it would not make sense for scatter-gather. | 
 | 	 * The dma fixup is only required on models that don't support | 
 | 	 * scatter-gather, so that is not a problem. | 
 | 	 */ | 
 | 	return 1; | 
 |  | 
 | error: | 
 | 	WARN_ON_ONCE(1); | 
 | 	dma_unmap_sg(host->dev, data->sg, data->sg_len, get_dma_dir(data)); | 
 | 	/* Disable FIFO */ | 
 | 	writeq(BIT_ULL(16), host->dma_base + MIO_EMM_DMA_FIFO_CFG(host)); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static u64 prepare_dma(struct cvm_mmc_host *host, struct mmc_data *data) | 
 | { | 
 | 	if (host->use_sg && data->sg_len > 1) | 
 | 		return prepare_dma_sg(host, data); | 
 | 	else | 
 | 		return prepare_dma_single(host, data); | 
 | } | 
 |  | 
 | static u64 prepare_ext_dma(struct mmc_host *mmc, struct mmc_request *mrq) | 
 | { | 
 | 	struct cvm_mmc_slot *slot = mmc_priv(mmc); | 
 | 	u64 emm_dma; | 
 |  | 
 | 	emm_dma = FIELD_PREP(MIO_EMM_DMA_VAL, 1) | | 
 | 		  FIELD_PREP(MIO_EMM_DMA_SECTOR, | 
 | 			     mmc_card_is_blockaddr(mmc->card) ? 1 : 0) | | 
 | 		  FIELD_PREP(MIO_EMM_DMA_RW, | 
 | 			     (mrq->data->flags & MMC_DATA_WRITE) ? 1 : 0) | | 
 | 		  FIELD_PREP(MIO_EMM_DMA_BLOCK_CNT, mrq->data->blocks) | | 
 | 		  FIELD_PREP(MIO_EMM_DMA_CARD_ADDR, mrq->cmd->arg); | 
 | 	set_bus_id(&emm_dma, slot->bus_id); | 
 |  | 
 | 	if (mmc_card_mmc(mmc->card) || (mmc_card_sd(mmc->card) && | 
 | 	    (mmc->card->scr.cmds & SD_SCR_CMD23_SUPPORT))) | 
 | 		emm_dma |= FIELD_PREP(MIO_EMM_DMA_MULTI, 1); | 
 |  | 
 | 	pr_debug("[%s] blocks: %u  multi: %d\n", | 
 | 		(emm_dma & MIO_EMM_DMA_RW) ? "W" : "R", | 
 | 		 mrq->data->blocks, (emm_dma & MIO_EMM_DMA_MULTI) ? 1 : 0); | 
 | 	return emm_dma; | 
 | } | 
 |  | 
 | static void cvm_mmc_dma_request(struct mmc_host *mmc, | 
 | 				struct mmc_request *mrq) | 
 | { | 
 | 	struct cvm_mmc_slot *slot = mmc_priv(mmc); | 
 | 	struct cvm_mmc_host *host = slot->host; | 
 | 	struct mmc_data *data; | 
 | 	u64 emm_dma, addr; | 
 |  | 
 | 	if (!mrq->data || !mrq->data->sg || !mrq->data->sg_len || | 
 | 	    !mrq->stop || mrq->stop->opcode != MMC_STOP_TRANSMISSION) { | 
 | 		dev_err(&mmc->card->dev, | 
 | 			"Error: cmv_mmc_dma_request no data\n"); | 
 | 		goto error; | 
 | 	} | 
 |  | 
 | 	cvm_mmc_switch_to(slot); | 
 |  | 
 | 	data = mrq->data; | 
 | 	pr_debug("DMA request  blocks: %d  block_size: %d  total_size: %d\n", | 
 | 		 data->blocks, data->blksz, data->blocks * data->blksz); | 
 | 	if (data->timeout_ns) | 
 | 		set_wdog(slot, data->timeout_ns); | 
 |  | 
 | 	WARN_ON(host->current_req); | 
 | 	host->current_req = mrq; | 
 |  | 
 | 	emm_dma = prepare_ext_dma(mmc, mrq); | 
 | 	addr = prepare_dma(host, data); | 
 | 	if (!addr) { | 
 | 		dev_err(host->dev, "prepare_dma failed\n"); | 
 | 		goto error; | 
 | 	} | 
 |  | 
 | 	host->dma_active = true; | 
 | 	host->int_enable(host, MIO_EMM_INT_CMD_ERR | MIO_EMM_INT_DMA_DONE | | 
 | 			 MIO_EMM_INT_DMA_ERR); | 
 |  | 
 | 	if (host->dmar_fixup) | 
 | 		host->dmar_fixup(host, mrq->cmd, data, addr); | 
 |  | 
 | 	/* | 
 | 	 * If we have a valid SD card in the slot, we set the response | 
 | 	 * bit mask to check for CRC errors and timeouts only. | 
 | 	 * Otherwise, use the default power reset value. | 
 | 	 */ | 
 | 	if (mmc_card_sd(mmc->card)) | 
 | 		writeq(0x00b00000ull, host->base + MIO_EMM_STS_MASK(host)); | 
 | 	else | 
 | 		writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK(host)); | 
 | 	writeq(emm_dma, host->base + MIO_EMM_DMA(host)); | 
 | 	return; | 
 |  | 
 | error: | 
 | 	mrq->cmd->error = -EINVAL; | 
 | 	if (mrq->done) | 
 | 		mrq->done(mrq); | 
 | 	host->release_bus(host); | 
 | } | 
 |  | 
 | static void do_read_request(struct cvm_mmc_host *host, struct mmc_request *mrq) | 
 | { | 
 | 	sg_miter_start(&host->smi, mrq->data->sg, mrq->data->sg_len, | 
 | 		       SG_MITER_ATOMIC | SG_MITER_TO_SG); | 
 | } | 
 |  | 
 | static void do_write_request(struct cvm_mmc_host *host, struct mmc_request *mrq) | 
 | { | 
 | 	unsigned int data_len = mrq->data->blocks * mrq->data->blksz; | 
 | 	struct sg_mapping_iter *smi = &host->smi; | 
 | 	unsigned int bytes_xfered; | 
 | 	int shift = 56; | 
 | 	u64 dat = 0; | 
 |  | 
 | 	/* Copy data to the xmit buffer before issuing the command. */ | 
 | 	sg_miter_start(smi, mrq->data->sg, mrq->data->sg_len, SG_MITER_FROM_SG); | 
 |  | 
 | 	/* Auto inc from offset zero, dbuf zero */ | 
 | 	writeq(0x10000ull, host->base + MIO_EMM_BUF_IDX(host)); | 
 |  | 
 | 	for (bytes_xfered = 0; bytes_xfered < data_len;) { | 
 | 		if (smi->consumed >= smi->length) { | 
 | 			if (!sg_miter_next(smi)) | 
 | 				break; | 
 | 			smi->consumed = 0; | 
 | 		} | 
 |  | 
 | 		while (smi->consumed < smi->length && shift >= 0) { | 
 | 			dat |= (u64)((u8 *)smi->addr)[smi->consumed] << shift; | 
 | 			bytes_xfered++; | 
 | 			smi->consumed++; | 
 | 			shift -= 8; | 
 | 		} | 
 |  | 
 | 		if (shift < 0) { | 
 | 			writeq(dat, host->base + MIO_EMM_BUF_DAT(host)); | 
 | 			shift = 56; | 
 | 			dat = 0; | 
 | 		} | 
 | 	} | 
 | 	sg_miter_stop(smi); | 
 | } | 
 |  | 
 | static void cvm_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq) | 
 | { | 
 | 	struct cvm_mmc_slot *slot = mmc_priv(mmc); | 
 | 	struct cvm_mmc_host *host = slot->host; | 
 | 	struct mmc_command *cmd = mrq->cmd; | 
 | 	struct cvm_mmc_cr_mods mods; | 
 | 	u64 emm_cmd, rsp_sts; | 
 | 	int retries = 100; | 
 |  | 
 | 	/* | 
 | 	 * Note about locking: | 
 | 	 * All MMC devices share the same bus and controller. Allow only a | 
 | 	 * single user of the bootbus/MMC bus at a time. The lock is acquired | 
 | 	 * on all entry points from the MMC layer. | 
 | 	 * | 
 | 	 * For requests the lock is only released after the completion | 
 | 	 * interrupt! | 
 | 	 */ | 
 | 	host->acquire_bus(host); | 
 |  | 
 | 	if (cmd->opcode == MMC_READ_MULTIPLE_BLOCK || | 
 | 	    cmd->opcode == MMC_WRITE_MULTIPLE_BLOCK) | 
 | 		return cvm_mmc_dma_request(mmc, mrq); | 
 |  | 
 | 	cvm_mmc_switch_to(slot); | 
 |  | 
 | 	mods = cvm_mmc_get_cr_mods(cmd); | 
 |  | 
 | 	WARN_ON(host->current_req); | 
 | 	host->current_req = mrq; | 
 |  | 
 | 	if (cmd->data) { | 
 | 		if (cmd->data->flags & MMC_DATA_READ) | 
 | 			do_read_request(host, mrq); | 
 | 		else | 
 | 			do_write_request(host, mrq); | 
 |  | 
 | 		if (cmd->data->timeout_ns) | 
 | 			set_wdog(slot, cmd->data->timeout_ns); | 
 | 	} else | 
 | 		set_wdog(slot, 0); | 
 |  | 
 | 	host->dma_active = false; | 
 | 	host->int_enable(host, MIO_EMM_INT_CMD_DONE | MIO_EMM_INT_CMD_ERR); | 
 |  | 
 | 	emm_cmd = FIELD_PREP(MIO_EMM_CMD_VAL, 1) | | 
 | 		  FIELD_PREP(MIO_EMM_CMD_CTYPE_XOR, mods.ctype_xor) | | 
 | 		  FIELD_PREP(MIO_EMM_CMD_RTYPE_XOR, mods.rtype_xor) | | 
 | 		  FIELD_PREP(MIO_EMM_CMD_IDX, cmd->opcode) | | 
 | 		  FIELD_PREP(MIO_EMM_CMD_ARG, cmd->arg); | 
 | 	set_bus_id(&emm_cmd, slot->bus_id); | 
 | 	if (cmd->data && mmc_cmd_type(cmd) == MMC_CMD_ADTC) | 
 | 		emm_cmd |= FIELD_PREP(MIO_EMM_CMD_OFFSET, | 
 | 				64 - ((cmd->data->blocks * cmd->data->blksz) / 8)); | 
 |  | 
 | 	writeq(0, host->base + MIO_EMM_STS_MASK(host)); | 
 |  | 
 | retry: | 
 | 	rsp_sts = readq(host->base + MIO_EMM_RSP_STS(host)); | 
 | 	if (rsp_sts & MIO_EMM_RSP_STS_DMA_VAL || | 
 | 	    rsp_sts & MIO_EMM_RSP_STS_CMD_VAL || | 
 | 	    rsp_sts & MIO_EMM_RSP_STS_SWITCH_VAL || | 
 | 	    rsp_sts & MIO_EMM_RSP_STS_DMA_PEND) { | 
 | 		udelay(10); | 
 | 		if (--retries) | 
 | 			goto retry; | 
 | 	} | 
 | 	if (!retries) | 
 | 		dev_err(host->dev, "Bad status: %llx before command write\n", rsp_sts); | 
 | 	writeq(emm_cmd, host->base + MIO_EMM_CMD(host)); | 
 | } | 
 |  | 
 | static void cvm_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) | 
 | { | 
 | 	struct cvm_mmc_slot *slot = mmc_priv(mmc); | 
 | 	struct cvm_mmc_host *host = slot->host; | 
 | 	int clk_period = 0, power_class = 10, bus_width = 0; | 
 | 	u64 clock, emm_switch; | 
 |  | 
 | 	host->acquire_bus(host); | 
 | 	cvm_mmc_switch_to(slot); | 
 |  | 
 | 	/* Set the power state */ | 
 | 	switch (ios->power_mode) { | 
 | 	case MMC_POWER_ON: | 
 | 		break; | 
 |  | 
 | 	case MMC_POWER_OFF: | 
 | 		cvm_mmc_reset_bus(slot); | 
 | 		if (host->global_pwr_gpiod) | 
 | 			host->set_shared_power(host, 0); | 
 | 		else if (!IS_ERR(mmc->supply.vmmc)) | 
 | 			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); | 
 | 		break; | 
 |  | 
 | 	case MMC_POWER_UP: | 
 | 		if (host->global_pwr_gpiod) | 
 | 			host->set_shared_power(host, 1); | 
 | 		else if (!IS_ERR(mmc->supply.vmmc)) | 
 | 			mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	/* Convert bus width to HW definition */ | 
 | 	switch (ios->bus_width) { | 
 | 	case MMC_BUS_WIDTH_8: | 
 | 		bus_width = 2; | 
 | 		break; | 
 | 	case MMC_BUS_WIDTH_4: | 
 | 		bus_width = 1; | 
 | 		break; | 
 | 	case MMC_BUS_WIDTH_1: | 
 | 		bus_width = 0; | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	/* DDR is available for 4/8 bit bus width */ | 
 | 	if (ios->bus_width && ios->timing == MMC_TIMING_MMC_DDR52) | 
 | 		bus_width |= 4; | 
 |  | 
 | 	/* Change the clock frequency. */ | 
 | 	clock = ios->clock; | 
 | 	if (clock > 52000000) | 
 | 		clock = 52000000; | 
 | 	slot->clock = clock; | 
 |  | 
 | 	if (clock) | 
 | 		clk_period = (host->sys_freq + clock - 1) / (2 * clock); | 
 |  | 
 | 	emm_switch = FIELD_PREP(MIO_EMM_SWITCH_HS_TIMING, | 
 | 				(ios->timing == MMC_TIMING_MMC_HS)) | | 
 | 		     FIELD_PREP(MIO_EMM_SWITCH_BUS_WIDTH, bus_width) | | 
 | 		     FIELD_PREP(MIO_EMM_SWITCH_POWER_CLASS, power_class) | | 
 | 		     FIELD_PREP(MIO_EMM_SWITCH_CLK_HI, clk_period) | | 
 | 		     FIELD_PREP(MIO_EMM_SWITCH_CLK_LO, clk_period); | 
 | 	set_bus_id(&emm_switch, slot->bus_id); | 
 |  | 
 | 	if (!switch_val_changed(slot, emm_switch)) | 
 | 		goto out; | 
 |  | 
 | 	set_wdog(slot, 0); | 
 | 	do_switch(host, emm_switch); | 
 | 	slot->cached_switch = emm_switch; | 
 | out: | 
 | 	host->release_bus(host); | 
 | } | 
 |  | 
 | static const struct mmc_host_ops cvm_mmc_ops = { | 
 | 	.request        = cvm_mmc_request, | 
 | 	.set_ios        = cvm_mmc_set_ios, | 
 | 	.get_ro		= mmc_gpio_get_ro, | 
 | 	.get_cd		= mmc_gpio_get_cd, | 
 | }; | 
 |  | 
 | static void cvm_mmc_set_clock(struct cvm_mmc_slot *slot, unsigned int clock) | 
 | { | 
 | 	struct mmc_host *mmc = slot->mmc; | 
 |  | 
 | 	clock = min(clock, mmc->f_max); | 
 | 	clock = max(clock, mmc->f_min); | 
 | 	slot->clock = clock; | 
 | } | 
 |  | 
 | static int cvm_mmc_init_lowlevel(struct cvm_mmc_slot *slot) | 
 | { | 
 | 	struct cvm_mmc_host *host = slot->host; | 
 | 	u64 emm_switch; | 
 |  | 
 | 	/* Enable this bus slot. */ | 
 | 	host->emm_cfg |= (1ull << slot->bus_id); | 
 | 	writeq(host->emm_cfg, slot->host->base + MIO_EMM_CFG(host)); | 
 | 	udelay(10); | 
 |  | 
 | 	/* Program initial clock speed and power. */ | 
 | 	cvm_mmc_set_clock(slot, slot->mmc->f_min); | 
 | 	emm_switch = FIELD_PREP(MIO_EMM_SWITCH_POWER_CLASS, 10); | 
 | 	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_CLK_HI, | 
 | 				 (host->sys_freq / slot->clock) / 2); | 
 | 	emm_switch |= FIELD_PREP(MIO_EMM_SWITCH_CLK_LO, | 
 | 				 (host->sys_freq / slot->clock) / 2); | 
 |  | 
 | 	/* Make the changes take effect on this bus slot. */ | 
 | 	set_bus_id(&emm_switch, slot->bus_id); | 
 | 	do_switch(host, emm_switch); | 
 |  | 
 | 	slot->cached_switch = emm_switch; | 
 |  | 
 | 	/* | 
 | 	 * Set watchdog timeout value and default reset value | 
 | 	 * for the mask register. Finally, set the CARD_RCA | 
 | 	 * bit so that we can get the card address relative | 
 | 	 * to the CMD register for CMD7 transactions. | 
 | 	 */ | 
 | 	set_wdog(slot, 0); | 
 | 	writeq(0xe4390080ull, host->base + MIO_EMM_STS_MASK(host)); | 
 | 	writeq(1, host->base + MIO_EMM_RCA(host)); | 
 | 	return 0; | 
 | } | 
 |  | 
 | static int cvm_mmc_of_parse(struct device *dev, struct cvm_mmc_slot *slot) | 
 | { | 
 | 	u32 id, cmd_skew = 0, dat_skew = 0, bus_width = 0; | 
 | 	struct device_node *node = dev->of_node; | 
 | 	struct mmc_host *mmc = slot->mmc; | 
 | 	u64 clock_period; | 
 | 	int ret; | 
 |  | 
 | 	ret = of_property_read_u32(node, "reg", &id); | 
 | 	if (ret) { | 
 | 		dev_err(dev, "Missing or invalid reg property on %pOF\n", node); | 
 | 		return ret; | 
 | 	} | 
 |  | 
 | 	if (id >= CAVIUM_MAX_MMC || slot->host->slot[id]) { | 
 | 		dev_err(dev, "Invalid reg property on %pOF\n", node); | 
 | 		return -EINVAL; | 
 | 	} | 
 |  | 
 | 	ret = mmc_regulator_get_supply(mmc); | 
 | 	if (ret) | 
 | 		return ret; | 
 | 	/* | 
 | 	 * Legacy Octeon firmware has no regulator entry, fall-back to | 
 | 	 * a hard-coded voltage to get a sane OCR. | 
 | 	 */ | 
 | 	if (IS_ERR(mmc->supply.vmmc)) | 
 | 		mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; | 
 |  | 
 | 	/* Common MMC bindings */ | 
 | 	ret = mmc_of_parse(mmc); | 
 | 	if (ret) | 
 | 		return ret; | 
 |  | 
 | 	/* Set bus width */ | 
 | 	if (!(mmc->caps & (MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA))) { | 
 | 		of_property_read_u32(node, "cavium,bus-max-width", &bus_width); | 
 | 		if (bus_width == 8) | 
 | 			mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_4_BIT_DATA; | 
 | 		else if (bus_width == 4) | 
 | 			mmc->caps |= MMC_CAP_4_BIT_DATA; | 
 | 	} | 
 |  | 
 | 	/* Set maximum and minimum frequency */ | 
 | 	if (!mmc->f_max) | 
 | 		of_property_read_u32(node, "spi-max-frequency", &mmc->f_max); | 
 | 	if (!mmc->f_max || mmc->f_max > 52000000) | 
 | 		mmc->f_max = 52000000; | 
 | 	mmc->f_min = 400000; | 
 |  | 
 | 	/* Sampling register settings, period in picoseconds */ | 
 | 	clock_period = 1000000000000ull / slot->host->sys_freq; | 
 | 	of_property_read_u32(node, "cavium,cmd-clk-skew", &cmd_skew); | 
 | 	of_property_read_u32(node, "cavium,dat-clk-skew", &dat_skew); | 
 | 	slot->cmd_cnt = (cmd_skew + clock_period / 2) / clock_period; | 
 | 	slot->dat_cnt = (dat_skew + clock_period / 2) / clock_period; | 
 |  | 
 | 	return id; | 
 | } | 
 |  | 
 | int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host) | 
 | { | 
 | 	struct cvm_mmc_slot *slot; | 
 | 	struct mmc_host *mmc; | 
 | 	int ret, id; | 
 |  | 
 | 	mmc = mmc_alloc_host(sizeof(struct cvm_mmc_slot), dev); | 
 | 	if (!mmc) | 
 | 		return -ENOMEM; | 
 |  | 
 | 	slot = mmc_priv(mmc); | 
 | 	slot->mmc = mmc; | 
 | 	slot->host = host; | 
 |  | 
 | 	ret = cvm_mmc_of_parse(dev, slot); | 
 | 	if (ret < 0) | 
 | 		goto error; | 
 | 	id = ret; | 
 |  | 
 | 	/* Set up host parameters */ | 
 | 	mmc->ops = &cvm_mmc_ops; | 
 |  | 
 | 	/* | 
 | 	 * We only have a 3.3v supply, we cannot support any | 
 | 	 * of the UHS modes. We do support the high speed DDR | 
 | 	 * modes up to 52MHz. | 
 | 	 * | 
 | 	 * Disable bounce buffers for max_segs = 1 | 
 | 	 */ | 
 | 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED | | 
 | 		     MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD | | 
 | 		     MMC_CAP_3_3V_DDR; | 
 |  | 
 | 	if (host->use_sg) | 
 | 		mmc->max_segs = 16; | 
 | 	else | 
 | 		mmc->max_segs = 1; | 
 |  | 
 | 	/* DMA size field can address up to 8 MB */ | 
 | 	mmc->max_seg_size = min_t(unsigned int, 8 * 1024 * 1024, | 
 | 				  dma_get_max_seg_size(host->dev)); | 
 | 	mmc->max_req_size = mmc->max_seg_size; | 
 | 	/* External DMA is in 512 byte blocks */ | 
 | 	mmc->max_blk_size = 512; | 
 | 	/* DMA block count field is 15 bits */ | 
 | 	mmc->max_blk_count = 32767; | 
 |  | 
 | 	slot->clock = mmc->f_min; | 
 | 	slot->bus_id = id; | 
 | 	slot->cached_rca = 1; | 
 |  | 
 | 	host->acquire_bus(host); | 
 | 	host->slot[id] = slot; | 
 | 	cvm_mmc_switch_to(slot); | 
 | 	cvm_mmc_init_lowlevel(slot); | 
 | 	host->release_bus(host); | 
 |  | 
 | 	ret = mmc_add_host(mmc); | 
 | 	if (ret) { | 
 | 		dev_err(dev, "mmc_add_host() returned %d\n", ret); | 
 | 		slot->host->slot[id] = NULL; | 
 | 		goto error; | 
 | 	} | 
 | 	return 0; | 
 |  | 
 | error: | 
 | 	mmc_free_host(slot->mmc); | 
 | 	return ret; | 
 | } | 
 |  | 
 | int cvm_mmc_of_slot_remove(struct cvm_mmc_slot *slot) | 
 | { | 
 | 	mmc_remove_host(slot->mmc); | 
 | 	slot->host->slot[slot->bus_id] = NULL; | 
 | 	mmc_free_host(slot->mmc); | 
 | 	return 0; | 
 | } |