1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0
272d42badSNobuhiro Iwamatsu /*
372d42badSNobuhiro Iwamatsu * drivers/mmc/sh_sdhi.c
472d42badSNobuhiro Iwamatsu *
572d42badSNobuhiro Iwamatsu * SD/MMC driver for Renesas rmobile ARM SoCs.
672d42badSNobuhiro Iwamatsu *
75eada1dbSKouei Abe * Copyright (C) 2011,2013-2017 Renesas Electronics Corporation
872d42badSNobuhiro Iwamatsu * Copyright (C) 2014 Nobuhiro Iwamatsu <nobuhiro.iwamatsu.yj@renesas.com>
972d42badSNobuhiro Iwamatsu * Copyright (C) 2008-2009 Renesas Solutions Corp.
1072d42badSNobuhiro Iwamatsu */
1172d42badSNobuhiro Iwamatsu
1272d42badSNobuhiro Iwamatsu #include <common.h>
1372d42badSNobuhiro Iwamatsu #include <malloc.h>
1472d42badSNobuhiro Iwamatsu #include <mmc.h>
15d1c18ca1SMarek Vasut #include <dm.h>
161221ce45SMasahiro Yamada #include <linux/errno.h>
17d1c18ca1SMarek Vasut #include <linux/compat.h>
18d1c18ca1SMarek Vasut #include <linux/io.h>
19d1c18ca1SMarek Vasut #include <linux/sizes.h>
2072d42badSNobuhiro Iwamatsu #include <asm/arch/rmobile.h>
2172d42badSNobuhiro Iwamatsu #include <asm/arch/sh_sdhi.h>
228cd46cbaSMarek Vasut #include <clk.h>
2372d42badSNobuhiro Iwamatsu
2472d42badSNobuhiro Iwamatsu #define DRIVER_NAME "sh-sdhi"
2572d42badSNobuhiro Iwamatsu
2672d42badSNobuhiro Iwamatsu struct sh_sdhi_host {
27d1c18ca1SMarek Vasut void __iomem *addr;
2872d42badSNobuhiro Iwamatsu int ch;
2972d42badSNobuhiro Iwamatsu int bus_shift;
3072d42badSNobuhiro Iwamatsu unsigned long quirks;
3172d42badSNobuhiro Iwamatsu unsigned char wait_int;
3272d42badSNobuhiro Iwamatsu unsigned char sd_error;
3372d42badSNobuhiro Iwamatsu unsigned char detect_waiting;
34a3f0a7d5SMarek Vasut unsigned char app_cmd;
3572d42badSNobuhiro Iwamatsu };
365eada1dbSKouei Abe
sh_sdhi_writeq(struct sh_sdhi_host * host,int reg,u64 val)375eada1dbSKouei Abe static inline void sh_sdhi_writeq(struct sh_sdhi_host *host, int reg, u64 val)
385eada1dbSKouei Abe {
395eada1dbSKouei Abe writeq(val, host->addr + (reg << host->bus_shift));
405eada1dbSKouei Abe }
415eada1dbSKouei Abe
sh_sdhi_readq(struct sh_sdhi_host * host,int reg)425eada1dbSKouei Abe static inline u64 sh_sdhi_readq(struct sh_sdhi_host *host, int reg)
435eada1dbSKouei Abe {
445eada1dbSKouei Abe return readq(host->addr + (reg << host->bus_shift));
455eada1dbSKouei Abe }
465eada1dbSKouei Abe
sh_sdhi_writew(struct sh_sdhi_host * host,int reg,u16 val)4772d42badSNobuhiro Iwamatsu static inline void sh_sdhi_writew(struct sh_sdhi_host *host, int reg, u16 val)
4872d42badSNobuhiro Iwamatsu {
4972d42badSNobuhiro Iwamatsu writew(val, host->addr + (reg << host->bus_shift));
5072d42badSNobuhiro Iwamatsu }
5172d42badSNobuhiro Iwamatsu
sh_sdhi_readw(struct sh_sdhi_host * host,int reg)5272d42badSNobuhiro Iwamatsu static inline u16 sh_sdhi_readw(struct sh_sdhi_host *host, int reg)
5372d42badSNobuhiro Iwamatsu {
5472d42badSNobuhiro Iwamatsu return readw(host->addr + (reg << host->bus_shift));
5572d42badSNobuhiro Iwamatsu }
5672d42badSNobuhiro Iwamatsu
sh_sdhi_detect(struct sh_sdhi_host * host)5772d42badSNobuhiro Iwamatsu static void sh_sdhi_detect(struct sh_sdhi_host *host)
5872d42badSNobuhiro Iwamatsu {
5972d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_OPTION,
6072d42badSNobuhiro Iwamatsu OPT_BUS_WIDTH_1 | sh_sdhi_readw(host, SDHI_OPTION));
6172d42badSNobuhiro Iwamatsu
6272d42badSNobuhiro Iwamatsu host->detect_waiting = 0;
6372d42badSNobuhiro Iwamatsu }
6472d42badSNobuhiro Iwamatsu
sh_sdhi_intr(void * dev_id)6572d42badSNobuhiro Iwamatsu static int sh_sdhi_intr(void *dev_id)
6672d42badSNobuhiro Iwamatsu {
6772d42badSNobuhiro Iwamatsu struct sh_sdhi_host *host = dev_id;
6872d42badSNobuhiro Iwamatsu int state1 = 0, state2 = 0;
6972d42badSNobuhiro Iwamatsu
7072d42badSNobuhiro Iwamatsu state1 = sh_sdhi_readw(host, SDHI_INFO1);
7172d42badSNobuhiro Iwamatsu state2 = sh_sdhi_readw(host, SDHI_INFO2);
7272d42badSNobuhiro Iwamatsu
7372d42badSNobuhiro Iwamatsu debug("%s: state1 = %x, state2 = %x\n", __func__, state1, state2);
7472d42badSNobuhiro Iwamatsu
7572d42badSNobuhiro Iwamatsu /* CARD Insert */
7672d42badSNobuhiro Iwamatsu if (state1 & INFO1_CARD_IN) {
7772d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_IN);
7872d42badSNobuhiro Iwamatsu if (!host->detect_waiting) {
7972d42badSNobuhiro Iwamatsu host->detect_waiting = 1;
8072d42badSNobuhiro Iwamatsu sh_sdhi_detect(host);
8172d42badSNobuhiro Iwamatsu }
8272d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
8372d42badSNobuhiro Iwamatsu INFO1M_ACCESS_END | INFO1M_CARD_IN |
8472d42badSNobuhiro Iwamatsu INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
8572d42badSNobuhiro Iwamatsu return -EAGAIN;
8672d42badSNobuhiro Iwamatsu }
8772d42badSNobuhiro Iwamatsu /* CARD Removal */
8872d42badSNobuhiro Iwamatsu if (state1 & INFO1_CARD_RE) {
8972d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_CARD_RE);
9072d42badSNobuhiro Iwamatsu if (!host->detect_waiting) {
9172d42badSNobuhiro Iwamatsu host->detect_waiting = 1;
9272d42badSNobuhiro Iwamatsu sh_sdhi_detect(host);
9372d42badSNobuhiro Iwamatsu }
9472d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
9572d42badSNobuhiro Iwamatsu INFO1M_ACCESS_END | INFO1M_CARD_RE |
9672d42badSNobuhiro Iwamatsu INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
9772d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_SDIO_INFO1_MASK, SDIO_INFO1M_ON);
9872d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_SDIO_MODE, SDIO_MODE_OFF);
9972d42badSNobuhiro Iwamatsu return -EAGAIN;
10072d42badSNobuhiro Iwamatsu }
10172d42badSNobuhiro Iwamatsu
10272d42badSNobuhiro Iwamatsu if (state2 & INFO2_ALL_ERR) {
10372d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2,
10472d42badSNobuhiro Iwamatsu (unsigned short)~(INFO2_ALL_ERR));
10572d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
10672d42badSNobuhiro Iwamatsu INFO2M_ALL_ERR |
10772d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
10872d42badSNobuhiro Iwamatsu host->sd_error = 1;
10972d42badSNobuhiro Iwamatsu host->wait_int = 1;
11072d42badSNobuhiro Iwamatsu return 0;
11172d42badSNobuhiro Iwamatsu }
11272d42badSNobuhiro Iwamatsu /* Respons End */
11372d42badSNobuhiro Iwamatsu if (state1 & INFO1_RESP_END) {
11472d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
11572d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
11672d42badSNobuhiro Iwamatsu INFO1M_RESP_END |
11772d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO1_MASK));
11872d42badSNobuhiro Iwamatsu host->wait_int = 1;
11972d42badSNobuhiro Iwamatsu return 0;
12072d42badSNobuhiro Iwamatsu }
12172d42badSNobuhiro Iwamatsu /* SD_BUF Read Enable */
12272d42badSNobuhiro Iwamatsu if (state2 & INFO2_BRE_ENABLE) {
12372d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BRE_ENABLE);
12472d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
12572d42badSNobuhiro Iwamatsu INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ |
12672d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
12772d42badSNobuhiro Iwamatsu host->wait_int = 1;
12872d42badSNobuhiro Iwamatsu return 0;
12972d42badSNobuhiro Iwamatsu }
13072d42badSNobuhiro Iwamatsu /* SD_BUF Write Enable */
13172d42badSNobuhiro Iwamatsu if (state2 & INFO2_BWE_ENABLE) {
13272d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2, ~INFO2_BWE_ENABLE);
13372d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
13472d42badSNobuhiro Iwamatsu INFO2_BWE_ENABLE | INFO2M_BUF_ILL_WRITE |
13572d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
13672d42badSNobuhiro Iwamatsu host->wait_int = 1;
13772d42badSNobuhiro Iwamatsu return 0;
13872d42badSNobuhiro Iwamatsu }
13972d42badSNobuhiro Iwamatsu /* Access End */
14072d42badSNobuhiro Iwamatsu if (state1 & INFO1_ACCESS_END) {
14172d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_ACCESS_END);
14272d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
14372d42badSNobuhiro Iwamatsu INFO1_ACCESS_END |
14472d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO1_MASK));
14572d42badSNobuhiro Iwamatsu host->wait_int = 1;
14672d42badSNobuhiro Iwamatsu return 0;
14772d42badSNobuhiro Iwamatsu }
14872d42badSNobuhiro Iwamatsu return -EAGAIN;
14972d42badSNobuhiro Iwamatsu }
15072d42badSNobuhiro Iwamatsu
sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host * host)15172d42badSNobuhiro Iwamatsu static int sh_sdhi_wait_interrupt_flag(struct sh_sdhi_host *host)
15272d42badSNobuhiro Iwamatsu {
15372d42badSNobuhiro Iwamatsu int timeout = 10000000;
15472d42badSNobuhiro Iwamatsu
15572d42badSNobuhiro Iwamatsu while (1) {
15672d42badSNobuhiro Iwamatsu timeout--;
15772d42badSNobuhiro Iwamatsu if (timeout < 0) {
15872d42badSNobuhiro Iwamatsu debug(DRIVER_NAME": %s timeout\n", __func__);
15972d42badSNobuhiro Iwamatsu return 0;
16072d42badSNobuhiro Iwamatsu }
16172d42badSNobuhiro Iwamatsu
16272d42badSNobuhiro Iwamatsu if (!sh_sdhi_intr(host))
16372d42badSNobuhiro Iwamatsu break;
16472d42badSNobuhiro Iwamatsu
16572d42badSNobuhiro Iwamatsu udelay(1); /* 1 usec */
16672d42badSNobuhiro Iwamatsu }
16772d42badSNobuhiro Iwamatsu
16872d42badSNobuhiro Iwamatsu return 1; /* Return value: NOT 0 = complete waiting */
16972d42badSNobuhiro Iwamatsu }
17072d42badSNobuhiro Iwamatsu
sh_sdhi_clock_control(struct sh_sdhi_host * host,unsigned long clk)17172d42badSNobuhiro Iwamatsu static int sh_sdhi_clock_control(struct sh_sdhi_host *host, unsigned long clk)
17272d42badSNobuhiro Iwamatsu {
17372d42badSNobuhiro Iwamatsu u32 clkdiv, i, timeout;
17472d42badSNobuhiro Iwamatsu
17572d42badSNobuhiro Iwamatsu if (sh_sdhi_readw(host, SDHI_INFO2) & (1 << 14)) {
17672d42badSNobuhiro Iwamatsu printf(DRIVER_NAME": Busy state ! Cannot change the clock\n");
17772d42badSNobuhiro Iwamatsu return -EBUSY;
17872d42badSNobuhiro Iwamatsu }
17972d42badSNobuhiro Iwamatsu
18072d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_CLK_CTRL,
18172d42badSNobuhiro Iwamatsu ~CLK_ENABLE & sh_sdhi_readw(host, SDHI_CLK_CTRL));
18272d42badSNobuhiro Iwamatsu
18372d42badSNobuhiro Iwamatsu if (clk == 0)
18472d42badSNobuhiro Iwamatsu return -EIO;
18572d42badSNobuhiro Iwamatsu
18672d42badSNobuhiro Iwamatsu clkdiv = 0x80;
18772d42badSNobuhiro Iwamatsu i = CONFIG_SH_SDHI_FREQ >> (0x8 + 1);
18872d42badSNobuhiro Iwamatsu for (; clkdiv && clk >= (i << 1); (clkdiv >>= 1))
18972d42badSNobuhiro Iwamatsu i <<= 1;
19072d42badSNobuhiro Iwamatsu
19172d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_CLK_CTRL, clkdiv);
19272d42badSNobuhiro Iwamatsu
19372d42badSNobuhiro Iwamatsu timeout = 100000;
19472d42badSNobuhiro Iwamatsu /* Waiting for SD Bus busy to be cleared */
19572d42badSNobuhiro Iwamatsu while (timeout--) {
19672d42badSNobuhiro Iwamatsu if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
19772d42badSNobuhiro Iwamatsu break;
19872d42badSNobuhiro Iwamatsu }
19972d42badSNobuhiro Iwamatsu
20072d42badSNobuhiro Iwamatsu if (timeout)
20172d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_CLK_CTRL,
20272d42badSNobuhiro Iwamatsu CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
20372d42badSNobuhiro Iwamatsu else
20472d42badSNobuhiro Iwamatsu return -EBUSY;
20572d42badSNobuhiro Iwamatsu
20672d42badSNobuhiro Iwamatsu return 0;
20772d42badSNobuhiro Iwamatsu }
20872d42badSNobuhiro Iwamatsu
sh_sdhi_sync_reset(struct sh_sdhi_host * host)20972d42badSNobuhiro Iwamatsu static int sh_sdhi_sync_reset(struct sh_sdhi_host *host)
21072d42badSNobuhiro Iwamatsu {
21172d42badSNobuhiro Iwamatsu u32 timeout;
21272d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_ON);
21372d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_SOFT_RST, SOFT_RST_OFF);
21472d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_CLK_CTRL,
21572d42badSNobuhiro Iwamatsu CLK_ENABLE | sh_sdhi_readw(host, SDHI_CLK_CTRL));
21672d42badSNobuhiro Iwamatsu
21772d42badSNobuhiro Iwamatsu timeout = 100000;
21872d42badSNobuhiro Iwamatsu while (timeout--) {
21972d42badSNobuhiro Iwamatsu if (!(sh_sdhi_readw(host, SDHI_INFO2) & INFO2_CBUSY))
22072d42badSNobuhiro Iwamatsu break;
22172d42badSNobuhiro Iwamatsu udelay(100);
22272d42badSNobuhiro Iwamatsu }
22372d42badSNobuhiro Iwamatsu
22472d42badSNobuhiro Iwamatsu if (!timeout)
22572d42badSNobuhiro Iwamatsu return -EBUSY;
22672d42badSNobuhiro Iwamatsu
22772d42badSNobuhiro Iwamatsu if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
22872d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_HOST_MODE, 1);
22972d42badSNobuhiro Iwamatsu
23072d42badSNobuhiro Iwamatsu return 0;
23172d42badSNobuhiro Iwamatsu }
23272d42badSNobuhiro Iwamatsu
sh_sdhi_error_manage(struct sh_sdhi_host * host)23372d42badSNobuhiro Iwamatsu static int sh_sdhi_error_manage(struct sh_sdhi_host *host)
23472d42badSNobuhiro Iwamatsu {
23572d42badSNobuhiro Iwamatsu unsigned short e_state1, e_state2;
23672d42badSNobuhiro Iwamatsu int ret;
23772d42badSNobuhiro Iwamatsu
23872d42badSNobuhiro Iwamatsu host->sd_error = 0;
23972d42badSNobuhiro Iwamatsu host->wait_int = 0;
24072d42badSNobuhiro Iwamatsu
24172d42badSNobuhiro Iwamatsu e_state1 = sh_sdhi_readw(host, SDHI_ERR_STS1);
24272d42badSNobuhiro Iwamatsu e_state2 = sh_sdhi_readw(host, SDHI_ERR_STS2);
24372d42badSNobuhiro Iwamatsu if (e_state2 & ERR_STS2_SYS_ERROR) {
24472d42badSNobuhiro Iwamatsu if (e_state2 & ERR_STS2_RES_STOP_TIMEOUT)
245915ffa52SJaehoon Chung ret = -ETIMEDOUT;
24672d42badSNobuhiro Iwamatsu else
24772d42badSNobuhiro Iwamatsu ret = -EILSEQ;
24872d42badSNobuhiro Iwamatsu debug("%s: ERR_STS2 = %04x\n",
24972d42badSNobuhiro Iwamatsu DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS2));
25072d42badSNobuhiro Iwamatsu sh_sdhi_sync_reset(host);
25172d42badSNobuhiro Iwamatsu
25272d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
25372d42badSNobuhiro Iwamatsu INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
25472d42badSNobuhiro Iwamatsu return ret;
25572d42badSNobuhiro Iwamatsu }
25672d42badSNobuhiro Iwamatsu if (e_state1 & ERR_STS1_CRC_ERROR || e_state1 & ERR_STS1_CMD_ERROR)
25772d42badSNobuhiro Iwamatsu ret = -EILSEQ;
25872d42badSNobuhiro Iwamatsu else
259915ffa52SJaehoon Chung ret = -ETIMEDOUT;
26072d42badSNobuhiro Iwamatsu
26172d42badSNobuhiro Iwamatsu debug("%s: ERR_STS1 = %04x\n",
26272d42badSNobuhiro Iwamatsu DRIVER_NAME, sh_sdhi_readw(host, SDHI_ERR_STS1));
26372d42badSNobuhiro Iwamatsu sh_sdhi_sync_reset(host);
26472d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
26572d42badSNobuhiro Iwamatsu INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
26672d42badSNobuhiro Iwamatsu return ret;
26772d42badSNobuhiro Iwamatsu }
26872d42badSNobuhiro Iwamatsu
sh_sdhi_single_read(struct sh_sdhi_host * host,struct mmc_data * data)26972d42badSNobuhiro Iwamatsu static int sh_sdhi_single_read(struct sh_sdhi_host *host, struct mmc_data *data)
27072d42badSNobuhiro Iwamatsu {
27172d42badSNobuhiro Iwamatsu long time;
27272d42badSNobuhiro Iwamatsu unsigned short blocksize, i;
27372d42badSNobuhiro Iwamatsu unsigned short *p = (unsigned short *)data->dest;
2745eada1dbSKouei Abe u64 *q = (u64 *)data->dest;
27572d42badSNobuhiro Iwamatsu
27672d42badSNobuhiro Iwamatsu if ((unsigned long)p & 0x00000001) {
27772d42badSNobuhiro Iwamatsu debug(DRIVER_NAME": %s: The data pointer is unaligned.",
27872d42badSNobuhiro Iwamatsu __func__);
27972d42badSNobuhiro Iwamatsu return -EIO;
28072d42badSNobuhiro Iwamatsu }
28172d42badSNobuhiro Iwamatsu
28272d42badSNobuhiro Iwamatsu host->wait_int = 0;
28372d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
28472d42badSNobuhiro Iwamatsu ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
28572d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
28672d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
28772d42badSNobuhiro Iwamatsu ~INFO1M_ACCESS_END &
28872d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO1_MASK));
28972d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
29072d42badSNobuhiro Iwamatsu if (time == 0 || host->sd_error != 0)
29172d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
29272d42badSNobuhiro Iwamatsu
29372d42badSNobuhiro Iwamatsu host->wait_int = 0;
29472d42badSNobuhiro Iwamatsu blocksize = sh_sdhi_readw(host, SDHI_SIZE);
2955eada1dbSKouei Abe if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
2965eada1dbSKouei Abe for (i = 0; i < blocksize / 8; i++)
2975eada1dbSKouei Abe *q++ = sh_sdhi_readq(host, SDHI_BUF0);
2985eada1dbSKouei Abe else
29972d42badSNobuhiro Iwamatsu for (i = 0; i < blocksize / 2; i++)
30072d42badSNobuhiro Iwamatsu *p++ = sh_sdhi_readw(host, SDHI_BUF0);
30172d42badSNobuhiro Iwamatsu
30272d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
30372d42badSNobuhiro Iwamatsu if (time == 0 || host->sd_error != 0)
30472d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
30572d42badSNobuhiro Iwamatsu
30672d42badSNobuhiro Iwamatsu host->wait_int = 0;
30772d42badSNobuhiro Iwamatsu return 0;
30872d42badSNobuhiro Iwamatsu }
30972d42badSNobuhiro Iwamatsu
sh_sdhi_multi_read(struct sh_sdhi_host * host,struct mmc_data * data)31072d42badSNobuhiro Iwamatsu static int sh_sdhi_multi_read(struct sh_sdhi_host *host, struct mmc_data *data)
31172d42badSNobuhiro Iwamatsu {
31272d42badSNobuhiro Iwamatsu long time;
31372d42badSNobuhiro Iwamatsu unsigned short blocksize, i, sec;
31472d42badSNobuhiro Iwamatsu unsigned short *p = (unsigned short *)data->dest;
3155eada1dbSKouei Abe u64 *q = (u64 *)data->dest;
31672d42badSNobuhiro Iwamatsu
31772d42badSNobuhiro Iwamatsu if ((unsigned long)p & 0x00000001) {
31872d42badSNobuhiro Iwamatsu debug(DRIVER_NAME": %s: The data pointer is unaligned.",
31972d42badSNobuhiro Iwamatsu __func__);
32072d42badSNobuhiro Iwamatsu return -EIO;
32172d42badSNobuhiro Iwamatsu }
32272d42badSNobuhiro Iwamatsu
32372d42badSNobuhiro Iwamatsu debug("%s: blocks = %d, blocksize = %d\n",
32472d42badSNobuhiro Iwamatsu __func__, data->blocks, data->blocksize);
32572d42badSNobuhiro Iwamatsu
32672d42badSNobuhiro Iwamatsu host->wait_int = 0;
32772d42badSNobuhiro Iwamatsu for (sec = 0; sec < data->blocks; sec++) {
32872d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
32972d42badSNobuhiro Iwamatsu ~(INFO2M_BRE_ENABLE | INFO2M_BUF_ILL_READ) &
33072d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
33172d42badSNobuhiro Iwamatsu
33272d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
33372d42badSNobuhiro Iwamatsu if (time == 0 || host->sd_error != 0)
33472d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
33572d42badSNobuhiro Iwamatsu
33672d42badSNobuhiro Iwamatsu host->wait_int = 0;
33772d42badSNobuhiro Iwamatsu blocksize = sh_sdhi_readw(host, SDHI_SIZE);
3385eada1dbSKouei Abe if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
3395eada1dbSKouei Abe for (i = 0; i < blocksize / 8; i++)
3405eada1dbSKouei Abe *q++ = sh_sdhi_readq(host, SDHI_BUF0);
3415eada1dbSKouei Abe else
34272d42badSNobuhiro Iwamatsu for (i = 0; i < blocksize / 2; i++)
34372d42badSNobuhiro Iwamatsu *p++ = sh_sdhi_readw(host, SDHI_BUF0);
34472d42badSNobuhiro Iwamatsu }
34572d42badSNobuhiro Iwamatsu
34672d42badSNobuhiro Iwamatsu return 0;
34772d42badSNobuhiro Iwamatsu }
34872d42badSNobuhiro Iwamatsu
sh_sdhi_single_write(struct sh_sdhi_host * host,struct mmc_data * data)34972d42badSNobuhiro Iwamatsu static int sh_sdhi_single_write(struct sh_sdhi_host *host,
35072d42badSNobuhiro Iwamatsu struct mmc_data *data)
35172d42badSNobuhiro Iwamatsu {
35272d42badSNobuhiro Iwamatsu long time;
35372d42badSNobuhiro Iwamatsu unsigned short blocksize, i;
35472d42badSNobuhiro Iwamatsu const unsigned short *p = (const unsigned short *)data->src;
3555eada1dbSKouei Abe const u64 *q = (const u64 *)data->src;
35672d42badSNobuhiro Iwamatsu
35772d42badSNobuhiro Iwamatsu if ((unsigned long)p & 0x00000001) {
35872d42badSNobuhiro Iwamatsu debug(DRIVER_NAME": %s: The data pointer is unaligned.",
35972d42badSNobuhiro Iwamatsu __func__);
36072d42badSNobuhiro Iwamatsu return -EIO;
36172d42badSNobuhiro Iwamatsu }
36272d42badSNobuhiro Iwamatsu
36372d42badSNobuhiro Iwamatsu debug("%s: blocks = %d, blocksize = %d\n",
36472d42badSNobuhiro Iwamatsu __func__, data->blocks, data->blocksize);
36572d42badSNobuhiro Iwamatsu
36672d42badSNobuhiro Iwamatsu host->wait_int = 0;
36772d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
36872d42badSNobuhiro Iwamatsu ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
36972d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
37072d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
37172d42badSNobuhiro Iwamatsu ~INFO1M_ACCESS_END &
37272d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO1_MASK));
37372d42badSNobuhiro Iwamatsu
37472d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
37572d42badSNobuhiro Iwamatsu if (time == 0 || host->sd_error != 0)
37672d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
37772d42badSNobuhiro Iwamatsu
37872d42badSNobuhiro Iwamatsu host->wait_int = 0;
37972d42badSNobuhiro Iwamatsu blocksize = sh_sdhi_readw(host, SDHI_SIZE);
3805eada1dbSKouei Abe if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
3815eada1dbSKouei Abe for (i = 0; i < blocksize / 8; i++)
3825eada1dbSKouei Abe sh_sdhi_writeq(host, SDHI_BUF0, *q++);
3835eada1dbSKouei Abe else
38472d42badSNobuhiro Iwamatsu for (i = 0; i < blocksize / 2; i++)
38572d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_BUF0, *p++);
38672d42badSNobuhiro Iwamatsu
38772d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
38872d42badSNobuhiro Iwamatsu if (time == 0 || host->sd_error != 0)
38972d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
39072d42badSNobuhiro Iwamatsu
39172d42badSNobuhiro Iwamatsu host->wait_int = 0;
39272d42badSNobuhiro Iwamatsu return 0;
39372d42badSNobuhiro Iwamatsu }
39472d42badSNobuhiro Iwamatsu
sh_sdhi_multi_write(struct sh_sdhi_host * host,struct mmc_data * data)39572d42badSNobuhiro Iwamatsu static int sh_sdhi_multi_write(struct sh_sdhi_host *host, struct mmc_data *data)
39672d42badSNobuhiro Iwamatsu {
39772d42badSNobuhiro Iwamatsu long time;
39872d42badSNobuhiro Iwamatsu unsigned short i, sec, blocksize;
39972d42badSNobuhiro Iwamatsu const unsigned short *p = (const unsigned short *)data->src;
4005eada1dbSKouei Abe const u64 *q = (const u64 *)data->src;
40172d42badSNobuhiro Iwamatsu
40272d42badSNobuhiro Iwamatsu debug("%s: blocks = %d, blocksize = %d\n",
40372d42badSNobuhiro Iwamatsu __func__, data->blocks, data->blocksize);
40472d42badSNobuhiro Iwamatsu
40572d42badSNobuhiro Iwamatsu host->wait_int = 0;
40672d42badSNobuhiro Iwamatsu for (sec = 0; sec < data->blocks; sec++) {
40772d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
40872d42badSNobuhiro Iwamatsu ~(INFO2M_BWE_ENABLE | INFO2M_BUF_ILL_WRITE) &
40972d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
41072d42badSNobuhiro Iwamatsu
41172d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
41272d42badSNobuhiro Iwamatsu if (time == 0 || host->sd_error != 0)
41372d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
41472d42badSNobuhiro Iwamatsu
41572d42badSNobuhiro Iwamatsu host->wait_int = 0;
41672d42badSNobuhiro Iwamatsu blocksize = sh_sdhi_readw(host, SDHI_SIZE);
4175eada1dbSKouei Abe if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
4185eada1dbSKouei Abe for (i = 0; i < blocksize / 8; i++)
4195eada1dbSKouei Abe sh_sdhi_writeq(host, SDHI_BUF0, *q++);
4205eada1dbSKouei Abe else
42172d42badSNobuhiro Iwamatsu for (i = 0; i < blocksize / 2; i++)
42272d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_BUF0, *p++);
42372d42badSNobuhiro Iwamatsu }
42472d42badSNobuhiro Iwamatsu
42572d42badSNobuhiro Iwamatsu return 0;
42672d42badSNobuhiro Iwamatsu }
42772d42badSNobuhiro Iwamatsu
sh_sdhi_get_response(struct sh_sdhi_host * host,struct mmc_cmd * cmd)42872d42badSNobuhiro Iwamatsu static void sh_sdhi_get_response(struct sh_sdhi_host *host, struct mmc_cmd *cmd)
42972d42badSNobuhiro Iwamatsu {
43072d42badSNobuhiro Iwamatsu unsigned short i, j, cnt = 1;
43172d42badSNobuhiro Iwamatsu unsigned short resp[8];
43272d42badSNobuhiro Iwamatsu
43372d42badSNobuhiro Iwamatsu if (cmd->resp_type & MMC_RSP_136) {
43472d42badSNobuhiro Iwamatsu cnt = 4;
43572d42badSNobuhiro Iwamatsu resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
43672d42badSNobuhiro Iwamatsu resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
43772d42badSNobuhiro Iwamatsu resp[2] = sh_sdhi_readw(host, SDHI_RSP02);
43872d42badSNobuhiro Iwamatsu resp[3] = sh_sdhi_readw(host, SDHI_RSP03);
43972d42badSNobuhiro Iwamatsu resp[4] = sh_sdhi_readw(host, SDHI_RSP04);
44072d42badSNobuhiro Iwamatsu resp[5] = sh_sdhi_readw(host, SDHI_RSP05);
44172d42badSNobuhiro Iwamatsu resp[6] = sh_sdhi_readw(host, SDHI_RSP06);
44272d42badSNobuhiro Iwamatsu resp[7] = sh_sdhi_readw(host, SDHI_RSP07);
44372d42badSNobuhiro Iwamatsu
44472d42badSNobuhiro Iwamatsu /* SDHI REGISTER SPECIFICATION */
44572d42badSNobuhiro Iwamatsu for (i = 7, j = 6; i > 0; i--) {
44672d42badSNobuhiro Iwamatsu resp[i] = (resp[i] << 8) & 0xff00;
44772d42badSNobuhiro Iwamatsu resp[i] |= (resp[j--] >> 8) & 0x00ff;
44872d42badSNobuhiro Iwamatsu }
44972d42badSNobuhiro Iwamatsu resp[0] = (resp[0] << 8) & 0xff00;
45072d42badSNobuhiro Iwamatsu } else {
45172d42badSNobuhiro Iwamatsu resp[0] = sh_sdhi_readw(host, SDHI_RSP00);
45272d42badSNobuhiro Iwamatsu resp[1] = sh_sdhi_readw(host, SDHI_RSP01);
45372d42badSNobuhiro Iwamatsu }
45472d42badSNobuhiro Iwamatsu
45572d42badSNobuhiro Iwamatsu #if defined(__BIG_ENDIAN_BITFIELD)
4566f107e4cSmasakazu.mochizuki.wd@hitachi.com if (cnt == 4) {
4576f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[0] = (resp[6] << 16) | resp[7];
4586f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[1] = (resp[4] << 16) | resp[5];
4596f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[2] = (resp[2] << 16) | resp[3];
4606f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[3] = (resp[0] << 16) | resp[1];
4616f107e4cSmasakazu.mochizuki.wd@hitachi.com } else {
4626f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[0] = (resp[0] << 16) | resp[1];
46372d42badSNobuhiro Iwamatsu }
46472d42badSNobuhiro Iwamatsu #else
4656f107e4cSmasakazu.mochizuki.wd@hitachi.com if (cnt == 4) {
4666f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[0] = (resp[7] << 16) | resp[6];
4676f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[1] = (resp[5] << 16) | resp[4];
4686f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[2] = (resp[3] << 16) | resp[2];
4696f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[3] = (resp[1] << 16) | resp[0];
4706f107e4cSmasakazu.mochizuki.wd@hitachi.com } else {
4716f107e4cSmasakazu.mochizuki.wd@hitachi.com cmd->response[0] = (resp[1] << 16) | resp[0];
4726f107e4cSmasakazu.mochizuki.wd@hitachi.com }
47372d42badSNobuhiro Iwamatsu #endif /* __BIG_ENDIAN_BITFIELD */
47472d42badSNobuhiro Iwamatsu }
47572d42badSNobuhiro Iwamatsu
sh_sdhi_set_cmd(struct sh_sdhi_host * host,struct mmc_data * data,unsigned short opc)47672d42badSNobuhiro Iwamatsu static unsigned short sh_sdhi_set_cmd(struct sh_sdhi_host *host,
47772d42badSNobuhiro Iwamatsu struct mmc_data *data, unsigned short opc)
47872d42badSNobuhiro Iwamatsu {
479a3f0a7d5SMarek Vasut if (host->app_cmd) {
48072d42badSNobuhiro Iwamatsu if (!data)
481a3f0a7d5SMarek Vasut host->app_cmd = 0;
482a3f0a7d5SMarek Vasut return opc | BIT(6);
48372d42badSNobuhiro Iwamatsu }
484a3f0a7d5SMarek Vasut
485a3f0a7d5SMarek Vasut switch (opc) {
486a3f0a7d5SMarek Vasut case MMC_CMD_SWITCH:
487a3f0a7d5SMarek Vasut return opc | (data ? 0x1c00 : 0x40);
488a3f0a7d5SMarek Vasut case MMC_CMD_SEND_EXT_CSD:
489a3f0a7d5SMarek Vasut return opc | (data ? 0x1c00 : 0);
490a3f0a7d5SMarek Vasut case MMC_CMD_SEND_OP_COND:
491a3f0a7d5SMarek Vasut return opc | 0x0700;
492a3f0a7d5SMarek Vasut case MMC_CMD_APP_CMD:
493a3f0a7d5SMarek Vasut host->app_cmd = 1;
494a3f0a7d5SMarek Vasut default:
49572d42badSNobuhiro Iwamatsu return opc;
49672d42badSNobuhiro Iwamatsu }
497a3f0a7d5SMarek Vasut }
49872d42badSNobuhiro Iwamatsu
sh_sdhi_data_trans(struct sh_sdhi_host * host,struct mmc_data * data,unsigned short opc)49972d42badSNobuhiro Iwamatsu static unsigned short sh_sdhi_data_trans(struct sh_sdhi_host *host,
50072d42badSNobuhiro Iwamatsu struct mmc_data *data, unsigned short opc)
50172d42badSNobuhiro Iwamatsu {
502a3f0a7d5SMarek Vasut if (host->app_cmd) {
503a3f0a7d5SMarek Vasut host->app_cmd = 0;
50472d42badSNobuhiro Iwamatsu switch (opc) {
505a3f0a7d5SMarek Vasut case SD_CMD_APP_SEND_SCR:
506a3f0a7d5SMarek Vasut case SD_CMD_APP_SD_STATUS:
507a3f0a7d5SMarek Vasut return sh_sdhi_single_read(host, data);
508a3f0a7d5SMarek Vasut default:
509a3f0a7d5SMarek Vasut printf(DRIVER_NAME": SD: NOT SUPPORT APP CMD = d'%04d\n",
510a3f0a7d5SMarek Vasut opc);
511a3f0a7d5SMarek Vasut return -EINVAL;
512a3f0a7d5SMarek Vasut }
513a3f0a7d5SMarek Vasut } else {
514a3f0a7d5SMarek Vasut switch (opc) {
51572d42badSNobuhiro Iwamatsu case MMC_CMD_WRITE_MULTIPLE_BLOCK:
516a3f0a7d5SMarek Vasut return sh_sdhi_multi_write(host, data);
517a3f0a7d5SMarek Vasut case MMC_CMD_READ_MULTIPLE_BLOCK:
518a3f0a7d5SMarek Vasut return sh_sdhi_multi_read(host, data);
51972d42badSNobuhiro Iwamatsu case MMC_CMD_WRITE_SINGLE_BLOCK:
520a3f0a7d5SMarek Vasut return sh_sdhi_single_write(host, data);
52172d42badSNobuhiro Iwamatsu case MMC_CMD_READ_SINGLE_BLOCK:
522a3f0a7d5SMarek Vasut case MMC_CMD_SWITCH:
523a3f0a7d5SMarek Vasut case MMC_CMD_SEND_EXT_CSD:;
524a3f0a7d5SMarek Vasut return sh_sdhi_single_read(host, data);
52572d42badSNobuhiro Iwamatsu default:
52672d42badSNobuhiro Iwamatsu printf(DRIVER_NAME": SD: NOT SUPPORT CMD = d'%04d\n", opc);
527a3f0a7d5SMarek Vasut return -EINVAL;
52872d42badSNobuhiro Iwamatsu }
529a3f0a7d5SMarek Vasut }
53072d42badSNobuhiro Iwamatsu }
53172d42badSNobuhiro Iwamatsu
sh_sdhi_start_cmd(struct sh_sdhi_host * host,struct mmc_data * data,struct mmc_cmd * cmd)53272d42badSNobuhiro Iwamatsu static int sh_sdhi_start_cmd(struct sh_sdhi_host *host,
53372d42badSNobuhiro Iwamatsu struct mmc_data *data, struct mmc_cmd *cmd)
53472d42badSNobuhiro Iwamatsu {
53572d42badSNobuhiro Iwamatsu long time;
536a3f0a7d5SMarek Vasut unsigned short shcmd, opc = cmd->cmdidx;
53772d42badSNobuhiro Iwamatsu int ret = 0;
53872d42badSNobuhiro Iwamatsu unsigned long timeout;
53972d42badSNobuhiro Iwamatsu
54072d42badSNobuhiro Iwamatsu debug("opc = %d, arg = %x, resp_type = %x\n",
54172d42badSNobuhiro Iwamatsu opc, cmd->cmdarg, cmd->resp_type);
54272d42badSNobuhiro Iwamatsu
54372d42badSNobuhiro Iwamatsu if (opc == MMC_CMD_STOP_TRANSMISSION) {
54472d42badSNobuhiro Iwamatsu /* SDHI sends the STOP command automatically by STOP reg */
54572d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK, ~INFO1M_ACCESS_END &
54672d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO1_MASK));
54772d42badSNobuhiro Iwamatsu
54872d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
54972d42badSNobuhiro Iwamatsu if (time == 0 || host->sd_error != 0)
55072d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
55172d42badSNobuhiro Iwamatsu
55272d42badSNobuhiro Iwamatsu sh_sdhi_get_response(host, cmd);
55372d42badSNobuhiro Iwamatsu return 0;
55472d42badSNobuhiro Iwamatsu }
55572d42badSNobuhiro Iwamatsu
55672d42badSNobuhiro Iwamatsu if (data) {
55772d42badSNobuhiro Iwamatsu if ((opc == MMC_CMD_READ_MULTIPLE_BLOCK) ||
55872d42badSNobuhiro Iwamatsu opc == MMC_CMD_WRITE_MULTIPLE_BLOCK) {
55972d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_STOP, STOP_SEC_ENABLE);
56072d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_SECCNT, data->blocks);
56172d42badSNobuhiro Iwamatsu }
56272d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_SIZE, data->blocksize);
56372d42badSNobuhiro Iwamatsu }
564a3f0a7d5SMarek Vasut
565a3f0a7d5SMarek Vasut shcmd = sh_sdhi_set_cmd(host, data, opc);
56672d42badSNobuhiro Iwamatsu
56772d42badSNobuhiro Iwamatsu /*
568a187559eSBin Meng * U-Boot cannot use interrupt.
56972d42badSNobuhiro Iwamatsu * So this flag may not be clear by timing
57072d42badSNobuhiro Iwamatsu */
57172d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1, ~INFO1_RESP_END);
57272d42badSNobuhiro Iwamatsu
57372d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
57472d42badSNobuhiro Iwamatsu INFO1M_RESP_END | sh_sdhi_readw(host, SDHI_INFO1_MASK));
57572d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_ARG0,
57672d42badSNobuhiro Iwamatsu (unsigned short)(cmd->cmdarg & ARG0_MASK));
57772d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_ARG1,
57872d42badSNobuhiro Iwamatsu (unsigned short)((cmd->cmdarg >> 16) & ARG1_MASK));
57972d42badSNobuhiro Iwamatsu
58072d42badSNobuhiro Iwamatsu timeout = 100000;
58172d42badSNobuhiro Iwamatsu /* Waiting for SD Bus busy to be cleared */
58272d42badSNobuhiro Iwamatsu while (timeout--) {
58372d42badSNobuhiro Iwamatsu if ((sh_sdhi_readw(host, SDHI_INFO2) & 0x2000))
58472d42badSNobuhiro Iwamatsu break;
58572d42badSNobuhiro Iwamatsu }
58672d42badSNobuhiro Iwamatsu
58772d42badSNobuhiro Iwamatsu host->wait_int = 0;
58872d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK,
58972d42badSNobuhiro Iwamatsu ~INFO1M_RESP_END & sh_sdhi_readw(host, SDHI_INFO1_MASK));
59072d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO2_MASK,
59172d42badSNobuhiro Iwamatsu ~(INFO2M_CMD_ERROR | INFO2M_CRC_ERROR |
59272d42badSNobuhiro Iwamatsu INFO2M_END_ERROR | INFO2M_TIMEOUT |
59372d42badSNobuhiro Iwamatsu INFO2M_RESP_TIMEOUT | INFO2M_ILA) &
59472d42badSNobuhiro Iwamatsu sh_sdhi_readw(host, SDHI_INFO2_MASK));
59572d42badSNobuhiro Iwamatsu
596a3f0a7d5SMarek Vasut sh_sdhi_writew(host, SDHI_CMD, (unsigned short)(shcmd & CMD_MASK));
59772d42badSNobuhiro Iwamatsu time = sh_sdhi_wait_interrupt_flag(host);
598a3f0a7d5SMarek Vasut if (!time) {
599a3f0a7d5SMarek Vasut host->app_cmd = 0;
60072d42badSNobuhiro Iwamatsu return sh_sdhi_error_manage(host);
601a3f0a7d5SMarek Vasut }
60272d42badSNobuhiro Iwamatsu
60372d42badSNobuhiro Iwamatsu if (host->sd_error) {
60472d42badSNobuhiro Iwamatsu switch (cmd->cmdidx) {
60572d42badSNobuhiro Iwamatsu case MMC_CMD_ALL_SEND_CID:
60672d42badSNobuhiro Iwamatsu case MMC_CMD_SELECT_CARD:
60772d42badSNobuhiro Iwamatsu case SD_CMD_SEND_IF_COND:
60872d42badSNobuhiro Iwamatsu case MMC_CMD_APP_CMD:
609915ffa52SJaehoon Chung ret = -ETIMEDOUT;
61072d42badSNobuhiro Iwamatsu break;
61172d42badSNobuhiro Iwamatsu default:
61272d42badSNobuhiro Iwamatsu debug(DRIVER_NAME": Cmd(d'%d) err\n", opc);
61372d42badSNobuhiro Iwamatsu debug(DRIVER_NAME": cmdidx = %d\n", cmd->cmdidx);
61472d42badSNobuhiro Iwamatsu ret = sh_sdhi_error_manage(host);
61572d42badSNobuhiro Iwamatsu break;
61672d42badSNobuhiro Iwamatsu }
61772d42badSNobuhiro Iwamatsu host->sd_error = 0;
61872d42badSNobuhiro Iwamatsu host->wait_int = 0;
619a3f0a7d5SMarek Vasut host->app_cmd = 0;
62072d42badSNobuhiro Iwamatsu return ret;
62172d42badSNobuhiro Iwamatsu }
622a3f0a7d5SMarek Vasut
623a3f0a7d5SMarek Vasut if (sh_sdhi_readw(host, SDHI_INFO1) & INFO1_RESP_END) {
624a3f0a7d5SMarek Vasut host->app_cmd = 0;
62572d42badSNobuhiro Iwamatsu return -EINVAL;
626a3f0a7d5SMarek Vasut }
62772d42badSNobuhiro Iwamatsu
62872d42badSNobuhiro Iwamatsu if (host->wait_int) {
62972d42badSNobuhiro Iwamatsu sh_sdhi_get_response(host, cmd);
63072d42badSNobuhiro Iwamatsu host->wait_int = 0;
63172d42badSNobuhiro Iwamatsu }
632a3f0a7d5SMarek Vasut
63372d42badSNobuhiro Iwamatsu if (data)
63472d42badSNobuhiro Iwamatsu ret = sh_sdhi_data_trans(host, data, opc);
63572d42badSNobuhiro Iwamatsu
63672d42badSNobuhiro Iwamatsu debug("ret = %d, resp = %08x, %08x, %08x, %08x\n",
63772d42badSNobuhiro Iwamatsu ret, cmd->response[0], cmd->response[1],
63872d42badSNobuhiro Iwamatsu cmd->response[2], cmd->response[3]);
63972d42badSNobuhiro Iwamatsu return ret;
64072d42badSNobuhiro Iwamatsu }
64172d42badSNobuhiro Iwamatsu
sh_sdhi_send_cmd_common(struct sh_sdhi_host * host,struct mmc_cmd * cmd,struct mmc_data * data)642d1c18ca1SMarek Vasut static int sh_sdhi_send_cmd_common(struct sh_sdhi_host *host,
643d1c18ca1SMarek Vasut struct mmc_cmd *cmd, struct mmc_data *data)
64472d42badSNobuhiro Iwamatsu {
64572d42badSNobuhiro Iwamatsu host->sd_error = 0;
64672d42badSNobuhiro Iwamatsu
647d1c18ca1SMarek Vasut return sh_sdhi_start_cmd(host, data, cmd);
64872d42badSNobuhiro Iwamatsu }
64972d42badSNobuhiro Iwamatsu
sh_sdhi_set_ios_common(struct sh_sdhi_host * host,struct mmc * mmc)650d1c18ca1SMarek Vasut static int sh_sdhi_set_ios_common(struct sh_sdhi_host *host, struct mmc *mmc)
65172d42badSNobuhiro Iwamatsu {
65272d42badSNobuhiro Iwamatsu int ret;
65372d42badSNobuhiro Iwamatsu
65472d42badSNobuhiro Iwamatsu ret = sh_sdhi_clock_control(host, mmc->clock);
65572d42badSNobuhiro Iwamatsu if (ret)
65607b0b9c0SJaehoon Chung return -EINVAL;
65772d42badSNobuhiro Iwamatsu
65891a16c3bSKouei Abe if (mmc->bus_width == 8)
65991a16c3bSKouei Abe sh_sdhi_writew(host, SDHI_OPTION,
66091a16c3bSKouei Abe OPT_BUS_WIDTH_8 | (~OPT_BUS_WIDTH_M &
66191a16c3bSKouei Abe sh_sdhi_readw(host, SDHI_OPTION)));
66291a16c3bSKouei Abe else if (mmc->bus_width == 4)
66391a16c3bSKouei Abe sh_sdhi_writew(host, SDHI_OPTION,
66491a16c3bSKouei Abe OPT_BUS_WIDTH_4 | (~OPT_BUS_WIDTH_M &
66591a16c3bSKouei Abe sh_sdhi_readw(host, SDHI_OPTION)));
66672d42badSNobuhiro Iwamatsu else
66791a16c3bSKouei Abe sh_sdhi_writew(host, SDHI_OPTION,
66891a16c3bSKouei Abe OPT_BUS_WIDTH_1 | (~OPT_BUS_WIDTH_M &
66991a16c3bSKouei Abe sh_sdhi_readw(host, SDHI_OPTION)));
67072d42badSNobuhiro Iwamatsu
67172d42badSNobuhiro Iwamatsu debug("clock = %d, buswidth = %d\n", mmc->clock, mmc->bus_width);
67207b0b9c0SJaehoon Chung
67307b0b9c0SJaehoon Chung return 0;
67472d42badSNobuhiro Iwamatsu }
67572d42badSNobuhiro Iwamatsu
sh_sdhi_initialize_common(struct sh_sdhi_host * host)676d1c18ca1SMarek Vasut static int sh_sdhi_initialize_common(struct sh_sdhi_host *host)
67772d42badSNobuhiro Iwamatsu {
67872d42badSNobuhiro Iwamatsu int ret = sh_sdhi_sync_reset(host);
67972d42badSNobuhiro Iwamatsu
68072d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_PORTSEL, USE_1PORT);
68172d42badSNobuhiro Iwamatsu
68272d42badSNobuhiro Iwamatsu #if defined(__BIG_ENDIAN_BITFIELD)
68372d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_EXT_SWAP, SET_SWAP);
68472d42badSNobuhiro Iwamatsu #endif
68572d42badSNobuhiro Iwamatsu
68672d42badSNobuhiro Iwamatsu sh_sdhi_writew(host, SDHI_INFO1_MASK, INFO1M_RESP_END |
68772d42badSNobuhiro Iwamatsu INFO1M_ACCESS_END | INFO1M_CARD_RE |
68872d42badSNobuhiro Iwamatsu INFO1M_DATA3_CARD_RE | INFO1M_DATA3_CARD_IN);
68972d42badSNobuhiro Iwamatsu
69072d42badSNobuhiro Iwamatsu return ret;
69172d42badSNobuhiro Iwamatsu }
69272d42badSNobuhiro Iwamatsu
693d1c18ca1SMarek Vasut #ifndef CONFIG_DM_MMC
mmc_priv(struct mmc * mmc)694d1c18ca1SMarek Vasut static void *mmc_priv(struct mmc *mmc)
695d1c18ca1SMarek Vasut {
696d1c18ca1SMarek Vasut return (void *)mmc->priv;
697d1c18ca1SMarek Vasut }
698d1c18ca1SMarek Vasut
sh_sdhi_send_cmd(struct mmc * mmc,struct mmc_cmd * cmd,struct mmc_data * data)699d1c18ca1SMarek Vasut static int sh_sdhi_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
700d1c18ca1SMarek Vasut struct mmc_data *data)
701d1c18ca1SMarek Vasut {
702d1c18ca1SMarek Vasut struct sh_sdhi_host *host = mmc_priv(mmc);
703d1c18ca1SMarek Vasut
704d1c18ca1SMarek Vasut return sh_sdhi_send_cmd_common(host, cmd, data);
705d1c18ca1SMarek Vasut }
706d1c18ca1SMarek Vasut
sh_sdhi_set_ios(struct mmc * mmc)707d1c18ca1SMarek Vasut static int sh_sdhi_set_ios(struct mmc *mmc)
708d1c18ca1SMarek Vasut {
709d1c18ca1SMarek Vasut struct sh_sdhi_host *host = mmc_priv(mmc);
710d1c18ca1SMarek Vasut
711d1c18ca1SMarek Vasut return sh_sdhi_set_ios_common(host, mmc);
712d1c18ca1SMarek Vasut }
713d1c18ca1SMarek Vasut
sh_sdhi_initialize(struct mmc * mmc)714d1c18ca1SMarek Vasut static int sh_sdhi_initialize(struct mmc *mmc)
715d1c18ca1SMarek Vasut {
716d1c18ca1SMarek Vasut struct sh_sdhi_host *host = mmc_priv(mmc);
717d1c18ca1SMarek Vasut
718d1c18ca1SMarek Vasut return sh_sdhi_initialize_common(host);
719d1c18ca1SMarek Vasut }
720d1c18ca1SMarek Vasut
72172d42badSNobuhiro Iwamatsu static const struct mmc_ops sh_sdhi_ops = {
72272d42badSNobuhiro Iwamatsu .send_cmd = sh_sdhi_send_cmd,
72372d42badSNobuhiro Iwamatsu .set_ios = sh_sdhi_set_ios,
72472d42badSNobuhiro Iwamatsu .init = sh_sdhi_initialize,
72572d42badSNobuhiro Iwamatsu };
72672d42badSNobuhiro Iwamatsu
727a5950f8dSKouei Abe #ifdef CONFIG_RCAR_GEN3
728a5950f8dSKouei Abe static struct mmc_config sh_sdhi_cfg = {
729a5950f8dSKouei Abe .name = DRIVER_NAME,
730a5950f8dSKouei Abe .ops = &sh_sdhi_ops,
731a5950f8dSKouei Abe .f_min = CLKDEV_INIT,
732a5950f8dSKouei Abe .f_max = CLKDEV_HS_DATA,
733a5950f8dSKouei Abe .voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34,
734a5950f8dSKouei Abe .host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT | MMC_MODE_HS |
735a5950f8dSKouei Abe MMC_MODE_HS_52MHz,
736a5950f8dSKouei Abe .part_type = PART_TYPE_DOS,
737a5950f8dSKouei Abe .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
738a5950f8dSKouei Abe };
739a5950f8dSKouei Abe #else
74072d42badSNobuhiro Iwamatsu static struct mmc_config sh_sdhi_cfg = {
74172d42badSNobuhiro Iwamatsu .name = DRIVER_NAME,
74272d42badSNobuhiro Iwamatsu .ops = &sh_sdhi_ops,
74372d42badSNobuhiro Iwamatsu .f_min = CLKDEV_INIT,
74472d42badSNobuhiro Iwamatsu .f_max = CLKDEV_HS_DATA,
74572d42badSNobuhiro Iwamatsu .voltages = MMC_VDD_32_33 | MMC_VDD_33_34,
74672d42badSNobuhiro Iwamatsu .host_caps = MMC_MODE_4BIT | MMC_MODE_HS,
74772d42badSNobuhiro Iwamatsu .part_type = PART_TYPE_DOS,
74872d42badSNobuhiro Iwamatsu .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
74972d42badSNobuhiro Iwamatsu };
750a5950f8dSKouei Abe #endif
75172d42badSNobuhiro Iwamatsu
sh_sdhi_init(unsigned long addr,int ch,unsigned long quirks)75272d42badSNobuhiro Iwamatsu int sh_sdhi_init(unsigned long addr, int ch, unsigned long quirks)
75372d42badSNobuhiro Iwamatsu {
75472d42badSNobuhiro Iwamatsu int ret = 0;
75572d42badSNobuhiro Iwamatsu struct mmc *mmc;
75672d42badSNobuhiro Iwamatsu struct sh_sdhi_host *host = NULL;
75772d42badSNobuhiro Iwamatsu
75872d42badSNobuhiro Iwamatsu if (ch >= CONFIG_SYS_SH_SDHI_NR_CHANNEL)
75972d42badSNobuhiro Iwamatsu return -ENODEV;
76072d42badSNobuhiro Iwamatsu
76172d42badSNobuhiro Iwamatsu host = malloc(sizeof(struct sh_sdhi_host));
76272d42badSNobuhiro Iwamatsu if (!host)
76372d42badSNobuhiro Iwamatsu return -ENOMEM;
76472d42badSNobuhiro Iwamatsu
76572d42badSNobuhiro Iwamatsu mmc = mmc_create(&sh_sdhi_cfg, host);
76672d42badSNobuhiro Iwamatsu if (!mmc) {
76772d42badSNobuhiro Iwamatsu ret = -1;
76872d42badSNobuhiro Iwamatsu goto error;
76972d42badSNobuhiro Iwamatsu }
77072d42badSNobuhiro Iwamatsu
77172d42badSNobuhiro Iwamatsu host->ch = ch;
772d1c18ca1SMarek Vasut host->addr = (void __iomem *)addr;
77372d42badSNobuhiro Iwamatsu host->quirks = quirks;
77472d42badSNobuhiro Iwamatsu
7755eada1dbSKouei Abe if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
7765eada1dbSKouei Abe host->bus_shift = 2;
7775eada1dbSKouei Abe else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
77872d42badSNobuhiro Iwamatsu host->bus_shift = 1;
77972d42badSNobuhiro Iwamatsu
78072d42badSNobuhiro Iwamatsu return ret;
78172d42badSNobuhiro Iwamatsu error:
78272d42badSNobuhiro Iwamatsu if (host)
78372d42badSNobuhiro Iwamatsu free(host);
78472d42badSNobuhiro Iwamatsu return ret;
78572d42badSNobuhiro Iwamatsu }
786d1c18ca1SMarek Vasut
787d1c18ca1SMarek Vasut #else
788d1c18ca1SMarek Vasut
789d1c18ca1SMarek Vasut struct sh_sdhi_plat {
790d1c18ca1SMarek Vasut struct mmc_config cfg;
791d1c18ca1SMarek Vasut struct mmc mmc;
792d1c18ca1SMarek Vasut };
793d1c18ca1SMarek Vasut
sh_sdhi_dm_send_cmd(struct udevice * dev,struct mmc_cmd * cmd,struct mmc_data * data)794d1c18ca1SMarek Vasut int sh_sdhi_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
795d1c18ca1SMarek Vasut struct mmc_data *data)
796d1c18ca1SMarek Vasut {
797d1c18ca1SMarek Vasut struct sh_sdhi_host *host = dev_get_priv(dev);
798d1c18ca1SMarek Vasut
799d1c18ca1SMarek Vasut return sh_sdhi_send_cmd_common(host, cmd, data);
800d1c18ca1SMarek Vasut }
801d1c18ca1SMarek Vasut
sh_sdhi_dm_set_ios(struct udevice * dev)802d1c18ca1SMarek Vasut int sh_sdhi_dm_set_ios(struct udevice *dev)
803d1c18ca1SMarek Vasut {
804d1c18ca1SMarek Vasut struct sh_sdhi_host *host = dev_get_priv(dev);
805d1c18ca1SMarek Vasut struct mmc *mmc = mmc_get_mmc_dev(dev);
806d1c18ca1SMarek Vasut
807d1c18ca1SMarek Vasut return sh_sdhi_set_ios_common(host, mmc);
808d1c18ca1SMarek Vasut }
809d1c18ca1SMarek Vasut
810d1c18ca1SMarek Vasut static const struct dm_mmc_ops sh_sdhi_dm_ops = {
811d1c18ca1SMarek Vasut .send_cmd = sh_sdhi_dm_send_cmd,
812d1c18ca1SMarek Vasut .set_ios = sh_sdhi_dm_set_ios,
813d1c18ca1SMarek Vasut };
814d1c18ca1SMarek Vasut
sh_sdhi_dm_bind(struct udevice * dev)815d1c18ca1SMarek Vasut static int sh_sdhi_dm_bind(struct udevice *dev)
816d1c18ca1SMarek Vasut {
817d1c18ca1SMarek Vasut struct sh_sdhi_plat *plat = dev_get_platdata(dev);
818d1c18ca1SMarek Vasut
819d1c18ca1SMarek Vasut return mmc_bind(dev, &plat->mmc, &plat->cfg);
820d1c18ca1SMarek Vasut }
821d1c18ca1SMarek Vasut
sh_sdhi_dm_probe(struct udevice * dev)822d1c18ca1SMarek Vasut static int sh_sdhi_dm_probe(struct udevice *dev)
823d1c18ca1SMarek Vasut {
824d1c18ca1SMarek Vasut struct sh_sdhi_plat *plat = dev_get_platdata(dev);
825d1c18ca1SMarek Vasut struct sh_sdhi_host *host = dev_get_priv(dev);
826d1c18ca1SMarek Vasut struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
8278cd46cbaSMarek Vasut struct clk sh_sdhi_clk;
828d1c18ca1SMarek Vasut const u32 quirks = dev_get_driver_data(dev);
829d1c18ca1SMarek Vasut fdt_addr_t base;
8308cd46cbaSMarek Vasut int ret;
831d1c18ca1SMarek Vasut
832d1c18ca1SMarek Vasut base = devfdt_get_addr(dev);
833d1c18ca1SMarek Vasut if (base == FDT_ADDR_T_NONE)
834d1c18ca1SMarek Vasut return -EINVAL;
835d1c18ca1SMarek Vasut
836d1c18ca1SMarek Vasut host->addr = devm_ioremap(dev, base, SZ_2K);
837d1c18ca1SMarek Vasut if (!host->addr)
838d1c18ca1SMarek Vasut return -ENOMEM;
839d1c18ca1SMarek Vasut
8408cd46cbaSMarek Vasut ret = clk_get_by_index(dev, 0, &sh_sdhi_clk);
8418cd46cbaSMarek Vasut if (ret) {
8428cd46cbaSMarek Vasut debug("failed to get clock, ret=%d\n", ret);
8438cd46cbaSMarek Vasut return ret;
8448cd46cbaSMarek Vasut }
8458cd46cbaSMarek Vasut
8468cd46cbaSMarek Vasut ret = clk_enable(&sh_sdhi_clk);
8478cd46cbaSMarek Vasut if (ret) {
8488cd46cbaSMarek Vasut debug("failed to enable clock, ret=%d\n", ret);
8498cd46cbaSMarek Vasut return ret;
8508cd46cbaSMarek Vasut }
8518cd46cbaSMarek Vasut
852d1c18ca1SMarek Vasut host->quirks = quirks;
853d1c18ca1SMarek Vasut
854d1c18ca1SMarek Vasut if (host->quirks & SH_SDHI_QUIRK_64BIT_BUF)
855d1c18ca1SMarek Vasut host->bus_shift = 2;
856d1c18ca1SMarek Vasut else if (host->quirks & SH_SDHI_QUIRK_16BIT_BUF)
857d1c18ca1SMarek Vasut host->bus_shift = 1;
858d1c18ca1SMarek Vasut
859d1c18ca1SMarek Vasut plat->cfg.name = dev->name;
860d1c18ca1SMarek Vasut plat->cfg.host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
861d1c18ca1SMarek Vasut
862d1c18ca1SMarek Vasut switch (fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), "bus-width",
863d1c18ca1SMarek Vasut 1)) {
864d1c18ca1SMarek Vasut case 8:
865d1c18ca1SMarek Vasut plat->cfg.host_caps |= MMC_MODE_8BIT;
866d1c18ca1SMarek Vasut break;
867d1c18ca1SMarek Vasut case 4:
868d1c18ca1SMarek Vasut plat->cfg.host_caps |= MMC_MODE_4BIT;
869d1c18ca1SMarek Vasut break;
870d1c18ca1SMarek Vasut case 1:
871d1c18ca1SMarek Vasut break;
872d1c18ca1SMarek Vasut default:
873d1c18ca1SMarek Vasut dev_err(dev, "Invalid \"bus-width\" value\n");
874d1c18ca1SMarek Vasut return -EINVAL;
875d1c18ca1SMarek Vasut }
876d1c18ca1SMarek Vasut
877d1c18ca1SMarek Vasut sh_sdhi_initialize_common(host);
878d1c18ca1SMarek Vasut
879d1c18ca1SMarek Vasut plat->cfg.voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
880d1c18ca1SMarek Vasut plat->cfg.f_min = CLKDEV_INIT;
881d1c18ca1SMarek Vasut plat->cfg.f_max = CLKDEV_HS_DATA;
882d1c18ca1SMarek Vasut plat->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
883d1c18ca1SMarek Vasut
884d1c18ca1SMarek Vasut upriv->mmc = &plat->mmc;
885d1c18ca1SMarek Vasut
886d1c18ca1SMarek Vasut return 0;
887d1c18ca1SMarek Vasut }
888d1c18ca1SMarek Vasut
889d1c18ca1SMarek Vasut static const struct udevice_id sh_sdhi_sd_match[] = {
890d1c18ca1SMarek Vasut { .compatible = "renesas,sdhi-r8a7795", .data = SH_SDHI_QUIRK_64BIT_BUF },
891d1c18ca1SMarek Vasut { .compatible = "renesas,sdhi-r8a7796", .data = SH_SDHI_QUIRK_64BIT_BUF },
892d1c18ca1SMarek Vasut { /* sentinel */ }
893d1c18ca1SMarek Vasut };
894d1c18ca1SMarek Vasut
895d1c18ca1SMarek Vasut U_BOOT_DRIVER(sh_sdhi_mmc) = {
896d1c18ca1SMarek Vasut .name = "sh-sdhi-mmc",
897d1c18ca1SMarek Vasut .id = UCLASS_MMC,
898d1c18ca1SMarek Vasut .of_match = sh_sdhi_sd_match,
899d1c18ca1SMarek Vasut .bind = sh_sdhi_dm_bind,
900d1c18ca1SMarek Vasut .probe = sh_sdhi_dm_probe,
901d1c18ca1SMarek Vasut .priv_auto_alloc_size = sizeof(struct sh_sdhi_host),
902d1c18ca1SMarek Vasut .platdata_auto_alloc_size = sizeof(struct sh_sdhi_plat),
903d1c18ca1SMarek Vasut .ops = &sh_sdhi_dm_ops,
904d1c18ca1SMarek Vasut };
905d1c18ca1SMarek Vasut #endif
906