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 sh_mmcif_bitclr(CLK_ENABLE, &host->regs->ce_clk_ctrl); 107afb35666SYoshihiro Shimoda sh_mmcif_bitclr(CLK_CLEAR, &host->regs->ce_clk_ctrl); 108afb35666SYoshihiro Shimoda 109afb35666SYoshihiro Shimoda if (!clk) 110afb35666SYoshihiro Shimoda return; 11121ea3503SNobuhiro Iwamatsu 11221ea3503SNobuhiro Iwamatsu if (clk == CLKDEV_EMMC_DATA) 113afb35666SYoshihiro Shimoda sh_mmcif_bitset(CLK_PCLK, &host->regs->ce_clk_ctrl); 11421ea3503SNobuhiro Iwamatsu else 11521ea3503SNobuhiro Iwamatsu sh_mmcif_bitset((fls(DIV_ROUND_UP(host->clk, 11621ea3503SNobuhiro Iwamatsu clk) - 1) - 1) << 16, 11721ea3503SNobuhiro Iwamatsu &host->regs->ce_clk_ctrl); 118afb35666SYoshihiro Shimoda sh_mmcif_bitset(CLK_ENABLE, &host->regs->ce_clk_ctrl); 119afb35666SYoshihiro Shimoda } 120afb35666SYoshihiro Shimoda 121afb35666SYoshihiro Shimoda static void sh_mmcif_sync_reset(struct sh_mmcif_host *host) 122afb35666SYoshihiro Shimoda { 123afb35666SYoshihiro Shimoda u32 tmp; 124afb35666SYoshihiro Shimoda 125afb35666SYoshihiro Shimoda tmp = sh_mmcif_read(&host->regs->ce_clk_ctrl) & (CLK_ENABLE | 126afb35666SYoshihiro Shimoda CLK_CLEAR); 127afb35666SYoshihiro Shimoda 128afb35666SYoshihiro Shimoda sh_mmcif_write(SOFT_RST_ON, &host->regs->ce_version); 129afb35666SYoshihiro Shimoda sh_mmcif_write(SOFT_RST_OFF, &host->regs->ce_version); 130afb35666SYoshihiro Shimoda sh_mmcif_bitset(tmp | SRSPTO_256 | SRBSYTO_29 | SRWDTO_29 | SCCSTO_29, 131afb35666SYoshihiro Shimoda &host->regs->ce_clk_ctrl); 132afb35666SYoshihiro Shimoda /* byte swap on */ 133afb35666SYoshihiro Shimoda sh_mmcif_bitset(BUF_ACC_ATYP, &host->regs->ce_buf_acc); 134afb35666SYoshihiro Shimoda } 135afb35666SYoshihiro Shimoda 136afb35666SYoshihiro Shimoda static int sh_mmcif_error_manage(struct sh_mmcif_host *host) 137afb35666SYoshihiro Shimoda { 138afb35666SYoshihiro Shimoda u32 state1, state2; 139afb35666SYoshihiro Shimoda int ret, timeout = 10000000; 140afb35666SYoshihiro Shimoda 141afb35666SYoshihiro Shimoda host->sd_error = 0; 142afb35666SYoshihiro Shimoda host->wait_int = 0; 143afb35666SYoshihiro Shimoda 144afb35666SYoshihiro Shimoda state1 = sh_mmcif_read(&host->regs->ce_host_sts1); 145afb35666SYoshihiro Shimoda state2 = sh_mmcif_read(&host->regs->ce_host_sts2); 146afb35666SYoshihiro Shimoda debug("%s: ERR HOST_STS1 = %08x\n", \ 147afb35666SYoshihiro Shimoda DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts1)); 148afb35666SYoshihiro Shimoda debug("%s: ERR HOST_STS2 = %08x\n", \ 149afb35666SYoshihiro Shimoda DRIVER_NAME, sh_mmcif_read(&host->regs->ce_host_sts2)); 150afb35666SYoshihiro Shimoda 151afb35666SYoshihiro Shimoda if (state1 & STS1_CMDSEQ) { 152afb35666SYoshihiro Shimoda debug("%s: Forced end of command sequence\n", DRIVER_NAME); 153afb35666SYoshihiro Shimoda sh_mmcif_bitset(CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); 154afb35666SYoshihiro Shimoda sh_mmcif_bitset(~CMD_CTRL_BREAK, &host->regs->ce_cmd_ctrl); 155afb35666SYoshihiro Shimoda while (1) { 156afb35666SYoshihiro Shimoda timeout--; 157afb35666SYoshihiro Shimoda if (timeout < 0) { 158afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Forceed end of " \ 159afb35666SYoshihiro Shimoda "command sequence timeout err\n"); 160afb35666SYoshihiro Shimoda return -EILSEQ; 161afb35666SYoshihiro Shimoda } 162afb35666SYoshihiro Shimoda if (!(sh_mmcif_read(&host->regs->ce_host_sts1) 163afb35666SYoshihiro Shimoda & STS1_CMDSEQ)) 164afb35666SYoshihiro Shimoda break; 165afb35666SYoshihiro Shimoda } 166afb35666SYoshihiro Shimoda sh_mmcif_sync_reset(host); 167afb35666SYoshihiro Shimoda return -EILSEQ; 168afb35666SYoshihiro Shimoda } 169afb35666SYoshihiro Shimoda 170afb35666SYoshihiro Shimoda if (state2 & STS2_CRC_ERR) 171afb35666SYoshihiro Shimoda ret = -EILSEQ; 172afb35666SYoshihiro Shimoda else if (state2 & STS2_TIMEOUT_ERR) 173afb35666SYoshihiro Shimoda ret = TIMEOUT; 174afb35666SYoshihiro Shimoda else 175afb35666SYoshihiro Shimoda ret = -EILSEQ; 176afb35666SYoshihiro Shimoda return ret; 177afb35666SYoshihiro Shimoda } 178afb35666SYoshihiro Shimoda 179afb35666SYoshihiro Shimoda static int sh_mmcif_single_read(struct sh_mmcif_host *host, 180afb35666SYoshihiro Shimoda struct mmc_data *data) 181afb35666SYoshihiro Shimoda { 182afb35666SYoshihiro Shimoda long time; 183afb35666SYoshihiro Shimoda u32 blocksize, i; 184afb35666SYoshihiro Shimoda unsigned long *p = (unsigned long *)data->dest; 185afb35666SYoshihiro Shimoda 186afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 187afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 188afb35666SYoshihiro Shimoda return -EIO; 189afb35666SYoshihiro Shimoda } 190afb35666SYoshihiro Shimoda 191afb35666SYoshihiro Shimoda host->wait_int = 0; 192afb35666SYoshihiro Shimoda 193afb35666SYoshihiro Shimoda /* buf read enable */ 194afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); 195afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 196afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 197afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 198afb35666SYoshihiro Shimoda 199afb35666SYoshihiro Shimoda host->wait_int = 0; 200afb35666SYoshihiro Shimoda blocksize = (BLOCK_SIZE_MASK & 201afb35666SYoshihiro Shimoda sh_mmcif_read(&host->regs->ce_block_set)) + 3; 202afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 203afb35666SYoshihiro Shimoda *p++ = sh_mmcif_read(&host->regs->ce_data); 204afb35666SYoshihiro Shimoda 205afb35666SYoshihiro Shimoda /* buffer read end */ 206afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFRE, &host->regs->ce_int_mask); 207afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 208afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 209afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 210afb35666SYoshihiro Shimoda 211afb35666SYoshihiro Shimoda host->wait_int = 0; 212afb35666SYoshihiro Shimoda return 0; 213afb35666SYoshihiro Shimoda } 214afb35666SYoshihiro Shimoda 215afb35666SYoshihiro Shimoda static int sh_mmcif_multi_read(struct sh_mmcif_host *host, 216afb35666SYoshihiro Shimoda struct mmc_data *data) 217afb35666SYoshihiro Shimoda { 218afb35666SYoshihiro Shimoda long time; 219afb35666SYoshihiro Shimoda u32 blocksize, i, j; 220afb35666SYoshihiro Shimoda unsigned long *p = (unsigned long *)data->dest; 221afb35666SYoshihiro Shimoda 222afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 223afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 224afb35666SYoshihiro Shimoda return -EIO; 225afb35666SYoshihiro Shimoda } 226afb35666SYoshihiro Shimoda 227afb35666SYoshihiro Shimoda host->wait_int = 0; 228afb35666SYoshihiro Shimoda blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); 229afb35666SYoshihiro Shimoda for (j = 0; j < data->blocks; j++) { 230afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFREN, &host->regs->ce_int_mask); 231afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 232afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 233afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 234afb35666SYoshihiro Shimoda 235afb35666SYoshihiro Shimoda host->wait_int = 0; 236afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 237afb35666SYoshihiro Shimoda *p++ = sh_mmcif_read(&host->regs->ce_data); 238afb35666SYoshihiro Shimoda 239afb35666SYoshihiro Shimoda WATCHDOG_RESET(); 240afb35666SYoshihiro Shimoda } 241afb35666SYoshihiro Shimoda return 0; 242afb35666SYoshihiro Shimoda } 243afb35666SYoshihiro Shimoda 244afb35666SYoshihiro Shimoda static int sh_mmcif_single_write(struct sh_mmcif_host *host, 245afb35666SYoshihiro Shimoda struct mmc_data *data) 246afb35666SYoshihiro Shimoda { 247afb35666SYoshihiro Shimoda long time; 248afb35666SYoshihiro Shimoda u32 blocksize, i; 249afb35666SYoshihiro Shimoda const unsigned long *p = (unsigned long *)data->dest; 250afb35666SYoshihiro Shimoda 251afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 252afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 253afb35666SYoshihiro Shimoda return -EIO; 254afb35666SYoshihiro Shimoda } 255afb35666SYoshihiro Shimoda 256afb35666SYoshihiro Shimoda host->wait_int = 0; 257afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); 258afb35666SYoshihiro Shimoda 259afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 260afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 261afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 262afb35666SYoshihiro Shimoda 263afb35666SYoshihiro Shimoda host->wait_int = 0; 264afb35666SYoshihiro Shimoda blocksize = (BLOCK_SIZE_MASK & 265afb35666SYoshihiro Shimoda sh_mmcif_read(&host->regs->ce_block_set)) + 3; 266afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 267afb35666SYoshihiro Shimoda sh_mmcif_write(*p++, &host->regs->ce_data); 268afb35666SYoshihiro Shimoda 269afb35666SYoshihiro Shimoda /* buffer write end */ 270afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MDTRANE, &host->regs->ce_int_mask); 271afb35666SYoshihiro Shimoda 272afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 273afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 274afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 275afb35666SYoshihiro Shimoda 276afb35666SYoshihiro Shimoda host->wait_int = 0; 277afb35666SYoshihiro Shimoda return 0; 278afb35666SYoshihiro Shimoda } 279afb35666SYoshihiro Shimoda 280afb35666SYoshihiro Shimoda static int sh_mmcif_multi_write(struct sh_mmcif_host *host, 281afb35666SYoshihiro Shimoda struct mmc_data *data) 282afb35666SYoshihiro Shimoda { 283afb35666SYoshihiro Shimoda long time; 284afb35666SYoshihiro Shimoda u32 i, j, blocksize; 285afb35666SYoshihiro Shimoda const unsigned long *p = (unsigned long *)data->dest; 286afb35666SYoshihiro Shimoda 287afb35666SYoshihiro Shimoda if ((unsigned long)p & 0x00000001) { 288afb35666SYoshihiro Shimoda printf("%s: The data pointer is unaligned.", __func__); 289afb35666SYoshihiro Shimoda return -EIO; 290afb35666SYoshihiro Shimoda } 291afb35666SYoshihiro Shimoda 292afb35666SYoshihiro Shimoda host->wait_int = 0; 293afb35666SYoshihiro Shimoda blocksize = BLOCK_SIZE_MASK & sh_mmcif_read(&host->regs->ce_block_set); 294afb35666SYoshihiro Shimoda for (j = 0; j < data->blocks; j++) { 295afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MBUFWEN, &host->regs->ce_int_mask); 296afb35666SYoshihiro Shimoda 297afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 298afb35666SYoshihiro Shimoda 299afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 300afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 301afb35666SYoshihiro Shimoda 302afb35666SYoshihiro Shimoda host->wait_int = 0; 303afb35666SYoshihiro Shimoda for (i = 0; i < blocksize / 4; i++) 304afb35666SYoshihiro Shimoda sh_mmcif_write(*p++, &host->regs->ce_data); 305afb35666SYoshihiro Shimoda 306afb35666SYoshihiro Shimoda WATCHDOG_RESET(); 307afb35666SYoshihiro Shimoda } 308afb35666SYoshihiro Shimoda return 0; 309afb35666SYoshihiro Shimoda } 310afb35666SYoshihiro Shimoda 311afb35666SYoshihiro Shimoda static void sh_mmcif_get_response(struct sh_mmcif_host *host, 312afb35666SYoshihiro Shimoda struct mmc_cmd *cmd) 313afb35666SYoshihiro Shimoda { 314afb35666SYoshihiro Shimoda if (cmd->resp_type & MMC_RSP_136) { 315afb35666SYoshihiro Shimoda cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp3); 316afb35666SYoshihiro Shimoda cmd->response[1] = sh_mmcif_read(&host->regs->ce_resp2); 317afb35666SYoshihiro Shimoda cmd->response[2] = sh_mmcif_read(&host->regs->ce_resp1); 318afb35666SYoshihiro Shimoda cmd->response[3] = sh_mmcif_read(&host->regs->ce_resp0); 319afb35666SYoshihiro Shimoda debug(" RESP %08x, %08x, %08x, %08x\n", cmd->response[0], 320afb35666SYoshihiro Shimoda cmd->response[1], cmd->response[2], cmd->response[3]); 321afb35666SYoshihiro Shimoda } else { 322afb35666SYoshihiro Shimoda cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp0); 323afb35666SYoshihiro Shimoda } 324afb35666SYoshihiro Shimoda } 325afb35666SYoshihiro Shimoda 326afb35666SYoshihiro Shimoda static void sh_mmcif_get_cmd12response(struct sh_mmcif_host *host, 327afb35666SYoshihiro Shimoda struct mmc_cmd *cmd) 328afb35666SYoshihiro Shimoda { 329afb35666SYoshihiro Shimoda cmd->response[0] = sh_mmcif_read(&host->regs->ce_resp_cmd12); 330afb35666SYoshihiro Shimoda } 331afb35666SYoshihiro Shimoda 332afb35666SYoshihiro Shimoda static u32 sh_mmcif_set_cmd(struct sh_mmcif_host *host, 333afb35666SYoshihiro Shimoda struct mmc_data *data, struct mmc_cmd *cmd) 334afb35666SYoshihiro Shimoda { 335afb35666SYoshihiro Shimoda u32 tmp = 0; 336afb35666SYoshihiro Shimoda u32 opc = cmd->cmdidx; 337afb35666SYoshihiro Shimoda 338afb35666SYoshihiro Shimoda /* Response Type check */ 339afb35666SYoshihiro Shimoda switch (cmd->resp_type) { 340afb35666SYoshihiro Shimoda case MMC_RSP_NONE: 341afb35666SYoshihiro Shimoda tmp |= CMD_SET_RTYP_NO; 342afb35666SYoshihiro Shimoda break; 343afb35666SYoshihiro Shimoda case MMC_RSP_R1: 344afb35666SYoshihiro Shimoda case MMC_RSP_R1b: 345afb35666SYoshihiro Shimoda case MMC_RSP_R3: 346afb35666SYoshihiro Shimoda tmp |= CMD_SET_RTYP_6B; 347afb35666SYoshihiro Shimoda break; 348afb35666SYoshihiro Shimoda case MMC_RSP_R2: 349afb35666SYoshihiro Shimoda tmp |= CMD_SET_RTYP_17B; 350afb35666SYoshihiro Shimoda break; 351afb35666SYoshihiro Shimoda default: 352afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Not support type response.\n"); 353afb35666SYoshihiro Shimoda break; 354afb35666SYoshihiro Shimoda } 355afb35666SYoshihiro Shimoda 356afb35666SYoshihiro Shimoda /* RBSY */ 357afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SWITCH) 358afb35666SYoshihiro Shimoda tmp |= CMD_SET_RBSY; 359afb35666SYoshihiro Shimoda 360afb35666SYoshihiro Shimoda /* WDAT / DATW */ 361afb35666SYoshihiro Shimoda if (host->data) { 362afb35666SYoshihiro Shimoda tmp |= CMD_SET_WDAT; 363afb35666SYoshihiro Shimoda switch (host->bus_width) { 364afb35666SYoshihiro Shimoda case MMC_BUS_WIDTH_1: 365afb35666SYoshihiro Shimoda tmp |= CMD_SET_DATW_1; 366afb35666SYoshihiro Shimoda break; 367afb35666SYoshihiro Shimoda case MMC_BUS_WIDTH_4: 368afb35666SYoshihiro Shimoda tmp |= CMD_SET_DATW_4; 369afb35666SYoshihiro Shimoda break; 370afb35666SYoshihiro Shimoda case MMC_BUS_WIDTH_8: 371afb35666SYoshihiro Shimoda tmp |= CMD_SET_DATW_8; 372afb35666SYoshihiro Shimoda break; 373afb35666SYoshihiro Shimoda default: 374afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Not support bus width.\n"); 375afb35666SYoshihiro Shimoda break; 376afb35666SYoshihiro Shimoda } 377afb35666SYoshihiro Shimoda } 378afb35666SYoshihiro Shimoda /* DWEN */ 379afb35666SYoshihiro Shimoda if (opc == MMC_CMD_WRITE_SINGLE_BLOCK || 380afb35666SYoshihiro Shimoda opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) 381afb35666SYoshihiro Shimoda tmp |= CMD_SET_DWEN; 382afb35666SYoshihiro Shimoda /* CMLTE/CMD12EN */ 383afb35666SYoshihiro Shimoda if (opc == MMC_CMD_READ_MULTIPLE_BLOCK || 384afb35666SYoshihiro Shimoda opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) { 385afb35666SYoshihiro Shimoda tmp |= CMD_SET_CMLTE | CMD_SET_CMD12EN; 386afb35666SYoshihiro Shimoda sh_mmcif_bitset(data->blocks << 16, &host->regs->ce_block_set); 387afb35666SYoshihiro Shimoda } 388afb35666SYoshihiro Shimoda /* RIDXC[1:0] check bits */ 389afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SEND_OP_COND || opc == MMC_CMD_ALL_SEND_CID || 390afb35666SYoshihiro Shimoda opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) 391afb35666SYoshihiro Shimoda tmp |= CMD_SET_RIDXC_BITS; 392afb35666SYoshihiro Shimoda /* RCRC7C[1:0] check bits */ 393afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SEND_OP_COND) 394afb35666SYoshihiro Shimoda tmp |= CMD_SET_CRC7C_BITS; 395afb35666SYoshihiro Shimoda /* RCRC7C[1:0] internal CRC7 */ 396afb35666SYoshihiro Shimoda if (opc == MMC_CMD_ALL_SEND_CID || 397afb35666SYoshihiro Shimoda opc == MMC_CMD_SEND_CSD || opc == MMC_CMD_SEND_CID) 398afb35666SYoshihiro Shimoda tmp |= CMD_SET_CRC7C_INTERNAL; 399afb35666SYoshihiro Shimoda 400afb35666SYoshihiro Shimoda return opc = ((opc << 24) | tmp); 401afb35666SYoshihiro Shimoda } 402afb35666SYoshihiro Shimoda 403afb35666SYoshihiro Shimoda static u32 sh_mmcif_data_trans(struct sh_mmcif_host *host, 404afb35666SYoshihiro Shimoda struct mmc_data *data, u16 opc) 405afb35666SYoshihiro Shimoda { 406afb35666SYoshihiro Shimoda u32 ret; 407afb35666SYoshihiro Shimoda 408afb35666SYoshihiro Shimoda switch (opc) { 409afb35666SYoshihiro Shimoda case MMC_CMD_READ_MULTIPLE_BLOCK: 410afb35666SYoshihiro Shimoda ret = sh_mmcif_multi_read(host, data); 411afb35666SYoshihiro Shimoda break; 412afb35666SYoshihiro Shimoda case MMC_CMD_WRITE_MULTIPLE_BLOCK: 413afb35666SYoshihiro Shimoda ret = sh_mmcif_multi_write(host, data); 414afb35666SYoshihiro Shimoda break; 415afb35666SYoshihiro Shimoda case MMC_CMD_WRITE_SINGLE_BLOCK: 416afb35666SYoshihiro Shimoda ret = sh_mmcif_single_write(host, data); 417afb35666SYoshihiro Shimoda break; 418afb35666SYoshihiro Shimoda case MMC_CMD_READ_SINGLE_BLOCK: 419afb35666SYoshihiro Shimoda case MMC_CMD_SEND_EXT_CSD: 420afb35666SYoshihiro Shimoda ret = sh_mmcif_single_read(host, data); 421afb35666SYoshihiro Shimoda break; 422afb35666SYoshihiro Shimoda default: 423afb35666SYoshihiro Shimoda printf(DRIVER_NAME": NOT SUPPORT CMD = d'%08d\n", opc); 424afb35666SYoshihiro Shimoda ret = -EINVAL; 425afb35666SYoshihiro Shimoda break; 426afb35666SYoshihiro Shimoda } 427afb35666SYoshihiro Shimoda return ret; 428afb35666SYoshihiro Shimoda } 429afb35666SYoshihiro Shimoda 430afb35666SYoshihiro Shimoda static int sh_mmcif_start_cmd(struct sh_mmcif_host *host, 431afb35666SYoshihiro Shimoda struct mmc_data *data, struct mmc_cmd *cmd) 432afb35666SYoshihiro Shimoda { 433afb35666SYoshihiro Shimoda long time; 434afb35666SYoshihiro Shimoda int ret = 0, mask = 0; 435afb35666SYoshihiro Shimoda u32 opc = cmd->cmdidx; 436afb35666SYoshihiro Shimoda 437afb35666SYoshihiro Shimoda if (opc == MMC_CMD_STOP_TRANSMISSION) { 438afb35666SYoshihiro Shimoda /* MMCIF sends the STOP command automatically */ 439afb35666SYoshihiro Shimoda if (host->last_cmd == MMC_CMD_READ_MULTIPLE_BLOCK) 440afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MCMD12DRE, 441afb35666SYoshihiro Shimoda &host->regs->ce_int_mask); 442afb35666SYoshihiro Shimoda else 443afb35666SYoshihiro Shimoda sh_mmcif_bitset(MASK_MCMD12RBE, 444afb35666SYoshihiro Shimoda &host->regs->ce_int_mask); 445afb35666SYoshihiro Shimoda 446afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 447afb35666SYoshihiro Shimoda if (time == 0 || host->sd_error != 0) 448afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 449afb35666SYoshihiro Shimoda 450afb35666SYoshihiro Shimoda sh_mmcif_get_cmd12response(host, cmd); 451afb35666SYoshihiro Shimoda return 0; 452afb35666SYoshihiro Shimoda } 453afb35666SYoshihiro Shimoda if (opc == MMC_CMD_SWITCH) 454afb35666SYoshihiro Shimoda mask = MASK_MRBSYE; 455afb35666SYoshihiro Shimoda else 456afb35666SYoshihiro Shimoda mask = MASK_MCRSPE; 457afb35666SYoshihiro Shimoda 458afb35666SYoshihiro Shimoda mask |= MASK_MCMDVIO | MASK_MBUFVIO | MASK_MWDATERR | 459afb35666SYoshihiro Shimoda MASK_MRDATERR | MASK_MRIDXERR | MASK_MRSPERR | 460afb35666SYoshihiro Shimoda MASK_MCCSTO | MASK_MCRCSTO | MASK_MWDATTO | 461afb35666SYoshihiro Shimoda MASK_MRDATTO | MASK_MRBSYTO | MASK_MRSPTO; 462afb35666SYoshihiro Shimoda 463afb35666SYoshihiro Shimoda if (host->data) { 464afb35666SYoshihiro Shimoda sh_mmcif_write(0, &host->regs->ce_block_set); 465afb35666SYoshihiro Shimoda sh_mmcif_write(data->blocksize, &host->regs->ce_block_set); 466afb35666SYoshihiro Shimoda } 467afb35666SYoshihiro Shimoda opc = sh_mmcif_set_cmd(host, data, cmd); 468afb35666SYoshihiro Shimoda 469afb35666SYoshihiro Shimoda sh_mmcif_write(INT_START_MAGIC, &host->regs->ce_int); 470afb35666SYoshihiro Shimoda sh_mmcif_write(mask, &host->regs->ce_int_mask); 471afb35666SYoshihiro Shimoda 472afb35666SYoshihiro Shimoda debug("CMD%d ARG:%08x\n", cmd->cmdidx, cmd->cmdarg); 473afb35666SYoshihiro Shimoda /* set arg */ 474afb35666SYoshihiro Shimoda sh_mmcif_write(cmd->cmdarg, &host->regs->ce_arg); 475afb35666SYoshihiro Shimoda host->wait_int = 0; 476afb35666SYoshihiro Shimoda /* set cmd */ 477afb35666SYoshihiro Shimoda sh_mmcif_write(opc, &host->regs->ce_cmd_set); 478afb35666SYoshihiro Shimoda 479afb35666SYoshihiro Shimoda time = mmcif_wait_interrupt_flag(host); 480afb35666SYoshihiro Shimoda if (time == 0) 481afb35666SYoshihiro Shimoda return sh_mmcif_error_manage(host); 482afb35666SYoshihiro Shimoda 483afb35666SYoshihiro Shimoda if (host->sd_error) { 484afb35666SYoshihiro Shimoda switch (cmd->cmdidx) { 485afb35666SYoshihiro Shimoda case MMC_CMD_ALL_SEND_CID: 486afb35666SYoshihiro Shimoda case MMC_CMD_SELECT_CARD: 487afb35666SYoshihiro Shimoda case MMC_CMD_APP_CMD: 488afb35666SYoshihiro Shimoda ret = TIMEOUT; 489afb35666SYoshihiro Shimoda break; 490afb35666SYoshihiro Shimoda default: 491afb35666SYoshihiro Shimoda printf(DRIVER_NAME": Cmd(d'%d) err\n", cmd->cmdidx); 492afb35666SYoshihiro Shimoda ret = sh_mmcif_error_manage(host); 493afb35666SYoshihiro Shimoda break; 494afb35666SYoshihiro Shimoda } 495afb35666SYoshihiro Shimoda host->sd_error = 0; 496afb35666SYoshihiro Shimoda host->wait_int = 0; 497afb35666SYoshihiro Shimoda return ret; 498afb35666SYoshihiro Shimoda } 499afb35666SYoshihiro Shimoda 500afb35666SYoshihiro Shimoda /* if no response */ 501afb35666SYoshihiro Shimoda if (!(opc & 0x00C00000)) 502afb35666SYoshihiro Shimoda return 0; 503afb35666SYoshihiro Shimoda 504afb35666SYoshihiro Shimoda if (host->wait_int == 1) { 505afb35666SYoshihiro Shimoda sh_mmcif_get_response(host, cmd); 506afb35666SYoshihiro Shimoda host->wait_int = 0; 507afb35666SYoshihiro Shimoda } 508afb35666SYoshihiro Shimoda if (host->data) 509afb35666SYoshihiro Shimoda ret = sh_mmcif_data_trans(host, data, cmd->cmdidx); 510afb35666SYoshihiro Shimoda host->last_cmd = cmd->cmdidx; 511afb35666SYoshihiro Shimoda 512afb35666SYoshihiro Shimoda return ret; 513afb35666SYoshihiro Shimoda } 514afb35666SYoshihiro Shimoda 515afb35666SYoshihiro Shimoda static int sh_mmcif_request(struct mmc *mmc, struct mmc_cmd *cmd, 516afb35666SYoshihiro Shimoda struct mmc_data *data) 517afb35666SYoshihiro Shimoda { 51893bfd616SPantelis Antoniou struct sh_mmcif_host *host = mmc->priv; 519afb35666SYoshihiro Shimoda int ret; 520afb35666SYoshihiro Shimoda 521afb35666SYoshihiro Shimoda WATCHDOG_RESET(); 522afb35666SYoshihiro Shimoda 523afb35666SYoshihiro Shimoda switch (cmd->cmdidx) { 524afb35666SYoshihiro Shimoda case MMC_CMD_APP_CMD: 525afb35666SYoshihiro Shimoda return TIMEOUT; 526afb35666SYoshihiro Shimoda case MMC_CMD_SEND_EXT_CSD: /* = SD_SEND_IF_COND (8) */ 527afb35666SYoshihiro Shimoda if (data) 528afb35666SYoshihiro Shimoda /* ext_csd */ 529afb35666SYoshihiro Shimoda break; 530afb35666SYoshihiro Shimoda else 531afb35666SYoshihiro Shimoda /* send_if_cond cmd (not support) */ 532afb35666SYoshihiro Shimoda return TIMEOUT; 533afb35666SYoshihiro Shimoda default: 534afb35666SYoshihiro Shimoda break; 535afb35666SYoshihiro Shimoda } 536afb35666SYoshihiro Shimoda host->sd_error = 0; 537afb35666SYoshihiro Shimoda host->data = data; 538afb35666SYoshihiro Shimoda ret = sh_mmcif_start_cmd(host, data, cmd); 539afb35666SYoshihiro Shimoda host->data = NULL; 540afb35666SYoshihiro Shimoda 541afb35666SYoshihiro Shimoda return ret; 542afb35666SYoshihiro Shimoda } 543afb35666SYoshihiro Shimoda 544afb35666SYoshihiro Shimoda static void sh_mmcif_set_ios(struct mmc *mmc) 545afb35666SYoshihiro Shimoda { 54693bfd616SPantelis Antoniou struct sh_mmcif_host *host = mmc->priv; 547afb35666SYoshihiro Shimoda 548afb35666SYoshihiro Shimoda if (mmc->clock) 549afb35666SYoshihiro Shimoda sh_mmcif_clock_control(host, mmc->clock); 550afb35666SYoshihiro Shimoda 551afb35666SYoshihiro Shimoda if (mmc->bus_width == 8) 552afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_8; 553afb35666SYoshihiro Shimoda else if (mmc->bus_width == 4) 554afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_4; 555afb35666SYoshihiro Shimoda else 556afb35666SYoshihiro Shimoda host->bus_width = MMC_BUS_WIDTH_1; 557afb35666SYoshihiro Shimoda 558afb35666SYoshihiro Shimoda debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width); 559afb35666SYoshihiro Shimoda } 560afb35666SYoshihiro Shimoda 561afb35666SYoshihiro Shimoda static int sh_mmcif_init(struct mmc *mmc) 562afb35666SYoshihiro Shimoda { 56393bfd616SPantelis Antoniou struct sh_mmcif_host *host = mmc->priv; 564afb35666SYoshihiro Shimoda 565afb35666SYoshihiro Shimoda sh_mmcif_sync_reset(host); 566afb35666SYoshihiro Shimoda sh_mmcif_write(MASK_ALL, &host->regs->ce_int_mask); 567afb35666SYoshihiro Shimoda return 0; 568afb35666SYoshihiro Shimoda } 569afb35666SYoshihiro Shimoda 570ab769f22SPantelis Antoniou static const struct mmc_ops sh_mmcif_ops = { 571ab769f22SPantelis Antoniou .send_cmd = sh_mmcif_request, 572ab769f22SPantelis Antoniou .set_ios = sh_mmcif_set_ios, 573ab769f22SPantelis Antoniou .init = sh_mmcif_init, 574ab769f22SPantelis Antoniou }; 575ab769f22SPantelis Antoniou 57693bfd616SPantelis Antoniou static struct mmc_config sh_mmcif_cfg = { 57793bfd616SPantelis Antoniou .name = DRIVER_NAME, 57893bfd616SPantelis Antoniou .ops = &sh_mmcif_ops, 57993bfd616SPantelis Antoniou .host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT | 580*5a20397bSRob Herring MMC_MODE_8BIT, 581cd2bf484SNobuhiro Iwamatsu .voltages = MMC_VDD_32_33 | MMC_VDD_33_34, 58293bfd616SPantelis Antoniou .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, 58393bfd616SPantelis Antoniou }; 58493bfd616SPantelis Antoniou 585afb35666SYoshihiro Shimoda int mmcif_mmc_init(void) 586afb35666SYoshihiro Shimoda { 587afb35666SYoshihiro Shimoda struct mmc *mmc; 588afb35666SYoshihiro Shimoda struct sh_mmcif_host *host = NULL; 589afb35666SYoshihiro Shimoda 590afb35666SYoshihiro Shimoda host = malloc(sizeof(struct sh_mmcif_host)); 591afb35666SYoshihiro Shimoda if (!host) 59274c32ef5SNobuhiro Iwamatsu return -ENOMEM; 593afb35666SYoshihiro Shimoda memset(host, 0, sizeof(*host)); 594afb35666SYoshihiro Shimoda 595afb35666SYoshihiro Shimoda host->regs = (struct sh_mmcif_regs *)CONFIG_SH_MMCIF_ADDR; 596afb35666SYoshihiro Shimoda host->clk = CONFIG_SH_MMCIF_CLK; 597afb35666SYoshihiro Shimoda 5987a7eb983SNobuhiro Iwamatsu sh_mmcif_cfg.f_min = MMC_CLK_DIV_MIN(host->clk); 5999675f610SNobuhiro Iwamatsu sh_mmcif_cfg.f_max = MMC_CLK_DIV_MAX(host->clk); 6007a7eb983SNobuhiro Iwamatsu 60193bfd616SPantelis Antoniou mmc = mmc_create(&sh_mmcif_cfg, host); 60293bfd616SPantelis Antoniou if (mmc == NULL) { 60393bfd616SPantelis Antoniou free(host); 60493bfd616SPantelis Antoniou return -ENOMEM; 60593bfd616SPantelis Antoniou } 606afb35666SYoshihiro Shimoda 60793bfd616SPantelis Antoniou return 0; 608afb35666SYoshihiro Shimoda } 609