1afb35666SYoshihiro Shimoda /* 2afb35666SYoshihiro Shimoda * MMCIF driver. 3afb35666SYoshihiro Shimoda * 4afb35666SYoshihiro Shimoda * Copyright (C) 2011 Renesas Solutions Corp. 5afb35666SYoshihiro Shimoda * 6afb35666SYoshihiro Shimoda * This program is free software; you can redistribute it and/or modify 7afb35666SYoshihiro Shimoda * it under the terms of the GNU General Public License as published by 8afb35666SYoshihiro Shimoda * the Free Software Foundation; either version 2 of the License. 9afb35666SYoshihiro Shimoda */ 10afb35666SYoshihiro Shimoda 11afb35666SYoshihiro Shimoda #include <config.h> 12afb35666SYoshihiro Shimoda #include <common.h> 13afb35666SYoshihiro Shimoda #include <watchdog.h> 14afb35666SYoshihiro Shimoda #include <command.h> 15afb35666SYoshihiro Shimoda #include <mmc.h> 16afb35666SYoshihiro Shimoda #include <malloc.h> 17afb35666SYoshihiro Shimoda #include <asm/errno.h> 18afb35666SYoshihiro Shimoda #include <asm/io.h> 19afb35666SYoshihiro Shimoda #include "sh_mmcif.h" 20afb35666SYoshihiro Shimoda 21afb35666SYoshihiro Shimoda #define DRIVER_NAME "sh_mmcif" 22afb35666SYoshihiro Shimoda 23afb35666SYoshihiro Shimoda static int sh_mmcif_intr(void *dev_id) 24afb35666SYoshihiro Shimoda { 25afb35666SYoshihiro Shimoda struct sh_mmcif_host *host = dev_id; 26afb35666SYoshihiro Shimoda u32 state = 0; 27afb35666SYoshihiro Shimoda 28afb35666SYoshihiro Shimoda state = sh_mmcif_read(&host->regs->ce_int); 29afb35666SYoshihiro Shimoda state &= sh_mmcif_read(&host->regs->ce_int_mask); 30afb35666SYoshihiro Shimoda 31afb35666SYoshihiro Shimoda if (state & INT_RBSYE) { 32afb35666SYoshihiro Shimoda sh_mmcif_write(~(INT_RBSYE | INT_CRSPE), &host->regs->ce_int); 33afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MRBSYE, &host->regs->ce_int_mask); 34afb35666SYoshihiro Shimoda goto end; 35afb35666SYoshihiro Shimoda } else if (state & INT_CRSPE) { 36afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_CRSPE, &host->regs->ce_int); 37afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MCRSPE, &host->regs->ce_int_mask); 38afb35666SYoshihiro Shimoda /* one more interrupt (INT_RBSYE) */ 39afb35666SYoshihiro Shimoda if (sh_mmcif_read(&host->regs->ce_cmd_set) & CMD_SET_RBSY) 40afb35666SYoshihiro Shimoda return -EAGAIN; 41afb35666SYoshihiro Shimoda goto end; 42afb35666SYoshihiro Shimoda } else if (state & INT_BUFREN) { 43afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_BUFREN, &host->regs->ce_int); 44afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MBUFREN, &host->regs->ce_int_mask); 45afb35666SYoshihiro Shimoda goto end; 46afb35666SYoshihiro Shimoda } else if (state & INT_BUFWEN) { 47afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_BUFWEN, &host->regs->ce_int); 48afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MBUFWEN, &host->regs->ce_int_mask); 49afb35666SYoshihiro Shimoda goto end; 50afb35666SYoshihiro Shimoda } else if (state & INT_CMD12DRE) { 51afb35666SYoshihiro Shimoda sh_mmcif_write(~(INT_CMD12DRE | INT_CMD12RBE | INT_CMD12CRE | 52afb35666SYoshihiro Shimoda INT_BUFRE), &host->regs->ce_int); 53afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MCMD12DRE, &host->regs->ce_int_mask); 54afb35666SYoshihiro Shimoda goto end; 55afb35666SYoshihiro Shimoda } else if (state & INT_BUFRE) { 56afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_BUFRE, &host->regs->ce_int); 57afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MBUFRE, &host->regs->ce_int_mask); 58afb35666SYoshihiro Shimoda goto end; 59afb35666SYoshihiro Shimoda } else if (state & INT_DTRANE) { 60afb35666SYoshihiro Shimoda sh_mmcif_write(~INT_DTRANE, &host->regs->ce_int); 61afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MDTRANE, &host->regs->ce_int_mask); 62afb35666SYoshihiro Shimoda goto end; 63afb35666SYoshihiro Shimoda } else if (state & INT_CMD12RBE) { 64afb35666SYoshihiro Shimoda sh_mmcif_write(~(INT_CMD12RBE | INT_CMD12CRE), 65afb35666SYoshihiro Shimoda &host->regs->ce_int); 66afb35666SYoshihiro Shimoda sh_mmcif_bitclr(MASK_MCMD12RBE, &host->regs->ce_int_mask); 67afb35666SYoshihiro Shimoda goto end; 68afb35666SYoshihiro Shimoda } else if (state & INT_ERR_STS) { 69afb35666SYoshihiro Shimoda /* err interrupts */ 70afb35666SYoshihiro Shimoda sh_mmcif_write(~state, &host->regs->ce_int); 71afb35666SYoshihiro Shimoda sh_mmcif_bitclr(state, &host->regs->ce_int_mask); 72afb35666SYoshihiro Shimoda goto err; 73afb35666SYoshihiro Shimoda } else 74afb35666SYoshihiro Shimoda return -EAGAIN; 75afb35666SYoshihiro Shimoda 76afb35666SYoshihiro Shimoda err: 77afb35666SYoshihiro Shimoda host->sd_error = 1; 78afb35666SYoshihiro Shimoda debug("%s: int err state = %08x\n", DRIVER_NAME, state); 79afb35666SYoshihiro Shimoda end: 80afb35666SYoshihiro Shimoda host->wait_int = 1; 81afb35666SYoshihiro Shimoda return 0; 82afb35666SYoshihiro Shimoda } 83afb35666SYoshihiro Shimoda 84afb35666SYoshihiro Shimoda static int mmcif_wait_interrupt_flag(struct sh_mmcif_host *host) 85afb35666SYoshihiro Shimoda { 86afb35666SYoshihiro Shimoda int timeout = 10000000; 87afb35666SYoshihiro Shimoda 88afb35666SYoshihiro Shimoda while (1) { 89afb35666SYoshihiro Shimoda timeout--; 90afb35666SYoshihiro Shimoda if (timeout < 0) { 91afb35666SYoshihiro Shimoda printf("timeout\n"); 92afb35666SYoshihiro Shimoda return 0; 93afb35666SYoshihiro Shimoda } 94afb35666SYoshihiro Shimoda 95afb35666SYoshihiro Shimoda if (!sh_mmcif_intr(host)) 96afb35666SYoshihiro Shimoda break; 97afb35666SYoshihiro Shimoda 98afb35666SYoshihiro Shimoda udelay(1); /* 1 usec */ 99afb35666SYoshihiro Shimoda } 100afb35666SYoshihiro Shimoda 101afb35666SYoshihiro Shimoda return 1; /* Return value: NOT 0 = complete waiting */ 102afb35666SYoshihiro Shimoda } 103afb35666SYoshihiro Shimoda 104afb35666SYoshihiro Shimoda static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) 105afb35666SYoshihiro Shimoda { 106afb35666SYoshihiro Shimoda int i; 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; 113afb35666SYoshihiro Shimoda if (clk == CLKDEV_EMMC_DATA) { 114afb35666SYoshihiro Shimoda sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl); 115afb35666SYoshihiro Shimoda } else { 116afb35666SYoshihiro Shimoda for (i = 1; (unsigned int)host->clk / (1 << i) >= clk; i++) 117afb35666SYoshihiro Shimoda ; 118afb35666SYoshihiro Shimoda sh_mmcif_bitset((i - 1) << 16, &host->regs->ce_clk_ctrl); 119afb35666SYoshihiro Shimoda } 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) 175afb35666SYoshihiro Shimoda ret = TIMEOUT; 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: 490afb35666SYoshihiro Shimoda ret = TIMEOUT; 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 517afb35666SYoshihiro Shimoda static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd, 518afb35666SYoshihiro Shimoda struct mmc_data *data) 519afb35666SYoshihiro Shimoda { 52093bfd616SPantelis Antoniou struct sh_mmcif_host *host = mmc->priv; 521afb35666SYoshihiro Shimoda int ret; 522afb35666SYoshihiro Shimoda 523afb35666SYoshihiro Shimoda WATCHDOG_RESET(); 524afb35666SYoshihiro Shimoda 525afb35666SYoshihiro Shimoda switch (cmd->cmdidx) { 526afb35666SYoshihiro Shimoda case MMC_CMD_APP_CMD: 527afb35666SYoshihiro Shimoda return TIMEOUT; 528afb35666SYoshihiro Shimoda case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ 529afb35666SYoshihiro Shimoda if (data) 530afb35666SYoshihiro Shimoda /* ext_csd */ 531afb35666SYoshihiro Shimoda break; 532afb35666SYoshihiro Shimoda else 533afb35666SYoshihiro Shimoda /* send_if_cond cmd (not support) */ 534afb35666SYoshihiro Shimoda return TIMEOUT; 535afb35666SYoshihiro Shimoda default: 536afb35666SYoshihiro Shimoda break; 537afb35666SYoshihiro Shimoda } 538afb35666SYoshihiro Shimoda host->sd_error = 0; 539afb35666SYoshihiro Shimoda host->data = data; 540afb35666SYoshihiro Shimoda ret = sh_mmcif_start_cmd(host, data, cmd); 541afb35666SYoshihiro Shimoda host->data = NULL; 542afb35666SYoshihiro Shimoda 543afb35666SYoshihiro Shimoda return ret; 544afb35666SYoshihiro Shimoda } 545afb35666SYoshihiro Shimoda 546afb35666SYoshihiro Shimoda static void sh_mmcif_set_ios(struct mmc *mmc) 547afb35666SYoshihiro Shimoda { 54893bfd616SPantelis Antoniou struct sh_mmcif_host *host = mmc->priv; 549afb35666SYoshihiro Shimoda 550afb35666SYoshihiro Shimoda if (mmc->clock) 551afb35666SYoshihiro Shimoda sh_mmcif_clock_control(host, mmc->clock); 552afb35666SYoshihiro Shimoda 553afb35666SYoshihiro Shimoda if (mmc->bus_width == 8) 554afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_8; 555afb35666SYoshihiro Shimoda else if (mmc->bus_width == 4) 556afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_4; 557afb35666SYoshihiro Shimoda else 558afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_1; 559afb35666SYoshihiro Shimoda 560afb35666SYoshihiro Shimoda debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width); 561afb35666SYoshihiro Shimoda } 562afb35666SYoshihiro Shimoda 563afb35666SYoshihiro Shimoda static int sh_mmcif_init(struct mmc *mmc) 564afb35666SYoshihiro Shimoda { 56593bfd616SPantelis Antoniou struct sh_mmcif_host *host = mmc->priv; 566afb35666SYoshihiro Shimoda 567afb35666SYoshihiro Shimoda sh_mmcif_sync_reset(host); 568afb35666SYoshihiro Shimoda sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask); 569afb35666SYoshihiro Shimoda return 0; 570afb35666SYoshihiro Shimoda } 571afb35666SYoshihiro Shimoda 572ab769f22SPantelis Antoniou static const struct mmc_ops sh_mmcif_ops = { 573ab769f22SPantelis Antoniou .send_cmd = sh_mmcif_request, 574ab769f22SPantelis Antoniou .set_ios = sh_mmcif_set_ios, 575ab769f22SPantelis Antoniou .init = sh_mmcif_init, 576ab769f22SPantelis Antoniou }; 577ab769f22SPantelis Antoniou 57893bfd616SPantelis Antoniou static struct mmc_config sh_mmcif_cfg = { 57993bfd616SPantelis Antoniou .name = DRIVER_NAME, 58093bfd616SPantelis Antoniou .ops = &sh_mmcif_ops, 58193bfd616SPantelis Antoniou .host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT | 58293bfd616SPantelis Antoniou MMC_MODE_8BIT | MMC_MODE_HC, 583*cd2bf484SNobuhiro Iwamatsu .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, 58493bfd616SPantelis Antoniou .f_min = CLKDEV_MMC_INIT, 58593bfd616SPantelis Antoniou .f_max = CLKDEV_EMMC_DATA, 58693bfd616SPantelis Antoniou .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, 58793bfd616SPantelis Antoniou }; 58893bfd616SPantelis Antoniou 589afb35666SYoshihiro Shimoda int mmcif_mmc_init(void) 590afb35666SYoshihiro Shimoda { 591afb35666SYoshihiro Shimoda int ret = 0; 592afb35666SYoshihiro Shimoda struct mmc *mmc; 593afb35666SYoshihiro Shimoda struct sh_mmcif_host *host = NULL; 594afb35666SYoshihiro Shimoda 595afb35666SYoshihiro Shimoda host = malloc(sizeof(struct sh_mmcif_host)); 596afb35666SYoshihiro Shimoda if (!host) 597afb35666SYoshihiro Shimoda ret = -ENOMEM; 598afb35666SYoshihiro Shimoda memset(host, 0, sizeof(*host)); 599afb35666SYoshihiro Shimoda 600afb35666SYoshihiro Shimoda host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR; 601afb35666SYoshihiro Shimoda host->clk = CONFIG_SH_MMCIF_CLK; 602afb35666SYoshihiro Shimoda 60393bfd616SPantelis Antoniou mmc = mmc_create(&sh_mmcif_cfg, host); 60493bfd616SPantelis Antoniou if (mmc == NULL) { 60593bfd616SPantelis Antoniou free(host); 60693bfd616SPantelis Antoniou return -ENOMEM; 60793bfd616SPantelis Antoniou } 608afb35666SYoshihiro Shimoda 60993bfd616SPantelis Antoniou return 0; 610afb35666SYoshihiro Shimoda } 611