From patchwork Sat Jun 29 06:57:03 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anup Patel X-Patchwork-Id: 1124717 X-Patchwork-Delegate: van.freenix@gmail.com Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.denx.de (client-ip=81.169.180.215; helo=lists.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=wdc.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=wdc.com header.i=@wdc.com header.b="UlR3mHTB"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=sharedspace.onmicrosoft.com header.i=@sharedspace.onmicrosoft.com header.b="txvBRhM+"; dkim-atps=neutral Received: from lists.denx.de (dione.denx.de [81.169.180.215]) by ozlabs.org (Postfix) with ESMTP id 45bPcH0GTBz9s3C for ; Sat, 29 Jun 2019 16:58:38 +1000 (AEST) Received: by lists.denx.de (Postfix, from userid 105) id 80CA6C21D83; Sat, 29 Jun 2019 06:57:51 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on lists.denx.de X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=T_DKIM_INVALID autolearn=unavailable autolearn_force=no version=3.4.0 Received: from lists.denx.de (localhost [IPv6:::1]) by lists.denx.de (Postfix) with ESMTP id 98D56C21DD9; Sat, 29 Jun 2019 06:57:33 +0000 (UTC) Received: by lists.denx.de (Postfix, from userid 105) id E0CEDC21DD7; Sat, 29 Jun 2019 06:57:14 +0000 (UTC) Received: from esa1.hgst.iphmx.com (esa1.hgst.iphmx.com [68.232.141.245]) by lists.denx.de (Postfix) with ESMTPS id C5B16C21E0B for ; Sat, 29 Jun 2019 06:57:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=wdc.com; i=@wdc.com; q=dns/txt; s=dkim.wdc.com; t=1561791429; x=1593327429; h=from:to:cc:subject:date:message-id:references: in-reply-to:content-transfer-encoding:mime-version; bh=7yrd4B6ipz6nMZG77pxDPCjkDw3jbcf1+1FbawTtdeQ=; b=UlR3mHTB9vtnYoypJ+/D4m+8abGXwcJjDVyRaa/iFJwSUqox6LQe202U mBRuyNRg1S8RjD74Cw35Mg3/ed/wvtvyORKlJUb4kmH5cs8AFAPH5UV2M HKrSvBOZkGJ/I7oGjcF4D13nSy3bKU/XyIoEuO2OalVANwXC9TQIdMSY9 0sSluZ5NYKzoYigQ3tZ6xpWJNO7I2JxEmn3sNIdxwyqkLr6SKAHVLsDcb YuxEz8DVa8gQaQmNo582rTz2jDvuAUXyKXrNDvZD0HJTGITctf29tDg/v CB2aK8p2iZtOc8TxnJagz2IhzEV5DnS0AEvrDBEJ5jvszfpSTd8xhwris A==; X-IronPort-AV: E=Sophos;i="5.63,430,1557158400"; d="scan'208";a="218211387" Received: from mail-cys01nam02lp2053.outbound.protection.outlook.com (HELO NAM02-CY1-obe.outbound.protection.outlook.com) ([104.47.37.53]) by ob1.hgst.iphmx.com with ESMTP; 29 Jun 2019 14:57:04 +0800 ARC-Seal: i=1; a=rsa-sha256; s=testarcselector01; d=microsoft.com; cv=none; b=lmnbVIdtEhetDWp5ovJcbFP/fv60/iLdNz6trkGPCY5lhsRUSsfKn6ryxYa8X6Nw5enuv+q7lRebSBOIcIGwB8N5D8DwiJl3p/0kJFmIWoav0OZFBKCP3Ztq5BuDgU4Kpi9r775zTUZtuJpnXUIx/a7mELtSscwMju/1FhsmbpA= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=testarcselector01; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=7yrd4B6ipz6nMZG77pxDPCjkDw3jbcf1+1FbawTtdeQ=; b=yG/n8Sd2YJBHPiHxF55bN3iR1ZF99KmAZfJkmLsUKscPFHEGMBES2oA1uHhdYxtzacJxPhIngUx8Yk9+2Q/OT7T3ZXH1deKDvZzJgtn3qWSv6TpsIhmZpG6aCtunjMxKkb9zwDe1s2aof/sz0Xk0URg9mf53rBuIE0YS9+Ny8Qs= ARC-Authentication-Results: i=1; test.office365.com 1;spf=none;dmarc=none;dkim=none;arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sharedspace.onmicrosoft.com; s=selector2-sharedspace-onmicrosoft-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=7yrd4B6ipz6nMZG77pxDPCjkDw3jbcf1+1FbawTtdeQ=; b=txvBRhM+MW5tlwM2q++qIums/cePyrnwCu3o/q4htz62tK+ERTL7/kPcHHgHcU/oGnwm0ym9G1A6qz5veMiHajA9JT6XhMdAYTDi5HYLu5IWKjdQii/I7OWMHdAyfsjpB7skywD8280i8TZBXg7kmhgYbAnh4dNH5VN8pt81bJU= Received: from MN2PR04MB6061.namprd04.prod.outlook.com (20.178.246.15) by MN2PR04MB6062.namprd04.prod.outlook.com (20.178.247.149) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.2008.18; Sat, 29 Jun 2019 06:57:03 +0000 Received: from MN2PR04MB6061.namprd04.prod.outlook.com ([fe80::84da:b4e7:4612:48b]) by MN2PR04MB6061.namprd04.prod.outlook.com ([fe80::84da:b4e7:4612:48b%7]) with mapi id 15.20.2032.018; Sat, 29 Jun 2019 06:57:03 +0000 From: Anup Patel To: Rick Chen , Bin Meng , Lukas Auer , Peng Fan , Jagan Teki Thread-Topic: [PATCH v2 3/5] mmc: mmc_spi: Re-write driver using DM framework Thread-Index: AQHVLkfbIaVAWHLVgkaDnPuDhyxsbw== Date: Sat, 29 Jun 2019 06:57:03 +0000 Message-ID: <20190629065621.65587-4-anup.patel@wdc.com> References: <20190629065621.65587-1-anup.patel@wdc.com> In-Reply-To: <20190629065621.65587-1-anup.patel@wdc.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: x-clientproxiedby: PN1PR0101CA0046.INDPRD01.PROD.OUTLOOK.COM (2603:1096:c00:c::32) To MN2PR04MB6061.namprd04.prod.outlook.com (2603:10b6:208:d8::15) authentication-results: spf=none (sender IP is ) smtp.mailfrom=Anup.Patel@wdc.com; x-ms-exchange-messagesentrepresentingtype: 1 x-mailer: git-send-email 2.17.1 x-originating-ip: [49.207.53.251] x-ms-publictraffictype: Email x-ms-office365-filtering-correlation-id: 11438fd2-a3a7-4736-6550-08d6fc5efd71 x-ms-office365-filtering-ht: Tenant x-microsoft-antispam: BCL:0; PCL:0; RULEID:(2390118)(7020095)(4652040)(8989299)(4534185)(7168020)(4627221)(201703031133081)(201702281549075)(8990200)(5600148)(711020)(4605104)(1401327)(4618075)(2017052603328)(7193020); SRVR:MN2PR04MB6062; x-ms-traffictypediagnostic: MN2PR04MB6062: x-microsoft-antispam-prvs: wdcipoutbound: EOP-TRUE x-ms-oob-tlc-oobclassifiers: OLM:15; x-forefront-prvs: 0083A7F08A x-forefront-antispam-report: SFV:NSPM; SFS:(10019020)(4636009)(376002)(366004)(346002)(39860400002)(396003)(136003)(189003)(199004)(52116002)(71190400001)(54906003)(478600001)(71200400001)(50226002)(2616005)(110136005)(86362001)(11346002)(6486002)(316002)(6436002)(99286004)(446003)(36756003)(72206003)(256004)(14444005)(6116002)(3846002)(14454004)(186003)(68736007)(7416002)(81156014)(486006)(26005)(476003)(76176011)(81166006)(44832011)(8676002)(8936002)(102836004)(6506007)(66946007)(73956011)(386003)(2906002)(66446008)(66556008)(66476007)(305945005)(1076003)(7736002)(6512007)(5660300002)(55236004)(64756008)(53946003)(30864003)(4326008)(66066001)(53936002)(25786009); DIR:OUT; SFP:1102; SCL:1; SRVR:MN2PR04MB6062; H:MN2PR04MB6061.namprd04.prod.outlook.com; FPR:; SPF:None; LANG:en; PTR:InfoNoRecords; MX:1; A:1; x-ms-exchange-senderadcheck: 1 x-microsoft-antispam-message-info: m5sd8SXuRqorKxG37ZDYiToxBCNtA6FP8c6wAPdQKDJZPeHLZu0CIytuFVTnTyaCorteOsQmYXF9rE1985298VVyActNo2mUmgf8I5IAIVJMOj+j65Du+TM1UyUXw+zeixhiYlFmyp9+cYYr//cEK8vtwDmC9co8fS1RdKFOThTOCJ08yyqed0u2NL4h+zLOGqil8JFiRSUjCVVCDCf3qLoT7hlhjLo4FiFAQleg3hujlNQ/Kz9JBm68v1VYKc/E2cY9ttjsXB7PdDku78Up46gkSZw/glW2tB2o3EdCeEJ/MvcBPxNEk+h8mTUhQf0jLUYhbfQM6JOzRyG+bdmzCRjIFz4878MJVcrj4lzas4fZyrY5bgjP3RcAyhzVrlWcM5Wn7gELg6qUUTYGo3+YfD8NNhDdscnF7FeEG8TBeBU= MIME-Version: 1.0 X-OriginatorOrg: wdc.com X-MS-Exchange-CrossTenant-Network-Message-Id: 11438fd2-a3a7-4736-6550-08d6fc5efd71 X-MS-Exchange-CrossTenant-originalarrivaltime: 29 Jun 2019 06:57:03.1544 (UTC) X-MS-Exchange-CrossTenant-fromentityheader: Hosted X-MS-Exchange-CrossTenant-id: b61c8803-16f3-4c35-9b17-6f65f441df86 X-MS-Exchange-CrossTenant-mailboxtype: HOSTED X-MS-Exchange-CrossTenant-userprincipalname: Anup.Patel@wdc.com X-MS-Exchange-Transport-CrossTenantHeadersStamped: MN2PR04MB6062 Cc: Palmer Dabbelt , U-Boot Mailing List , Bhargav Shah Subject: [U-Boot] [PATCH v2 3/5] mmc: mmc_spi: Re-write driver using DM framework X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.18 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" From: Bhargav Shah This patch rewrites MMC SPI driver using U-Boot DM framework and get it's working on SiFive Unleashed board. Signed-off-by: Bhargav Shah Signed-off-by: Anup Patel Reviewed-by: Bin Meng Tested-by: Bin Meng --- drivers/mmc/Kconfig | 18 ++ drivers/mmc/mmc_spi.c | 469 +++++++++++++++++++++++++++--------------- 2 files changed, 320 insertions(+), 167 deletions(-) diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig index c23299ea96..f750dad00a 100644 --- a/drivers/mmc/Kconfig +++ b/drivers/mmc/Kconfig @@ -46,6 +46,24 @@ config SPL_DM_MMC if MMC +config MMC_SPI + bool "Support for SPI-based MMC controller" + depends on DM_MMC && DM_SPI + help + This selects SPI-based MMC controllers. + If you have an MMC controller on a SPI bus, say Y here. + + If unsure, say N. + +config MMC_SPI_CRC_ON + bool "Support CRC for SPI-based MMC controller" + depends on MMC_SPI + default y + help + This enables CRC for SPI-based MMC controllers. + + If unsure, say N. + config ARM_PL180_MMCI bool "ARM AMBA Multimedia Card Interface and compatible support" depends on DM_MMC && OF_CONTROL diff --git a/drivers/mmc/mmc_spi.c b/drivers/mmc/mmc_spi.c index 4f57990d9c..f3d687ae80 100644 --- a/drivers/mmc/mmc_spi.c +++ b/drivers/mmc/mmc_spi.c @@ -2,6 +2,8 @@ * generic mmc spi driver * * Copyright (C) 2010 Thomas Chou + * Copyright 2019 Bhargav Shah + * * Licensed under the GPL-2 or later. */ #include @@ -9,21 +11,23 @@ #include #include #include -#include +#include #include #include #include +#include +#include /* MMC/SD in SPI mode reports R1 status always */ -#define R1_SPI_IDLE (1 << 0) -#define R1_SPI_ERASE_RESET (1 << 1) -#define R1_SPI_ILLEGAL_COMMAND (1 << 2) -#define R1_SPI_COM_CRC (1 << 3) -#define R1_SPI_ERASE_SEQ (1 << 4) -#define R1_SPI_ADDRESS (1 << 5) -#define R1_SPI_PARAMETER (1 << 6) +#define R1_SPI_IDLE BIT(0) +#define R1_SPI_ERASE_RESET BIT(1) +#define R1_SPI_ILLEGAL_COMMAND BIT(2) +#define R1_SPI_COM_CRC BIT(3) +#define R1_SPI_ERASE_SEQ BIT(4) +#define R1_SPI_ADDRESS BIT(5) +#define R1_SPI_PARAMETER BIT(6) /* R1 bit 7 is always zero, reuse this bit for error */ -#define R1_SPI_ERROR (1 << 7) +#define R1_SPI_ERROR BIT(7) /* Response tokens used to ack each block written: */ #define SPI_MMC_RESPONSE_CODE(x) ((x) & 0x1f) @@ -34,28 +38,45 @@ /* Read and write blocks start with these tokens and end with crc; * on error, read tokens act like a subset of R2_SPI_* values. */ -#define SPI_TOKEN_SINGLE 0xfe /* single block r/w, multiblock read */ -#define SPI_TOKEN_MULTI_WRITE 0xfc /* multiblock write */ -#define SPI_TOKEN_STOP_TRAN 0xfd /* terminate multiblock write */ +/* single block write multiblock read */ +#define SPI_TOKEN_SINGLE 0xfe +/* multiblock write */ +#define SPI_TOKEN_MULTI_WRITE 0xfc +/* terminate multiblock write */ +#define SPI_TOKEN_STOP_TRAN 0xfd /* MMC SPI commands start with a start bit "0" and a transmit bit "1" */ -#define MMC_SPI_CMD(x) (0x40 | (x & 0x3f)) +#define MMC_SPI_CMD(x) (0x40 | (x)) /* bus capability */ -#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34) -#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */ +#define MMC_SPI_VOLTAGE (MMC_VDD_32_33 | MMC_VDD_33_34) +#define MMC_SPI_MIN_CLOCK 400000 /* 400KHz to meet MMC spec */ +#define MMC_SPI_MAX_CLOCK 25000000 /* SD/MMC legacy speed */ /* timeout value */ -#define CTOUT 8 -#define RTOUT 3000000 /* 1 sec */ -#define WTOUT 3000000 /* 1 sec */ +#define CMD_TIMEOUT 8 +#define READ_TIMEOUT 3000000 /* 1 sec */ +#define WRITE_TIMEOUT 3000000 /* 1 sec */ -static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg) +struct mmc_spi_priv { + struct spi_slave *spi; + struct mmc_config cfg; + struct mmc mmc; +}; + +static int mmc_spi_sendcmd(struct udevice *dev, + ushort cmdidx, u32 cmdarg, u32 resp_type, + u8 *resp, u32 resp_size, + bool resp_match, u8 resp_match_value) { - struct spi_slave *spi = mmc->priv; - u8 cmdo[7]; - u8 r1; - int i; + int i, rpos = 0, ret = 0; + u8 cmdo[7], r; + + debug("%s: cmd%d cmdarg=0x%x resp_type=0x%x " + "resp_size=%d resp_match=%d resp_match_value=0x%x\n", + __func__, cmdidx, cmdarg, resp_type, + resp_size, resp_match, resp_match_value); + cmdo[0] = 0xff; cmdo[1] = MMC_SPI_CMD(cmdidx); cmdo[2] = cmdarg >> 24; @@ -63,37 +84,79 @@ static uint mmc_spi_sendcmd(struct mmc *mmc, ushort cmdidx, u32 cmdarg) cmdo[4] = cmdarg >> 8; cmdo[5] = cmdarg; cmdo[6] = (crc7(0, &cmdo[1], 5) << 1) | 0x01; - spi_xfer(spi, sizeof(cmdo) * 8, cmdo, NULL, 0); - for (i = 0; i < CTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); - if (i && (r1 & 0x80) == 0) /* r1 response */ - break; + ret = dm_spi_xfer(dev, sizeof(cmdo) * 8, cmdo, NULL, 0); + if (ret) + return ret; + + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + + if (!resp || !resp_size) + return 0; + + debug("%s: cmd%d", __func__, cmdidx); + + if (resp_match) { + r = ~resp_match_value; + i = CMD_TIMEOUT; + while (i--) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + debug(" resp%d=0x%x", rpos, r); + rpos++; + if (r == resp_match_value) + break; + } + if (!i && (r != resp_match_value)) + return -ETIMEDOUT; + } + + for (i = 0; i < resp_size; i++) { + if (i == 0 && resp_match) { + resp[i] = resp_match_value; + continue; + } + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r, 0); + if (ret) + return ret; + debug(" resp%d=0x%x", rpos, r); + rpos++; + resp[i] = r; } - debug("%s:cmd%d resp%d %x\n", __func__, cmdidx, i, r1); - return r1; + + debug("\n"); + + return 0; } -static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf, - u32 bcnt, u32 bsize) +static int mmc_spi_readdata(struct udevice *dev, + void *xbuf, u32 bcnt, u32 bsize) { - struct spi_slave *spi = mmc->priv; - u8 *buf = xbuf; - u8 r1; u16 crc; - int i; + u8 *buf = xbuf, r1; + int i, ret = 0; + while (bcnt--) { - for (i = 0; i < RTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); - if (r1 != 0xff) /* data token */ + for (i = 0; i < READ_TIMEOUT; i++) { + ret = dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); + if (ret) + return ret; + if (r1 == SPI_TOKEN_SINGLE) break; } - debug("%s:tok%d %x\n", __func__, i, r1); + debug("%s: data tok%d 0x%x\n", __func__, i, r1); if (r1 == SPI_TOKEN_SINGLE) { - spi_xfer(spi, bsize * 8, NULL, buf, 0); - spi_xfer(spi, 2 * 8, NULL, &crc, 0); + ret = dm_spi_xfer(dev, bsize * 8, NULL, buf, 0); + if (ret) + return ret; + ret = dm_spi_xfer(dev, 2 * 8, NULL, &crc, 0); + if (ret) + return ret; #ifdef CONFIG_MMC_SPI_CRC_ON - if (be_to_cpu16(crc16_ccitt(0, buf, bsize)) != crc) { - debug("%s: CRC error\n", mmc->cfg->name); + if (be16_to_cpu(crc16_ccitt(0, buf, bsize)) != crc) { + debug("%s: data crc error\n", __func__); r1 = R1_SPI_COM_CRC; break; } @@ -105,48 +168,56 @@ static uint mmc_spi_readdata(struct mmc *mmc, void *xbuf, } buf += bsize; } - return r1; + + if (r1 & R1_SPI_COM_CRC) + ret = -ECOMM; + else if (r1) /* other errors */ + ret = -ETIMEDOUT; + + return ret; } -static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, - u32 bcnt, u32 bsize, int multi) +static int mmc_spi_writedata(struct udevice *dev, const void *xbuf, + u32 bcnt, u32 bsize, int multi) { - struct spi_slave *spi = mmc->priv; const u8 *buf = xbuf; - u8 r1; + u8 r1, tok[2]; u16 crc; - u8 tok[2]; - int i; + int i, ret = 0; + tok[0] = 0xff; tok[1] = multi ? SPI_TOKEN_MULTI_WRITE : SPI_TOKEN_SINGLE; + while (bcnt--) { #ifdef CONFIG_MMC_SPI_CRC_ON crc = cpu_to_be16(crc16_ccitt(0, (u8 *)buf, bsize)); #endif - spi_xfer(spi, 2 * 8, tok, NULL, 0); - spi_xfer(spi, bsize * 8, buf, NULL, 0); - spi_xfer(spi, 2 * 8, &crc, NULL, 0); - for (i = 0; i < CTOUT; i++) { - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + dm_spi_xfer(dev, 2 * 8, tok, NULL, 0); + dm_spi_xfer(dev, bsize * 8, buf, NULL, 0); + dm_spi_xfer(dev, 2 * 8, &crc, NULL, 0); + for (i = 0; i < CMD_TIMEOUT; i++) { + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if ((r1 & 0x10) == 0) /* response token */ break; } - debug("%s:tok%d %x\n", __func__, i, r1); + debug("%s: data tok%d 0x%x\n", __func__, i, r1); if (SPI_MMC_RESPONSE_CODE(r1) == SPI_RESPONSE_ACCEPTED) { - for (i = 0; i < WTOUT; i++) { /* wait busy */ - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + debug("%s: data accepted\n", __func__); + for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */ + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } - if (i == WTOUT) { - debug("%s:wtout %x\n", __func__, r1); + if (i == WRITE_TIMEOUT) { + debug("%s: data write timeout 0x%x\n", + __func__, r1); r1 = R1_SPI_ERROR; break; } } else { - debug("%s: err %x\n", __func__, r1); + debug("%s: data error 0x%x\n", __func__, r1); r1 = R1_SPI_COM_CRC; break; } @@ -154,140 +225,204 @@ static uint mmc_spi_writedata(struct mmc *mmc, const void *xbuf, } if (multi && bcnt == -1) { /* stop multi write */ tok[1] = SPI_TOKEN_STOP_TRAN; - spi_xfer(spi, 2 * 8, tok, NULL, 0); - for (i = 0; i < WTOUT; i++) { /* wait busy */ - spi_xfer(spi, 1 * 8, NULL, &r1, 0); + dm_spi_xfer(dev, 2 * 8, tok, NULL, 0); + for (i = 0; i < WRITE_TIMEOUT; i++) { /* wait busy */ + dm_spi_xfer(dev, 1 * 8, NULL, &r1, 0); if (i && r1 == 0xff) { r1 = 0; break; } } - if (i == WTOUT) { - debug("%s:wstop %x\n", __func__, r1); + if (i == WRITE_TIMEOUT) { + debug("%s: data write timeout 0x%x\n", __func__, r1); r1 = R1_SPI_ERROR; } } - return r1; -} -static int mmc_spi_request(struct mmc *mmc, struct mmc_cmd *cmd, - struct mmc_data *data) -{ - struct spi_slave *spi = mmc->priv; - u8 r1; - int i; - int ret = 0; - debug("%s:cmd%d %x %x\n", __func__, - cmd->cmdidx, cmd->resp_type, cmd->cmdarg); - spi_claim_bus(spi); - spi_cs_activate(spi); - r1 = mmc_spi_sendcmd(mmc, cmd->cmdidx, cmd->cmdarg); - if (r1 == 0xff) { /* no response */ - ret = -ENOMEDIUM; - goto done; - } else if (r1 & R1_SPI_COM_CRC) { + if (r1 & R1_SPI_COM_CRC) ret = -ECOMM; - goto done; - } else if (r1 & ~R1_SPI_IDLE) { /* other errors */ + else if (r1) /* other errors */ ret = -ETIMEDOUT; + + return ret; +} + +static int dm_mmc_spi_set_ios(struct udevice *dev) +{ + return 0; +} + +static int dm_mmc_spi_request(struct udevice *dev, struct mmc_cmd *cmd, + struct mmc_data *data) +{ + int i, multi, ret = 0; + u8 *resp = NULL; + u32 resp_size = 0; + bool resp_match = false; + u8 resp8 = 0, resp40[5] = { 0 }, resp_match_value = 0; + + dm_spi_claim_bus(dev); + + for (i = 0; i < 4; i++) + cmd->response[i] = 0; + + switch (cmd->cmdidx) { + case SD_CMD_APP_SEND_OP_COND: + case MMC_CMD_SEND_OP_COND: + resp = &resp8; + resp_size = sizeof(resp8); + cmd->cmdarg = 0x40000000; + break; + case SD_CMD_SEND_IF_COND: + resp = (u8 *)&resp40[0]; + resp_size = sizeof(resp40); + resp_match = true; + resp_match_value = R1_SPI_IDLE; + break; + case MMC_CMD_SPI_READ_OCR: + resp = (u8 *)&resp40[0]; + resp_size = sizeof(resp40); + break; + case MMC_CMD_SEND_STATUS: + case MMC_CMD_SET_BLOCKLEN: + case MMC_CMD_SPI_CRC_ON_OFF: + case MMC_CMD_STOP_TRANSMISSION: + resp = &resp8; + resp_size = sizeof(resp8); + resp_match = true; + resp_match_value = 0x0; + break; + case MMC_CMD_SEND_CSD: + case MMC_CMD_SEND_CID: + case MMC_CMD_READ_SINGLE_BLOCK: + case MMC_CMD_READ_MULTIPLE_BLOCK: + case MMC_CMD_WRITE_SINGLE_BLOCK: + case MMC_CMD_WRITE_MULTIPLE_BLOCK: + break; + default: + resp = &resp8; + resp_size = sizeof(resp8); + resp_match = true; + resp_match_value = R1_SPI_IDLE; + break; + }; + + ret = mmc_spi_sendcmd(dev, cmd->cmdidx, cmd->cmdarg, cmd->resp_type, + resp, resp_size, resp_match, resp_match_value); + if (ret) goto done; - } else if (cmd->resp_type == MMC_RSP_R2) { - r1 = mmc_spi_readdata(mmc, cmd->response, 1, 16); + + switch (cmd->cmdidx) { + case SD_CMD_APP_SEND_OP_COND: + case MMC_CMD_SEND_OP_COND: + cmd->response[0] = (resp8 & R1_SPI_IDLE) ? 0 : OCR_BUSY; + break; + case SD_CMD_SEND_IF_COND: + case MMC_CMD_SPI_READ_OCR: + cmd->response[0] = resp40[4]; + cmd->response[0] |= (uint)resp40[3] << 8; + cmd->response[0] |= (uint)resp40[2] << 16; + cmd->response[0] |= (uint)resp40[1] << 24; + break; + case MMC_CMD_SEND_STATUS: + cmd->response[0] = (resp8 & 0xff) ? + MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; + break; + case MMC_CMD_SEND_CID: + case MMC_CMD_SEND_CSD: + ret = mmc_spi_readdata(dev, cmd->response, 1, 16); + if (ret) + return ret; for (i = 0; i < 4; i++) - cmd->response[i] = be32_to_cpu(cmd->response[i]); - debug("r128 %x %x %x %x\n", cmd->response[0], cmd->response[1], - cmd->response[2], cmd->response[3]); - } else if (!data) { - switch (cmd->cmdidx) { - case SD_CMD_APP_SEND_OP_COND: - case MMC_CMD_SEND_OP_COND: - cmd->response[0] = (r1 & R1_SPI_IDLE) ? 0 : OCR_BUSY; - break; - case SD_CMD_SEND_IF_COND: - case MMC_CMD_SPI_READ_OCR: - spi_xfer(spi, 4 * 8, NULL, cmd->response, 0); - cmd->response[0] = be32_to_cpu(cmd->response[0]); - debug("r32 %x\n", cmd->response[0]); - break; - case MMC_CMD_SEND_STATUS: - spi_xfer(spi, 1 * 8, NULL, cmd->response, 0); - cmd->response[0] = (cmd->response[0] & 0xff) ? - MMC_STATUS_ERROR : MMC_STATUS_RDY_FOR_DATA; - break; - } - } else { - debug("%s:data %x %x %x\n", __func__, - data->flags, data->blocks, data->blocksize); + cmd->response[i] = + cpu_to_be32(cmd->response[i]); + break; + default: + cmd->response[0] = resp8; + break; + } + + debug("%s: cmd%d resp0=0x%x resp1=0x%x resp2=0x%x resp3=0x%x\n", + __func__, cmd->cmdidx, cmd->response[0], cmd->response[1], + cmd->response[2], cmd->response[3]); + + if (data) { + debug("%s: data flags=0x%x blocks=%d block_size=%d\n", + __func__, data->flags, data->blocks, data->blocksize); + multi = (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK); if (data->flags == MMC_DATA_READ) - r1 = mmc_spi_readdata(mmc, data->dest, - data->blocks, data->blocksize); + ret = mmc_spi_readdata(dev, data->dest, + data->blocks, data->blocksize); else if (data->flags == MMC_DATA_WRITE) - r1 = mmc_spi_writedata(mmc, data->src, - data->blocks, data->blocksize, - (cmd->cmdidx == MMC_CMD_WRITE_MULTIPLE_BLOCK)); - if (r1 & R1_SPI_COM_CRC) - ret = -ECOMM; - else if (r1) /* other errors */ - ret = -ETIMEDOUT; + ret = mmc_spi_writedata(dev, data->src, + data->blocks, data->blocksize, + multi); } + done: - spi_cs_deactivate(spi); - spi_release_bus(spi); + dm_spi_release_bus(dev); + return ret; } -static int mmc_spi_set_ios(struct mmc *mmc) +static int mmc_spi_probe(struct udevice *dev) { - struct spi_slave *spi = mmc->priv; + struct mmc_spi_priv *priv = dev_get_priv(dev); + struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev); + char *name; + + priv->spi = dev_get_parent_priv(dev); + if (!priv->spi->max_hz) + priv->spi->max_hz = MMC_SPI_MAX_CLOCK; + priv->spi->speed = 0; + priv->spi->mode = SPI_MODE_0; + priv->spi->wordlen = 8; + + name = malloc(strlen(dev->parent->name) + strlen(dev->name) + 4); + if (!name) + return -ENOMEM; + sprintf(name, "%s:%s", dev->parent->name, dev->name); + + priv->cfg.name = name; + priv->cfg.host_caps = MMC_MODE_SPI; + priv->cfg.voltages = MMC_SPI_VOLTAGE; + priv->cfg.f_min = MMC_SPI_MIN_CLOCK; + priv->cfg.f_max = priv->spi->max_hz; + priv->cfg.part_type = PART_TYPE_DOS; + priv->cfg.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT; + + priv->mmc.cfg = &priv->cfg; + priv->mmc.priv = priv; + priv->mmc.dev = dev; + + upriv->mmc = &priv->mmc; - debug("%s: clock %u\n", __func__, mmc->clock); - if (mmc->clock) - spi_set_speed(spi, mmc->clock); return 0; } -static int mmc_spi_init_p(struct mmc *mmc) +static int mmc_spi_bind(struct udevice *dev) { - struct spi_slave *spi = mmc->priv; - spi_set_speed(spi, MMC_SPI_MIN_CLOCK); - spi_claim_bus(spi); - /* cs deactivated for 100+ clock */ - spi_xfer(spi, 18 * 8, NULL, NULL, 0); - spi_release_bus(spi); - return 0; + struct mmc_spi_priv *priv = dev_get_priv(dev); + + return mmc_bind(dev, &priv->mmc, &priv->cfg); } -static const struct mmc_ops mmc_spi_ops = { - .send_cmd = mmc_spi_request, - .set_ios = mmc_spi_set_ios, - .init = mmc_spi_init_p, +static const struct dm_mmc_ops mmc_spi_ops = { + .send_cmd = dm_mmc_spi_request, + .set_ios = dm_mmc_spi_set_ios, }; -static struct mmc_config mmc_spi_cfg = { - .name = "MMC_SPI", - .ops = &mmc_spi_ops, - .host_caps = MMC_MODE_SPI, - .voltages = MMC_SPI_VOLTAGE, - .f_min = MMC_SPI_MIN_CLOCK, - .part_type = PART_TYPE_DOS, - .b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT, +static const struct udevice_id dm_mmc_spi_match[] = { + { .compatible = "mmc-spi-slot" }, + { /* sentinel */ } }; -struct mmc *mmc_spi_init(uint bus, uint cs, uint speed, uint mode) -{ - struct mmc *mmc; - struct spi_slave *spi; - - spi = spi_setup_slave(bus, cs, speed, mode); - if (spi == NULL) - return NULL; - - mmc_spi_cfg.f_max = speed; - - mmc = mmc_create(&mmc_spi_cfg, spi); - if (mmc == NULL) { - spi_free_slave(spi); - return NULL; - } - return mmc; -} +U_BOOT_DRIVER(mmc_spi) = { + .name = "mmc_spi", + .id = UCLASS_MMC, + .of_match = dm_mmc_spi_match, + .ops = &mmc_spi_ops, + .probe = mmc_spi_probe, + .bind = mmc_spi_bind, + .priv_auto_alloc_size = sizeof(struct mmc_spi_priv), +};