162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MMCIF eMMC driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2010 Renesas Solutions Corp. 662306a36Sopenharmony_ci * Yusuke Goda <yusuke.goda.sx@renesas.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci/* 1062306a36Sopenharmony_ci * The MMCIF driver is now processing MMC requests asynchronously, according 1162306a36Sopenharmony_ci * to the Linux MMC API requirement. 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * The MMCIF driver processes MMC requests in up to 3 stages: command, optional 1462306a36Sopenharmony_ci * data, and optional stop. To achieve asynchronous processing each of these 1562306a36Sopenharmony_ci * stages is split into two halves: a top and a bottom half. The top half 1662306a36Sopenharmony_ci * initialises the hardware, installs a timeout handler to handle completion 1762306a36Sopenharmony_ci * timeouts, and returns. In case of the command stage this immediately returns 1862306a36Sopenharmony_ci * control to the caller, leaving all further processing to run asynchronously. 1962306a36Sopenharmony_ci * All further request processing is performed by the bottom halves. 2062306a36Sopenharmony_ci * 2162306a36Sopenharmony_ci * The bottom half further consists of a "hard" IRQ handler, an IRQ handler 2262306a36Sopenharmony_ci * thread, a DMA completion callback, if DMA is used, a timeout work, and 2362306a36Sopenharmony_ci * request- and stage-specific handler methods. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * Each bottom half run begins with either a hardware interrupt, a DMA callback 2662306a36Sopenharmony_ci * invocation, or a timeout work run. In case of an error or a successful 2762306a36Sopenharmony_ci * processing completion, the MMC core is informed and the request processing is 2862306a36Sopenharmony_ci * finished. In case processing has to continue, i.e., if data has to be read 2962306a36Sopenharmony_ci * from or written to the card, or if a stop command has to be sent, the next 3062306a36Sopenharmony_ci * top half is called, which performs the necessary hardware handling and 3162306a36Sopenharmony_ci * reschedules the timeout work. This returns the driver state machine into the 3262306a36Sopenharmony_ci * bottom half waiting state. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#include <linux/bitops.h> 3662306a36Sopenharmony_ci#include <linux/clk.h> 3762306a36Sopenharmony_ci#include <linux/completion.h> 3862306a36Sopenharmony_ci#include <linux/delay.h> 3962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 4062306a36Sopenharmony_ci#include <linux/dmaengine.h> 4162306a36Sopenharmony_ci#include <linux/mmc/card.h> 4262306a36Sopenharmony_ci#include <linux/mmc/core.h> 4362306a36Sopenharmony_ci#include <linux/mmc/host.h> 4462306a36Sopenharmony_ci#include <linux/mmc/mmc.h> 4562306a36Sopenharmony_ci#include <linux/mmc/sdio.h> 4662306a36Sopenharmony_ci#include <linux/mmc/slot-gpio.h> 4762306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 4862306a36Sopenharmony_ci#include <linux/mutex.h> 4962306a36Sopenharmony_ci#include <linux/pagemap.h> 5062306a36Sopenharmony_ci#include <linux/platform_data/sh_mmcif.h> 5162306a36Sopenharmony_ci#include <linux/platform_device.h> 5262306a36Sopenharmony_ci#include <linux/pm_qos.h> 5362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 5462306a36Sopenharmony_ci#include <linux/sh_dma.h> 5562306a36Sopenharmony_ci#include <linux/spinlock.h> 5662306a36Sopenharmony_ci#include <linux/module.h> 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci#define DRIVER_NAME "sh_mmcif" 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* CE_CMD_SET */ 6162306a36Sopenharmony_ci#define CMD_MASK 0x3f000000 6262306a36Sopenharmony_ci#define CMD_SET_RTYP_NO ((0 << 23) | (0 << 22)) 6362306a36Sopenharmony_ci#define CMD_SET_RTYP_6B ((0 << 23) | (1 << 22)) /* R1/R1b/R3/R4/R5 */ 6462306a36Sopenharmony_ci#define CMD_SET_RTYP_17B ((1 << 23) | (0 << 22)) /* R2 */ 6562306a36Sopenharmony_ci#define CMD_SET_RBSY (1 << 21) /* R1b */ 6662306a36Sopenharmony_ci#define CMD_SET_CCSEN (1 << 20) 6762306a36Sopenharmony_ci#define CMD_SET_WDAT (1 << 19) /* 1: on data, 0: no data */ 6862306a36Sopenharmony_ci#define CMD_SET_DWEN (1 << 18) /* 1: write, 0: read */ 6962306a36Sopenharmony_ci#define CMD_SET_CMLTE (1 << 17) /* 1: multi block trans, 0: single */ 7062306a36Sopenharmony_ci#define CMD_SET_CMD12EN (1 << 16) /* 1: CMD12 auto issue */ 7162306a36Sopenharmony_ci#define CMD_SET_RIDXC_INDEX ((0 << 15) | (0 << 14)) /* index check */ 7262306a36Sopenharmony_ci#define CMD_SET_RIDXC_BITS ((0 << 15) | (1 << 14)) /* check bits check */ 7362306a36Sopenharmony_ci#define CMD_SET_RIDXC_NO ((1 << 15) | (0 << 14)) /* no check */ 7462306a36Sopenharmony_ci#define CMD_SET_CRC7C ((0 << 13) | (0 << 12)) /* CRC7 check*/ 7562306a36Sopenharmony_ci#define CMD_SET_CRC7C_BITS ((0 << 13) | (1 << 12)) /* check bits check*/ 7662306a36Sopenharmony_ci#define CMD_SET_CRC7C_INTERNAL ((1 << 13) | (0 << 12)) /* internal CRC7 check*/ 7762306a36Sopenharmony_ci#define CMD_SET_CRC16C (1 << 10) /* 0: CRC16 check*/ 7862306a36Sopenharmony_ci#define CMD_SET_CRCSTE (1 << 8) /* 1: not receive CRC status */ 7962306a36Sopenharmony_ci#define CMD_SET_TBIT (1 << 7) /* 1: tran mission bit "Low" */ 8062306a36Sopenharmony_ci#define CMD_SET_OPDM (1 << 6) /* 1: open/drain */ 8162306a36Sopenharmony_ci#define CMD_SET_CCSH (1 << 5) 8262306a36Sopenharmony_ci#define CMD_SET_DARS (1 << 2) /* Dual Data Rate */ 8362306a36Sopenharmony_ci#define CMD_SET_DATW_1 ((0 << 1) | (0 << 0)) /* 1bit */ 8462306a36Sopenharmony_ci#define CMD_SET_DATW_4 ((0 << 1) | (1 << 0)) /* 4bit */ 8562306a36Sopenharmony_ci#define CMD_SET_DATW_8 ((1 << 1) | (0 << 0)) /* 8bit */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* CE_CMD_CTRL */ 8862306a36Sopenharmony_ci#define CMD_CTRL_BREAK (1 << 0) 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci/* CE_BLOCK_SET */ 9162306a36Sopenharmony_ci#define BLOCK_SIZE_MASK 0x0000ffff 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci/* CE_INT */ 9462306a36Sopenharmony_ci#define INT_CCSDE (1 << 29) 9562306a36Sopenharmony_ci#define INT_CMD12DRE (1 << 26) 9662306a36Sopenharmony_ci#define INT_CMD12RBE (1 << 25) 9762306a36Sopenharmony_ci#define INT_CMD12CRE (1 << 24) 9862306a36Sopenharmony_ci#define INT_DTRANE (1 << 23) 9962306a36Sopenharmony_ci#define INT_BUFRE (1 << 22) 10062306a36Sopenharmony_ci#define INT_BUFWEN (1 << 21) 10162306a36Sopenharmony_ci#define INT_BUFREN (1 << 20) 10262306a36Sopenharmony_ci#define INT_CCSRCV (1 << 19) 10362306a36Sopenharmony_ci#define INT_RBSYE (1 << 17) 10462306a36Sopenharmony_ci#define INT_CRSPE (1 << 16) 10562306a36Sopenharmony_ci#define INT_CMDVIO (1 << 15) 10662306a36Sopenharmony_ci#define INT_BUFVIO (1 << 14) 10762306a36Sopenharmony_ci#define INT_WDATERR (1 << 11) 10862306a36Sopenharmony_ci#define INT_RDATERR (1 << 10) 10962306a36Sopenharmony_ci#define INT_RIDXERR (1 << 9) 11062306a36Sopenharmony_ci#define INT_RSPERR (1 << 8) 11162306a36Sopenharmony_ci#define INT_CCSTO (1 << 5) 11262306a36Sopenharmony_ci#define INT_CRCSTO (1 << 4) 11362306a36Sopenharmony_ci#define INT_WDATTO (1 << 3) 11462306a36Sopenharmony_ci#define INT_RDATTO (1 << 2) 11562306a36Sopenharmony_ci#define INT_RBSYTO (1 << 1) 11662306a36Sopenharmony_ci#define INT_RSPTO (1 << 0) 11762306a36Sopenharmony_ci#define INT_ERR_STS (INT_CMDVIO | INT_BUFVIO | INT_WDATERR | \ 11862306a36Sopenharmony_ci INT_RDATERR | INT_RIDXERR | INT_RSPERR | \ 11962306a36Sopenharmony_ci INT_CCSTO | INT_CRCSTO | INT_WDATTO | \ 12062306a36Sopenharmony_ci INT_RDATTO | INT_RBSYTO | INT_RSPTO) 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define INT_ALL (INT_RBSYE | INT_CRSPE | INT_BUFREN | \ 12362306a36Sopenharmony_ci INT_BUFWEN | INT_CMD12DRE | INT_BUFRE | \ 12462306a36Sopenharmony_ci INT_DTRANE | INT_CMD12RBE | INT_CMD12CRE) 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci#define INT_CCS (INT_CCSTO | INT_CCSRCV | INT_CCSDE) 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci/* CE_INT_MASK */ 12962306a36Sopenharmony_ci#define MASK_ALL 0x00000000 13062306a36Sopenharmony_ci#define MASK_MCCSDE (1 << 29) 13162306a36Sopenharmony_ci#define MASK_MCMD12DRE (1 << 26) 13262306a36Sopenharmony_ci#define MASK_MCMD12RBE (1 << 25) 13362306a36Sopenharmony_ci#define MASK_MCMD12CRE (1 << 24) 13462306a36Sopenharmony_ci#define MASK_MDTRANE (1 << 23) 13562306a36Sopenharmony_ci#define MASK_MBUFRE (1 << 22) 13662306a36Sopenharmony_ci#define MASK_MBUFWEN (1 << 21) 13762306a36Sopenharmony_ci#define MASK_MBUFREN (1 << 20) 13862306a36Sopenharmony_ci#define MASK_MCCSRCV (1 << 19) 13962306a36Sopenharmony_ci#define MASK_MRBSYE (1 << 17) 14062306a36Sopenharmony_ci#define MASK_MCRSPE (1 << 16) 14162306a36Sopenharmony_ci#define MASK_MCMDVIO (1 << 15) 14262306a36Sopenharmony_ci#define MASK_MBUFVIO (1 << 14) 14362306a36Sopenharmony_ci#define MASK_MWDATERR (1 << 11) 14462306a36Sopenharmony_ci#define MASK_MRDATERR (1 << 10) 14562306a36Sopenharmony_ci#define MASK_MRIDXERR (1 << 9) 14662306a36Sopenharmony_ci#define MASK_MRSPERR (1 << 8) 14762306a36Sopenharmony_ci#define MASK_MCCSTO (1 << 5) 14862306a36Sopenharmony_ci#define MASK_MCRCSTO (1 << 4) 14962306a36Sopenharmony_ci#define MASK_MWDATTO (1 << 3) 15062306a36Sopenharmony_ci#define MASK_MRDATTO (1 << 2) 15162306a36Sopenharmony_ci#define MASK_MRBSYTO (1 << 1) 15262306a36Sopenharmony_ci#define MASK_MRSPTO (1 << 0) 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci#define MASK_START_CMD (MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | \ 15562306a36Sopenharmony_ci MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | \ 15662306a36Sopenharmony_ci MASK_MCRCSTO | MASK_MWDATTO | \ 15762306a36Sopenharmony_ci MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO) 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci#define MASK_CLEAN (INT_ERR_STS | MASK_MRBSYE | MASK_MCRSPE | \ 16062306a36Sopenharmony_ci MASK_MBUFREN | MASK_MBUFWEN | \ 16162306a36Sopenharmony_ci MASK_MCMD12DRE | MASK_MBUFRE | MASK_MDTRANE | \ 16262306a36Sopenharmony_ci MASK_MCMD12RBE | MASK_MCMD12CRE) 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci/* CE_HOST_STS1 */ 16562306a36Sopenharmony_ci#define STS1_CMDSEQ (1 << 31) 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* CE_HOST_STS2 */ 16862306a36Sopenharmony_ci#define STS2_CRCSTE (1 << 31) 16962306a36Sopenharmony_ci#define STS2_CRC16E (1 << 30) 17062306a36Sopenharmony_ci#define STS2_AC12CRCE (1 << 29) 17162306a36Sopenharmony_ci#define STS2_RSPCRC7E (1 << 28) 17262306a36Sopenharmony_ci#define STS2_CRCSTEBE (1 << 27) 17362306a36Sopenharmony_ci#define STS2_RDATEBE (1 << 26) 17462306a36Sopenharmony_ci#define STS2_AC12REBE (1 << 25) 17562306a36Sopenharmony_ci#define STS2_RSPEBE (1 << 24) 17662306a36Sopenharmony_ci#define STS2_AC12IDXE (1 << 23) 17762306a36Sopenharmony_ci#define STS2_RSPIDXE (1 << 22) 17862306a36Sopenharmony_ci#define STS2_CCSTO (1 << 15) 17962306a36Sopenharmony_ci#define STS2_RDATTO (1 << 14) 18062306a36Sopenharmony_ci#define STS2_DATBSYTO (1 << 13) 18162306a36Sopenharmony_ci#define STS2_CRCSTTO (1 << 12) 18262306a36Sopenharmony_ci#define STS2_AC12BSYTO (1 << 11) 18362306a36Sopenharmony_ci#define STS2_RSPBSYTO (1 << 10) 18462306a36Sopenharmony_ci#define STS2_AC12RSPTO (1 << 9) 18562306a36Sopenharmony_ci#define STS2_RSPTO (1 << 8) 18662306a36Sopenharmony_ci#define STS2_CRC_ERR (STS2_CRCSTE | STS2_CRC16E | \ 18762306a36Sopenharmony_ci STS2_AC12CRCE | STS2_RSPCRC7E | STS2_CRCSTEBE) 18862306a36Sopenharmony_ci#define STS2_TIMEOUT_ERR (STS2_CCSTO | STS2_RDATTO | \ 18962306a36Sopenharmony_ci STS2_DATBSYTO | STS2_CRCSTTO | \ 19062306a36Sopenharmony_ci STS2_AC12BSYTO | STS2_RSPBSYTO | \ 19162306a36Sopenharmony_ci STS2_AC12RSPTO | STS2_RSPTO) 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci#define CLKDEV_EMMC_DATA 52000000 /* 52 MHz */ 19462306a36Sopenharmony_ci#define CLKDEV_MMC_DATA 20000000 /* 20 MHz */ 19562306a36Sopenharmony_ci#define CLKDEV_INIT 400000 /* 400 kHz */ 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cienum sh_mmcif_state { 19862306a36Sopenharmony_ci STATE_IDLE, 19962306a36Sopenharmony_ci STATE_REQUEST, 20062306a36Sopenharmony_ci STATE_IOS, 20162306a36Sopenharmony_ci STATE_TIMEOUT, 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cienum sh_mmcif_wait_for { 20562306a36Sopenharmony_ci MMCIF_WAIT_FOR_REQUEST, 20662306a36Sopenharmony_ci MMCIF_WAIT_FOR_CMD, 20762306a36Sopenharmony_ci MMCIF_WAIT_FOR_MREAD, 20862306a36Sopenharmony_ci MMCIF_WAIT_FOR_MWRITE, 20962306a36Sopenharmony_ci MMCIF_WAIT_FOR_READ, 21062306a36Sopenharmony_ci MMCIF_WAIT_FOR_WRITE, 21162306a36Sopenharmony_ci MMCIF_WAIT_FOR_READ_END, 21262306a36Sopenharmony_ci MMCIF_WAIT_FOR_WRITE_END, 21362306a36Sopenharmony_ci MMCIF_WAIT_FOR_STOP, 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci/* 21762306a36Sopenharmony_ci * difference for each SoC 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_cistruct sh_mmcif_host { 22062306a36Sopenharmony_ci struct mmc_host *mmc; 22162306a36Sopenharmony_ci struct mmc_request *mrq; 22262306a36Sopenharmony_ci struct platform_device *pd; 22362306a36Sopenharmony_ci struct clk *clk; 22462306a36Sopenharmony_ci int bus_width; 22562306a36Sopenharmony_ci unsigned char timing; 22662306a36Sopenharmony_ci bool sd_error; 22762306a36Sopenharmony_ci bool dying; 22862306a36Sopenharmony_ci long timeout; 22962306a36Sopenharmony_ci void __iomem *addr; 23062306a36Sopenharmony_ci u32 *pio_ptr; 23162306a36Sopenharmony_ci spinlock_t lock; /* protect sh_mmcif_host::state */ 23262306a36Sopenharmony_ci enum sh_mmcif_state state; 23362306a36Sopenharmony_ci enum sh_mmcif_wait_for wait_for; 23462306a36Sopenharmony_ci struct delayed_work timeout_work; 23562306a36Sopenharmony_ci size_t blocksize; 23662306a36Sopenharmony_ci int sg_idx; 23762306a36Sopenharmony_ci int sg_blkidx; 23862306a36Sopenharmony_ci bool power; 23962306a36Sopenharmony_ci bool ccs_enable; /* Command Completion Signal support */ 24062306a36Sopenharmony_ci bool clk_ctrl2_enable; 24162306a36Sopenharmony_ci struct mutex thread_lock; 24262306a36Sopenharmony_ci u32 clkdiv_map; /* see CE_CLK_CTRL::CLKDIV */ 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* DMA support */ 24562306a36Sopenharmony_ci struct dma_chan *chan_rx; 24662306a36Sopenharmony_ci struct dma_chan *chan_tx; 24762306a36Sopenharmony_ci struct completion dma_complete; 24862306a36Sopenharmony_ci bool dma_active; 24962306a36Sopenharmony_ci}; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic const struct of_device_id sh_mmcif_of_match[] = { 25262306a36Sopenharmony_ci { .compatible = "renesas,sh-mmcif" }, 25362306a36Sopenharmony_ci { } 25462306a36Sopenharmony_ci}; 25562306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sh_mmcif_of_match); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci#define sh_mmcif_host_to_dev(host) (&host->pd->dev) 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cistatic inline void sh_mmcif_bitset(struct sh_mmcif_host *host, 26062306a36Sopenharmony_ci unsigned int reg, u32 val) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci writel(val | readl(host->addr + reg), host->addr + reg); 26362306a36Sopenharmony_ci} 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_cistatic inline void sh_mmcif_bitclr(struct sh_mmcif_host *host, 26662306a36Sopenharmony_ci unsigned int reg, u32 val) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci writel(~val & readl(host->addr + reg), host->addr + reg); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic void sh_mmcif_dma_complete(void *arg) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci struct sh_mmcif_host *host = arg; 27462306a36Sopenharmony_ci struct mmc_request *mrq = host->mrq; 27562306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci dev_dbg(dev, "Command completed\n"); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci if (WARN(!mrq || !mrq->data, "%s: NULL data in DMA completion!\n", 28062306a36Sopenharmony_ci dev_name(dev))) 28162306a36Sopenharmony_ci return; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci complete(&host->dma_complete); 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void sh_mmcif_start_dma_rx(struct sh_mmcif_host *host) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 28962306a36Sopenharmony_ci struct scatterlist *sg = data->sg; 29062306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc = NULL; 29162306a36Sopenharmony_ci struct dma_chan *chan = host->chan_rx; 29262306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 29362306a36Sopenharmony_ci dma_cookie_t cookie = -EINVAL; 29462306a36Sopenharmony_ci int ret; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci ret = dma_map_sg(chan->device->dev, sg, data->sg_len, 29762306a36Sopenharmony_ci DMA_FROM_DEVICE); 29862306a36Sopenharmony_ci if (ret > 0) { 29962306a36Sopenharmony_ci host->dma_active = true; 30062306a36Sopenharmony_ci desc = dmaengine_prep_slave_sg(chan, sg, ret, 30162306a36Sopenharmony_ci DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (desc) { 30562306a36Sopenharmony_ci desc->callback = sh_mmcif_dma_complete; 30662306a36Sopenharmony_ci desc->callback_param = host; 30762306a36Sopenharmony_ci cookie = dmaengine_submit(desc); 30862306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN); 30962306a36Sopenharmony_ci dma_async_issue_pending(chan); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci dev_dbg(dev, "%s(): mapped %d -> %d, cookie %d\n", 31262306a36Sopenharmony_ci __func__, data->sg_len, ret, cookie); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (!desc) { 31562306a36Sopenharmony_ci /* DMA failed, fall back to PIO */ 31662306a36Sopenharmony_ci if (ret >= 0) 31762306a36Sopenharmony_ci ret = -EIO; 31862306a36Sopenharmony_ci host->chan_rx = NULL; 31962306a36Sopenharmony_ci host->dma_active = false; 32062306a36Sopenharmony_ci dma_release_channel(chan); 32162306a36Sopenharmony_ci /* Free the Tx channel too */ 32262306a36Sopenharmony_ci chan = host->chan_tx; 32362306a36Sopenharmony_ci if (chan) { 32462306a36Sopenharmony_ci host->chan_tx = NULL; 32562306a36Sopenharmony_ci dma_release_channel(chan); 32662306a36Sopenharmony_ci } 32762306a36Sopenharmony_ci dev_warn(dev, 32862306a36Sopenharmony_ci "DMA failed: %d, falling back to PIO\n", ret); 32962306a36Sopenharmony_ci sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci dev_dbg(dev, "%s(): desc %p, cookie %d, sg[%d]\n", __func__, 33362306a36Sopenharmony_ci desc, cookie, data->sg_len); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void sh_mmcif_start_dma_tx(struct sh_mmcif_host *host) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 33962306a36Sopenharmony_ci struct scatterlist *sg = data->sg; 34062306a36Sopenharmony_ci struct dma_async_tx_descriptor *desc = NULL; 34162306a36Sopenharmony_ci struct dma_chan *chan = host->chan_tx; 34262306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 34362306a36Sopenharmony_ci dma_cookie_t cookie = -EINVAL; 34462306a36Sopenharmony_ci int ret; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci ret = dma_map_sg(chan->device->dev, sg, data->sg_len, 34762306a36Sopenharmony_ci DMA_TO_DEVICE); 34862306a36Sopenharmony_ci if (ret > 0) { 34962306a36Sopenharmony_ci host->dma_active = true; 35062306a36Sopenharmony_ci desc = dmaengine_prep_slave_sg(chan, sg, ret, 35162306a36Sopenharmony_ci DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT | DMA_CTRL_ACK); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (desc) { 35562306a36Sopenharmony_ci desc->callback = sh_mmcif_dma_complete; 35662306a36Sopenharmony_ci desc->callback_param = host; 35762306a36Sopenharmony_ci cookie = dmaengine_submit(desc); 35862306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAWEN); 35962306a36Sopenharmony_ci dma_async_issue_pending(chan); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci dev_dbg(dev, "%s(): mapped %d -> %d, cookie %d\n", 36262306a36Sopenharmony_ci __func__, data->sg_len, ret, cookie); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci if (!desc) { 36562306a36Sopenharmony_ci /* DMA failed, fall back to PIO */ 36662306a36Sopenharmony_ci if (ret >= 0) 36762306a36Sopenharmony_ci ret = -EIO; 36862306a36Sopenharmony_ci host->chan_tx = NULL; 36962306a36Sopenharmony_ci host->dma_active = false; 37062306a36Sopenharmony_ci dma_release_channel(chan); 37162306a36Sopenharmony_ci /* Free the Rx channel too */ 37262306a36Sopenharmony_ci chan = host->chan_rx; 37362306a36Sopenharmony_ci if (chan) { 37462306a36Sopenharmony_ci host->chan_rx = NULL; 37562306a36Sopenharmony_ci dma_release_channel(chan); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci dev_warn(dev, 37862306a36Sopenharmony_ci "DMA failed: %d, falling back to PIO\n", ret); 37962306a36Sopenharmony_ci sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci dev_dbg(dev, "%s(): desc %p, cookie %d\n", __func__, 38362306a36Sopenharmony_ci desc, cookie); 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_cistatic struct dma_chan * 38762306a36Sopenharmony_cish_mmcif_request_dma_pdata(struct sh_mmcif_host *host, uintptr_t slave_id) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci dma_cap_mask_t mask; 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci dma_cap_zero(mask); 39262306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, mask); 39362306a36Sopenharmony_ci if (slave_id <= 0) 39462306a36Sopenharmony_ci return NULL; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return dma_request_channel(mask, shdma_chan_filter, (void *)slave_id); 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int sh_mmcif_dma_slave_config(struct sh_mmcif_host *host, 40062306a36Sopenharmony_ci struct dma_chan *chan, 40162306a36Sopenharmony_ci enum dma_transfer_direction direction) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct resource *res; 40462306a36Sopenharmony_ci struct dma_slave_config cfg = { 0, }; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci res = platform_get_resource(host->pd, IORESOURCE_MEM, 0); 40762306a36Sopenharmony_ci if (!res) 40862306a36Sopenharmony_ci return -EINVAL; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci cfg.direction = direction; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (direction == DMA_DEV_TO_MEM) { 41362306a36Sopenharmony_ci cfg.src_addr = res->start + MMCIF_CE_DATA; 41462306a36Sopenharmony_ci cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 41562306a36Sopenharmony_ci } else { 41662306a36Sopenharmony_ci cfg.dst_addr = res->start + MMCIF_CE_DATA; 41762306a36Sopenharmony_ci cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return dmaengine_slave_config(chan, &cfg); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void sh_mmcif_request_dma(struct sh_mmcif_host *host) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 42662306a36Sopenharmony_ci host->dma_active = false; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* We can only either use DMA for both Tx and Rx or not use it at all */ 42962306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_SUPERH) && dev->platform_data) { 43062306a36Sopenharmony_ci struct sh_mmcif_plat_data *pdata = dev->platform_data; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci host->chan_tx = sh_mmcif_request_dma_pdata(host, 43362306a36Sopenharmony_ci pdata->slave_id_tx); 43462306a36Sopenharmony_ci host->chan_rx = sh_mmcif_request_dma_pdata(host, 43562306a36Sopenharmony_ci pdata->slave_id_rx); 43662306a36Sopenharmony_ci } else { 43762306a36Sopenharmony_ci host->chan_tx = dma_request_chan(dev, "tx"); 43862306a36Sopenharmony_ci if (IS_ERR(host->chan_tx)) 43962306a36Sopenharmony_ci host->chan_tx = NULL; 44062306a36Sopenharmony_ci host->chan_rx = dma_request_chan(dev, "rx"); 44162306a36Sopenharmony_ci if (IS_ERR(host->chan_rx)) 44262306a36Sopenharmony_ci host->chan_rx = NULL; 44362306a36Sopenharmony_ci } 44462306a36Sopenharmony_ci dev_dbg(dev, "%s: got channel TX %p RX %p\n", __func__, host->chan_tx, 44562306a36Sopenharmony_ci host->chan_rx); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (!host->chan_tx || !host->chan_rx || 44862306a36Sopenharmony_ci sh_mmcif_dma_slave_config(host, host->chan_tx, DMA_MEM_TO_DEV) || 44962306a36Sopenharmony_ci sh_mmcif_dma_slave_config(host, host->chan_rx, DMA_DEV_TO_MEM)) 45062306a36Sopenharmony_ci goto error; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci return; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_cierror: 45562306a36Sopenharmony_ci if (host->chan_tx) 45662306a36Sopenharmony_ci dma_release_channel(host->chan_tx); 45762306a36Sopenharmony_ci if (host->chan_rx) 45862306a36Sopenharmony_ci dma_release_channel(host->chan_rx); 45962306a36Sopenharmony_ci host->chan_tx = host->chan_rx = NULL; 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_cistatic void sh_mmcif_release_dma(struct sh_mmcif_host *host) 46362306a36Sopenharmony_ci{ 46462306a36Sopenharmony_ci sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, BUF_ACC_DMAREN | BUF_ACC_DMAWEN); 46562306a36Sopenharmony_ci /* Descriptors are freed automatically */ 46662306a36Sopenharmony_ci if (host->chan_tx) { 46762306a36Sopenharmony_ci struct dma_chan *chan = host->chan_tx; 46862306a36Sopenharmony_ci host->chan_tx = NULL; 46962306a36Sopenharmony_ci dma_release_channel(chan); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci if (host->chan_rx) { 47262306a36Sopenharmony_ci struct dma_chan *chan = host->chan_rx; 47362306a36Sopenharmony_ci host->chan_rx = NULL; 47462306a36Sopenharmony_ci dma_release_channel(chan); 47562306a36Sopenharmony_ci } 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci host->dma_active = false; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 48362306a36Sopenharmony_ci struct sh_mmcif_plat_data *p = dev->platform_data; 48462306a36Sopenharmony_ci bool sup_pclk = p ? p->sup_pclk : false; 48562306a36Sopenharmony_ci unsigned int current_clk = clk_get_rate(host->clk); 48662306a36Sopenharmony_ci unsigned int clkdiv; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); 48962306a36Sopenharmony_ci sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if (!clk) 49262306a36Sopenharmony_ci return; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (host->clkdiv_map) { 49562306a36Sopenharmony_ci unsigned int freq, best_freq, myclk, div, diff_min, diff; 49662306a36Sopenharmony_ci int i; 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci clkdiv = 0; 49962306a36Sopenharmony_ci diff_min = ~0; 50062306a36Sopenharmony_ci best_freq = 0; 50162306a36Sopenharmony_ci for (i = 31; i >= 0; i--) { 50262306a36Sopenharmony_ci if (!((1 << i) & host->clkdiv_map)) 50362306a36Sopenharmony_ci continue; 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* 50662306a36Sopenharmony_ci * clk = parent_freq / div 50762306a36Sopenharmony_ci * -> parent_freq = clk x div 50862306a36Sopenharmony_ci */ 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci div = 1 << (i + 1); 51162306a36Sopenharmony_ci freq = clk_round_rate(host->clk, clk * div); 51262306a36Sopenharmony_ci myclk = freq / div; 51362306a36Sopenharmony_ci diff = (myclk > clk) ? myclk - clk : clk - myclk; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci if (diff <= diff_min) { 51662306a36Sopenharmony_ci best_freq = freq; 51762306a36Sopenharmony_ci clkdiv = i; 51862306a36Sopenharmony_ci diff_min = diff; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci dev_dbg(dev, "clk %u/%u (%u, 0x%x)\n", 52362306a36Sopenharmony_ci (best_freq >> (clkdiv + 1)), clk, best_freq, clkdiv); 52462306a36Sopenharmony_ci 52562306a36Sopenharmony_ci clk_set_rate(host->clk, best_freq); 52662306a36Sopenharmony_ci clkdiv = clkdiv << 16; 52762306a36Sopenharmony_ci } else if (sup_pclk && clk == current_clk) { 52862306a36Sopenharmony_ci clkdiv = CLK_SUP_PCLK; 52962306a36Sopenharmony_ci } else { 53062306a36Sopenharmony_ci clkdiv = (fls(DIV_ROUND_UP(current_clk, clk) - 1) - 1) << 16; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & clkdiv); 53462306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cistatic void sh_mmcif_sync_reset(struct sh_mmcif_host *host) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci u32 tmp; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci tmp = 0x010f0000 & sh_mmcif_readl(host->addr, MMCIF_CE_CLK_CTRL); 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_ON); 54462306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_VERSION, SOFT_RST_OFF); 54562306a36Sopenharmony_ci if (host->ccs_enable) 54662306a36Sopenharmony_ci tmp |= SCCSTO_29; 54762306a36Sopenharmony_ci if (host->clk_ctrl2_enable) 54862306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_CLK_CTRL2, 0x0F0F0000); 54962306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, tmp | 55062306a36Sopenharmony_ci SRSPTO_256 | SRBSYTO_29 | SRWDTO_29); 55162306a36Sopenharmony_ci /* byte swap on */ 55262306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_BUF_ACC, BUF_ACC_ATYP); 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic int sh_mmcif_error_manage(struct sh_mmcif_host *host) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 55862306a36Sopenharmony_ci u32 state1, state2; 55962306a36Sopenharmony_ci int ret, timeout; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci host->sd_error = false; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci state1 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1); 56462306a36Sopenharmony_ci state2 = sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS2); 56562306a36Sopenharmony_ci dev_dbg(dev, "ERR HOST_STS1 = %08x\n", state1); 56662306a36Sopenharmony_ci dev_dbg(dev, "ERR HOST_STS2 = %08x\n", state2); 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci if (state1 & STS1_CMDSEQ) { 56962306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, CMD_CTRL_BREAK); 57062306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_CMD_CTRL, ~CMD_CTRL_BREAK); 57162306a36Sopenharmony_ci for (timeout = 10000; timeout; timeout--) { 57262306a36Sopenharmony_ci if (!(sh_mmcif_readl(host->addr, MMCIF_CE_HOST_STS1) 57362306a36Sopenharmony_ci & STS1_CMDSEQ)) 57462306a36Sopenharmony_ci break; 57562306a36Sopenharmony_ci mdelay(1); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci if (!timeout) { 57862306a36Sopenharmony_ci dev_err(dev, 57962306a36Sopenharmony_ci "Forced end of command sequence timeout err\n"); 58062306a36Sopenharmony_ci return -EIO; 58162306a36Sopenharmony_ci } 58262306a36Sopenharmony_ci sh_mmcif_sync_reset(host); 58362306a36Sopenharmony_ci dev_dbg(dev, "Forced end of command sequence\n"); 58462306a36Sopenharmony_ci return -EIO; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (state2 & STS2_CRC_ERR) { 58862306a36Sopenharmony_ci dev_err(dev, " CRC error: state %u, wait %u\n", 58962306a36Sopenharmony_ci host->state, host->wait_for); 59062306a36Sopenharmony_ci ret = -EIO; 59162306a36Sopenharmony_ci } else if (state2 & STS2_TIMEOUT_ERR) { 59262306a36Sopenharmony_ci dev_err(dev, " Timeout: state %u, wait %u\n", 59362306a36Sopenharmony_ci host->state, host->wait_for); 59462306a36Sopenharmony_ci ret = -ETIMEDOUT; 59562306a36Sopenharmony_ci } else { 59662306a36Sopenharmony_ci dev_dbg(dev, " End/Index error: state %u, wait %u\n", 59762306a36Sopenharmony_ci host->state, host->wait_for); 59862306a36Sopenharmony_ci ret = -EIO; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci return ret; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic bool sh_mmcif_next_block(struct sh_mmcif_host *host, u32 *p) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci host->sg_blkidx += host->blocksize; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci /* data->sg->length must be a multiple of host->blocksize? */ 61062306a36Sopenharmony_ci BUG_ON(host->sg_blkidx > data->sg->length); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (host->sg_blkidx == data->sg->length) { 61362306a36Sopenharmony_ci host->sg_blkidx = 0; 61462306a36Sopenharmony_ci if (++host->sg_idx < data->sg_len) 61562306a36Sopenharmony_ci host->pio_ptr = sg_virt(++data->sg); 61662306a36Sopenharmony_ci } else { 61762306a36Sopenharmony_ci host->pio_ptr = p; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci return host->sg_idx != data->sg_len; 62162306a36Sopenharmony_ci} 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_cistatic void sh_mmcif_single_read(struct sh_mmcif_host *host, 62462306a36Sopenharmony_ci struct mmc_request *mrq) 62562306a36Sopenharmony_ci{ 62662306a36Sopenharmony_ci host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & 62762306a36Sopenharmony_ci BLOCK_SIZE_MASK) + 3; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_READ; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci /* buf read enable */ 63262306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic bool sh_mmcif_read_block(struct sh_mmcif_host *host) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 63862306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 63962306a36Sopenharmony_ci u32 *p = sg_virt(data->sg); 64062306a36Sopenharmony_ci int i; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (host->sd_error) { 64362306a36Sopenharmony_ci data->error = sh_mmcif_error_manage(host); 64462306a36Sopenharmony_ci dev_dbg(dev, "%s(): %d\n", __func__, data->error); 64562306a36Sopenharmony_ci return false; 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_ci for (i = 0; i < host->blocksize / 4; i++) 64962306a36Sopenharmony_ci *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci /* buffer read end */ 65262306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFRE); 65362306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_READ_END; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci return true; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic void sh_mmcif_multi_read(struct sh_mmcif_host *host, 65962306a36Sopenharmony_ci struct mmc_request *mrq) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (!data->sg_len || !data->sg->length) 66462306a36Sopenharmony_ci return; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & 66762306a36Sopenharmony_ci BLOCK_SIZE_MASK; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_MREAD; 67062306a36Sopenharmony_ci host->sg_idx = 0; 67162306a36Sopenharmony_ci host->sg_blkidx = 0; 67262306a36Sopenharmony_ci host->pio_ptr = sg_virt(data->sg); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_cistatic bool sh_mmcif_mread_block(struct sh_mmcif_host *host) 67862306a36Sopenharmony_ci{ 67962306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 68062306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 68162306a36Sopenharmony_ci u32 *p = host->pio_ptr; 68262306a36Sopenharmony_ci int i; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (host->sd_error) { 68562306a36Sopenharmony_ci data->error = sh_mmcif_error_manage(host); 68662306a36Sopenharmony_ci dev_dbg(dev, "%s(): %d\n", __func__, data->error); 68762306a36Sopenharmony_ci return false; 68862306a36Sopenharmony_ci } 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci BUG_ON(!data->sg->length); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci for (i = 0; i < host->blocksize / 4; i++) 69362306a36Sopenharmony_ci *p++ = sh_mmcif_readl(host->addr, MMCIF_CE_DATA); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci if (!sh_mmcif_next_block(host, p)) 69662306a36Sopenharmony_ci return false; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFREN); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci return true; 70162306a36Sopenharmony_ci} 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_cistatic void sh_mmcif_single_write(struct sh_mmcif_host *host, 70462306a36Sopenharmony_ci struct mmc_request *mrq) 70562306a36Sopenharmony_ci{ 70662306a36Sopenharmony_ci host->blocksize = (sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & 70762306a36Sopenharmony_ci BLOCK_SIZE_MASK) + 3; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_WRITE; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci /* buf write enable */ 71262306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cistatic bool sh_mmcif_write_block(struct sh_mmcif_host *host) 71662306a36Sopenharmony_ci{ 71762306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 71862306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 71962306a36Sopenharmony_ci u32 *p = sg_virt(data->sg); 72062306a36Sopenharmony_ci int i; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci if (host->sd_error) { 72362306a36Sopenharmony_ci data->error = sh_mmcif_error_manage(host); 72462306a36Sopenharmony_ci dev_dbg(dev, "%s(): %d\n", __func__, data->error); 72562306a36Sopenharmony_ci return false; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci for (i = 0; i < host->blocksize / 4; i++) 72962306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci /* buffer write end */ 73262306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MDTRANE); 73362306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_WRITE_END; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return true; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic void sh_mmcif_multi_write(struct sh_mmcif_host *host, 73962306a36Sopenharmony_ci struct mmc_request *mrq) 74062306a36Sopenharmony_ci{ 74162306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (!data->sg_len || !data->sg->length) 74462306a36Sopenharmony_ci return; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci host->blocksize = sh_mmcif_readl(host->addr, MMCIF_CE_BLOCK_SET) & 74762306a36Sopenharmony_ci BLOCK_SIZE_MASK; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_MWRITE; 75062306a36Sopenharmony_ci host->sg_idx = 0; 75162306a36Sopenharmony_ci host->sg_blkidx = 0; 75262306a36Sopenharmony_ci host->pio_ptr = sg_virt(data->sg); 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_cistatic bool sh_mmcif_mwrite_block(struct sh_mmcif_host *host) 75862306a36Sopenharmony_ci{ 75962306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 76062306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 76162306a36Sopenharmony_ci u32 *p = host->pio_ptr; 76262306a36Sopenharmony_ci int i; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (host->sd_error) { 76562306a36Sopenharmony_ci data->error = sh_mmcif_error_manage(host); 76662306a36Sopenharmony_ci dev_dbg(dev, "%s(): %d\n", __func__, data->error); 76762306a36Sopenharmony_ci return false; 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci BUG_ON(!data->sg->length); 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci for (i = 0; i < host->blocksize / 4; i++) 77362306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_DATA, *p++); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (!sh_mmcif_next_block(host, p)) 77662306a36Sopenharmony_ci return false; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MBUFWEN); 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci return true; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic void sh_mmcif_get_response(struct sh_mmcif_host *host, 78462306a36Sopenharmony_ci struct mmc_command *cmd) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci if (cmd->flags & MMC_RSP_136) { 78762306a36Sopenharmony_ci cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP3); 78862306a36Sopenharmony_ci cmd->resp[1] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP2); 78962306a36Sopenharmony_ci cmd->resp[2] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP1); 79062306a36Sopenharmony_ci cmd->resp[3] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); 79162306a36Sopenharmony_ci } else 79262306a36Sopenharmony_ci cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP0); 79362306a36Sopenharmony_ci} 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_cistatic void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, 79662306a36Sopenharmony_ci struct mmc_command *cmd) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci cmd->resp[0] = sh_mmcif_readl(host->addr, MMCIF_CE_RESP_CMD12); 79962306a36Sopenharmony_ci} 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cistatic u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, 80262306a36Sopenharmony_ci struct mmc_request *mrq) 80362306a36Sopenharmony_ci{ 80462306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 80562306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 80662306a36Sopenharmony_ci struct mmc_command *cmd = mrq->cmd; 80762306a36Sopenharmony_ci u32 opc = cmd->opcode; 80862306a36Sopenharmony_ci u32 tmp = 0; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* Response Type check */ 81162306a36Sopenharmony_ci switch (mmc_resp_type(cmd)) { 81262306a36Sopenharmony_ci case MMC_RSP_NONE: 81362306a36Sopenharmony_ci tmp |= CMD_SET_RTYP_NO; 81462306a36Sopenharmony_ci break; 81562306a36Sopenharmony_ci case MMC_RSP_R1: 81662306a36Sopenharmony_ci case MMC_RSP_R3: 81762306a36Sopenharmony_ci tmp |= CMD_SET_RTYP_6B; 81862306a36Sopenharmony_ci break; 81962306a36Sopenharmony_ci case MMC_RSP_R1B: 82062306a36Sopenharmony_ci tmp |= CMD_SET_RBSY | CMD_SET_RTYP_6B; 82162306a36Sopenharmony_ci break; 82262306a36Sopenharmony_ci case MMC_RSP_R2: 82362306a36Sopenharmony_ci tmp |= CMD_SET_RTYP_17B; 82462306a36Sopenharmony_ci break; 82562306a36Sopenharmony_ci default: 82662306a36Sopenharmony_ci dev_err(dev, "Unsupported response type.\n"); 82762306a36Sopenharmony_ci break; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci /* WDAT / DATW */ 83162306a36Sopenharmony_ci if (data) { 83262306a36Sopenharmony_ci tmp |= CMD_SET_WDAT; 83362306a36Sopenharmony_ci switch (host->bus_width) { 83462306a36Sopenharmony_ci case MMC_BUS_WIDTH_1: 83562306a36Sopenharmony_ci tmp |= CMD_SET_DATW_1; 83662306a36Sopenharmony_ci break; 83762306a36Sopenharmony_ci case MMC_BUS_WIDTH_4: 83862306a36Sopenharmony_ci tmp |= CMD_SET_DATW_4; 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci case MMC_BUS_WIDTH_8: 84162306a36Sopenharmony_ci tmp |= CMD_SET_DATW_8; 84262306a36Sopenharmony_ci break; 84362306a36Sopenharmony_ci default: 84462306a36Sopenharmony_ci dev_err(dev, "Unsupported bus width.\n"); 84562306a36Sopenharmony_ci break; 84662306a36Sopenharmony_ci } 84762306a36Sopenharmony_ci switch (host->timing) { 84862306a36Sopenharmony_ci case MMC_TIMING_MMC_DDR52: 84962306a36Sopenharmony_ci /* 85062306a36Sopenharmony_ci * MMC core will only set this timing, if the host 85162306a36Sopenharmony_ci * advertises the MMC_CAP_1_8V_DDR/MMC_CAP_1_2V_DDR 85262306a36Sopenharmony_ci * capability. MMCIF implementations with this 85362306a36Sopenharmony_ci * capability, e.g. sh73a0, will have to set it 85462306a36Sopenharmony_ci * in their platform data. 85562306a36Sopenharmony_ci */ 85662306a36Sopenharmony_ci tmp |= CMD_SET_DARS; 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci } 86062306a36Sopenharmony_ci /* DWEN */ 86162306a36Sopenharmony_ci if (opc == MMC_WRITE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) 86262306a36Sopenharmony_ci tmp |= CMD_SET_DWEN; 86362306a36Sopenharmony_ci /* CMLTE/CMD12EN */ 86462306a36Sopenharmony_ci if (opc == MMC_READ_MULTIPLE_BLOCK || opc == MMC_WRITE_MULTIPLE_BLOCK) { 86562306a36Sopenharmony_ci tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; 86662306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_BLOCK_SET, 86762306a36Sopenharmony_ci data->blocks << 16); 86862306a36Sopenharmony_ci } 86962306a36Sopenharmony_ci /* RIDXC[1:0] check bits */ 87062306a36Sopenharmony_ci if (opc == MMC_SEND_OP_COND || opc == MMC_ALL_SEND_CID || 87162306a36Sopenharmony_ci opc == MMC_SEND_CSD || opc == MMC_SEND_CID) 87262306a36Sopenharmony_ci tmp |= CMD_SET_RIDXC_BITS; 87362306a36Sopenharmony_ci /* RCRC7C[1:0] check bits */ 87462306a36Sopenharmony_ci if (opc == MMC_SEND_OP_COND) 87562306a36Sopenharmony_ci tmp |= CMD_SET_CRC7C_BITS; 87662306a36Sopenharmony_ci /* RCRC7C[1:0] internal CRC7 */ 87762306a36Sopenharmony_ci if (opc == MMC_ALL_SEND_CID || 87862306a36Sopenharmony_ci opc == MMC_SEND_CSD || opc == MMC_SEND_CID) 87962306a36Sopenharmony_ci tmp |= CMD_SET_CRC7C_INTERNAL; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci return (opc << 24) | tmp; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int sh_mmcif_data_trans(struct sh_mmcif_host *host, 88562306a36Sopenharmony_ci struct mmc_request *mrq, u32 opc) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci switch (opc) { 89062306a36Sopenharmony_ci case MMC_READ_MULTIPLE_BLOCK: 89162306a36Sopenharmony_ci sh_mmcif_multi_read(host, mrq); 89262306a36Sopenharmony_ci return 0; 89362306a36Sopenharmony_ci case MMC_WRITE_MULTIPLE_BLOCK: 89462306a36Sopenharmony_ci sh_mmcif_multi_write(host, mrq); 89562306a36Sopenharmony_ci return 0; 89662306a36Sopenharmony_ci case MMC_WRITE_BLOCK: 89762306a36Sopenharmony_ci sh_mmcif_single_write(host, mrq); 89862306a36Sopenharmony_ci return 0; 89962306a36Sopenharmony_ci case MMC_READ_SINGLE_BLOCK: 90062306a36Sopenharmony_ci case MMC_SEND_EXT_CSD: 90162306a36Sopenharmony_ci sh_mmcif_single_read(host, mrq); 90262306a36Sopenharmony_ci return 0; 90362306a36Sopenharmony_ci default: 90462306a36Sopenharmony_ci dev_err(dev, "Unsupported CMD%d\n", opc); 90562306a36Sopenharmony_ci return -EINVAL; 90662306a36Sopenharmony_ci } 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic void sh_mmcif_start_cmd(struct sh_mmcif_host *host, 91062306a36Sopenharmony_ci struct mmc_request *mrq) 91162306a36Sopenharmony_ci{ 91262306a36Sopenharmony_ci struct mmc_command *cmd = mrq->cmd; 91362306a36Sopenharmony_ci u32 opc; 91462306a36Sopenharmony_ci u32 mask = 0; 91562306a36Sopenharmony_ci unsigned long flags; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci if (cmd->flags & MMC_RSP_BUSY) 91862306a36Sopenharmony_ci mask = MASK_START_CMD | MASK_MRBSYE; 91962306a36Sopenharmony_ci else 92062306a36Sopenharmony_ci mask = MASK_START_CMD | MASK_MCRSPE; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci if (host->ccs_enable) 92362306a36Sopenharmony_ci mask |= MASK_MCCSTO; 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (mrq->data) { 92662306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 0); 92762306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_BLOCK_SET, 92862306a36Sopenharmony_ci mrq->data->blksz); 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci opc = sh_mmcif_set_cmd(host, mrq); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (host->ccs_enable) 93362306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0); 93462306a36Sopenharmony_ci else 93562306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT, 0xD80430C0 | INT_CCS); 93662306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, mask); 93762306a36Sopenharmony_ci /* set arg */ 93862306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_ARG, cmd->arg); 93962306a36Sopenharmony_ci /* set cmd */ 94062306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 94162306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_CMD_SET, opc); 94262306a36Sopenharmony_ci 94362306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_CMD; 94462306a36Sopenharmony_ci schedule_delayed_work(&host->timeout_work, host->timeout); 94562306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 94662306a36Sopenharmony_ci} 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_cistatic void sh_mmcif_stop_cmd(struct sh_mmcif_host *host, 94962306a36Sopenharmony_ci struct mmc_request *mrq) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci switch (mrq->cmd->opcode) { 95462306a36Sopenharmony_ci case MMC_READ_MULTIPLE_BLOCK: 95562306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12DRE); 95662306a36Sopenharmony_ci break; 95762306a36Sopenharmony_ci case MMC_WRITE_MULTIPLE_BLOCK: 95862306a36Sopenharmony_ci sh_mmcif_bitset(host, MMCIF_CE_INT_MASK, MASK_MCMD12RBE); 95962306a36Sopenharmony_ci break; 96062306a36Sopenharmony_ci default: 96162306a36Sopenharmony_ci dev_err(dev, "unsupported stop cmd\n"); 96262306a36Sopenharmony_ci mrq->stop->error = sh_mmcif_error_manage(host); 96362306a36Sopenharmony_ci return; 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci 96662306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_STOP; 96762306a36Sopenharmony_ci} 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_cistatic void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) 97062306a36Sopenharmony_ci{ 97162306a36Sopenharmony_ci struct sh_mmcif_host *host = mmc_priv(mmc); 97262306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 97362306a36Sopenharmony_ci unsigned long flags; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 97662306a36Sopenharmony_ci if (host->state != STATE_IDLE) { 97762306a36Sopenharmony_ci dev_dbg(dev, "%s() rejected, state %u\n", 97862306a36Sopenharmony_ci __func__, host->state); 97962306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 98062306a36Sopenharmony_ci mrq->cmd->error = -EAGAIN; 98162306a36Sopenharmony_ci mmc_request_done(mmc, mrq); 98262306a36Sopenharmony_ci return; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci host->state = STATE_REQUEST; 98662306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci host->mrq = mrq; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci sh_mmcif_start_cmd(host, mrq); 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cistatic void sh_mmcif_clk_setup(struct sh_mmcif_host *host) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci if (host->mmc->f_max) { 99862306a36Sopenharmony_ci unsigned int f_max, f_min = 0, f_min_old; 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci f_max = host->mmc->f_max; 100162306a36Sopenharmony_ci for (f_min_old = f_max; f_min_old > 2;) { 100262306a36Sopenharmony_ci f_min = clk_round_rate(host->clk, f_min_old / 2); 100362306a36Sopenharmony_ci if (f_min == f_min_old) 100462306a36Sopenharmony_ci break; 100562306a36Sopenharmony_ci f_min_old = f_min; 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci /* 100962306a36Sopenharmony_ci * This driver assumes this SoC is R-Car Gen2 or later 101062306a36Sopenharmony_ci */ 101162306a36Sopenharmony_ci host->clkdiv_map = 0x3ff; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci host->mmc->f_max = f_max >> ffs(host->clkdiv_map); 101462306a36Sopenharmony_ci host->mmc->f_min = f_min >> fls(host->clkdiv_map); 101562306a36Sopenharmony_ci } else { 101662306a36Sopenharmony_ci unsigned int clk = clk_get_rate(host->clk); 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_ci host->mmc->f_max = clk / 2; 101962306a36Sopenharmony_ci host->mmc->f_min = clk / 512; 102062306a36Sopenharmony_ci } 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci dev_dbg(dev, "clk max/min = %d/%d\n", 102362306a36Sopenharmony_ci host->mmc->f_max, host->mmc->f_min); 102462306a36Sopenharmony_ci} 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_cistatic void sh_mmcif_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) 102762306a36Sopenharmony_ci{ 102862306a36Sopenharmony_ci struct sh_mmcif_host *host = mmc_priv(mmc); 102962306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 103062306a36Sopenharmony_ci unsigned long flags; 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 103362306a36Sopenharmony_ci if (host->state != STATE_IDLE) { 103462306a36Sopenharmony_ci dev_dbg(dev, "%s() rejected, state %u\n", 103562306a36Sopenharmony_ci __func__, host->state); 103662306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 103762306a36Sopenharmony_ci return; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci 104062306a36Sopenharmony_ci host->state = STATE_IOS; 104162306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci switch (ios->power_mode) { 104462306a36Sopenharmony_ci case MMC_POWER_UP: 104562306a36Sopenharmony_ci if (!IS_ERR(mmc->supply.vmmc)) 104662306a36Sopenharmony_ci mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd); 104762306a36Sopenharmony_ci if (!host->power) { 104862306a36Sopenharmony_ci clk_prepare_enable(host->clk); 104962306a36Sopenharmony_ci pm_runtime_get_sync(dev); 105062306a36Sopenharmony_ci sh_mmcif_sync_reset(host); 105162306a36Sopenharmony_ci sh_mmcif_request_dma(host); 105262306a36Sopenharmony_ci host->power = true; 105362306a36Sopenharmony_ci } 105462306a36Sopenharmony_ci break; 105562306a36Sopenharmony_ci case MMC_POWER_OFF: 105662306a36Sopenharmony_ci if (!IS_ERR(mmc->supply.vmmc)) 105762306a36Sopenharmony_ci mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, 0); 105862306a36Sopenharmony_ci if (host->power) { 105962306a36Sopenharmony_ci sh_mmcif_clock_control(host, 0); 106062306a36Sopenharmony_ci sh_mmcif_release_dma(host); 106162306a36Sopenharmony_ci pm_runtime_put(dev); 106262306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 106362306a36Sopenharmony_ci host->power = false; 106462306a36Sopenharmony_ci } 106562306a36Sopenharmony_ci break; 106662306a36Sopenharmony_ci case MMC_POWER_ON: 106762306a36Sopenharmony_ci sh_mmcif_clock_control(host, ios->clock); 106862306a36Sopenharmony_ci break; 106962306a36Sopenharmony_ci } 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci host->timing = ios->timing; 107262306a36Sopenharmony_ci host->bus_width = ios->bus_width; 107362306a36Sopenharmony_ci host->state = STATE_IDLE; 107462306a36Sopenharmony_ci} 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_cistatic const struct mmc_host_ops sh_mmcif_ops = { 107762306a36Sopenharmony_ci .request = sh_mmcif_request, 107862306a36Sopenharmony_ci .set_ios = sh_mmcif_set_ios, 107962306a36Sopenharmony_ci .get_cd = mmc_gpio_get_cd, 108062306a36Sopenharmony_ci}; 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_cistatic bool sh_mmcif_end_cmd(struct sh_mmcif_host *host) 108362306a36Sopenharmony_ci{ 108462306a36Sopenharmony_ci struct mmc_command *cmd = host->mrq->cmd; 108562306a36Sopenharmony_ci struct mmc_data *data = host->mrq->data; 108662306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 108762306a36Sopenharmony_ci long time; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci if (host->sd_error) { 109062306a36Sopenharmony_ci switch (cmd->opcode) { 109162306a36Sopenharmony_ci case MMC_ALL_SEND_CID: 109262306a36Sopenharmony_ci case MMC_SELECT_CARD: 109362306a36Sopenharmony_ci case MMC_APP_CMD: 109462306a36Sopenharmony_ci cmd->error = -ETIMEDOUT; 109562306a36Sopenharmony_ci break; 109662306a36Sopenharmony_ci default: 109762306a36Sopenharmony_ci cmd->error = sh_mmcif_error_manage(host); 109862306a36Sopenharmony_ci break; 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci dev_dbg(dev, "CMD%d error %d\n", 110162306a36Sopenharmony_ci cmd->opcode, cmd->error); 110262306a36Sopenharmony_ci host->sd_error = false; 110362306a36Sopenharmony_ci return false; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci if (!(cmd->flags & MMC_RSP_PRESENT)) { 110662306a36Sopenharmony_ci cmd->error = 0; 110762306a36Sopenharmony_ci return false; 110862306a36Sopenharmony_ci } 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci sh_mmcif_get_response(host, cmd); 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci if (!data) 111362306a36Sopenharmony_ci return false; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci /* 111662306a36Sopenharmony_ci * Completion can be signalled from DMA callback and error, so, have to 111762306a36Sopenharmony_ci * reset here, before setting .dma_active 111862306a36Sopenharmony_ci */ 111962306a36Sopenharmony_ci init_completion(&host->dma_complete); 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) { 112262306a36Sopenharmony_ci if (host->chan_rx) 112362306a36Sopenharmony_ci sh_mmcif_start_dma_rx(host); 112462306a36Sopenharmony_ci } else { 112562306a36Sopenharmony_ci if (host->chan_tx) 112662306a36Sopenharmony_ci sh_mmcif_start_dma_tx(host); 112762306a36Sopenharmony_ci } 112862306a36Sopenharmony_ci 112962306a36Sopenharmony_ci if (!host->dma_active) { 113062306a36Sopenharmony_ci data->error = sh_mmcif_data_trans(host, host->mrq, cmd->opcode); 113162306a36Sopenharmony_ci return !data->error; 113262306a36Sopenharmony_ci } 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci /* Running in the IRQ thread, can sleep */ 113562306a36Sopenharmony_ci time = wait_for_completion_interruptible_timeout(&host->dma_complete, 113662306a36Sopenharmony_ci host->timeout); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) 113962306a36Sopenharmony_ci dma_unmap_sg(host->chan_rx->device->dev, 114062306a36Sopenharmony_ci data->sg, data->sg_len, 114162306a36Sopenharmony_ci DMA_FROM_DEVICE); 114262306a36Sopenharmony_ci else 114362306a36Sopenharmony_ci dma_unmap_sg(host->chan_tx->device->dev, 114462306a36Sopenharmony_ci data->sg, data->sg_len, 114562306a36Sopenharmony_ci DMA_TO_DEVICE); 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci if (host->sd_error) { 114862306a36Sopenharmony_ci dev_err(host->mmc->parent, 114962306a36Sopenharmony_ci "Error IRQ while waiting for DMA completion!\n"); 115062306a36Sopenharmony_ci /* Woken up by an error IRQ: abort DMA */ 115162306a36Sopenharmony_ci data->error = sh_mmcif_error_manage(host); 115262306a36Sopenharmony_ci } else if (!time) { 115362306a36Sopenharmony_ci dev_err(host->mmc->parent, "DMA timeout!\n"); 115462306a36Sopenharmony_ci data->error = -ETIMEDOUT; 115562306a36Sopenharmony_ci } else if (time < 0) { 115662306a36Sopenharmony_ci dev_err(host->mmc->parent, 115762306a36Sopenharmony_ci "wait_for_completion_...() error %ld!\n", time); 115862306a36Sopenharmony_ci data->error = time; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci sh_mmcif_bitclr(host, MMCIF_CE_BUF_ACC, 116162306a36Sopenharmony_ci BUF_ACC_DMAREN | BUF_ACC_DMAWEN); 116262306a36Sopenharmony_ci host->dma_active = false; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (data->error) { 116562306a36Sopenharmony_ci data->bytes_xfered = 0; 116662306a36Sopenharmony_ci /* Abort DMA */ 116762306a36Sopenharmony_ci if (data->flags & MMC_DATA_READ) 116862306a36Sopenharmony_ci dmaengine_terminate_sync(host->chan_rx); 116962306a36Sopenharmony_ci else 117062306a36Sopenharmony_ci dmaengine_terminate_sync(host->chan_tx); 117162306a36Sopenharmony_ci } 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci return false; 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic irqreturn_t sh_mmcif_irqt(int irq, void *dev_id) 117762306a36Sopenharmony_ci{ 117862306a36Sopenharmony_ci struct sh_mmcif_host *host = dev_id; 117962306a36Sopenharmony_ci struct mmc_request *mrq; 118062306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 118162306a36Sopenharmony_ci bool wait = false; 118262306a36Sopenharmony_ci unsigned long flags; 118362306a36Sopenharmony_ci int wait_work; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 118662306a36Sopenharmony_ci wait_work = host->wait_for; 118762306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci cancel_delayed_work_sync(&host->timeout_work); 119062306a36Sopenharmony_ci 119162306a36Sopenharmony_ci mutex_lock(&host->thread_lock); 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci mrq = host->mrq; 119462306a36Sopenharmony_ci if (!mrq) { 119562306a36Sopenharmony_ci dev_dbg(dev, "IRQ thread state %u, wait %u: NULL mrq!\n", 119662306a36Sopenharmony_ci host->state, host->wait_for); 119762306a36Sopenharmony_ci mutex_unlock(&host->thread_lock); 119862306a36Sopenharmony_ci return IRQ_HANDLED; 119962306a36Sopenharmony_ci } 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* 120262306a36Sopenharmony_ci * All handlers return true, if processing continues, and false, if the 120362306a36Sopenharmony_ci * request has to be completed - successfully or not 120462306a36Sopenharmony_ci */ 120562306a36Sopenharmony_ci switch (wait_work) { 120662306a36Sopenharmony_ci case MMCIF_WAIT_FOR_REQUEST: 120762306a36Sopenharmony_ci /* We're too late, the timeout has already kicked in */ 120862306a36Sopenharmony_ci mutex_unlock(&host->thread_lock); 120962306a36Sopenharmony_ci return IRQ_HANDLED; 121062306a36Sopenharmony_ci case MMCIF_WAIT_FOR_CMD: 121162306a36Sopenharmony_ci /* Wait for data? */ 121262306a36Sopenharmony_ci wait = sh_mmcif_end_cmd(host); 121362306a36Sopenharmony_ci break; 121462306a36Sopenharmony_ci case MMCIF_WAIT_FOR_MREAD: 121562306a36Sopenharmony_ci /* Wait for more data? */ 121662306a36Sopenharmony_ci wait = sh_mmcif_mread_block(host); 121762306a36Sopenharmony_ci break; 121862306a36Sopenharmony_ci case MMCIF_WAIT_FOR_READ: 121962306a36Sopenharmony_ci /* Wait for data end? */ 122062306a36Sopenharmony_ci wait = sh_mmcif_read_block(host); 122162306a36Sopenharmony_ci break; 122262306a36Sopenharmony_ci case MMCIF_WAIT_FOR_MWRITE: 122362306a36Sopenharmony_ci /* Wait data to write? */ 122462306a36Sopenharmony_ci wait = sh_mmcif_mwrite_block(host); 122562306a36Sopenharmony_ci break; 122662306a36Sopenharmony_ci case MMCIF_WAIT_FOR_WRITE: 122762306a36Sopenharmony_ci /* Wait for data end? */ 122862306a36Sopenharmony_ci wait = sh_mmcif_write_block(host); 122962306a36Sopenharmony_ci break; 123062306a36Sopenharmony_ci case MMCIF_WAIT_FOR_STOP: 123162306a36Sopenharmony_ci if (host->sd_error) { 123262306a36Sopenharmony_ci mrq->stop->error = sh_mmcif_error_manage(host); 123362306a36Sopenharmony_ci dev_dbg(dev, "%s(): %d\n", __func__, mrq->stop->error); 123462306a36Sopenharmony_ci break; 123562306a36Sopenharmony_ci } 123662306a36Sopenharmony_ci sh_mmcif_get_cmd12response(host, mrq->stop); 123762306a36Sopenharmony_ci mrq->stop->error = 0; 123862306a36Sopenharmony_ci break; 123962306a36Sopenharmony_ci case MMCIF_WAIT_FOR_READ_END: 124062306a36Sopenharmony_ci case MMCIF_WAIT_FOR_WRITE_END: 124162306a36Sopenharmony_ci if (host->sd_error) { 124262306a36Sopenharmony_ci mrq->data->error = sh_mmcif_error_manage(host); 124362306a36Sopenharmony_ci dev_dbg(dev, "%s(): %d\n", __func__, mrq->data->error); 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci break; 124662306a36Sopenharmony_ci default: 124762306a36Sopenharmony_ci BUG(); 124862306a36Sopenharmony_ci } 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_ci if (wait) { 125162306a36Sopenharmony_ci schedule_delayed_work(&host->timeout_work, host->timeout); 125262306a36Sopenharmony_ci /* Wait for more data */ 125362306a36Sopenharmony_ci mutex_unlock(&host->thread_lock); 125462306a36Sopenharmony_ci return IRQ_HANDLED; 125562306a36Sopenharmony_ci } 125662306a36Sopenharmony_ci 125762306a36Sopenharmony_ci if (host->wait_for != MMCIF_WAIT_FOR_STOP) { 125862306a36Sopenharmony_ci struct mmc_data *data = mrq->data; 125962306a36Sopenharmony_ci if (!mrq->cmd->error && data && !data->error) 126062306a36Sopenharmony_ci data->bytes_xfered = 126162306a36Sopenharmony_ci data->blocks * data->blksz; 126262306a36Sopenharmony_ci 126362306a36Sopenharmony_ci if (mrq->stop && !mrq->cmd->error && (!data || !data->error)) { 126462306a36Sopenharmony_ci sh_mmcif_stop_cmd(host, mrq); 126562306a36Sopenharmony_ci if (!mrq->stop->error) { 126662306a36Sopenharmony_ci schedule_delayed_work(&host->timeout_work, host->timeout); 126762306a36Sopenharmony_ci mutex_unlock(&host->thread_lock); 126862306a36Sopenharmony_ci return IRQ_HANDLED; 126962306a36Sopenharmony_ci } 127062306a36Sopenharmony_ci } 127162306a36Sopenharmony_ci } 127262306a36Sopenharmony_ci 127362306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_REQUEST; 127462306a36Sopenharmony_ci host->state = STATE_IDLE; 127562306a36Sopenharmony_ci host->mrq = NULL; 127662306a36Sopenharmony_ci mmc_request_done(host->mmc, mrq); 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci mutex_unlock(&host->thread_lock); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci return IRQ_HANDLED; 128162306a36Sopenharmony_ci} 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic irqreturn_t sh_mmcif_intr(int irq, void *dev_id) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct sh_mmcif_host *host = dev_id; 128662306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 128762306a36Sopenharmony_ci u32 state, mask; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci state = sh_mmcif_readl(host->addr, MMCIF_CE_INT); 129062306a36Sopenharmony_ci mask = sh_mmcif_readl(host->addr, MMCIF_CE_INT_MASK); 129162306a36Sopenharmony_ci if (host->ccs_enable) 129262306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT, ~(state & mask)); 129362306a36Sopenharmony_ci else 129462306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT, INT_CCS | ~(state & mask)); 129562306a36Sopenharmony_ci sh_mmcif_bitclr(host, MMCIF_CE_INT_MASK, state & MASK_CLEAN); 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci if (state & ~MASK_CLEAN) 129862306a36Sopenharmony_ci dev_dbg(dev, "IRQ state = 0x%08x incompletely cleared\n", 129962306a36Sopenharmony_ci state); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (state & INT_ERR_STS || state & ~INT_ALL) { 130262306a36Sopenharmony_ci host->sd_error = true; 130362306a36Sopenharmony_ci dev_dbg(dev, "int err state = 0x%08x\n", state); 130462306a36Sopenharmony_ci } 130562306a36Sopenharmony_ci if (state & ~(INT_CMD12RBE | INT_CMD12CRE)) { 130662306a36Sopenharmony_ci if (!host->mrq) 130762306a36Sopenharmony_ci dev_dbg(dev, "NULL IRQ state = 0x%08x\n", state); 130862306a36Sopenharmony_ci if (!host->dma_active) 130962306a36Sopenharmony_ci return IRQ_WAKE_THREAD; 131062306a36Sopenharmony_ci else if (host->sd_error) 131162306a36Sopenharmony_ci sh_mmcif_dma_complete(host); 131262306a36Sopenharmony_ci } else { 131362306a36Sopenharmony_ci dev_dbg(dev, "Unexpected IRQ 0x%x\n", state); 131462306a36Sopenharmony_ci } 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci return IRQ_HANDLED; 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistatic void sh_mmcif_timeout_work(struct work_struct *work) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci struct delayed_work *d = to_delayed_work(work); 132262306a36Sopenharmony_ci struct sh_mmcif_host *host = container_of(d, struct sh_mmcif_host, timeout_work); 132362306a36Sopenharmony_ci struct mmc_request *mrq = host->mrq; 132462306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 132562306a36Sopenharmony_ci unsigned long flags; 132662306a36Sopenharmony_ci 132762306a36Sopenharmony_ci if (host->dying) 132862306a36Sopenharmony_ci /* Don't run after mmc_remove_host() */ 132962306a36Sopenharmony_ci return; 133062306a36Sopenharmony_ci 133162306a36Sopenharmony_ci spin_lock_irqsave(&host->lock, flags); 133262306a36Sopenharmony_ci if (host->state == STATE_IDLE) { 133362306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 133462306a36Sopenharmony_ci return; 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci 133762306a36Sopenharmony_ci dev_err(dev, "Timeout waiting for %u on CMD%u\n", 133862306a36Sopenharmony_ci host->wait_for, mrq->cmd->opcode); 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci host->state = STATE_TIMEOUT; 134162306a36Sopenharmony_ci spin_unlock_irqrestore(&host->lock, flags); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci /* 134462306a36Sopenharmony_ci * Handle races with cancel_delayed_work(), unless 134562306a36Sopenharmony_ci * cancel_delayed_work_sync() is used 134662306a36Sopenharmony_ci */ 134762306a36Sopenharmony_ci switch (host->wait_for) { 134862306a36Sopenharmony_ci case MMCIF_WAIT_FOR_CMD: 134962306a36Sopenharmony_ci mrq->cmd->error = sh_mmcif_error_manage(host); 135062306a36Sopenharmony_ci break; 135162306a36Sopenharmony_ci case MMCIF_WAIT_FOR_STOP: 135262306a36Sopenharmony_ci mrq->stop->error = sh_mmcif_error_manage(host); 135362306a36Sopenharmony_ci break; 135462306a36Sopenharmony_ci case MMCIF_WAIT_FOR_MREAD: 135562306a36Sopenharmony_ci case MMCIF_WAIT_FOR_MWRITE: 135662306a36Sopenharmony_ci case MMCIF_WAIT_FOR_READ: 135762306a36Sopenharmony_ci case MMCIF_WAIT_FOR_WRITE: 135862306a36Sopenharmony_ci case MMCIF_WAIT_FOR_READ_END: 135962306a36Sopenharmony_ci case MMCIF_WAIT_FOR_WRITE_END: 136062306a36Sopenharmony_ci mrq->data->error = sh_mmcif_error_manage(host); 136162306a36Sopenharmony_ci break; 136262306a36Sopenharmony_ci default: 136362306a36Sopenharmony_ci BUG(); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci host->state = STATE_IDLE; 136762306a36Sopenharmony_ci host->wait_for = MMCIF_WAIT_FOR_REQUEST; 136862306a36Sopenharmony_ci host->mrq = NULL; 136962306a36Sopenharmony_ci mmc_request_done(host->mmc, mrq); 137062306a36Sopenharmony_ci} 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_cistatic void sh_mmcif_init_ocr(struct sh_mmcif_host *host) 137362306a36Sopenharmony_ci{ 137462306a36Sopenharmony_ci struct device *dev = sh_mmcif_host_to_dev(host); 137562306a36Sopenharmony_ci struct sh_mmcif_plat_data *pd = dev->platform_data; 137662306a36Sopenharmony_ci struct mmc_host *mmc = host->mmc; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci mmc_regulator_get_supply(mmc); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci if (!pd) 138162306a36Sopenharmony_ci return; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (!mmc->ocr_avail) 138462306a36Sopenharmony_ci mmc->ocr_avail = pd->ocr; 138562306a36Sopenharmony_ci else if (pd->ocr) 138662306a36Sopenharmony_ci dev_warn(mmc_dev(mmc), "Platform OCR mask is ignored\n"); 138762306a36Sopenharmony_ci} 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_cistatic int sh_mmcif_probe(struct platform_device *pdev) 139062306a36Sopenharmony_ci{ 139162306a36Sopenharmony_ci int ret = 0, irq[2]; 139262306a36Sopenharmony_ci struct mmc_host *mmc; 139362306a36Sopenharmony_ci struct sh_mmcif_host *host; 139462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 139562306a36Sopenharmony_ci struct sh_mmcif_plat_data *pd = dev->platform_data; 139662306a36Sopenharmony_ci void __iomem *reg; 139762306a36Sopenharmony_ci const char *name; 139862306a36Sopenharmony_ci 139962306a36Sopenharmony_ci irq[0] = platform_get_irq(pdev, 0); 140062306a36Sopenharmony_ci irq[1] = platform_get_irq_optional(pdev, 1); 140162306a36Sopenharmony_ci if (irq[0] < 0) 140262306a36Sopenharmony_ci return irq[0]; 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci reg = devm_platform_ioremap_resource(pdev, 0); 140562306a36Sopenharmony_ci if (IS_ERR(reg)) 140662306a36Sopenharmony_ci return PTR_ERR(reg); 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci mmc = mmc_alloc_host(sizeof(struct sh_mmcif_host), dev); 140962306a36Sopenharmony_ci if (!mmc) 141062306a36Sopenharmony_ci return -ENOMEM; 141162306a36Sopenharmony_ci 141262306a36Sopenharmony_ci ret = mmc_of_parse(mmc); 141362306a36Sopenharmony_ci if (ret < 0) 141462306a36Sopenharmony_ci goto err_host; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci host = mmc_priv(mmc); 141762306a36Sopenharmony_ci host->mmc = mmc; 141862306a36Sopenharmony_ci host->addr = reg; 141962306a36Sopenharmony_ci host->timeout = msecs_to_jiffies(10000); 142062306a36Sopenharmony_ci host->ccs_enable = true; 142162306a36Sopenharmony_ci host->clk_ctrl2_enable = false; 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci host->pd = pdev; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci spin_lock_init(&host->lock); 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci mmc->ops = &sh_mmcif_ops; 142862306a36Sopenharmony_ci sh_mmcif_init_ocr(host); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_WAIT_WHILE_BUSY; 143162306a36Sopenharmony_ci mmc->caps2 |= MMC_CAP2_NO_SD | MMC_CAP2_NO_SDIO; 143262306a36Sopenharmony_ci mmc->max_busy_timeout = 10000; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci if (pd && pd->caps) 143562306a36Sopenharmony_ci mmc->caps |= pd->caps; 143662306a36Sopenharmony_ci mmc->max_segs = 32; 143762306a36Sopenharmony_ci mmc->max_blk_size = 512; 143862306a36Sopenharmony_ci mmc->max_req_size = PAGE_SIZE * mmc->max_segs; 143962306a36Sopenharmony_ci mmc->max_blk_count = mmc->max_req_size / mmc->max_blk_size; 144062306a36Sopenharmony_ci mmc->max_seg_size = mmc->max_req_size; 144162306a36Sopenharmony_ci 144262306a36Sopenharmony_ci platform_set_drvdata(pdev, host); 144362306a36Sopenharmony_ci 144462306a36Sopenharmony_ci host->clk = devm_clk_get(dev, NULL); 144562306a36Sopenharmony_ci if (IS_ERR(host->clk)) { 144662306a36Sopenharmony_ci ret = PTR_ERR(host->clk); 144762306a36Sopenharmony_ci dev_err(dev, "cannot get clock: %d\n", ret); 144862306a36Sopenharmony_ci goto err_host; 144962306a36Sopenharmony_ci } 145062306a36Sopenharmony_ci 145162306a36Sopenharmony_ci ret = clk_prepare_enable(host->clk); 145262306a36Sopenharmony_ci if (ret < 0) 145362306a36Sopenharmony_ci goto err_host; 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci sh_mmcif_clk_setup(host); 145662306a36Sopenharmony_ci 145762306a36Sopenharmony_ci pm_runtime_enable(dev); 145862306a36Sopenharmony_ci host->power = false; 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci ret = pm_runtime_get_sync(dev); 146162306a36Sopenharmony_ci if (ret < 0) 146262306a36Sopenharmony_ci goto err_clk; 146362306a36Sopenharmony_ci 146462306a36Sopenharmony_ci INIT_DELAYED_WORK(&host->timeout_work, sh_mmcif_timeout_work); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci sh_mmcif_sync_reset(host); 146762306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); 146862306a36Sopenharmony_ci 146962306a36Sopenharmony_ci name = irq[1] < 0 ? dev_name(dev) : "sh_mmc:error"; 147062306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, irq[0], sh_mmcif_intr, 147162306a36Sopenharmony_ci sh_mmcif_irqt, 0, name, host); 147262306a36Sopenharmony_ci if (ret) { 147362306a36Sopenharmony_ci dev_err(dev, "request_irq error (%s)\n", name); 147462306a36Sopenharmony_ci goto err_clk; 147562306a36Sopenharmony_ci } 147662306a36Sopenharmony_ci if (irq[1] >= 0) { 147762306a36Sopenharmony_ci ret = devm_request_threaded_irq(dev, irq[1], 147862306a36Sopenharmony_ci sh_mmcif_intr, sh_mmcif_irqt, 147962306a36Sopenharmony_ci 0, "sh_mmc:int", host); 148062306a36Sopenharmony_ci if (ret) { 148162306a36Sopenharmony_ci dev_err(dev, "request_irq error (sh_mmc:int)\n"); 148262306a36Sopenharmony_ci goto err_clk; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci } 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci mutex_init(&host->thread_lock); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci ret = mmc_add_host(mmc); 148962306a36Sopenharmony_ci if (ret < 0) 149062306a36Sopenharmony_ci goto err_clk; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci dev_pm_qos_expose_latency_limit(dev, 100); 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci dev_info(dev, "Chip version 0x%04x, clock rate %luMHz\n", 149562306a36Sopenharmony_ci sh_mmcif_readl(host->addr, MMCIF_CE_VERSION) & 0xffff, 149662306a36Sopenharmony_ci clk_get_rate(host->clk) / 1000000UL); 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci pm_runtime_put(dev); 149962306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 150062306a36Sopenharmony_ci return ret; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_cierr_clk: 150362306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 150462306a36Sopenharmony_ci pm_runtime_put_sync(dev); 150562306a36Sopenharmony_ci pm_runtime_disable(dev); 150662306a36Sopenharmony_cierr_host: 150762306a36Sopenharmony_ci mmc_free_host(mmc); 150862306a36Sopenharmony_ci return ret; 150962306a36Sopenharmony_ci} 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_cistatic void sh_mmcif_remove(struct platform_device *pdev) 151262306a36Sopenharmony_ci{ 151362306a36Sopenharmony_ci struct sh_mmcif_host *host = platform_get_drvdata(pdev); 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci host->dying = true; 151662306a36Sopenharmony_ci clk_prepare_enable(host->clk); 151762306a36Sopenharmony_ci pm_runtime_get_sync(&pdev->dev); 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci dev_pm_qos_hide_latency_limit(&pdev->dev); 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci mmc_remove_host(host->mmc); 152262306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci /* 152562306a36Sopenharmony_ci * FIXME: cancel_delayed_work(_sync)() and free_irq() race with the 152662306a36Sopenharmony_ci * mmc_remove_host() call above. But swapping order doesn't help either 152762306a36Sopenharmony_ci * (a query on the linux-mmc mailing list didn't bring any replies). 152862306a36Sopenharmony_ci */ 152962306a36Sopenharmony_ci cancel_delayed_work_sync(&host->timeout_work); 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_ci clk_disable_unprepare(host->clk); 153262306a36Sopenharmony_ci mmc_free_host(host->mmc); 153362306a36Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 153462306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 153562306a36Sopenharmony_ci} 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 153862306a36Sopenharmony_cistatic int sh_mmcif_suspend(struct device *dev) 153962306a36Sopenharmony_ci{ 154062306a36Sopenharmony_ci struct sh_mmcif_host *host = dev_get_drvdata(dev); 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci pm_runtime_get_sync(dev); 154362306a36Sopenharmony_ci sh_mmcif_writel(host->addr, MMCIF_CE_INT_MASK, MASK_ALL); 154462306a36Sopenharmony_ci pm_runtime_put(dev); 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci return 0; 154762306a36Sopenharmony_ci} 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cistatic int sh_mmcif_resume(struct device *dev) 155062306a36Sopenharmony_ci{ 155162306a36Sopenharmony_ci return 0; 155262306a36Sopenharmony_ci} 155362306a36Sopenharmony_ci#endif 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_cistatic const struct dev_pm_ops sh_mmcif_dev_pm_ops = { 155662306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(sh_mmcif_suspend, sh_mmcif_resume) 155762306a36Sopenharmony_ci}; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_cistatic struct platform_driver sh_mmcif_driver = { 156062306a36Sopenharmony_ci .probe = sh_mmcif_probe, 156162306a36Sopenharmony_ci .remove_new = sh_mmcif_remove, 156262306a36Sopenharmony_ci .driver = { 156362306a36Sopenharmony_ci .name = DRIVER_NAME, 156462306a36Sopenharmony_ci .probe_type = PROBE_PREFER_ASYNCHRONOUS, 156562306a36Sopenharmony_ci .pm = &sh_mmcif_dev_pm_ops, 156662306a36Sopenharmony_ci .of_match_table = sh_mmcif_of_match, 156762306a36Sopenharmony_ci }, 156862306a36Sopenharmony_ci}; 156962306a36Sopenharmony_ci 157062306a36Sopenharmony_cimodule_platform_driver(sh_mmcif_driver); 157162306a36Sopenharmony_ci 157262306a36Sopenharmony_ciMODULE_DESCRIPTION("SuperH on-chip MMC/eMMC interface driver"); 157362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 157462306a36Sopenharmony_ciMODULE_ALIAS("platform:" DRIVER_NAME); 157562306a36Sopenharmony_ciMODULE_AUTHOR("Yusuke Goda <yusuke.goda.sx@renesas.com>"); 1576