1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+ 2f6c3b346SKuo-Jung Su /* 3f6c3b346SKuo-Jung Su * Faraday MMC/SD Host Controller 4f6c3b346SKuo-Jung Su * 5f6c3b346SKuo-Jung Su * (C) Copyright 2010 Faraday Technology 6f6c3b346SKuo-Jung Su * Dante Su <dantesu@faraday-tech.com> 7f6c3b346SKuo-Jung Su * 8bf9ba4dbSRick Chen * Copyright 2018 Andes Technology, Inc. 9bf9ba4dbSRick Chen * Author: Rick Chen (rick@andestech.com) 10f6c3b346SKuo-Jung Su */ 11f6c3b346SKuo-Jung Su 12f6c3b346SKuo-Jung Su #include <common.h> 13bf9ba4dbSRick Chen #include <clk.h> 14f6c3b346SKuo-Jung Su #include <malloc.h> 15f6c3b346SKuo-Jung Su #include <part.h> 16f6c3b346SKuo-Jung Su #include <mmc.h> 17252185f2SRick Chen #include <linux/io.h> 181221ce45SMasahiro Yamada #include <linux/errno.h> 19f6c3b346SKuo-Jung Su #include <asm/byteorder.h> 20f6c3b346SKuo-Jung Su #include <faraday/ftsdc010.h> 21252185f2SRick Chen #include "ftsdc010_mci.h" 22bf9ba4dbSRick Chen #include <dm.h> 23bf9ba4dbSRick Chen #include <dt-structs.h> 24bf9ba4dbSRick Chen #include <errno.h> 25bf9ba4dbSRick Chen #include <mapmem.h> 26bf9ba4dbSRick Chen #include <pwrseq.h> 27bf9ba4dbSRick Chen #include <syscon.h> 28bf9ba4dbSRick Chen #include <linux/err.h> 29bf9ba4dbSRick Chen 30bf9ba4dbSRick Chen DECLARE_GLOBAL_DATA_PTR; 31f6c3b346SKuo-Jung Su 32f6c3b346SKuo-Jung Su #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */ 33f6c3b346SKuo-Jung Su #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */ 34f6c3b346SKuo-Jung Su 35bf9ba4dbSRick Chen #if CONFIG_IS_ENABLED(OF_PLATDATA) 36bf9ba4dbSRick Chen struct ftsdc010 { 37bf9ba4dbSRick Chen fdt32_t bus_width; 38bf9ba4dbSRick Chen bool cap_mmc_highspeed; 39bf9ba4dbSRick Chen bool cap_sd_highspeed; 40bf9ba4dbSRick Chen fdt32_t clock_freq_min_max[2]; 41bf9ba4dbSRick Chen struct phandle_2_cell clocks[4]; 42bf9ba4dbSRick Chen fdt32_t fifo_depth; 43bf9ba4dbSRick Chen fdt32_t reg[2]; 44bf9ba4dbSRick Chen }; 45bf9ba4dbSRick Chen #endif 46bf9ba4dbSRick Chen 47bf9ba4dbSRick Chen struct ftsdc010_plat { 48bf9ba4dbSRick Chen #if CONFIG_IS_ENABLED(OF_PLATDATA) 49bf9ba4dbSRick Chen struct ftsdc010 dtplat; 50bf9ba4dbSRick Chen #endif 51bf9ba4dbSRick Chen struct mmc_config cfg; 52bf9ba4dbSRick Chen struct mmc mmc; 53bf9ba4dbSRick Chen }; 54bf9ba4dbSRick Chen 55bf9ba4dbSRick Chen struct ftsdc_priv { 56bf9ba4dbSRick Chen struct clk clk; 57bf9ba4dbSRick Chen struct ftsdc010_chip chip; 58bf9ba4dbSRick Chen int fifo_depth; 59bf9ba4dbSRick Chen bool fifo_mode; 60bf9ba4dbSRick Chen u32 minmax[2]; 61bf9ba4dbSRick Chen }; 62bf9ba4dbSRick Chen 63f6c3b346SKuo-Jung Su static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) 64f6c3b346SKuo-Jung Su { 65f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 66f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 67915ffa52SJaehoon Chung int ret = -ETIMEDOUT; 68f6c3b346SKuo-Jung Su uint32_t ts, st; 69f6c3b346SKuo-Jung Su uint32_t cmd = FTSDC010_CMD_IDX(mmc_cmd->cmdidx); 70f6c3b346SKuo-Jung Su uint32_t arg = mmc_cmd->cmdarg; 71f6c3b346SKuo-Jung Su uint32_t flags = mmc_cmd->resp_type; 72f6c3b346SKuo-Jung Su 73f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_CMD_EN; 74f6c3b346SKuo-Jung Su 75f6c3b346SKuo-Jung Su if (chip->acmd) { 76f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_APP_CMD; 77f6c3b346SKuo-Jung Su chip->acmd = 0; 78f6c3b346SKuo-Jung Su } 79f6c3b346SKuo-Jung Su 80f6c3b346SKuo-Jung Su if (flags & MMC_RSP_PRESENT) 81f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_NEED_RSP; 82f6c3b346SKuo-Jung Su 83f6c3b346SKuo-Jung Su if (flags & MMC_RSP_136) 84f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_LONG_RSP; 85f6c3b346SKuo-Jung Su 86f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND, 87f6c3b346SKuo-Jung Su ®s->clr); 88f6c3b346SKuo-Jung Su writel(arg, ®s->argu); 89f6c3b346SKuo-Jung Su writel(cmd, ®s->cmd); 90f6c3b346SKuo-Jung Su 91f6c3b346SKuo-Jung Su if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) { 92f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { 93f6c3b346SKuo-Jung Su if (readl(®s->status) & FTSDC010_STATUS_CMD_SEND) { 94f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_CMD_SEND, ®s->clr); 95f6c3b346SKuo-Jung Su ret = 0; 96f6c3b346SKuo-Jung Su break; 97f6c3b346SKuo-Jung Su } 98f6c3b346SKuo-Jung Su } 99f6c3b346SKuo-Jung Su } else { 100f6c3b346SKuo-Jung Su st = 0; 101f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { 102f6c3b346SKuo-Jung Su st = readl(®s->status); 103f6c3b346SKuo-Jung Su writel(st & FTSDC010_STATUS_RSP_MASK, ®s->clr); 104f6c3b346SKuo-Jung Su if (st & FTSDC010_STATUS_RSP_MASK) 105f6c3b346SKuo-Jung Su break; 106f6c3b346SKuo-Jung Su } 107f6c3b346SKuo-Jung Su if (st & FTSDC010_STATUS_RSP_CRC_OK) { 108f6c3b346SKuo-Jung Su if (flags & MMC_RSP_136) { 109f6c3b346SKuo-Jung Su mmc_cmd->response[0] = readl(®s->rsp3); 110f6c3b346SKuo-Jung Su mmc_cmd->response[1] = readl(®s->rsp2); 111f6c3b346SKuo-Jung Su mmc_cmd->response[2] = readl(®s->rsp1); 112f6c3b346SKuo-Jung Su mmc_cmd->response[3] = readl(®s->rsp0); 113f6c3b346SKuo-Jung Su } else { 114f6c3b346SKuo-Jung Su mmc_cmd->response[0] = readl(®s->rsp0); 115f6c3b346SKuo-Jung Su } 116f6c3b346SKuo-Jung Su ret = 0; 117f6c3b346SKuo-Jung Su } else { 118f6c3b346SKuo-Jung Su debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n", 119f6c3b346SKuo-Jung Su mmc_cmd->cmdidx, st); 120f6c3b346SKuo-Jung Su } 121f6c3b346SKuo-Jung Su } 122f6c3b346SKuo-Jung Su 123f6c3b346SKuo-Jung Su if (ret) { 124f6c3b346SKuo-Jung Su debug("ftsdc010: cmd timeout (op code=%d)\n", 125f6c3b346SKuo-Jung Su mmc_cmd->cmdidx); 126f6c3b346SKuo-Jung Su } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) { 127f6c3b346SKuo-Jung Su chip->acmd = 1; 128f6c3b346SKuo-Jung Su } 129f6c3b346SKuo-Jung Su 130f6c3b346SKuo-Jung Su return ret; 131f6c3b346SKuo-Jung Su } 132f6c3b346SKuo-Jung Su 133f6c3b346SKuo-Jung Su static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate) 134f6c3b346SKuo-Jung Su { 135f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 136f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 137f6c3b346SKuo-Jung Su uint32_t div; 138f6c3b346SKuo-Jung Su 139f6c3b346SKuo-Jung Su for (div = 0; div < 0x7f; ++div) { 140f6c3b346SKuo-Jung Su if (rate >= chip->sclk / (2 * (div + 1))) 141f6c3b346SKuo-Jung Su break; 142f6c3b346SKuo-Jung Su } 143f6c3b346SKuo-Jung Su chip->rate = chip->sclk / (2 * (div + 1)); 144f6c3b346SKuo-Jung Su 145f6c3b346SKuo-Jung Su writel(FTSDC010_CCR_CLK_DIV(div), ®s->ccr); 146f6c3b346SKuo-Jung Su 147f6c3b346SKuo-Jung Su if (IS_SD(mmc)) { 148f6c3b346SKuo-Jung Su setbits_le32(®s->ccr, FTSDC010_CCR_CLK_SD); 149f6c3b346SKuo-Jung Su 150f6c3b346SKuo-Jung Su if (chip->rate > 25000000) 151f6c3b346SKuo-Jung Su setbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD); 152f6c3b346SKuo-Jung Su else 153f6c3b346SKuo-Jung Su clrbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD); 154f6c3b346SKuo-Jung Su } 155f6c3b346SKuo-Jung Su } 156f6c3b346SKuo-Jung Su 157f6c3b346SKuo-Jung Su static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) 158f6c3b346SKuo-Jung Su { 159915ffa52SJaehoon Chung int ret = -ETIMEDOUT; 160252185f2SRick Chen uint32_t st, timeout = 10000000; 161252185f2SRick Chen while (timeout--) { 162f6c3b346SKuo-Jung Su st = readl(®s->status); 163f6c3b346SKuo-Jung Su if (!(st & mask)) 164f6c3b346SKuo-Jung Su continue; 165f6c3b346SKuo-Jung Su writel(st & mask, ®s->clr); 166f6c3b346SKuo-Jung Su ret = 0; 167f6c3b346SKuo-Jung Su break; 168f6c3b346SKuo-Jung Su } 169f6c3b346SKuo-Jung Su 1701a9db640SRick Chen if (ret){ 171f6c3b346SKuo-Jung Su debug("ftsdc010: wait st(0x%x) timeout\n", mask); 1721a9db640SRick Chen } 173f6c3b346SKuo-Jung Su 174f6c3b346SKuo-Jung Su return ret; 175f6c3b346SKuo-Jung Su } 176f6c3b346SKuo-Jung Su 177f6c3b346SKuo-Jung Su /* 178f6c3b346SKuo-Jung Su * u-boot mmc api 179f6c3b346SKuo-Jung Su */ 180252185f2SRick Chen static int ftsdc010_request(struct udevice *dev, struct mmc_cmd *cmd, 181252185f2SRick Chen struct mmc_data *data) 182252185f2SRick Chen { 183252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev); 184915ffa52SJaehoon Chung int ret = -EOPNOTSUPP; 185f6c3b346SKuo-Jung Su uint32_t len = 0; 186f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 187f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 188f6c3b346SKuo-Jung Su 189f6c3b346SKuo-Jung Su if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) { 190f6c3b346SKuo-Jung Su printf("ftsdc010: the card is write protected!\n"); 191f6c3b346SKuo-Jung Su return ret; 192f6c3b346SKuo-Jung Su } 193f6c3b346SKuo-Jung Su 194f6c3b346SKuo-Jung Su if (data) { 195f6c3b346SKuo-Jung Su uint32_t dcr; 196f6c3b346SKuo-Jung Su 197f6c3b346SKuo-Jung Su len = data->blocksize * data->blocks; 198f6c3b346SKuo-Jung Su 199f6c3b346SKuo-Jung Su /* 1. data disable + fifo reset */ 200dbb713baSGabor Juhos dcr = 0; 201dbb713baSGabor Juhos #ifdef CONFIG_FTSDC010_SDIO 202dbb713baSGabor Juhos dcr |= FTSDC010_DCR_FIFO_RST; 203dbb713baSGabor Juhos #endif 204dbb713baSGabor Juhos writel(dcr, ®s->dcr); 205f6c3b346SKuo-Jung Su 206f6c3b346SKuo-Jung Su /* 2. clear status register */ 207f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN 208f6c3b346SKuo-Jung Su | FTSDC010_STATUS_FIFO_ORUN, ®s->clr); 209f6c3b346SKuo-Jung Su 210f6c3b346SKuo-Jung Su /* 3. data timeout (1 sec) */ 211f6c3b346SKuo-Jung Su writel(chip->rate, ®s->dtr); 212f6c3b346SKuo-Jung Su 213f6c3b346SKuo-Jung Su /* 4. data length (bytes) */ 214f6c3b346SKuo-Jung Su writel(len, ®s->dlr); 215f6c3b346SKuo-Jung Su 216f6c3b346SKuo-Jung Su /* 5. data enable */ 217f6c3b346SKuo-Jung Su dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN; 218f6c3b346SKuo-Jung Su if (data->flags & MMC_DATA_WRITE) 219f6c3b346SKuo-Jung Su dcr |= FTSDC010_DCR_DATA_WRITE; 220f6c3b346SKuo-Jung Su writel(dcr, ®s->dcr); 221f6c3b346SKuo-Jung Su } 222f6c3b346SKuo-Jung Su 223f6c3b346SKuo-Jung Su ret = ftsdc010_send_cmd(mmc, cmd); 224f6c3b346SKuo-Jung Su if (ret) { 225f6c3b346SKuo-Jung Su printf("ftsdc010: CMD%d failed\n", cmd->cmdidx); 226f6c3b346SKuo-Jung Su return ret; 227f6c3b346SKuo-Jung Su } 228f6c3b346SKuo-Jung Su 229f6c3b346SKuo-Jung Su if (!data) 230f6c3b346SKuo-Jung Su return ret; 231f6c3b346SKuo-Jung Su 232f6c3b346SKuo-Jung Su if (data->flags & MMC_DATA_WRITE) { 233f6c3b346SKuo-Jung Su const uint8_t *buf = (const uint8_t *)data->src; 234f6c3b346SKuo-Jung Su 235f6c3b346SKuo-Jung Su while (len > 0) { 236f6c3b346SKuo-Jung Su int wlen; 237f6c3b346SKuo-Jung Su 238f6c3b346SKuo-Jung Su /* wait for tx ready */ 239f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN); 240f6c3b346SKuo-Jung Su if (ret) 241f6c3b346SKuo-Jung Su break; 242f6c3b346SKuo-Jung Su 243f6c3b346SKuo-Jung Su /* write bytes to ftsdc010 */ 244f6c3b346SKuo-Jung Su for (wlen = 0; wlen < len && wlen < chip->fifo; ) { 245f6c3b346SKuo-Jung Su writel(*(uint32_t *)buf, ®s->dwr); 246f6c3b346SKuo-Jung Su buf += 4; 247f6c3b346SKuo-Jung Su wlen += 4; 248f6c3b346SKuo-Jung Su } 249f6c3b346SKuo-Jung Su 250f6c3b346SKuo-Jung Su len -= wlen; 251f6c3b346SKuo-Jung Su } 252f6c3b346SKuo-Jung Su 253f6c3b346SKuo-Jung Su } else { 254f6c3b346SKuo-Jung Su uint8_t *buf = (uint8_t *)data->dest; 255f6c3b346SKuo-Jung Su 256f6c3b346SKuo-Jung Su while (len > 0) { 257f6c3b346SKuo-Jung Su int rlen; 258f6c3b346SKuo-Jung Su 259f6c3b346SKuo-Jung Su /* wait for rx ready */ 260f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN); 261f6c3b346SKuo-Jung Su if (ret) 262f6c3b346SKuo-Jung Su break; 263f6c3b346SKuo-Jung Su 264f6c3b346SKuo-Jung Su /* fetch bytes from ftsdc010 */ 265f6c3b346SKuo-Jung Su for (rlen = 0; rlen < len && rlen < chip->fifo; ) { 266f6c3b346SKuo-Jung Su *(uint32_t *)buf = readl(®s->dwr); 267f6c3b346SKuo-Jung Su buf += 4; 268f6c3b346SKuo-Jung Su rlen += 4; 269f6c3b346SKuo-Jung Su } 270f6c3b346SKuo-Jung Su 271f6c3b346SKuo-Jung Su len -= rlen; 272f6c3b346SKuo-Jung Su } 273f6c3b346SKuo-Jung Su 274f6c3b346SKuo-Jung Su } 275f6c3b346SKuo-Jung Su 276f6c3b346SKuo-Jung Su if (!ret) { 277f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, 2781a9db640SRick Chen FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_CRC_OK); 279f6c3b346SKuo-Jung Su } 280f6c3b346SKuo-Jung Su 281f6c3b346SKuo-Jung Su return ret; 282f6c3b346SKuo-Jung Su } 283f6c3b346SKuo-Jung Su 284252185f2SRick Chen static int ftsdc010_set_ios(struct udevice *dev) 285252185f2SRick Chen { 286252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev); 287f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 288f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 289f6c3b346SKuo-Jung Su 290f6c3b346SKuo-Jung Su ftsdc010_clkset(mmc, mmc->clock); 291f6c3b346SKuo-Jung Su 292f6c3b346SKuo-Jung Su clrbits_le32(®s->bwr, FTSDC010_BWR_MODE_MASK); 293f6c3b346SKuo-Jung Su switch (mmc->bus_width) { 294f6c3b346SKuo-Jung Su case 4: 295f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_4BIT); 296f6c3b346SKuo-Jung Su break; 297f6c3b346SKuo-Jung Su case 8: 298f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_8BIT); 299f6c3b346SKuo-Jung Su break; 300f6c3b346SKuo-Jung Su default: 301f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_1BIT); 302f6c3b346SKuo-Jung Su break; 303f6c3b346SKuo-Jung Su } 30407b0b9c0SJaehoon Chung 30507b0b9c0SJaehoon Chung return 0; 306f6c3b346SKuo-Jung Su } 307f6c3b346SKuo-Jung Su 308252185f2SRick Chen static int ftsdc010_get_cd(struct udevice *dev) 309252185f2SRick Chen { 310252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev); 311252185f2SRick Chen struct ftsdc010_chip *chip = mmc->priv; 312252185f2SRick Chen struct ftsdc010_mmc __iomem *regs = chip->regs; 313252185f2SRick Chen return !(readl(®s->status) & FTSDC010_STATUS_CARD_DETECT); 314252185f2SRick Chen } 315252185f2SRick Chen 316252185f2SRick Chen static int ftsdc010_get_wp(struct udevice *dev) 317252185f2SRick Chen { 318252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev); 319252185f2SRick Chen struct ftsdc010_chip *chip = mmc->priv; 320252185f2SRick Chen struct ftsdc010_mmc __iomem *regs = chip->regs; 321252185f2SRick Chen if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) { 322252185f2SRick Chen printf("ftsdc010: write protected\n"); 323252185f2SRick Chen chip->wprot = 1; 324252185f2SRick Chen } 325252185f2SRick Chen 326252185f2SRick Chen return 0; 327252185f2SRick Chen } 328252185f2SRick Chen 329f6c3b346SKuo-Jung Su static int ftsdc010_init(struct mmc *mmc) 330f6c3b346SKuo-Jung Su { 331f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 332f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 333f6c3b346SKuo-Jung Su uint32_t ts; 334f6c3b346SKuo-Jung Su 335f6c3b346SKuo-Jung Su chip->fifo = (readl(®s->feature) & 0xff) << 2; 336f6c3b346SKuo-Jung Su 337f6c3b346SKuo-Jung Su /* 1. chip reset */ 338f6c3b346SKuo-Jung Su writel(FTSDC010_CMD_SDC_RST, ®s->cmd); 339f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) { 340f6c3b346SKuo-Jung Su if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) 341f6c3b346SKuo-Jung Su continue; 342f6c3b346SKuo-Jung Su break; 343f6c3b346SKuo-Jung Su } 344f6c3b346SKuo-Jung Su if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) { 345f6c3b346SKuo-Jung Su printf("ftsdc010: reset failed\n"); 346915ffa52SJaehoon Chung return -EOPNOTSUPP; 347f6c3b346SKuo-Jung Su } 348f6c3b346SKuo-Jung Su 349f6c3b346SKuo-Jung Su /* 2. enter low speed mode (400k card detection) */ 350f6c3b346SKuo-Jung Su ftsdc010_clkset(mmc, 400000); 351f6c3b346SKuo-Jung Su 352f6c3b346SKuo-Jung Su /* 3. interrupt disabled */ 353f6c3b346SKuo-Jung Su writel(0, ®s->int_mask); 354f6c3b346SKuo-Jung Su 355f6c3b346SKuo-Jung Su return 0; 356f6c3b346SKuo-Jung Su } 357f6c3b346SKuo-Jung Su 358bf9ba4dbSRick Chen static int ftsdc010_probe(struct udevice *dev) 359252185f2SRick Chen { 360252185f2SRick Chen struct mmc *mmc = mmc_get_mmc_dev(dev); 361252185f2SRick Chen return ftsdc010_init(mmc); 362252185f2SRick Chen } 363252185f2SRick Chen 364bf9ba4dbSRick Chen const struct dm_mmc_ops dm_ftsdc010_mmc_ops = { 365252185f2SRick Chen .send_cmd = ftsdc010_request, 366252185f2SRick Chen .set_ios = ftsdc010_set_ios, 367252185f2SRick Chen .get_cd = ftsdc010_get_cd, 368252185f2SRick Chen .get_wp = ftsdc010_get_wp, 369252185f2SRick Chen }; 370252185f2SRick Chen 371bf9ba4dbSRick Chen static void ftsdc_setup_cfg(struct mmc_config *cfg, const char *name, int buswidth, 372252185f2SRick Chen uint caps, u32 max_clk, u32 min_clk) 373252185f2SRick Chen { 374252185f2SRick Chen cfg->name = name; 375252185f2SRick Chen cfg->f_min = min_clk; 376252185f2SRick Chen cfg->f_max = max_clk; 377252185f2SRick Chen cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195; 378252185f2SRick Chen cfg->host_caps = caps; 379252185f2SRick Chen if (buswidth == 8) { 380252185f2SRick Chen cfg->host_caps |= MMC_MODE_8BIT; 381252185f2SRick Chen cfg->host_caps &= ~MMC_MODE_4BIT; 382252185f2SRick Chen } else { 383252185f2SRick Chen cfg->host_caps |= MMC_MODE_4BIT; 384252185f2SRick Chen cfg->host_caps &= ~MMC_MODE_8BIT; 385252185f2SRick Chen } 386252185f2SRick Chen cfg->part_type = PART_TYPE_DOS; 387252185f2SRick Chen cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; 388252185f2SRick Chen } 389252185f2SRick Chen 390bf9ba4dbSRick Chen static int ftsdc010_mmc_ofdata_to_platdata(struct udevice *dev) 391252185f2SRick Chen { 392bf9ba4dbSRick Chen #if !CONFIG_IS_ENABLED(OF_PLATDATA) 393bf9ba4dbSRick Chen struct ftsdc_priv *priv = dev_get_priv(dev); 394bf9ba4dbSRick Chen struct ftsdc010_chip *chip = &priv->chip; 395bf9ba4dbSRick Chen chip->name = dev->name; 396bf9ba4dbSRick Chen chip->ioaddr = (void *)devfdt_get_addr(dev); 397bf9ba4dbSRick Chen chip->buswidth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 398bf9ba4dbSRick Chen "bus-width", 4); 399bf9ba4dbSRick Chen chip->priv = dev; 400bf9ba4dbSRick Chen priv->fifo_depth = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 401bf9ba4dbSRick Chen "fifo-depth", 0); 402bf9ba4dbSRick Chen priv->fifo_mode = fdtdec_get_bool(gd->fdt_blob, dev_of_offset(dev), 403bf9ba4dbSRick Chen "fifo-mode"); 404bf9ba4dbSRick Chen if (fdtdec_get_int_array(gd->fdt_blob, dev_of_offset(dev), 405bf9ba4dbSRick Chen "clock-freq-min-max", priv->minmax, 2)) { 406bf9ba4dbSRick Chen int val = fdtdec_get_int(gd->fdt_blob, dev_of_offset(dev), 407bf9ba4dbSRick Chen "max-frequency", -EINVAL); 408bf9ba4dbSRick Chen if (val < 0) 409bf9ba4dbSRick Chen return val; 410bf9ba4dbSRick Chen 411bf9ba4dbSRick Chen priv->minmax[0] = 400000; /* 400 kHz */ 412bf9ba4dbSRick Chen priv->minmax[1] = val; 413bf9ba4dbSRick Chen } else { 414bf9ba4dbSRick Chen debug("%s: 'clock-freq-min-max' property was deprecated.\n", 415bf9ba4dbSRick Chen __func__); 416252185f2SRick Chen } 417bf9ba4dbSRick Chen #endif 418bf9ba4dbSRick Chen chip->sclk = priv->minmax[1]; 419bf9ba4dbSRick Chen chip->regs = chip->ioaddr; 420bf9ba4dbSRick Chen return 0; 421bf9ba4dbSRick Chen } 422bf9ba4dbSRick Chen 423bf9ba4dbSRick Chen static int ftsdc010_mmc_probe(struct udevice *dev) 424bf9ba4dbSRick Chen { 425bf9ba4dbSRick Chen struct ftsdc010_plat *plat = dev_get_platdata(dev); 426bf9ba4dbSRick Chen struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); 427bf9ba4dbSRick Chen struct ftsdc_priv *priv = dev_get_priv(dev); 428bf9ba4dbSRick Chen struct ftsdc010_chip *chip = &priv->chip; 429bf9ba4dbSRick Chen struct udevice *pwr_dev __maybe_unused; 430bf9ba4dbSRick Chen 431bf9ba4dbSRick Chen #if CONFIG_IS_ENABLED(OF_PLATDATA) 432bf9ba4dbSRick Chen int ret; 433bf9ba4dbSRick Chen struct ftsdc010 *dtplat = &plat->dtplat; 434bf9ba4dbSRick Chen chip->name = dev->name; 435bf9ba4dbSRick Chen chip->ioaddr = map_sysmem(dtplat->reg[0], dtplat->reg[1]); 436bf9ba4dbSRick Chen chip->buswidth = dtplat->bus_width; 437bf9ba4dbSRick Chen chip->priv = dev; 438bf9ba4dbSRick Chen chip->dev_index = 1; 439bf9ba4dbSRick Chen memcpy(priv->minmax, dtplat->clock_freq_min_max, sizeof(priv->minmax)); 440bf9ba4dbSRick Chen ret = clk_get_by_index_platdata(dev, 0, dtplat->clocks, &priv->clk); 441bf9ba4dbSRick Chen if (ret < 0) 442bf9ba4dbSRick Chen return ret; 443bf9ba4dbSRick Chen #endif 444bf9ba4dbSRick Chen 445bf9ba4dbSRick Chen if (dev_read_bool(dev, "cap-mmc-highspeed") || \ 446bf9ba4dbSRick Chen dev_read_bool(dev, "cap-sd-highspeed")) 447bf9ba4dbSRick Chen chip->caps |= MMC_MODE_HS | MMC_MODE_HS_52MHz; 448bf9ba4dbSRick Chen 449bf9ba4dbSRick Chen ftsdc_setup_cfg(&plat->cfg, dev->name, chip->buswidth, chip->caps, 450bf9ba4dbSRick Chen priv->minmax[1] , priv->minmax[0]); 451bf9ba4dbSRick Chen chip->mmc = &plat->mmc; 452bf9ba4dbSRick Chen chip->mmc->priv = &priv->chip; 453bf9ba4dbSRick Chen chip->mmc->dev = dev; 454bf9ba4dbSRick Chen upriv->mmc = chip->mmc; 455bf9ba4dbSRick Chen return ftsdc010_probe(dev); 456bf9ba4dbSRick Chen } 457bf9ba4dbSRick Chen 458bf9ba4dbSRick Chen int ftsdc010_mmc_bind(struct udevice *dev) 459bf9ba4dbSRick Chen { 460bf9ba4dbSRick Chen struct ftsdc010_plat *plat = dev_get_platdata(dev); 461bf9ba4dbSRick Chen 462bf9ba4dbSRick Chen return mmc_bind(dev, &plat->mmc, &plat->cfg); 463bf9ba4dbSRick Chen } 464bf9ba4dbSRick Chen 465bf9ba4dbSRick Chen static const struct udevice_id ftsdc010_mmc_ids[] = { 466bf9ba4dbSRick Chen { .compatible = "andestech,atsdc010" }, 467bf9ba4dbSRick Chen { } 468bf9ba4dbSRick Chen }; 469bf9ba4dbSRick Chen 470bf9ba4dbSRick Chen U_BOOT_DRIVER(ftsdc010_mmc) = { 471bf9ba4dbSRick Chen .name = "ftsdc010_mmc", 472bf9ba4dbSRick Chen .id = UCLASS_MMC, 473bf9ba4dbSRick Chen .of_match = ftsdc010_mmc_ids, 474bf9ba4dbSRick Chen .ofdata_to_platdata = ftsdc010_mmc_ofdata_to_platdata, 475bf9ba4dbSRick Chen .ops = &dm_ftsdc010_mmc_ops, 476bf9ba4dbSRick Chen .bind = ftsdc010_mmc_bind, 477bf9ba4dbSRick Chen .probe = ftsdc010_mmc_probe, 478bf9ba4dbSRick Chen .priv_auto_alloc_size = sizeof(struct ftsdc_priv), 479bf9ba4dbSRick Chen .platdata_auto_alloc_size = sizeof(struct ftsdc010_plat), 480bf9ba4dbSRick Chen }; 481