1afb35666SYoshihiro Shimoda /* 2afb35666SYoshihiro Shimoda * MMCIF driver. 3afb35666SYoshihiro Shimoda * 4afb35666SYoshihiro Shimoda * Copyright (C) 2011 Renesas Solutions Corp. 5afb35666SYoshihiro Shimoda * 65b8031ccSTom Rini * SPDX-License-Identifier: GPL-2.0 7afb35666SYoshihiro Shimoda */ 8afb35666SYoshihiro Shimoda 9afb35666SYoshihiro Shimoda #include <config.h> 10afb35666SYoshihiro Shimoda #include <common.h> 11afb35666SYoshihiro Shimoda #include <watchdog.h> 12afb35666SYoshihiro Shimoda #include <command.h> 13afb35666SYoshihiro Shimoda #include <mmc.h> 14*48f54a2dSMarek Vasut #include <clk.h> 15*48f54a2dSMarek Vasut #include <dm.h> 16afb35666SYoshihiro Shimoda #include <malloc.h> 171221ce45SMasahiro Yamada #include <linux/errno.h> 18*48f54a2dSMarek Vasut #include <linux/compat.h> 19*48f54a2dSMarek Vasut #include <linux/io.h> 20*48f54a2dSMarek Vasut #include <linux/sizes.h> 21afb35666SYoshihiro Shimoda #include "sh_mmcif.h" 22afb35666SYoshihiro Shimoda 23afb35666SYoshihiro Shimoda #define DRIVER_NAME "sh_mmcif" 24afb35666SYoshihiro Shimoda 25afb35666SYoshihiro Shimoda static int sh_mmcif_intr(void *dev_id) 26afb35666SYoshihiro Shimoda { 27afb35666SYoshihiro Shimoda struct sh_mmcif_host *host = dev_id; 28afb35666SYoshihiro Shimoda u32 state = 0; 29afb35666SYoshihiro Shimoda 30afb35666SYoshihiro Shimoda state = sh_mmcif_read(&host->regs->ce_int); 31afb35666SYoshihiro Shimoda state &= sh_mmcif_read(&host->regs->ce_int_mask); 32afb35666SYoshihiro Shimoda 33afb35666SYoshihiro Shimoda if (state & INT_RBSYE) { 34afb35666SYoshihiro Shimoda sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int); 35afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask); 36afb35666SYoshihiro Shimoda goto end; 37afb35666SYoshihiro Shimoda } else if (state & INT_CRSPE) { 38afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int); 39afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask); 40afb35666SYoshihiro Shimoda /* one more interrupt (INT_RBSYE) */ 41afb35666SYoshihiro Shimoda if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY) 42afb35666SYoshihiro Shimoda return -EAGAIN; 43afb35666SYoshihiro Shimoda goto end; 44afb35666SYoshihiro Shimoda } else if (state & INT_BUFREN) { 45afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int); 46afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask); 47afb35666SYoshihiro Shimoda goto end; 48afb35666SYoshihiro Shimoda } else if (state & INT_BUFWEN) { 49afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int); 50afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask); 51afb35666SYoshihiro Shimoda goto end; 52afb35666SYoshihiro Shimoda } else if (state & INT_CMD12DRE) { 53afb35666SYoshihiro Shimoda sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | 54afb35666SYoshihiro Shimoda INT_BUFRE), &host->regs->ce_int); 55afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask); 56afb35666SYoshihiro Shimoda goto end; 57afb35666SYoshihiro Shimoda } else if (state & INT_BUFRE) { 58afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int); 59afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask); 60afb35666SYoshihiro Shimoda goto end; 61afb35666SYoshihiro Shimoda } else if (state & INT_DTRANE) { 62afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int); 63afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask); 64afb35666SYoshihiro Shimoda goto end; 65afb35666SYoshihiro Shimoda } else if (state & INT_CMD12RBE) { 66afb35666SYoshihiro Shimoda sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE), 67afb35666SYoshihiro Shimoda &host->regs->ce_int); 68afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask); 69afb35666SYoshihiro Shimoda goto end; 70afb35666SYoshihiro Shimoda } else if (state & INT_ERR_STS) { 71afb35666SYoshihiro Shimoda /* err interrupts */ 72afb35666SYoshihiro Shimoda sh_mmcif_write(~state, &host->regs->ce_int); 73afb35666SYoshihiro Shimoda sh_mmcif_bitclr(state, &host->regs->ce_int_mask); 74afb35666SYoshihiro Shimoda goto err; 75afb35666SYoshihiro Shimoda } else 76afb35666SYoshihiro Shimoda return -EAGAIN; 77afb35666SYoshihiro Shimoda 78afb35666SYoshihiro Shimoda err: 79afb35666SYoshihiro Shimoda host->sd_error = 1; 80afb35666SYoshihiro Shimoda debug("%s: int err state = %08x\n", DRIVER_NAME, state); 81afb35666SYoshihiro Shimoda end: 82afb35666SYoshihiro Shimoda host->wait_int = 1; 83afb35666SYoshihiro Shimoda return 0; 84afb35666SYoshihiro Shimoda } 85afb35666SYoshihiro Shimoda 86afb35666SYoshihiro Shimoda static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host) 87afb35666SYoshihiro Shimoda { 88afb35666SYoshihiro Shimoda int timeout = 10000000; 89afb35666SYoshihiro Shimoda 90afb35666SYoshihiro Shimoda while (1) { 91afb35666SYoshihiro Shimoda timeout--; 92afb35666SYoshihiro Shimoda if (timeout < 0) { 93afb35666SYoshihiro Shimoda printf("timeout\n"); 94afb35666SYoshihiro Shimoda return 0; 95afb35666SYoshihiro Shimoda } 96afb35666SYoshihiro Shimoda 97afb35666SYoshihiro Shimoda if (!sh_mmcif_intr(host)) 98afb35666SYoshihiro Shimoda break; 99afb35666SYoshihiro Shimoda 100afb35666SYoshihiro Shimoda udelay(1); /* 1 usec */ 101afb35666SYoshihiro Shimoda } 102afb35666SYoshihiro Shimoda 103afb35666SYoshihiro Shimoda return 1; /* Return value: NOT 0 = complete waiting */ 104afb35666SYoshihiro Shimoda } 105afb35666SYoshihiro Shimoda 106afb35666SYoshihiro Shimoda static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) 107afb35666SYoshihiro Shimoda { 108afb35666SYoshihiro Shimoda sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl); 109afb35666SYoshihiro Shimoda sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl); 110afb35666SYoshihiro Shimoda 111afb35666SYoshihiro Shimoda if (!clk) 112afb35666SYoshihiro Shimoda return; 11321ea3503SNobuhiro Iwamatsu 11421ea3503SNobuhiro Iwamatsu if (clk == CLKDEV_EMMC_DATA) 115afb35666SYoshihiro Shimoda sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl); 11621ea3503SNobuhiro Iwamatsu else 11721ea3503SNobuhiro Iwamatsu sh_mmcif_bitset((fls(DIV_ROUND_UP(host->clk, 11821ea3503SNobuhiro Iwamatsu clk) - 1) - 1) << 16, 11921ea3503SNobuhiro Iwamatsu &host->regs->ce_clk_ctrl); 120afb35666SYoshihiro Shimoda sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl); 121afb35666SYoshihiro Shimoda } 122afb35666SYoshihiro Shimoda 123afb35666SYoshihiro Shimoda static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) 124afb35666SYoshihiro Shimoda { 125afb35666SYoshihiro Shimoda u32 tmp; 126afb35666SYoshihiro Shimoda 127afb35666SYoshihiro Shimoda tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE | 128afb35666SYoshihiro Shimoda CLK_CLEAR); 129afb35666SYoshihiro Shimoda 130afb35666SYoshihiro Shimoda sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version); 131afb35666SYoshihiro Shimoda sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version); 132afb35666SYoshihiro Shimoda sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29, 133afb35666SYoshihiro Shimoda &host->regs->ce_clk_ctrl); 134afb35666SYoshihiro Shimoda /* byte swap on */ 135afb35666SYoshihiro Shimoda sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc); 136afb35666SYoshihiro Shimoda } 137afb35666SYoshihiro Shimoda 138afb35666SYoshihiro Shimoda static int sh_mmcif_error_manage(struct sh_mmcif_host *host) 139afb35666SYoshihiro Shimoda { 140afb35666SYoshihiro Shimoda u32 state1, state2; 141afb35666SYoshihiro Shimoda int ret, timeout = 10000000; 142afb35666SYoshihiro Shimoda 143afb35666SYoshihiro Shimoda host->sd_error = 0; 144afb35666SYoshihiro Shimoda host->wait_int = 0; 145afb35666SYoshihiro Shimoda 146afb35666SYoshihiro Shimoda state1 = sh_mmcif_read(&host->regs->ce_host_sts1); 147afb35666SYoshihiro Shimoda state2 = sh_mmcif_read(&host->regs->ce_host_sts2); 148afb35666SYoshihiro Shimoda debug("%s: ERR HOST_STS1 = %08x\n", \ 149afb35666SYoshihiro Shimoda DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1)); 150afb35666SYoshihiro Shimoda debug("%s: ERR HOST_STS2 = %08x\n", \ 151afb35666SYoshihiro Shimoda DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2)); 152afb35666SYoshihiro Shimoda 153afb35666SYoshihiro Shimoda if (state1 & STS1_CMDSEQ) { 154afb35666SYoshihiro Shimoda debug("%s: Forced end of command sequence\n", DRIVER_NAME); 155afb35666SYoshihiro Shimoda sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); 156afb35666SYoshihiro Shimoda sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); 157afb35666SYoshihiro Shimoda while (1) { 158afb35666SYoshihiro Shimoda timeout--; 159afb35666SYoshihiro Shimoda if (timeout < 0) { 160afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Forceed end of " \ 161afb35666SYoshihiro Shimoda "command sequence timeout err\n"); 162afb35666SYoshihiro Shimoda return -EILSEQ; 163afb35666SYoshihiro Shimoda } 164afb35666SYoshihiro Shimoda if (!(sh_mmcif_read(&host->regs->ce_host_sts1) 165afb35666SYoshihiro Shimoda & STS1_CMDSEQ)) 166afb35666SYoshihiro Shimoda break; 167afb35666SYoshihiro Shimoda } 168afb35666SYoshihiro Shimoda sh_mmcif_sync_reset(host); 169afb35666SYoshihiro Shimoda return -EILSEQ; 170afb35666SYoshihiro Shimoda } 171afb35666SYoshihiro Shimoda 172afb35666SYoshihiro Shimoda if (state2 & STS2_CRC_ERR) 173afb35666SYoshihiro Shimoda ret = -EILSEQ; 174afb35666SYoshihiro Shimoda else if (state2 & STS2_TIMEOUT_ERR) 175915ffa52SJaehoon Chung ret = -ETIMEDOUT; 176afb35666SYoshihiro Shimoda else 177afb35666SYoshihiro Shimoda ret = -EILSEQ; 178afb35666SYoshihiro Shimoda return ret; 179afb35666SYoshihiro Shimoda } 180afb35666SYoshihiro Shimoda 181afb35666SYoshihiro Shimoda static int sh_mmcif_single_read(struct sh_mmcif_host *host, 182afb35666SYoshihiro Shimoda struct mmc_data *data) 183afb35666SYoshihiro Shimoda { 184afb35666SYoshihiro Shimoda long time; 185afb35666SYoshihiro Shimoda u32 blocksize, i; 186afb35666SYoshihiro Shimoda unsigned long *p = (unsigned long *)data->dest; 187afb35666SYoshihiro Shimoda 188afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 189afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 190afb35666SYoshihiro Shimoda return -EIO; 191afb35666SYoshihiro Shimoda } 192afb35666SYoshihiro Shimoda 193afb35666SYoshihiro Shimoda host->wait_int = 0; 194afb35666SYoshihiro Shimoda 195afb35666SYoshihiro Shimoda /* buf read enable */ 196afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); 197afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 198afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 199afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 200afb35666SYoshihiro Shimoda 201afb35666SYoshihiro Shimoda host->wait_int = 0; 202afb35666SYoshihiro Shimoda blocksize = (BLOCK_SIZE_MASK & 203afb35666SYoshihiro Shimoda sh_mmcif_read(&host->regs->ce_block_set)) + 3; 204afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 205afb35666SYoshihiro Shimoda *p++ = sh_mmcif_read(&host->regs->ce_data); 206afb35666SYoshihiro Shimoda 207afb35666SYoshihiro Shimoda /* buffer read end */ 208afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask); 209afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 210afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 211afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 212afb35666SYoshihiro Shimoda 213afb35666SYoshihiro Shimoda host->wait_int = 0; 214afb35666SYoshihiro Shimoda return 0; 215afb35666SYoshihiro Shimoda } 216afb35666SYoshihiro Shimoda 217afb35666SYoshihiro Shimoda static int sh_mmcif_multi_read(struct sh_mmcif_host *host, 218afb35666SYoshihiro Shimoda struct mmc_data *data) 219afb35666SYoshihiro Shimoda { 220afb35666SYoshihiro Shimoda long time; 221afb35666SYoshihiro Shimoda u32 blocksize, i, j; 222afb35666SYoshihiro Shimoda unsigned long *p = (unsigned long *)data->dest; 223afb35666SYoshihiro Shimoda 224afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 225afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 226afb35666SYoshihiro Shimoda return -EIO; 227afb35666SYoshihiro Shimoda } 228afb35666SYoshihiro Shimoda 229afb35666SYoshihiro Shimoda host->wait_int = 0; 230afb35666SYoshihiro Shimoda blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); 231afb35666SYoshihiro Shimoda for (j = 0; j < data->blocks; j++) { 232afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); 233afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 234afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 235afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 236afb35666SYoshihiro Shimoda 237afb35666SYoshihiro Shimoda host->wait_int = 0; 238afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 239afb35666SYoshihiro Shimoda *p++ = sh_mmcif_read(&host->regs->ce_data); 240afb35666SYoshihiro Shimoda 241afb35666SYoshihiro Shimoda WATCHDOG_RESET(); 242afb35666SYoshihiro Shimoda } 243afb35666SYoshihiro Shimoda return 0; 244afb35666SYoshihiro Shimoda } 245afb35666SYoshihiro Shimoda 246afb35666SYoshihiro Shimoda static int sh_mmcif_single_write(struct sh_mmcif_host *host, 247afb35666SYoshihiro Shimoda struct mmc_data *data) 248afb35666SYoshihiro Shimoda { 249afb35666SYoshihiro Shimoda long time; 250afb35666SYoshihiro Shimoda u32 blocksize, i; 251afb35666SYoshihiro Shimoda const unsigned long *p = (unsigned long *)data->dest; 252afb35666SYoshihiro Shimoda 253afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 254afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 255afb35666SYoshihiro Shimoda return -EIO; 256afb35666SYoshihiro Shimoda } 257afb35666SYoshihiro Shimoda 258afb35666SYoshihiro Shimoda host->wait_int = 0; 259afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); 260afb35666SYoshihiro Shimoda 261afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 262afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 263afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 264afb35666SYoshihiro Shimoda 265afb35666SYoshihiro Shimoda host->wait_int = 0; 266afb35666SYoshihiro Shimoda blocksize = (BLOCK_SIZE_MASK & 267afb35666SYoshihiro Shimoda sh_mmcif_read(&host->regs->ce_block_set)) + 3; 268afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 269afb35666SYoshihiro Shimoda sh_mmcif_write(*p++, &host->regs->ce_data); 270afb35666SYoshihiro Shimoda 271afb35666SYoshihiro Shimoda /* buffer write end */ 272afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask); 273afb35666SYoshihiro Shimoda 274afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 275afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 276afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 277afb35666SYoshihiro Shimoda 278afb35666SYoshihiro Shimoda host->wait_int = 0; 279afb35666SYoshihiro Shimoda return 0; 280afb35666SYoshihiro Shimoda } 281afb35666SYoshihiro Shimoda 282afb35666SYoshihiro Shimoda static int sh_mmcif_multi_write(struct sh_mmcif_host *host, 283afb35666SYoshihiro Shimoda struct mmc_data *data) 284afb35666SYoshihiro Shimoda { 285afb35666SYoshihiro Shimoda long time; 286afb35666SYoshihiro Shimoda u32 i, j, blocksize; 287afb35666SYoshihiro Shimoda const unsigned long *p = (unsigned long *)data->dest; 288afb35666SYoshihiro Shimoda 289afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 290afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 291afb35666SYoshihiro Shimoda return -EIO; 292afb35666SYoshihiro Shimoda } 293afb35666SYoshihiro Shimoda 294afb35666SYoshihiro Shimoda host->wait_int = 0; 295afb35666SYoshihiro Shimoda blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); 296afb35666SYoshihiro Shimoda for (j = 0; j < data->blocks; j++) { 297afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); 298afb35666SYoshihiro Shimoda 299afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 300afb35666SYoshihiro Shimoda 301afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 302afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 303afb35666SYoshihiro Shimoda 304afb35666SYoshihiro Shimoda host->wait_int = 0; 305afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 306afb35666SYoshihiro Shimoda sh_mmcif_write(*p++, &host->regs->ce_data); 307afb35666SYoshihiro Shimoda 308afb35666SYoshihiro Shimoda WATCHDOG_RESET(); 309afb35666SYoshihiro Shimoda } 310afb35666SYoshihiro Shimoda return 0; 311afb35666SYoshihiro Shimoda } 312afb35666SYoshihiro Shimoda 313afb35666SYoshihiro Shimoda static void sh_mmcif_get_response(struct sh_mmcif_host *host, 314afb35666SYoshihiro Shimoda struct mmc_cmd *cmd) 315afb35666SYoshihiro Shimoda { 316afb35666SYoshihiro Shimoda if (cmd->resp_type & MMC_RSP_136) { 317afb35666SYoshihiro Shimoda cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3); 318afb35666SYoshihiro Shimoda cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2); 319afb35666SYoshihiro Shimoda cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1); 320afb35666SYoshihiro Shimoda cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0); 321afb35666SYoshihiro Shimoda debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0], 322afb35666SYoshihiro Shimoda cmd->response[1], cmd->response[2], cmd->response[3]); 323afb35666SYoshihiro Shimoda } else { 324afb35666SYoshihiro Shimoda cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0); 325afb35666SYoshihiro Shimoda } 326afb35666SYoshihiro Shimoda } 327afb35666SYoshihiro Shimoda 328afb35666SYoshihiro Shimoda static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, 329afb35666SYoshihiro Shimoda struct mmc_cmd *cmd) 330afb35666SYoshihiro Shimoda { 331afb35666SYoshihiro Shimoda cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12); 332afb35666SYoshihiro Shimoda } 333afb35666SYoshihiro Shimoda 334afb35666SYoshihiro Shimoda static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, 335afb35666SYoshihiro Shimoda struct mmc_data *data, struct mmc_cmd *cmd) 336afb35666SYoshihiro Shimoda { 337afb35666SYoshihiro Shimoda u32 tmp = 0; 338afb35666SYoshihiro Shimoda u32 opc = cmd->cmdidx; 339afb35666SYoshihiro Shimoda 340afb35666SYoshihiro Shimoda /* Response Type check */ 341afb35666SYoshihiro Shimoda switch (cmd->resp_type) { 342afb35666SYoshihiro Shimoda case MMC_RSP_NONE: 343afb35666SYoshihiro Shimoda tmp |= CMD_SET_RTYP_NO; 344afb35666SYoshihiro Shimoda break; 345afb35666SYoshihiro Shimoda case MMC_RSP_R1: 346afb35666SYoshihiro Shimoda case MMC_RSP_R1b: 347afb35666SYoshihiro Shimoda case MMC_RSP_R3: 348afb35666SYoshihiro Shimoda tmp |= CMD_SET_RTYP_6B; 349afb35666SYoshihiro Shimoda break; 350afb35666SYoshihiro Shimoda case MMC_RSP_R2: 351afb35666SYoshihiro Shimoda tmp |= CMD_SET_RTYP_17B; 352afb35666SYoshihiro Shimoda break; 353afb35666SYoshihiro Shimoda default: 354afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Not support type response.\n"); 355afb35666SYoshihiro Shimoda break; 356afb35666SYoshihiro Shimoda } 357afb35666SYoshihiro Shimoda 358afb35666SYoshihiro Shimoda /* RBSY */ 359afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SWITCH) 360afb35666SYoshihiro Shimoda tmp |= CMD_SET_RBSY; 361afb35666SYoshihiro Shimoda 362afb35666SYoshihiro Shimoda /* WDAT / DATW */ 363afb35666SYoshihiro Shimoda if (host->data) { 364afb35666SYoshihiro Shimoda tmp |= CMD_SET_WDAT; 365afb35666SYoshihiro Shimoda switch (host->bus_width) { 366afb35666SYoshihiro Shimoda case MMC_BUS_WIDTH_1: 367afb35666SYoshihiro Shimoda tmp |= CMD_SET_DATW_1; 368afb35666SYoshihiro Shimoda break; 369afb35666SYoshihiro Shimoda case MMC_BUS_WIDTH_4: 370afb35666SYoshihiro Shimoda tmp |= CMD_SET_DATW_4; 371afb35666SYoshihiro Shimoda break; 372afb35666SYoshihiro Shimoda case MMC_BUS_WIDTH_8: 373afb35666SYoshihiro Shimoda tmp |= CMD_SET_DATW_8; 374afb35666SYoshihiro Shimoda break; 375afb35666SYoshihiro Shimoda default: 376afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Not support bus width.\n"); 377afb35666SYoshihiro Shimoda break; 378afb35666SYoshihiro Shimoda } 379afb35666SYoshihiro Shimoda } 380afb35666SYoshihiro Shimoda /* DWEN */ 381afb35666SYoshihiro Shimoda if (opc == MMC_CMD_WRITE_SINGLE_BLOCK || 382afb35666SYoshihiro Shimoda opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) 383afb35666SYoshihiro Shimoda tmp |= CMD_SET_DWEN; 384afb35666SYoshihiro Shimoda /* CMLTE/CMD12EN */ 385afb35666SYoshihiro Shimoda if (opc == MMC_CMD_READ_MULTIPLE_BLOCK || 386afb35666SYoshihiro Shimoda opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) { 387afb35666SYoshihiro Shimoda tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; 388afb35666SYoshihiro Shimoda sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set); 389afb35666SYoshihiro Shimoda } 390afb35666SYoshihiro Shimoda /* RIDXC[1:0] check bits */ 391afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID || 392afb35666SYoshihiro Shimoda opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) 393afb35666SYoshihiro Shimoda tmp |= CMD_SET_RIDXC_BITS; 394afb35666SYoshihiro Shimoda /* RCRC7C[1:0] check bits */ 395afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SEND_OP_COND) 396afb35666SYoshihiro Shimoda tmp |= CMD_SET_CRC7C_BITS; 397afb35666SYoshihiro Shimoda /* RCRC7C[1:0] internal CRC7 */ 398afb35666SYoshihiro Shimoda if (opc == MMC_CMD_ALL_SEND_CID || 399afb35666SYoshihiro Shimoda opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) 400afb35666SYoshihiro Shimoda tmp |= CMD_SET_CRC7C_INTERNAL; 401afb35666SYoshihiro Shimoda 402afb35666SYoshihiro Shimoda return opc = ((opc << 24) | tmp); 403afb35666SYoshihiro Shimoda } 404afb35666SYoshihiro Shimoda 405afb35666SYoshihiro Shimoda static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host, 406afb35666SYoshihiro Shimoda struct mmc_data *data, u16 opc) 407afb35666SYoshihiro Shimoda { 408afb35666SYoshihiro Shimoda u32 ret; 409afb35666SYoshihiro Shimoda 410afb35666SYoshihiro Shimoda switch (opc) { 411afb35666SYoshihiro Shimoda case MMC_CMD_READ_MULTIPLE_BLOCK: 412afb35666SYoshihiro Shimoda ret = sh_mmcif_multi_read(host, data); 413afb35666SYoshihiro Shimoda break; 414afb35666SYoshihiro Shimoda case MMC_CMD_WRITE_MULTIPLE_BLOCK: 415afb35666SYoshihiro Shimoda ret = sh_mmcif_multi_write(host, data); 416afb35666SYoshihiro Shimoda break; 417afb35666SYoshihiro Shimoda case MMC_CMD_WRITE_SINGLE_BLOCK: 418afb35666SYoshihiro Shimoda ret = sh_mmcif_single_write(host, data); 419afb35666SYoshihiro Shimoda break; 420afb35666SYoshihiro Shimoda case MMC_CMD_READ_SINGLE_BLOCK: 421afb35666SYoshihiro Shimoda case MMC_CMD_SEND_EXT_CSD: 422afb35666SYoshihiro Shimoda ret = sh_mmcif_single_read(host, data); 423afb35666SYoshihiro Shimoda break; 424afb35666SYoshihiro Shimoda default: 425afb35666SYoshihiro Shimoda printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc); 426afb35666SYoshihiro Shimoda ret = -EINVAL; 427afb35666SYoshihiro Shimoda break; 428afb35666SYoshihiro Shimoda } 429afb35666SYoshihiro Shimoda return ret; 430afb35666SYoshihiro Shimoda } 431afb35666SYoshihiro Shimoda 432afb35666SYoshihiro Shimoda static int sh_mmcif_start_cmd(struct sh_mmcif_host *host, 433afb35666SYoshihiro Shimoda struct mmc_data *data, struct mmc_cmd *cmd) 434afb35666SYoshihiro Shimoda { 435afb35666SYoshihiro Shimoda long time; 436afb35666SYoshihiro Shimoda int ret = 0, mask = 0; 437afb35666SYoshihiro Shimoda u32 opc = cmd->cmdidx; 438afb35666SYoshihiro Shimoda 439afb35666SYoshihiro Shimoda if (opc == MMC_CMD_STOP_TRANSMISSION) { 440afb35666SYoshihiro Shimoda /* MMCIF sends the STOP command automatically */ 441afb35666SYoshihiro Shimoda if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK) 442afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MCMD12DRE, 443afb35666SYoshihiro Shimoda &host->regs->ce_int_mask); 444afb35666SYoshihiro Shimoda else 445afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MCMD12RBE, 446afb35666SYoshihiro Shimoda &host->regs->ce_int_mask); 447afb35666SYoshihiro Shimoda 448afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 449afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 450afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 451afb35666SYoshihiro Shimoda 452afb35666SYoshihiro Shimoda sh_mmcif_get_cmd12response(host, cmd); 453afb35666SYoshihiro Shimoda return 0; 454afb35666SYoshihiro Shimoda } 455afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SWITCH) 456afb35666SYoshihiro Shimoda mask = MASK_MRBSYE; 457afb35666SYoshihiro Shimoda else 458afb35666SYoshihiro Shimoda mask = MASK_MCRSPE; 459afb35666SYoshihiro Shimoda 460afb35666SYoshihiro Shimoda mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | 461afb35666SYoshihiro Shimoda MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | 462afb35666SYoshihiro Shimoda MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | 463afb35666SYoshihiro Shimoda MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; 464afb35666SYoshihiro Shimoda 465afb35666SYoshihiro Shimoda if (host->data) { 466afb35666SYoshihiro Shimoda sh_mmcif_write(0, &host->regs->ce_block_set); 467afb35666SYoshihiro Shimoda sh_mmcif_write(data->blocksize, &host->regs->ce_block_set); 468afb35666SYoshihiro Shimoda } 469afb35666SYoshihiro Shimoda opc = sh_mmcif_set_cmd(host, data, cmd); 470afb35666SYoshihiro Shimoda 471afb35666SYoshihiro Shimoda sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int); 472afb35666SYoshihiro Shimoda sh_mmcif_write(mask, &host->regs->ce_int_mask); 473afb35666SYoshihiro Shimoda 474afb35666SYoshihiro Shimoda debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg); 475afb35666SYoshihiro Shimoda /* set arg */ 476afb35666SYoshihiro Shimoda sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg); 477afb35666SYoshihiro Shimoda host->wait_int = 0; 478afb35666SYoshihiro Shimoda /* set cmd */ 479afb35666SYoshihiro Shimoda sh_mmcif_write(opc, &host->regs->ce_cmd_set); 480afb35666SYoshihiro Shimoda 481afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 482afb35666SYoshihiro Shimoda if (time == 0) 483afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 484afb35666SYoshihiro Shimoda 485afb35666SYoshihiro Shimoda if (host->sd_error) { 486afb35666SYoshihiro Shimoda switch (cmd->cmdidx) { 487afb35666SYoshihiro Shimoda case MMC_CMD_ALL_SEND_CID: 488afb35666SYoshihiro Shimoda case MMC_CMD_SELECT_CARD: 489afb35666SYoshihiro Shimoda case MMC_CMD_APP_CMD: 490915ffa52SJaehoon Chung ret = -ETIMEDOUT; 491afb35666SYoshihiro Shimoda break; 492afb35666SYoshihiro Shimoda default: 493afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx); 494afb35666SYoshihiro Shimoda ret = sh_mmcif_error_manage(host); 495afb35666SYoshihiro Shimoda break; 496afb35666SYoshihiro Shimoda } 497afb35666SYoshihiro Shimoda host->sd_error = 0; 498afb35666SYoshihiro Shimoda host->wait_int = 0; 499afb35666SYoshihiro Shimoda return ret; 500afb35666SYoshihiro Shimoda } 501afb35666SYoshihiro Shimoda 502afb35666SYoshihiro Shimoda /* if no response */ 503afb35666SYoshihiro Shimoda if (!(opc & 0x00C00000)) 504afb35666SYoshihiro Shimoda return 0; 505afb35666SYoshihiro Shimoda 506afb35666SYoshihiro Shimoda if (host->wait_int == 1) { 507afb35666SYoshihiro Shimoda sh_mmcif_get_response(host, cmd); 508afb35666SYoshihiro Shimoda host->wait_int = 0; 509afb35666SYoshihiro Shimoda } 510afb35666SYoshihiro Shimoda if (host->data) 511afb35666SYoshihiro Shimoda ret = sh_mmcif_data_trans(host, data, cmd->cmdidx); 512afb35666SYoshihiro Shimoda host->last_cmd = cmd->cmdidx; 513afb35666SYoshihiro Shimoda 514afb35666SYoshihiro Shimoda return ret; 515afb35666SYoshihiro Shimoda } 516afb35666SYoshihiro Shimoda 517*48f54a2dSMarek Vasut static int sh_mmcif_send_cmd_common(struct sh_mmcif_host *host, 518*48f54a2dSMarek Vasut struct mmc_cmd *cmd, struct mmc_data *data) 519afb35666SYoshihiro Shimoda { 520afb35666SYoshihiro Shimoda int ret; 521afb35666SYoshihiro Shimoda 522afb35666SYoshihiro Shimoda WATCHDOG_RESET(); 523afb35666SYoshihiro Shimoda 524afb35666SYoshihiro Shimoda switch (cmd->cmdidx) { 525afb35666SYoshihiro Shimoda case MMC_CMD_APP_CMD: 526915ffa52SJaehoon Chung return -ETIMEDOUT; 527afb35666SYoshihiro Shimoda case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ 528afb35666SYoshihiro Shimoda if (data) 529afb35666SYoshihiro Shimoda /* ext_csd */ 530afb35666SYoshihiro Shimoda break; 531afb35666SYoshihiro Shimoda else 532afb35666SYoshihiro Shimoda /* send_if_cond cmd (not support) */ 533915ffa52SJaehoon Chung return -ETIMEDOUT; 534afb35666SYoshihiro Shimoda default: 535afb35666SYoshihiro Shimoda break; 536afb35666SYoshihiro Shimoda } 537afb35666SYoshihiro Shimoda host->sd_error = 0; 538afb35666SYoshihiro Shimoda host->data = data; 539afb35666SYoshihiro Shimoda ret = sh_mmcif_start_cmd(host, data, cmd); 540afb35666SYoshihiro Shimoda host->data = NULL; 541afb35666SYoshihiro Shimoda 542afb35666SYoshihiro Shimoda return ret; 543afb35666SYoshihiro Shimoda } 544afb35666SYoshihiro Shimoda 545*48f54a2dSMarek Vasut static int sh_mmcif_set_ios_common(struct sh_mmcif_host *host, struct mmc *mmc) 546afb35666SYoshihiro Shimoda { 547afb35666SYoshihiro Shimoda if (mmc->clock) 548afb35666SYoshihiro Shimoda sh_mmcif_clock_control(host, mmc->clock); 549afb35666SYoshihiro Shimoda 550afb35666SYoshihiro Shimoda if (mmc->bus_width == 8) 551afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_8; 552afb35666SYoshihiro Shimoda else if (mmc->bus_width == 4) 553afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_4; 554afb35666SYoshihiro Shimoda else 555afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_1; 556afb35666SYoshihiro Shimoda 557afb35666SYoshihiro Shimoda debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width); 55807b0b9c0SJaehoon Chung 55907b0b9c0SJaehoon Chung return 0; 560afb35666SYoshihiro Shimoda } 561afb35666SYoshihiro Shimoda 562*48f54a2dSMarek Vasut static int sh_mmcif_initialize_common(struct sh_mmcif_host *host) 563afb35666SYoshihiro Shimoda { 564afb35666SYoshihiro Shimoda sh_mmcif_sync_reset(host); 565afb35666SYoshihiro Shimoda sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask); 566afb35666SYoshihiro Shimoda return 0; 567afb35666SYoshihiro Shimoda } 568afb35666SYoshihiro Shimoda 569*48f54a2dSMarek Vasut #ifndef CONFIG_DM_MMC 570*48f54a2dSMarek Vasut static void *mmc_priv(struct mmc *mmc) 571*48f54a2dSMarek Vasut { 572*48f54a2dSMarek Vasut return (void *)mmc->priv; 573*48f54a2dSMarek Vasut } 574*48f54a2dSMarek Vasut 575*48f54a2dSMarek Vasut static int sh_mmcif_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, 576*48f54a2dSMarek Vasut struct mmc_data *data) 577*48f54a2dSMarek Vasut { 578*48f54a2dSMarek Vasut struct sh_mmcif_host *host = mmc_priv(mmc); 579*48f54a2dSMarek Vasut 580*48f54a2dSMarek Vasut return sh_mmcif_send_cmd_common(host, cmd, data); 581*48f54a2dSMarek Vasut } 582*48f54a2dSMarek Vasut 583*48f54a2dSMarek Vasut static int sh_mmcif_set_ios(struct mmc *mmc) 584*48f54a2dSMarek Vasut { 585*48f54a2dSMarek Vasut struct sh_mmcif_host *host = mmc_priv(mmc); 586*48f54a2dSMarek Vasut 587*48f54a2dSMarek Vasut return sh_mmcif_set_ios_common(host, mmc); 588*48f54a2dSMarek Vasut } 589*48f54a2dSMarek Vasut 590*48f54a2dSMarek Vasut static int sh_mmcif_initialize(struct mmc *mmc) 591*48f54a2dSMarek Vasut { 592*48f54a2dSMarek Vasut struct sh_mmcif_host *host = mmc_priv(mmc); 593*48f54a2dSMarek Vasut 594*48f54a2dSMarek Vasut return sh_mmcif_initialize_common(host); 595*48f54a2dSMarek Vasut } 596*48f54a2dSMarek Vasut 597ab769f22SPantelis Antoniou static const struct mmc_ops sh_mmcif_ops = { 598*48f54a2dSMarek Vasut .send_cmd = sh_mmcif_send_cmd, 599ab769f22SPantelis Antoniou .set_ios = sh_mmcif_set_ios, 600*48f54a2dSMarek Vasut .init = sh_mmcif_initialize, 601ab769f22SPantelis Antoniou }; 602ab769f22SPantelis Antoniou 60393bfd616SPantelis Antoniou static struct mmc_config sh_mmcif_cfg = { 60493bfd616SPantelis Antoniou .name = DRIVER_NAME, 60593bfd616SPantelis Antoniou .ops = &sh_mmcif_ops, 60693bfd616SPantelis Antoniou .host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT | 6075a20397bSRob Herring MMC_MODE_8BIT, 608cd2bf484SNobuhiro Iwamatsu .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, 60993bfd616SPantelis Antoniou .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, 61093bfd616SPantelis Antoniou }; 61193bfd616SPantelis Antoniou 612afb35666SYoshihiro Shimoda int mmcif_mmc_init(void) 613afb35666SYoshihiro Shimoda { 614afb35666SYoshihiro Shimoda struct mmc *mmc; 615afb35666SYoshihiro Shimoda struct sh_mmcif_host *host = NULL; 616afb35666SYoshihiro Shimoda 617afb35666SYoshihiro Shimoda host = malloc(sizeof(struct sh_mmcif_host)); 618afb35666SYoshihiro Shimoda if (!host) 61974c32ef5SNobuhiro Iwamatsu return -ENOMEM; 620afb35666SYoshihiro Shimoda memset(host, 0, sizeof(*host)); 621afb35666SYoshihiro Shimoda 622afb35666SYoshihiro Shimoda host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR; 623afb35666SYoshihiro Shimoda host->clk = CONFIG_SH_MMCIF_CLK; 624afb35666SYoshihiro Shimoda 6257a7eb983SNobuhiro Iwamatsu sh_mmcif_cfg.f_min = MMC_CLK_DIV_MIN(host->clk); 6269675f610SNobuhiro Iwamatsu sh_mmcif_cfg.f_max = MMC_CLK_DIV_MAX(host->clk); 6277a7eb983SNobuhiro Iwamatsu 62893bfd616SPantelis Antoniou mmc = mmc_create(&sh_mmcif_cfg, host); 62993bfd616SPantelis Antoniou if (mmc == NULL) { 63093bfd616SPantelis Antoniou free(host); 63193bfd616SPantelis Antoniou return -ENOMEM; 63293bfd616SPantelis Antoniou } 633afb35666SYoshihiro Shimoda 63493bfd616SPantelis Antoniou return 0; 635afb35666SYoshihiro Shimoda } 636*48f54a2dSMarek Vasut 637*48f54a2dSMarek Vasut #else 638*48f54a2dSMarek Vasut struct sh_mmcif_plat { 639*48f54a2dSMarek Vasut struct mmc_config cfg; 640*48f54a2dSMarek Vasut struct mmc mmc; 641*48f54a2dSMarek Vasut }; 642*48f54a2dSMarek Vasut 643*48f54a2dSMarek Vasut int sh_mmcif_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd, 644*48f54a2dSMarek Vasut struct mmc_data *data) 645*48f54a2dSMarek Vasut { 646*48f54a2dSMarek Vasut struct sh_mmcif_host *host = dev_get_priv(dev); 647*48f54a2dSMarek Vasut 648*48f54a2dSMarek Vasut return sh_mmcif_send_cmd_common(host, cmd, data); 649*48f54a2dSMarek Vasut } 650*48f54a2dSMarek Vasut 651*48f54a2dSMarek Vasut int sh_mmcif_dm_set_ios(struct udevice *dev) 652*48f54a2dSMarek Vasut { 653*48f54a2dSMarek Vasut struct sh_mmcif_host *host = dev_get_priv(dev); 654*48f54a2dSMarek Vasut struct mmc *mmc = mmc_get_mmc_dev(dev); 655*48f54a2dSMarek Vasut 656*48f54a2dSMarek Vasut return sh_mmcif_set_ios_common(host, mmc); 657*48f54a2dSMarek Vasut } 658*48f54a2dSMarek Vasut 659*48f54a2dSMarek Vasut static const struct dm_mmc_ops sh_mmcif_dm_ops = { 660*48f54a2dSMarek Vasut .send_cmd = sh_mmcif_dm_send_cmd, 661*48f54a2dSMarek Vasut .set_ios = sh_mmcif_dm_set_ios, 662*48f54a2dSMarek Vasut }; 663*48f54a2dSMarek Vasut 664*48f54a2dSMarek Vasut static int sh_mmcif_dm_bind(struct udevice *dev) 665*48f54a2dSMarek Vasut { 666*48f54a2dSMarek Vasut struct sh_mmcif_plat *plat = dev_get_platdata(dev); 667*48f54a2dSMarek Vasut 668*48f54a2dSMarek Vasut return mmc_bind(dev, &plat->mmc, &plat->cfg); 669*48f54a2dSMarek Vasut } 670*48f54a2dSMarek Vasut 671*48f54a2dSMarek Vasut static int sh_mmcif_dm_probe(struct udevice *dev) 672*48f54a2dSMarek Vasut { 673*48f54a2dSMarek Vasut struct sh_mmcif_plat *plat = dev_get_platdata(dev); 674*48f54a2dSMarek Vasut struct sh_mmcif_host *host = dev_get_priv(dev); 675*48f54a2dSMarek Vasut struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 676*48f54a2dSMarek Vasut struct clk sh_mmcif_clk; 677*48f54a2dSMarek Vasut fdt_addr_t base; 678*48f54a2dSMarek Vasut int ret; 679*48f54a2dSMarek Vasut 680*48f54a2dSMarek Vasut base = devfdt_get_addr(dev); 681*48f54a2dSMarek Vasut if (base == FDT_ADDR_T_NONE) 682*48f54a2dSMarek Vasut return -EINVAL; 683*48f54a2dSMarek Vasut 684*48f54a2dSMarek Vasut host->regs = (struct sh_mmcif_regs *)devm_ioremap(dev, base, SZ_2K); 685*48f54a2dSMarek Vasut if (!host->regs) 686*48f54a2dSMarek Vasut return -ENOMEM; 687*48f54a2dSMarek Vasut 688*48f54a2dSMarek Vasut ret = clk_get_by_index(dev, 0, &sh_mmcif_clk); 689*48f54a2dSMarek Vasut if (ret) { 690*48f54a2dSMarek Vasut debug("failed to get clock, ret=%d\n", ret); 691*48f54a2dSMarek Vasut return ret; 692*48f54a2dSMarek Vasut } 693*48f54a2dSMarek Vasut 694*48f54a2dSMarek Vasut ret = clk_enable(&sh_mmcif_clk); 695*48f54a2dSMarek Vasut if (ret) { 696*48f54a2dSMarek Vasut debug("failed to enable clock, ret=%d\n", ret); 697*48f54a2dSMarek Vasut return ret; 698*48f54a2dSMarek Vasut } 699*48f54a2dSMarek Vasut 700*48f54a2dSMarek Vasut host->clk = clk_get_rate(&sh_mmcif_clk); 701*48f54a2dSMarek Vasut 702*48f54a2dSMarek Vasut plat->cfg.name = dev->name; 703*48f54a2dSMarek Vasut plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS; 704*48f54a2dSMarek Vasut 705*48f54a2dSMarek Vasut switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width", 706*48f54a2dSMarek Vasut 1)) { 707*48f54a2dSMarek Vasut case 8: 708*48f54a2dSMarek Vasut plat->cfg.host_caps |= MMC_MODE_8BIT; 709*48f54a2dSMarek Vasut break; 710*48f54a2dSMarek Vasut case 4: 711*48f54a2dSMarek Vasut plat->cfg.host_caps |= MMC_MODE_4BIT; 712*48f54a2dSMarek Vasut break; 713*48f54a2dSMarek Vasut case 1: 714*48f54a2dSMarek Vasut break; 715*48f54a2dSMarek Vasut default: 716*48f54a2dSMarek Vasut dev_err(dev, "Invalid \"bus-width\" value\n"); 717*48f54a2dSMarek Vasut return -EINVAL; 718*48f54a2dSMarek Vasut } 719*48f54a2dSMarek Vasut 720*48f54a2dSMarek Vasut sh_mmcif_initialize_common(host); 721*48f54a2dSMarek Vasut 722*48f54a2dSMarek Vasut plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34; 723*48f54a2dSMarek Vasut plat->cfg.f_min = MMC_CLK_DIV_MIN(host->clk); 724*48f54a2dSMarek Vasut plat->cfg.f_max = MMC_CLK_DIV_MAX(host->clk); 725*48f54a2dSMarek Vasut plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 726*48f54a2dSMarek Vasut 727*48f54a2dSMarek Vasut upriv->mmc = &plat->mmc; 728*48f54a2dSMarek Vasut 729*48f54a2dSMarek Vasut return 0; 730*48f54a2dSMarek Vasut } 731*48f54a2dSMarek Vasut 732*48f54a2dSMarek Vasut static const struct udevice_id sh_mmcif_sd_match[] = { 733*48f54a2dSMarek Vasut { .compatible = "renesas,sh-mmcif" }, 734*48f54a2dSMarek Vasut { /* sentinel */ } 735*48f54a2dSMarek Vasut }; 736*48f54a2dSMarek Vasut 737*48f54a2dSMarek Vasut U_BOOT_DRIVER(sh_mmcif_mmc) = { 738*48f54a2dSMarek Vasut .name = "sh-mmcif", 739*48f54a2dSMarek Vasut .id = UCLASS_MMC, 740*48f54a2dSMarek Vasut .of_match = sh_mmcif_sd_match, 741*48f54a2dSMarek Vasut .bind = sh_mmcif_dm_bind, 742*48f54a2dSMarek Vasut .probe = sh_mmcif_dm_probe, 743*48f54a2dSMarek Vasut .priv_auto_alloc_size = sizeof(struct sh_mmcif_host), 744*48f54a2dSMarek Vasut .platdata_auto_alloc_size = sizeof(struct sh_mmcif_plat), 745*48f54a2dSMarek Vasut .ops = &sh_mmcif_dm_ops, 746*48f54a2dSMarek Vasut }; 747*48f54a2dSMarek Vasut #endif 748