1*f6c3b346SKuo-Jung Su /* 2*f6c3b346SKuo-Jung Su * Faraday MMC/SD Host Controller 3*f6c3b346SKuo-Jung Su * 4*f6c3b346SKuo-Jung Su * (C) Copyright 2010 Faraday Technology 5*f6c3b346SKuo-Jung Su * Dante Su <dantesu@faraday-tech.com> 6*f6c3b346SKuo-Jung Su * 7*f6c3b346SKuo-Jung Su * This file is released under the terms of GPL v2 and any later version. 8*f6c3b346SKuo-Jung Su * See the file COPYING in the root directory of the source tree for details. 9*f6c3b346SKuo-Jung Su */ 10*f6c3b346SKuo-Jung Su 11*f6c3b346SKuo-Jung Su #include <common.h> 12*f6c3b346SKuo-Jung Su #include <malloc.h> 13*f6c3b346SKuo-Jung Su #include <part.h> 14*f6c3b346SKuo-Jung Su #include <mmc.h> 15*f6c3b346SKuo-Jung Su 16*f6c3b346SKuo-Jung Su #include <asm/io.h> 17*f6c3b346SKuo-Jung Su #include <asm/errno.h> 18*f6c3b346SKuo-Jung Su #include <asm/byteorder.h> 19*f6c3b346SKuo-Jung Su #include <faraday/ftsdc010.h> 20*f6c3b346SKuo-Jung Su 21*f6c3b346SKuo-Jung Su #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */ 22*f6c3b346SKuo-Jung Su #define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */ 23*f6c3b346SKuo-Jung Su 24*f6c3b346SKuo-Jung Su struct ftsdc010_chip { 25*f6c3b346SKuo-Jung Su void __iomem *regs; 26*f6c3b346SKuo-Jung Su uint32_t wprot; /* write protected (locked) */ 27*f6c3b346SKuo-Jung Su uint32_t rate; /* actual SD clock in Hz */ 28*f6c3b346SKuo-Jung Su uint32_t sclk; /* FTSDC010 source clock in Hz */ 29*f6c3b346SKuo-Jung Su uint32_t fifo; /* fifo depth in bytes */ 30*f6c3b346SKuo-Jung Su uint32_t acmd; 31*f6c3b346SKuo-Jung Su }; 32*f6c3b346SKuo-Jung Su 33*f6c3b346SKuo-Jung Su static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd) 34*f6c3b346SKuo-Jung Su { 35*f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 36*f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 37*f6c3b346SKuo-Jung Su int ret = TIMEOUT; 38*f6c3b346SKuo-Jung Su uint32_t ts, st; 39*f6c3b346SKuo-Jung Su uint32_t cmd = FTSDC010_CMD_IDX(mmc_cmd->cmdidx); 40*f6c3b346SKuo-Jung Su uint32_t arg = mmc_cmd->cmdarg; 41*f6c3b346SKuo-Jung Su uint32_t flags = mmc_cmd->resp_type; 42*f6c3b346SKuo-Jung Su 43*f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_CMD_EN; 44*f6c3b346SKuo-Jung Su 45*f6c3b346SKuo-Jung Su if (chip->acmd) { 46*f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_APP_CMD; 47*f6c3b346SKuo-Jung Su chip->acmd = 0; 48*f6c3b346SKuo-Jung Su } 49*f6c3b346SKuo-Jung Su 50*f6c3b346SKuo-Jung Su if (flags & MMC_RSP_PRESENT) 51*f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_NEED_RSP; 52*f6c3b346SKuo-Jung Su 53*f6c3b346SKuo-Jung Su if (flags & MMC_RSP_136) 54*f6c3b346SKuo-Jung Su cmd |= FTSDC010_CMD_LONG_RSP; 55*f6c3b346SKuo-Jung Su 56*f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND, 57*f6c3b346SKuo-Jung Su ®s->clr); 58*f6c3b346SKuo-Jung Su writel(arg, ®s->argu); 59*f6c3b346SKuo-Jung Su writel(cmd, ®s->cmd); 60*f6c3b346SKuo-Jung Su 61*f6c3b346SKuo-Jung Su if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) { 62*f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { 63*f6c3b346SKuo-Jung Su if (readl(®s->status) & FTSDC010_STATUS_CMD_SEND) { 64*f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_CMD_SEND, ®s->clr); 65*f6c3b346SKuo-Jung Su ret = 0; 66*f6c3b346SKuo-Jung Su break; 67*f6c3b346SKuo-Jung Su } 68*f6c3b346SKuo-Jung Su } 69*f6c3b346SKuo-Jung Su } else { 70*f6c3b346SKuo-Jung Su st = 0; 71*f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { 72*f6c3b346SKuo-Jung Su st = readl(®s->status); 73*f6c3b346SKuo-Jung Su writel(st & FTSDC010_STATUS_RSP_MASK, ®s->clr); 74*f6c3b346SKuo-Jung Su if (st & FTSDC010_STATUS_RSP_MASK) 75*f6c3b346SKuo-Jung Su break; 76*f6c3b346SKuo-Jung Su } 77*f6c3b346SKuo-Jung Su if (st & FTSDC010_STATUS_RSP_CRC_OK) { 78*f6c3b346SKuo-Jung Su if (flags & MMC_RSP_136) { 79*f6c3b346SKuo-Jung Su mmc_cmd->response[0] = readl(®s->rsp3); 80*f6c3b346SKuo-Jung Su mmc_cmd->response[1] = readl(®s->rsp2); 81*f6c3b346SKuo-Jung Su mmc_cmd->response[2] = readl(®s->rsp1); 82*f6c3b346SKuo-Jung Su mmc_cmd->response[3] = readl(®s->rsp0); 83*f6c3b346SKuo-Jung Su } else { 84*f6c3b346SKuo-Jung Su mmc_cmd->response[0] = readl(®s->rsp0); 85*f6c3b346SKuo-Jung Su } 86*f6c3b346SKuo-Jung Su ret = 0; 87*f6c3b346SKuo-Jung Su } else { 88*f6c3b346SKuo-Jung Su debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n", 89*f6c3b346SKuo-Jung Su mmc_cmd->cmdidx, st); 90*f6c3b346SKuo-Jung Su } 91*f6c3b346SKuo-Jung Su } 92*f6c3b346SKuo-Jung Su 93*f6c3b346SKuo-Jung Su if (ret) { 94*f6c3b346SKuo-Jung Su debug("ftsdc010: cmd timeout (op code=%d)\n", 95*f6c3b346SKuo-Jung Su mmc_cmd->cmdidx); 96*f6c3b346SKuo-Jung Su } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) { 97*f6c3b346SKuo-Jung Su chip->acmd = 1; 98*f6c3b346SKuo-Jung Su } 99*f6c3b346SKuo-Jung Su 100*f6c3b346SKuo-Jung Su return ret; 101*f6c3b346SKuo-Jung Su } 102*f6c3b346SKuo-Jung Su 103*f6c3b346SKuo-Jung Su static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate) 104*f6c3b346SKuo-Jung Su { 105*f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 106*f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 107*f6c3b346SKuo-Jung Su uint32_t div; 108*f6c3b346SKuo-Jung Su 109*f6c3b346SKuo-Jung Su for (div = 0; div < 0x7f; ++div) { 110*f6c3b346SKuo-Jung Su if (rate >= chip->sclk / (2 * (div + 1))) 111*f6c3b346SKuo-Jung Su break; 112*f6c3b346SKuo-Jung Su } 113*f6c3b346SKuo-Jung Su chip->rate = chip->sclk / (2 * (div + 1)); 114*f6c3b346SKuo-Jung Su 115*f6c3b346SKuo-Jung Su writel(FTSDC010_CCR_CLK_DIV(div), ®s->ccr); 116*f6c3b346SKuo-Jung Su 117*f6c3b346SKuo-Jung Su if (IS_SD(mmc)) { 118*f6c3b346SKuo-Jung Su setbits_le32(®s->ccr, FTSDC010_CCR_CLK_SD); 119*f6c3b346SKuo-Jung Su 120*f6c3b346SKuo-Jung Su if (chip->rate > 25000000) 121*f6c3b346SKuo-Jung Su setbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD); 122*f6c3b346SKuo-Jung Su else 123*f6c3b346SKuo-Jung Su clrbits_le32(®s->ccr, FTSDC010_CCR_CLK_HISPD); 124*f6c3b346SKuo-Jung Su } 125*f6c3b346SKuo-Jung Su } 126*f6c3b346SKuo-Jung Su 127*f6c3b346SKuo-Jung Su static inline int ftsdc010_is_ro(struct mmc *mmc) 128*f6c3b346SKuo-Jung Su { 129*f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 130*f6c3b346SKuo-Jung Su const uint8_t *csd = (const uint8_t *)mmc->csd; 131*f6c3b346SKuo-Jung Su 132*f6c3b346SKuo-Jung Su return chip->wprot || (csd[1] & 0x30); 133*f6c3b346SKuo-Jung Su } 134*f6c3b346SKuo-Jung Su 135*f6c3b346SKuo-Jung Su static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask) 136*f6c3b346SKuo-Jung Su { 137*f6c3b346SKuo-Jung Su int ret = TIMEOUT; 138*f6c3b346SKuo-Jung Su uint32_t st, ts; 139*f6c3b346SKuo-Jung Su 140*f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) { 141*f6c3b346SKuo-Jung Su st = readl(®s->status); 142*f6c3b346SKuo-Jung Su if (!(st & mask)) 143*f6c3b346SKuo-Jung Su continue; 144*f6c3b346SKuo-Jung Su writel(st & mask, ®s->clr); 145*f6c3b346SKuo-Jung Su ret = 0; 146*f6c3b346SKuo-Jung Su break; 147*f6c3b346SKuo-Jung Su } 148*f6c3b346SKuo-Jung Su 149*f6c3b346SKuo-Jung Su if (ret) 150*f6c3b346SKuo-Jung Su debug("ftsdc010: wait st(0x%x) timeout\n", mask); 151*f6c3b346SKuo-Jung Su 152*f6c3b346SKuo-Jung Su return ret; 153*f6c3b346SKuo-Jung Su } 154*f6c3b346SKuo-Jung Su 155*f6c3b346SKuo-Jung Su /* 156*f6c3b346SKuo-Jung Su * u-boot mmc api 157*f6c3b346SKuo-Jung Su */ 158*f6c3b346SKuo-Jung Su 159*f6c3b346SKuo-Jung Su static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd, 160*f6c3b346SKuo-Jung Su struct mmc_data *data) 161*f6c3b346SKuo-Jung Su { 162*f6c3b346SKuo-Jung Su int ret = UNUSABLE_ERR; 163*f6c3b346SKuo-Jung Su uint32_t len = 0; 164*f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 165*f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 166*f6c3b346SKuo-Jung Su 167*f6c3b346SKuo-Jung Su if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) { 168*f6c3b346SKuo-Jung Su printf("ftsdc010: the card is write protected!\n"); 169*f6c3b346SKuo-Jung Su return ret; 170*f6c3b346SKuo-Jung Su } 171*f6c3b346SKuo-Jung Su 172*f6c3b346SKuo-Jung Su if (data) { 173*f6c3b346SKuo-Jung Su uint32_t dcr; 174*f6c3b346SKuo-Jung Su 175*f6c3b346SKuo-Jung Su len = data->blocksize * data->blocks; 176*f6c3b346SKuo-Jung Su 177*f6c3b346SKuo-Jung Su /* 1. data disable + fifo reset */ 178*f6c3b346SKuo-Jung Su writel(FTSDC010_DCR_FIFO_RST, ®s->dcr); 179*f6c3b346SKuo-Jung Su 180*f6c3b346SKuo-Jung Su /* 2. clear status register */ 181*f6c3b346SKuo-Jung Su writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN 182*f6c3b346SKuo-Jung Su | FTSDC010_STATUS_FIFO_ORUN, ®s->clr); 183*f6c3b346SKuo-Jung Su 184*f6c3b346SKuo-Jung Su /* 3. data timeout (1 sec) */ 185*f6c3b346SKuo-Jung Su writel(chip->rate, ®s->dtr); 186*f6c3b346SKuo-Jung Su 187*f6c3b346SKuo-Jung Su /* 4. data length (bytes) */ 188*f6c3b346SKuo-Jung Su writel(len, ®s->dlr); 189*f6c3b346SKuo-Jung Su 190*f6c3b346SKuo-Jung Su /* 5. data enable */ 191*f6c3b346SKuo-Jung Su dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN; 192*f6c3b346SKuo-Jung Su if (data->flags & MMC_DATA_WRITE) 193*f6c3b346SKuo-Jung Su dcr |= FTSDC010_DCR_DATA_WRITE; 194*f6c3b346SKuo-Jung Su writel(dcr, ®s->dcr); 195*f6c3b346SKuo-Jung Su } 196*f6c3b346SKuo-Jung Su 197*f6c3b346SKuo-Jung Su ret = ftsdc010_send_cmd(mmc, cmd); 198*f6c3b346SKuo-Jung Su if (ret) { 199*f6c3b346SKuo-Jung Su printf("ftsdc010: CMD%d failed\n", cmd->cmdidx); 200*f6c3b346SKuo-Jung Su return ret; 201*f6c3b346SKuo-Jung Su } 202*f6c3b346SKuo-Jung Su 203*f6c3b346SKuo-Jung Su if (!data) 204*f6c3b346SKuo-Jung Su return ret; 205*f6c3b346SKuo-Jung Su 206*f6c3b346SKuo-Jung Su if (data->flags & MMC_DATA_WRITE) { 207*f6c3b346SKuo-Jung Su const uint8_t *buf = (const uint8_t *)data->src; 208*f6c3b346SKuo-Jung Su 209*f6c3b346SKuo-Jung Su while (len > 0) { 210*f6c3b346SKuo-Jung Su int wlen; 211*f6c3b346SKuo-Jung Su 212*f6c3b346SKuo-Jung Su /* wait for tx ready */ 213*f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN); 214*f6c3b346SKuo-Jung Su if (ret) 215*f6c3b346SKuo-Jung Su break; 216*f6c3b346SKuo-Jung Su 217*f6c3b346SKuo-Jung Su /* write bytes to ftsdc010 */ 218*f6c3b346SKuo-Jung Su for (wlen = 0; wlen < len && wlen < chip->fifo; ) { 219*f6c3b346SKuo-Jung Su writel(*(uint32_t *)buf, ®s->dwr); 220*f6c3b346SKuo-Jung Su buf += 4; 221*f6c3b346SKuo-Jung Su wlen += 4; 222*f6c3b346SKuo-Jung Su } 223*f6c3b346SKuo-Jung Su 224*f6c3b346SKuo-Jung Su len -= wlen; 225*f6c3b346SKuo-Jung Su } 226*f6c3b346SKuo-Jung Su 227*f6c3b346SKuo-Jung Su } else { 228*f6c3b346SKuo-Jung Su uint8_t *buf = (uint8_t *)data->dest; 229*f6c3b346SKuo-Jung Su 230*f6c3b346SKuo-Jung Su while (len > 0) { 231*f6c3b346SKuo-Jung Su int rlen; 232*f6c3b346SKuo-Jung Su 233*f6c3b346SKuo-Jung Su /* wait for rx ready */ 234*f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN); 235*f6c3b346SKuo-Jung Su if (ret) 236*f6c3b346SKuo-Jung Su break; 237*f6c3b346SKuo-Jung Su 238*f6c3b346SKuo-Jung Su /* fetch bytes from ftsdc010 */ 239*f6c3b346SKuo-Jung Su for (rlen = 0; rlen < len && rlen < chip->fifo; ) { 240*f6c3b346SKuo-Jung Su *(uint32_t *)buf = readl(®s->dwr); 241*f6c3b346SKuo-Jung Su buf += 4; 242*f6c3b346SKuo-Jung Su rlen += 4; 243*f6c3b346SKuo-Jung Su } 244*f6c3b346SKuo-Jung Su 245*f6c3b346SKuo-Jung Su len -= rlen; 246*f6c3b346SKuo-Jung Su } 247*f6c3b346SKuo-Jung Su 248*f6c3b346SKuo-Jung Su } 249*f6c3b346SKuo-Jung Su 250*f6c3b346SKuo-Jung Su if (!ret) { 251*f6c3b346SKuo-Jung Su ret = ftsdc010_wait(regs, 252*f6c3b346SKuo-Jung Su FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR); 253*f6c3b346SKuo-Jung Su } 254*f6c3b346SKuo-Jung Su 255*f6c3b346SKuo-Jung Su return ret; 256*f6c3b346SKuo-Jung Su } 257*f6c3b346SKuo-Jung Su 258*f6c3b346SKuo-Jung Su static void ftsdc010_set_ios(struct mmc *mmc) 259*f6c3b346SKuo-Jung Su { 260*f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 261*f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 262*f6c3b346SKuo-Jung Su 263*f6c3b346SKuo-Jung Su ftsdc010_clkset(mmc, mmc->clock); 264*f6c3b346SKuo-Jung Su 265*f6c3b346SKuo-Jung Su clrbits_le32(®s->bwr, FTSDC010_BWR_MODE_MASK); 266*f6c3b346SKuo-Jung Su switch (mmc->bus_width) { 267*f6c3b346SKuo-Jung Su case 4: 268*f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_4BIT); 269*f6c3b346SKuo-Jung Su break; 270*f6c3b346SKuo-Jung Su case 8: 271*f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_8BIT); 272*f6c3b346SKuo-Jung Su break; 273*f6c3b346SKuo-Jung Su default: 274*f6c3b346SKuo-Jung Su setbits_le32(®s->bwr, FTSDC010_BWR_MODE_1BIT); 275*f6c3b346SKuo-Jung Su break; 276*f6c3b346SKuo-Jung Su } 277*f6c3b346SKuo-Jung Su } 278*f6c3b346SKuo-Jung Su 279*f6c3b346SKuo-Jung Su static int ftsdc010_init(struct mmc *mmc) 280*f6c3b346SKuo-Jung Su { 281*f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip = mmc->priv; 282*f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs = chip->regs; 283*f6c3b346SKuo-Jung Su uint32_t ts; 284*f6c3b346SKuo-Jung Su 285*f6c3b346SKuo-Jung Su if (readl(®s->status) & FTSDC010_STATUS_CARD_DETECT) 286*f6c3b346SKuo-Jung Su return NO_CARD_ERR; 287*f6c3b346SKuo-Jung Su 288*f6c3b346SKuo-Jung Su if (readl(®s->status) & FTSDC010_STATUS_WRITE_PROT) { 289*f6c3b346SKuo-Jung Su printf("ftsdc010: write protected\n"); 290*f6c3b346SKuo-Jung Su chip->wprot = 1; 291*f6c3b346SKuo-Jung Su } 292*f6c3b346SKuo-Jung Su 293*f6c3b346SKuo-Jung Su chip->fifo = (readl(®s->feature) & 0xff) << 2; 294*f6c3b346SKuo-Jung Su 295*f6c3b346SKuo-Jung Su /* 1. chip reset */ 296*f6c3b346SKuo-Jung Su writel(FTSDC010_CMD_SDC_RST, ®s->cmd); 297*f6c3b346SKuo-Jung Su for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) { 298*f6c3b346SKuo-Jung Su if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) 299*f6c3b346SKuo-Jung Su continue; 300*f6c3b346SKuo-Jung Su break; 301*f6c3b346SKuo-Jung Su } 302*f6c3b346SKuo-Jung Su if (readl(®s->cmd) & FTSDC010_CMD_SDC_RST) { 303*f6c3b346SKuo-Jung Su printf("ftsdc010: reset failed\n"); 304*f6c3b346SKuo-Jung Su return UNUSABLE_ERR; 305*f6c3b346SKuo-Jung Su } 306*f6c3b346SKuo-Jung Su 307*f6c3b346SKuo-Jung Su /* 2. enter low speed mode (400k card detection) */ 308*f6c3b346SKuo-Jung Su ftsdc010_clkset(mmc, 400000); 309*f6c3b346SKuo-Jung Su 310*f6c3b346SKuo-Jung Su /* 3. interrupt disabled */ 311*f6c3b346SKuo-Jung Su writel(0, ®s->int_mask); 312*f6c3b346SKuo-Jung Su 313*f6c3b346SKuo-Jung Su return 0; 314*f6c3b346SKuo-Jung Su } 315*f6c3b346SKuo-Jung Su 316*f6c3b346SKuo-Jung Su int ftsdc010_mmc_init(int devid) 317*f6c3b346SKuo-Jung Su { 318*f6c3b346SKuo-Jung Su struct mmc *mmc; 319*f6c3b346SKuo-Jung Su struct ftsdc010_chip *chip; 320*f6c3b346SKuo-Jung Su struct ftsdc010_mmc __iomem *regs; 321*f6c3b346SKuo-Jung Su #ifdef CONFIG_FTSDC010_BASE_LIST 322*f6c3b346SKuo-Jung Su uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST; 323*f6c3b346SKuo-Jung Su 324*f6c3b346SKuo-Jung Su if (devid < 0 || devid >= ARRAY_SIZE(base_list)) 325*f6c3b346SKuo-Jung Su return -1; 326*f6c3b346SKuo-Jung Su regs = (void __iomem *)base_list[devid]; 327*f6c3b346SKuo-Jung Su #else 328*f6c3b346SKuo-Jung Su regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20)); 329*f6c3b346SKuo-Jung Su #endif 330*f6c3b346SKuo-Jung Su 331*f6c3b346SKuo-Jung Su mmc = malloc(sizeof(struct mmc)); 332*f6c3b346SKuo-Jung Su if (!mmc) 333*f6c3b346SKuo-Jung Su return -ENOMEM; 334*f6c3b346SKuo-Jung Su memset(mmc, 0, sizeof(struct mmc)); 335*f6c3b346SKuo-Jung Su 336*f6c3b346SKuo-Jung Su chip = malloc(sizeof(struct ftsdc010_chip)); 337*f6c3b346SKuo-Jung Su if (!chip) { 338*f6c3b346SKuo-Jung Su free(mmc); 339*f6c3b346SKuo-Jung Su return -ENOMEM; 340*f6c3b346SKuo-Jung Su } 341*f6c3b346SKuo-Jung Su memset(chip, 0, sizeof(struct ftsdc010_chip)); 342*f6c3b346SKuo-Jung Su 343*f6c3b346SKuo-Jung Su chip->regs = regs; 344*f6c3b346SKuo-Jung Su mmc->priv = chip; 345*f6c3b346SKuo-Jung Su 346*f6c3b346SKuo-Jung Su sprintf(mmc->name, "ftsdc010"); 347*f6c3b346SKuo-Jung Su mmc->send_cmd = ftsdc010_request; 348*f6c3b346SKuo-Jung Su mmc->set_ios = ftsdc010_set_ios; 349*f6c3b346SKuo-Jung Su mmc->init = ftsdc010_init; 350*f6c3b346SKuo-Jung Su 351*f6c3b346SKuo-Jung Su mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz; 352*f6c3b346SKuo-Jung Su switch (readl(®s->bwr) & FTSDC010_BWR_CAPS_MASK) { 353*f6c3b346SKuo-Jung Su case FTSDC010_BWR_CAPS_4BIT: 354*f6c3b346SKuo-Jung Su mmc->host_caps |= MMC_MODE_4BIT; 355*f6c3b346SKuo-Jung Su break; 356*f6c3b346SKuo-Jung Su case FTSDC010_BWR_CAPS_8BIT: 357*f6c3b346SKuo-Jung Su mmc->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT; 358*f6c3b346SKuo-Jung Su break; 359*f6c3b346SKuo-Jung Su default: 360*f6c3b346SKuo-Jung Su break; 361*f6c3b346SKuo-Jung Su } 362*f6c3b346SKuo-Jung Su 363*f6c3b346SKuo-Jung Su #ifdef CONFIG_SYS_CLK_FREQ 364*f6c3b346SKuo-Jung Su chip->sclk = CONFIG_SYS_CLK_FREQ; 365*f6c3b346SKuo-Jung Su #else 366*f6c3b346SKuo-Jung Su chip->sclk = clk_get_rate("SDC"); 367*f6c3b346SKuo-Jung Su #endif 368*f6c3b346SKuo-Jung Su 369*f6c3b346SKuo-Jung Su mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34; 370*f6c3b346SKuo-Jung Su mmc->f_max = chip->sclk / 2; 371*f6c3b346SKuo-Jung Su mmc->f_min = chip->sclk / 0x100; 372*f6c3b346SKuo-Jung Su mmc->block_dev.part_type = PART_TYPE_DOS; 373*f6c3b346SKuo-Jung Su 374*f6c3b346SKuo-Jung Su mmc_register(mmc); 375*f6c3b346SKuo-Jung Su 376*f6c3b346SKuo-Jung Su return 0; 377*f6c3b346SKuo-Jung Su } 378