xref: /device/qemu/drivers/virtio/virtblock.c (revision d6aed566)
1d6aed566Sopenharmony_ci/*
2d6aed566Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
3d6aed566Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4d6aed566Sopenharmony_ci * you may not use this file except in compliance with the License.
5d6aed566Sopenharmony_ci * You may obtain a copy of the License at
6d6aed566Sopenharmony_ci *
7d6aed566Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8d6aed566Sopenharmony_ci *
9d6aed566Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10d6aed566Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11d6aed566Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12d6aed566Sopenharmony_ci * See the License for the specific language governing permissions and
13d6aed566Sopenharmony_ci * limitations under the License.
14d6aed566Sopenharmony_ci */
15d6aed566Sopenharmony_ci/*
16d6aed566Sopenharmony_ci * Simple virtio-mmio block driver emulating MMC device (spec 4.3).
17d6aed566Sopenharmony_ci */
18d6aed566Sopenharmony_ci
19d6aed566Sopenharmony_ci#include "los_vm_iomap.h"
20d6aed566Sopenharmony_ci#include "mmc_block.h"
21d6aed566Sopenharmony_ci#include "dmac_core.h"
22d6aed566Sopenharmony_ci#include "osal.h"
23d6aed566Sopenharmony_ci#include "osal/osal_io.h"
24d6aed566Sopenharmony_ci#include "virtmmio.h"
25d6aed566Sopenharmony_ci
26d6aed566Sopenharmony_ci/*
27d6aed566Sopenharmony_ci * Kernel take care lock & cache(bcache), we only take care I/O.
28d6aed566Sopenharmony_ci * When I/O is carrying, we must wait for completion. Since any
29d6aed566Sopenharmony_ci * time there is only one I/O request come here, we can use the
30d6aed566Sopenharmony_ci * most simple virt-queue -- only have 4 descriptors: one for
31d6aed566Sopenharmony_ci * "request header", one for "I/O buffer", one for "response",
32d6aed566Sopenharmony_ci * and one left unused. That is, the driver and the device are
33d6aed566Sopenharmony_ci * always in synchonous mode!
34d6aed566Sopenharmony_ci */
35d6aed566Sopenharmony_ci#define VIRTQ_REQUEST_QSZ       4
36d6aed566Sopenharmony_ci
37d6aed566Sopenharmony_ci#define VIRTIO_BLK_F_RO         (1 << 5)
38d6aed566Sopenharmony_ci#define VIRTIO_BLK_F_BLK_SIZE   (1 << 6)
39d6aed566Sopenharmony_ci#define VIRTMMIO_BLK_NAME       "virtblock"
40d6aed566Sopenharmony_ci#define VIRTBLK_DRIVER          "/dev/mmcblk"
41d6aed566Sopenharmony_ci#define VIRTBLK_DEF_BLK_SIZE    8192
42d6aed566Sopenharmony_ci
43d6aed566Sopenharmony_cistruct VirtblkConfig {
44d6aed566Sopenharmony_ci    uint64_t capacity;
45d6aed566Sopenharmony_ci    uint32_t segMax;
46d6aed566Sopenharmony_ci    struct VirtblkGeometry {
47d6aed566Sopenharmony_ci        uint16_t cylinders;
48d6aed566Sopenharmony_ci        uint8_t heads;
49d6aed566Sopenharmony_ci        uint8_t sectors;
50d6aed566Sopenharmony_ci    } geometry;
51d6aed566Sopenharmony_ci    uint32_t blkSize;
52d6aed566Sopenharmony_ci    uint8_t otherFieldsOmitted[0];
53d6aed566Sopenharmony_ci};
54d6aed566Sopenharmony_ci
55d6aed566Sopenharmony_ci/* request type: only support IN, OUT */
56d6aed566Sopenharmony_ci#define VIRTIO_BLK_T_IN             0
57d6aed566Sopenharmony_ci#define VIRTIO_BLK_T_OUT            1
58d6aed566Sopenharmony_ci#define VIRTIO_BLK_T_FLUSH          4
59d6aed566Sopenharmony_ci#define VIRTIO_BLK_T_DISCARD        11
60d6aed566Sopenharmony_ci#define VIRTIO_BLK_T_WRITE_ZEROES   13
61d6aed566Sopenharmony_ci
62d6aed566Sopenharmony_ci/* response status */
63d6aed566Sopenharmony_ci#define VIRTIO_BLK_S_OK             0
64d6aed566Sopenharmony_ci#define VIRTIO_BLK_S_IOERR          1
65d6aed566Sopenharmony_ci#define VIRTIO_BLK_S_UNSUPP         2
66d6aed566Sopenharmony_ci
67d6aed566Sopenharmony_cistruct VirtblkReq {
68d6aed566Sopenharmony_ci    uint32_t type;
69d6aed566Sopenharmony_ci    uint32_t reserved;
70d6aed566Sopenharmony_ci    uint64_t startSector;
71d6aed566Sopenharmony_ci};
72d6aed566Sopenharmony_ci
73d6aed566Sopenharmony_cistruct Virtblk {
74d6aed566Sopenharmony_ci    struct VirtmmioDev dev;
75d6aed566Sopenharmony_ci
76d6aed566Sopenharmony_ci    uint64_t capacity;      /* in 512-byte-sectors */
77d6aed566Sopenharmony_ci    uint32_t blkSize;       /* block(cluster) size */
78d6aed566Sopenharmony_ci    struct VirtblkReq req;  /* static memory for request */
79d6aed566Sopenharmony_ci    uint8_t resp;           /*              and response */
80d6aed566Sopenharmony_ci    DmacEvent event;        /* for waiting I/O completion */
81d6aed566Sopenharmony_ci};
82d6aed566Sopenharmony_ci
83d6aed566Sopenharmony_ci#define FAT32_MAX_CLUSTER_SECS  128
84d6aed566Sopenharmony_ci
85d6aed566Sopenharmony_cistatic bool Feature0(uint32_t features, uint32_t *supported, void *dev)
86d6aed566Sopenharmony_ci{
87d6aed566Sopenharmony_ci    struct Virtblk *blk = dev;
88d6aed566Sopenharmony_ci    struct VirtblkConfig *conf = (void *)(blk->dev.base + VIRTMMIO_REG_CONFIG);
89d6aed566Sopenharmony_ci    uint32_t bs;
90d6aed566Sopenharmony_ci
91d6aed566Sopenharmony_ci    if (features & VIRTIO_BLK_F_RO) {
92d6aed566Sopenharmony_ci        HDF_LOGE("[%s]not support readonly device", __func__);
93d6aed566Sopenharmony_ci        return false;
94d6aed566Sopenharmony_ci    }
95d6aed566Sopenharmony_ci
96d6aed566Sopenharmony_ci    blk->blkSize = VIRTBLK_DEF_BLK_SIZE;
97d6aed566Sopenharmony_ci    if (features & VIRTIO_BLK_F_BLK_SIZE) {
98d6aed566Sopenharmony_ci        bs = conf->blkSize;
99d6aed566Sopenharmony_ci        if ((bs >= MMC_SEC_SIZE) && (bs <= FAT32_MAX_CLUSTER_SECS * MMC_SEC_SIZE) &&
100d6aed566Sopenharmony_ci            ((bs & (bs - 1)) == 0)) {
101d6aed566Sopenharmony_ci            blk->blkSize = bs;
102d6aed566Sopenharmony_ci            *supported |= VIRTIO_BLK_F_BLK_SIZE;
103d6aed566Sopenharmony_ci        }
104d6aed566Sopenharmony_ci    }
105d6aed566Sopenharmony_ci
106d6aed566Sopenharmony_ci    blk->capacity = conf->capacity;
107d6aed566Sopenharmony_ci    return true;
108d6aed566Sopenharmony_ci}
109d6aed566Sopenharmony_ci
110d6aed566Sopenharmony_cistatic bool Feature1(uint32_t features, uint32_t *supported, void *dev)
111d6aed566Sopenharmony_ci{
112d6aed566Sopenharmony_ci    (void)dev;
113d6aed566Sopenharmony_ci    if (features & VIRTIO_F_VERSION_1) {
114d6aed566Sopenharmony_ci        *supported |= VIRTIO_F_VERSION_1;
115d6aed566Sopenharmony_ci    } else {
116d6aed566Sopenharmony_ci        HDF_LOGE("[%s]virtio-mmio block has no VERSION_1 feature", __func__);
117d6aed566Sopenharmony_ci        return false;
118d6aed566Sopenharmony_ci    }
119d6aed566Sopenharmony_ci
120d6aed566Sopenharmony_ci    return true;
121d6aed566Sopenharmony_ci}
122d6aed566Sopenharmony_ci
123d6aed566Sopenharmony_cistatic void PopulateRequestQ(const struct Virtblk *blk)
124d6aed566Sopenharmony_ci{
125d6aed566Sopenharmony_ci    const struct Virtq *q = &blk->dev.vq[0];
126d6aed566Sopenharmony_ci    int i = 0;
127d6aed566Sopenharmony_ci
128d6aed566Sopenharmony_ci    q->desc[i].pAddr = VMM_TO_DMA_ADDR((VADDR_T)&blk->req);
129d6aed566Sopenharmony_ci    q->desc[i].len = sizeof(struct VirtblkReq);
130d6aed566Sopenharmony_ci    q->desc[i].flag = VIRTQ_DESC_F_NEXT;
131d6aed566Sopenharmony_ci    q->desc[i].next = i + 1;
132d6aed566Sopenharmony_ci
133d6aed566Sopenharmony_ci    i++;
134d6aed566Sopenharmony_ci    q->desc[i].next = i + 1;
135d6aed566Sopenharmony_ci
136d6aed566Sopenharmony_ci    i++;
137d6aed566Sopenharmony_ci    q->desc[i].pAddr = VMM_TO_DMA_ADDR((VADDR_T)&blk->resp);
138d6aed566Sopenharmony_ci    q->desc[i].len = sizeof(uint8_t);
139d6aed566Sopenharmony_ci    q->desc[i].flag = VIRTQ_DESC_F_WRITE;
140d6aed566Sopenharmony_ci}
141d6aed566Sopenharmony_ci
142d6aed566Sopenharmony_cistatic uint8_t VirtblkIO(struct Virtblk *blk, uint32_t cmd, uint64_t startSector,
143d6aed566Sopenharmony_ci                         uint8_t *buf, uint32_t sectors)
144d6aed566Sopenharmony_ci{
145d6aed566Sopenharmony_ci    uint32_t ret;
146d6aed566Sopenharmony_ci    struct Virtq *q = &blk->dev.vq[0];
147d6aed566Sopenharmony_ci
148d6aed566Sopenharmony_ci    /* fill in and notify virt queue */
149d6aed566Sopenharmony_ci    blk->req.type = cmd;
150d6aed566Sopenharmony_ci    blk->req.startSector = startSector;
151d6aed566Sopenharmony_ci    q->desc[1].pAddr = VMM_TO_DMA_ADDR((VADDR_T)buf);
152d6aed566Sopenharmony_ci    q->desc[1].len = sectors * MMC_SEC_SIZE;
153d6aed566Sopenharmony_ci    if (cmd == VIRTIO_BLK_T_IN) {
154d6aed566Sopenharmony_ci        q->desc[1].flag = VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE;
155d6aed566Sopenharmony_ci    } else { /* must be VIRTIO_BLK_T_OUT */
156d6aed566Sopenharmony_ci        q->desc[1].flag = VIRTQ_DESC_F_NEXT;
157d6aed566Sopenharmony_ci    }
158d6aed566Sopenharmony_ci    q->avail->ring[q->avail->index % q->qsz] = 0;
159d6aed566Sopenharmony_ci    DSB;
160d6aed566Sopenharmony_ci    q->avail->index++;
161d6aed566Sopenharmony_ci    OSAL_WRITEL(0, blk->dev.base + VIRTMMIO_REG_QUEUENOTIFY);
162d6aed566Sopenharmony_ci
163d6aed566Sopenharmony_ci    /* wait for completion */
164d6aed566Sopenharmony_ci    if ((ret = DmaEventWait(&blk->event, 1, HDF_WAIT_FOREVER)) != 1) {
165d6aed566Sopenharmony_ci        HDF_LOGE("[%s]FATAL: wait event failed: %u", __func__, ret);
166d6aed566Sopenharmony_ci        return VIRTIO_BLK_S_IOERR;
167d6aed566Sopenharmony_ci    }
168d6aed566Sopenharmony_ci
169d6aed566Sopenharmony_ci    return blk->resp;
170d6aed566Sopenharmony_ci}
171d6aed566Sopenharmony_ci
172d6aed566Sopenharmony_cistatic uint32_t VirtblkIRQhandle(uint32_t swIrq, void *dev)
173d6aed566Sopenharmony_ci{
174d6aed566Sopenharmony_ci    (void)swIrq;
175d6aed566Sopenharmony_ci    struct Virtblk *blk = dev;
176d6aed566Sopenharmony_ci    struct Virtq *q = &blk->dev.vq[0];
177d6aed566Sopenharmony_ci
178d6aed566Sopenharmony_ci    if (!(OSAL_READL(blk->dev.base + VIRTMMIO_REG_INTERRUPTSTATUS) & VIRTMMIO_IRQ_NOTIFY_USED)) {
179d6aed566Sopenharmony_ci        return 1;
180d6aed566Sopenharmony_ci    }
181d6aed566Sopenharmony_ci
182d6aed566Sopenharmony_ci    (void)DmaEventSignal(&blk->event, 1);
183d6aed566Sopenharmony_ci    q->last++;
184d6aed566Sopenharmony_ci
185d6aed566Sopenharmony_ci    OSAL_WRITEL(VIRTMMIO_IRQ_NOTIFY_USED, blk->dev.base + VIRTMMIO_REG_INTERRUPTACK);
186d6aed566Sopenharmony_ci    return 0;
187d6aed566Sopenharmony_ci}
188d6aed566Sopenharmony_ci
189d6aed566Sopenharmony_cistatic void VirtblkDeInit(struct Virtblk *blk)
190d6aed566Sopenharmony_ci{
191d6aed566Sopenharmony_ci    if (blk->dev.irq & ~_IRQ_MASK) {
192d6aed566Sopenharmony_ci        OsalUnregisterIrq(blk->dev.irq & _IRQ_MASK, blk);
193d6aed566Sopenharmony_ci    }
194d6aed566Sopenharmony_ci    LOS_DmaMemFree(blk);
195d6aed566Sopenharmony_ci}
196d6aed566Sopenharmony_ci
197d6aed566Sopenharmony_cistatic struct Virtblk *VirtblkInitDev(void)
198d6aed566Sopenharmony_ci{
199d6aed566Sopenharmony_ci    struct Virtblk *blk = NULL;
200d6aed566Sopenharmony_ci    VADDR_T base;
201d6aed566Sopenharmony_ci    uint16_t qsz;
202d6aed566Sopenharmony_ci    int len, ret;
203d6aed566Sopenharmony_ci
204d6aed566Sopenharmony_ci    len = sizeof(struct Virtblk) + VirtqSize(VIRTQ_REQUEST_QSZ);
205d6aed566Sopenharmony_ci    if ((blk = LOS_DmaMemAlloc(NULL, len, sizeof(void *), DMA_CACHE)) == NULL) {
206d6aed566Sopenharmony_ci        HDF_LOGE("[%s]alloc virtio-block memory failed", __func__);
207d6aed566Sopenharmony_ci        return NULL;
208d6aed566Sopenharmony_ci    }
209d6aed566Sopenharmony_ci    memset_s(blk, len, 0, len);
210d6aed566Sopenharmony_ci
211d6aed566Sopenharmony_ci    if (!VirtmmioDiscover(VIRTMMIO_DEVICE_ID_BLK, &blk->dev)) {
212d6aed566Sopenharmony_ci        goto ERR_OUT;
213d6aed566Sopenharmony_ci    }
214d6aed566Sopenharmony_ci
215d6aed566Sopenharmony_ci    VirtmmioInitBegin(&blk->dev);
216d6aed566Sopenharmony_ci    if (!VirtmmioNegotiate(&blk->dev, Feature0, Feature1, blk)) {
217d6aed566Sopenharmony_ci        goto ERR_OUT1;
218d6aed566Sopenharmony_ci    }
219d6aed566Sopenharmony_ci    base = ALIGN((VADDR_T)blk + sizeof(struct Virtblk), VIRTQ_ALIGN_DESC);
220d6aed566Sopenharmony_ci    qsz = VIRTQ_REQUEST_QSZ;
221d6aed566Sopenharmony_ci    if (VirtmmioConfigQueue(&blk->dev, base, &qsz, 1) == 0) {
222d6aed566Sopenharmony_ci        goto ERR_OUT1;
223d6aed566Sopenharmony_ci    }
224d6aed566Sopenharmony_ci
225d6aed566Sopenharmony_ci    if ((ret = DmaEventInit(&blk->event)) != HDF_SUCCESS) {
226d6aed566Sopenharmony_ci        HDF_LOGE("[%s]initialize event control block failed: %#x", __func__, ret);
227d6aed566Sopenharmony_ci        goto ERR_OUT1;
228d6aed566Sopenharmony_ci    }
229d6aed566Sopenharmony_ci    ret = OsalRegisterIrq(blk->dev.irq, OSAL_IRQF_TRIGGER_NONE, (OsalIRQHandle)VirtblkIRQhandle,
230d6aed566Sopenharmony_ci                          VIRTMMIO_BLK_NAME, blk);
231d6aed566Sopenharmony_ci    if (ret != HDF_SUCCESS) {
232d6aed566Sopenharmony_ci        HDF_LOGE("[%s]register IRQ failed: %d", __func__, ret);
233d6aed566Sopenharmony_ci        goto ERR_OUT1;
234d6aed566Sopenharmony_ci    }
235d6aed566Sopenharmony_ci    blk->dev.irq |= ~_IRQ_MASK;
236d6aed566Sopenharmony_ci
237d6aed566Sopenharmony_ci    PopulateRequestQ(blk);
238d6aed566Sopenharmony_ci    VritmmioInitEnd(&blk->dev);  /* now virt queue can be used */
239d6aed566Sopenharmony_ci    return blk;
240d6aed566Sopenharmony_ci
241d6aed566Sopenharmony_ciERR_OUT1:
242d6aed566Sopenharmony_ci    VirtmmioInitFailed(&blk->dev);
243d6aed566Sopenharmony_ciERR_OUT:
244d6aed566Sopenharmony_ci    VirtblkDeInit(blk);
245d6aed566Sopenharmony_ci    return NULL;
246d6aed566Sopenharmony_ci}
247d6aed566Sopenharmony_ci
248d6aed566Sopenharmony_ci
249d6aed566Sopenharmony_ci/*
250d6aed566Sopenharmony_ci * MMC code
251d6aed566Sopenharmony_ci *
252d6aed566Sopenharmony_ci * HDF MmcCntlr act like an application adapter, they discover MMC device,
253d6aed566Sopenharmony_ci * send I/O request, receive response data.
254d6aed566Sopenharmony_ci * We act like a card adapter, receive requests, control MMC bus, drive 'card'
255d6aed566Sopenharmony_ci * execution, and report result. Yes, we are part of MmcCntlr -- MMC controller!
256d6aed566Sopenharmony_ci * Every hardware internal information are in our scope, such as state, CRC, RCA.
257d6aed566Sopenharmony_ci * So, we COULD(SHOULD) safely ignore them!
258d6aed566Sopenharmony_ci */
259d6aed566Sopenharmony_ci
260d6aed566Sopenharmony_ci#define OCR_LE_2G       (0x00FF8080 | MMC_CARD_BUSY_STATUS)
261d6aed566Sopenharmony_ci#define OCR_GT_2G       (0x40FF8080 | MMC_CARD_BUSY_STATUS)
262d6aed566Sopenharmony_ci#define CAPACITY_2G     (0x80000000 / 512)
263d6aed566Sopenharmony_ci#define READ_BL_LEN     11
264d6aed566Sopenharmony_ci#define C_SIZE_MULT     7
265d6aed566Sopenharmony_ci#define U32_BITS        32
266d6aed566Sopenharmony_ci
267d6aed566Sopenharmony_ci/*
268d6aed566Sopenharmony_ci * Example bits: start=62 bits=4 value=0b1011
269d6aed566Sopenharmony_ci *
270d6aed566Sopenharmony_ci *             bit127
271d6aed566Sopenharmony_ci *  resp[0]
272d6aed566Sopenharmony_ci *  resp[1]                         1   0
273d6aed566Sopenharmony_ci *  resp[2]      1    1
274d6aed566Sopenharmony_ci *  resp[3]
275d6aed566Sopenharmony_ci *                                     bit0
276d6aed566Sopenharmony_ci *
277d6aed566Sopenharmony_ci * NOTE: no error check, related 'resp' bits must be zeroed and set only once.
278d6aed566Sopenharmony_ci */
279d6aed566Sopenharmony_cistatic void FillCidCsdBits(uint32_t *resp, int start, int bits, uint32_t value)
280d6aed566Sopenharmony_ci{
281d6aed566Sopenharmony_ci    uint32_t index, lsb;
282d6aed566Sopenharmony_ci
283d6aed566Sopenharmony_ci    index = CID_LEN - 1 - start / U32_BITS; /* CSD has the same length */
284d6aed566Sopenharmony_ci    lsb = start % U32_BITS;
285d6aed566Sopenharmony_ci    resp[index] |= value << lsb;
286d6aed566Sopenharmony_ci
287d6aed566Sopenharmony_ci    if (lsb + bits > U32_BITS) {
288d6aed566Sopenharmony_ci        resp[index - 1] |= value >> (U32_BITS - lsb);
289d6aed566Sopenharmony_ci    }
290d6aed566Sopenharmony_ci}
291d6aed566Sopenharmony_ci
292d6aed566Sopenharmony_ci#define MMC_CID_CBX_SBIT    112
293d6aed566Sopenharmony_ci#define MMC_CID_CBX_WIDTH   2
294d6aed566Sopenharmony_ci#define MMC_CID_PNM_SBYTE   3
295d6aed566Sopenharmony_ci#define MMC_CID_PNM_BYTES   6
296d6aed566Sopenharmony_ci#define MMC_CID_PSN_SBYTE   10
297d6aed566Sopenharmony_cistatic void VirtMmcFillRespCid(struct MmcCmd *cmd, const struct Virtblk *blk)
298d6aed566Sopenharmony_ci{
299d6aed566Sopenharmony_ci    uint8_t *b = (uint8_t *)cmd->resp;
300d6aed566Sopenharmony_ci
301d6aed566Sopenharmony_ci    /* embedded card, so can leverage kernel eMMC rootfs support */
302d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CID_CBX_SBIT, MMC_CID_CBX_WIDTH, 1);
303d6aed566Sopenharmony_ci
304d6aed566Sopenharmony_ci    (void)memcpy_s(&b[MMC_CID_PNM_SBYTE], MMC_CID_PNM_BYTES, VIRTMMIO_BLK_NAME, MMC_CID_PNM_BYTES);
305d6aed566Sopenharmony_ci    *(uint32_t *)&b[MMC_CID_PSN_SBYTE] = (uint32_t)blk; /* unique sn */
306d6aed566Sopenharmony_ci    /* leave other fields random */
307d6aed566Sopenharmony_ci}
308d6aed566Sopenharmony_ci
309d6aed566Sopenharmony_ci#define MMC_CSD_STRUCT_SBIT     126
310d6aed566Sopenharmony_ci#define MMC_CSD_STRUCT_WIDTH    2
311d6aed566Sopenharmony_ci
312d6aed566Sopenharmony_ci#define MMC_CSD_VERS_SBIT       122
313d6aed566Sopenharmony_ci#define MMC_CSD_VERS_WIDTH      4
314d6aed566Sopenharmony_ci
315d6aed566Sopenharmony_ci#define MMC_CSD_CCC_SBIT        84
316d6aed566Sopenharmony_ci#define MMC_CSD_CCC_WIDTH       12
317d6aed566Sopenharmony_ci
318d6aed566Sopenharmony_ci#define MMC_CSD_RBLEN_SBIT      80
319d6aed566Sopenharmony_ci#define MMC_CSD_RBLEN_WIDTH     4
320d6aed566Sopenharmony_ci
321d6aed566Sopenharmony_ci#define MMC_CSD_RBPART_SBIT     79
322d6aed566Sopenharmony_ci
323d6aed566Sopenharmony_ci#define MMC_CSD_WBMISALIGN_SBIT 78
324d6aed566Sopenharmony_ci
325d6aed566Sopenharmony_ci#define MMC_CSD_RBMISALIGN_SBIT 77
326d6aed566Sopenharmony_ci
327d6aed566Sopenharmony_ci#define MMC_CSD_DSRIMP_SBIT     76
328d6aed566Sopenharmony_ci
329d6aed566Sopenharmony_ci#define MMC_CSD_CSIZE_SBIT      62
330d6aed566Sopenharmony_ci#define MMC_CSD_CSIZE_WIDTH     12
331d6aed566Sopenharmony_ci#define MMC_CSD_CSIZE_VAL       0xFFF
332d6aed566Sopenharmony_ci
333d6aed566Sopenharmony_ci#define MMC_CSD_CSIZEMUL_SBIT   47
334d6aed566Sopenharmony_ci#define MMC_CSD_CSIZEMUL_WIDTH  3
335d6aed566Sopenharmony_ci
336d6aed566Sopenharmony_ci#define MMC_CSD_EGRPSIZE_SBIT   42
337d6aed566Sopenharmony_ci#define MMC_CSD_EGRPSIZE_WIDTH  5
338d6aed566Sopenharmony_ci#define MMC_CSD_EGRPSIZE_VAL    31
339d6aed566Sopenharmony_ci
340d6aed566Sopenharmony_ci#define MMC_CSD_EGRPMULT_SBIT   37
341d6aed566Sopenharmony_ci#define MMC_CSD_EGRPMULT_WIDTH  5
342d6aed566Sopenharmony_ci#define MMC_CSD_EGRPMULT_VAL    15
343d6aed566Sopenharmony_ci
344d6aed566Sopenharmony_ci#define MMC_CSD_WBLEN_SBIT      22
345d6aed566Sopenharmony_ci#define MMC_CSD_WBLEN_WIDTH     4
346d6aed566Sopenharmony_ci
347d6aed566Sopenharmony_ci#define MMC_CSD_WBPART_SBIT     21
348d6aed566Sopenharmony_ci
349d6aed566Sopenharmony_ci#define MMC_CSD_FFORMGRP_SBIT   15
350d6aed566Sopenharmony_ci
351d6aed566Sopenharmony_ci#define MMC_CSD_FFORMAT_SBIT    10
352d6aed566Sopenharmony_ci#define MMC_CSD_FFORMAT_WIDTH   2
353d6aed566Sopenharmony_cistatic void VirtMmcFillRespCsd(struct MmcCmd *cmd, const struct Virtblk *blk)
354d6aed566Sopenharmony_ci{
355d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_STRUCT_SBIT, MMC_CSD_STRUCT_WIDTH, MMC_CSD_STRUCTURE_VER_1_2);
356d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_VERS_SBIT, MMC_CSD_VERS_WIDTH, MMC_CSD_SPEC_VER_4);
357d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_CCC_SBIT, MMC_CSD_CCC_WIDTH, MMC_CSD_CCC_BASIC |
358d6aed566Sopenharmony_ci                                                MMC_CSD_CCC_BLOCK_READ | MMC_CSD_CCC_BLOCK_WRITE);
359d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_RBPART_SBIT, 1, 0);       /* READ_BL_PARTIAL: no */
360d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_WBMISALIGN_SBIT, 1, 0);   /* WRITE_BLK_MISALIGN: no */
361d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_RBMISALIGN_SBIT, 1, 0);   /* READ_BLK_MISALIGN: no */
362d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_DSRIMP_SBIT, 1, 0);       /* DSR_IMP: no */
363d6aed566Sopenharmony_ci    if (blk->capacity > CAPACITY_2G) {
364d6aed566Sopenharmony_ci        uint32_t e = U32_BITS - __builtin_clz(blk->blkSize) - 1;
365d6aed566Sopenharmony_ci        FillCidCsdBits(cmd->resp, MMC_CSD_RBLEN_SBIT, MMC_CSD_RBLEN_WIDTH, e);  /* READ_BL_LEN */
366d6aed566Sopenharmony_ci        FillCidCsdBits(cmd->resp, MMC_CSD_WBLEN_SBIT, MMC_CSD_WBLEN_WIDTH, e);  /* WRITE_BL_LEN */
367d6aed566Sopenharmony_ci        FillCidCsdBits(cmd->resp, MMC_CSD_CSIZE_SBIT, MMC_CSD_CSIZE_WIDTH, MMC_CSD_CSIZE_VAL);
368d6aed566Sopenharmony_ci    } else {                                /* ensure c_size can up to 2G (512B can't) */
369d6aed566Sopenharmony_ci        FillCidCsdBits(cmd->resp, MMC_CSD_RBLEN_SBIT, MMC_CSD_RBLEN_WIDTH, READ_BL_LEN);
370d6aed566Sopenharmony_ci        FillCidCsdBits(cmd->resp, MMC_CSD_WBLEN_SBIT, MMC_CSD_WBLEN_WIDTH, READ_BL_LEN);
371d6aed566Sopenharmony_ci        uint32_t size = blk->capacity*MMC_SEC_SIZE / (1<<READ_BL_LEN) / (1<<(C_SIZE_MULT+2)) - 1;
372d6aed566Sopenharmony_ci        FillCidCsdBits(cmd->resp, MMC_CSD_CSIZE_SBIT, MMC_CSD_CSIZE_WIDTH, size);   /* C_SIZE */
373d6aed566Sopenharmony_ci    }
374d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_CSIZEMUL_SBIT, MMC_CSD_CSIZEMUL_WIDTH, C_SIZE_MULT);
375d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_EGRPSIZE_SBIT, MMC_CSD_EGRPSIZE_WIDTH, MMC_CSD_EGRPSIZE_VAL);
376d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_EGRPMULT_SBIT, MMC_CSD_EGRPMULT_WIDTH, MMC_CSD_EGRPMULT_VAL);
377d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_WBPART_SBIT, 1, 0);   /* WRITE_BL_PARTIAL: no */
378d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_FFORMGRP_SBIT, 1, 0); /* FILE_FORMAT_GRP */
379d6aed566Sopenharmony_ci    FillCidCsdBits(cmd->resp, MMC_CSD_FFORMAT_SBIT, MMC_CSD_FFORMAT_WIDTH, 0);  /* hard disk-like */
380d6aed566Sopenharmony_ci    /* leave other fields random */
381d6aed566Sopenharmony_ci}
382d6aed566Sopenharmony_ci
383d6aed566Sopenharmony_ci#define EMMC_EXT_CSD_CMD_SET_REV    189
384d6aed566Sopenharmony_ci#define EMMC_EXT_CSD_CMD_SET        191
385d6aed566Sopenharmony_ci#define EMMC_EXT_CSD_ACC_SIZE       225
386d6aed566Sopenharmony_ci#define EMMC_EXT_CSD_S_CMD_SET      504
387d6aed566Sopenharmony_cistatic void VirtMmcFillDataExtCsd(const struct MmcCmd *cmd, const struct Virtblk *blk)
388d6aed566Sopenharmony_ci{
389d6aed566Sopenharmony_ci    uint8_t *b = (uint8_t *)cmd->data->dataBuffer;
390d6aed566Sopenharmony_ci
391d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_S_CMD_SET] = 0;      /* standard MMC */
392d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_ACC_SIZE] = blk->blkSize / MMC_SEC_SIZE;
393d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_REL_WR_SEC_C] = blk->blkSize / MMC_SEC_SIZE;
394d6aed566Sopenharmony_ci    *(uint32_t*)&b[EMMC_EXT_CSD_SEC_CNT] = blk->capacity;
395d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_CARD_TYPE] = EMMC_EXT_CSD_CARD_TYPE_26 | EMMC_EXT_CSD_CARD_TYPE_52;
396d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_STRUCTURE] = EMMC_EXT_CSD_STRUCTURE_VER_1_2;
397d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_REV] = EMMC_EXT_CSD_REV_1_3;
398d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_CMD_SET] = 0;        /* standard MMC */
399d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_CMD_SET_REV] = 0;    /* v4.0 */
400d6aed566Sopenharmony_ci    b[EMMC_EXT_CSD_BUS_WIDTH] = EMMC_EXT_CSD_BUS_WIDTH_1;
401d6aed566Sopenharmony_ci    /* leave other fields random */
402d6aed566Sopenharmony_ci}
403d6aed566Sopenharmony_ci
404d6aed566Sopenharmony_ci#define MMC_RESP_STATE_BIT  9
405d6aed566Sopenharmony_cistatic inline void VirtMmcFillRespR1(struct MmcCmd *cmd)
406d6aed566Sopenharmony_ci{
407d6aed566Sopenharmony_ci    cmd->resp[0] = READY_FOR_DATA | (STATE_READY << MMC_RESP_STATE_BIT);
408d6aed566Sopenharmony_ci    cmd->resp[1] = cmd->cmdCode;
409d6aed566Sopenharmony_ci}
410d6aed566Sopenharmony_ci
411d6aed566Sopenharmony_cistatic int32_t VirtMmcIO(const struct MmcCntlr *cntlr, const struct MmcCmd *cmd)
412d6aed566Sopenharmony_ci{
413d6aed566Sopenharmony_ci    struct Virtblk *blk = cntlr->priv;
414d6aed566Sopenharmony_ci    uint64_t startSector = (uint64_t)cmd->argument;
415d6aed566Sopenharmony_ci    uint32_t io, ret;
416d6aed566Sopenharmony_ci
417d6aed566Sopenharmony_ci    if (cntlr->curDev->state.bits.blockAddr == 0) {
418d6aed566Sopenharmony_ci        startSector >>= MMC_SEC_SHIFT;
419d6aed566Sopenharmony_ci    }
420d6aed566Sopenharmony_ci
421d6aed566Sopenharmony_ci    if (cmd->data->dataFlags == DATA_READ) {
422d6aed566Sopenharmony_ci        io = VIRTIO_BLK_T_IN;
423d6aed566Sopenharmony_ci    } else {
424d6aed566Sopenharmony_ci        io = VIRTIO_BLK_T_OUT;
425d6aed566Sopenharmony_ci    }
426d6aed566Sopenharmony_ci
427d6aed566Sopenharmony_ci    ret = VirtblkIO(blk, io, startSector, cmd->data->dataBuffer, cmd->data->blockNum);
428d6aed566Sopenharmony_ci    if (ret == VIRTIO_BLK_S_OK) {
429d6aed566Sopenharmony_ci        cmd->data->returnError = HDF_SUCCESS;
430d6aed566Sopenharmony_ci    } else {
431d6aed566Sopenharmony_ci        HDF_LOGE("[%s]QEMU backend I/O error", __func__);
432d6aed566Sopenharmony_ci        cmd->data->returnError = HDF_ERR_IO;
433d6aed566Sopenharmony_ci    }
434d6aed566Sopenharmony_ci
435d6aed566Sopenharmony_ci    return HDF_SUCCESS;
436d6aed566Sopenharmony_ci}
437d6aed566Sopenharmony_ci
438d6aed566Sopenharmony_cistatic int32_t VirtMmcDoRequest(struct MmcCntlr *cntlr, struct MmcCmd *cmd)
439d6aed566Sopenharmony_ci{
440d6aed566Sopenharmony_ci    if ((cntlr == NULL) || (cntlr->priv == NULL) || (cmd == NULL)) {
441d6aed566Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
442d6aed566Sopenharmony_ci    }
443d6aed566Sopenharmony_ci    struct Virtblk *blk = cntlr->priv;
444d6aed566Sopenharmony_ci
445d6aed566Sopenharmony_ci    cmd->returnError = HDF_SUCCESS;
446d6aed566Sopenharmony_ci    switch (cmd->cmdCode) {
447d6aed566Sopenharmony_ci        case GO_IDLE_STATE:         // CMD0
448d6aed566Sopenharmony_ci            break;
449d6aed566Sopenharmony_ci        case SEND_OP_COND:          // CMD1
450d6aed566Sopenharmony_ci            if (blk->capacity > CAPACITY_2G) {
451d6aed566Sopenharmony_ci                cmd->resp[0] = OCR_GT_2G;
452d6aed566Sopenharmony_ci            } else {
453d6aed566Sopenharmony_ci                cmd->resp[0] = OCR_LE_2G;
454d6aed566Sopenharmony_ci            }
455d6aed566Sopenharmony_ci            break;
456d6aed566Sopenharmony_ci        case ALL_SEND_CID:          // CMD2, fall through
457d6aed566Sopenharmony_ci        case SEND_CID:              // CMD10
458d6aed566Sopenharmony_ci            VirtMmcFillRespCid(cmd, blk);
459d6aed566Sopenharmony_ci            break;
460d6aed566Sopenharmony_ci        case SEND_EXT_CSD:          // CMD8, fall through
461d6aed566Sopenharmony_ci            VirtMmcFillDataExtCsd(cmd, blk);
462d6aed566Sopenharmony_ci            cmd->data->returnError = HDF_SUCCESS;
463d6aed566Sopenharmony_ci        case SET_RELATIVE_ADDR:     // CMD3, fall through
464d6aed566Sopenharmony_ci        case SWITCH:                // CMD6, fall through
465d6aed566Sopenharmony_ci        case SELECT_CARD:           // CMD7, fall through
466d6aed566Sopenharmony_ci        case SEND_STATUS:           // CMD13
467d6aed566Sopenharmony_ci            VirtMmcFillRespR1(cmd);
468d6aed566Sopenharmony_ci            break;
469d6aed566Sopenharmony_ci        case SEND_CSD:              // CMD9
470d6aed566Sopenharmony_ci            VirtMmcFillRespCsd(cmd, blk);
471d6aed566Sopenharmony_ci            break;
472d6aed566Sopenharmony_ci        case READ_SINGLE_BLOCK:     // CMD17, fall through
473d6aed566Sopenharmony_ci        case READ_MULTIPLE_BLOCK:   // CMD18, fall through
474d6aed566Sopenharmony_ci        case WRITE_BLOCK:           // CMD24, fall through
475d6aed566Sopenharmony_ci        case WRITE_MULTIPLE_BLOCK:  // CMD25
476d6aed566Sopenharmony_ci            return VirtMmcIO(cntlr, cmd);
477d6aed566Sopenharmony_ci        default:
478d6aed566Sopenharmony_ci            HDF_LOGE("[%s]unsupported command: %u", __func__, cmd->cmdCode);
479d6aed566Sopenharmony_ci            cmd->returnError = HDF_ERR_NOT_SUPPORT;
480d6aed566Sopenharmony_ci    }
481d6aed566Sopenharmony_ci    return cmd->returnError;
482d6aed566Sopenharmony_ci}
483d6aed566Sopenharmony_ci
484d6aed566Sopenharmony_cistatic bool VirtMmcPlugged(struct MmcCntlr *cntlr)
485d6aed566Sopenharmony_ci{
486d6aed566Sopenharmony_ci    (void)cntlr;
487d6aed566Sopenharmony_ci    return true;
488d6aed566Sopenharmony_ci}
489d6aed566Sopenharmony_ci
490d6aed566Sopenharmony_cistatic bool VirtMmcBusy(struct MmcCntlr *cntlr)
491d6aed566Sopenharmony_ci{
492d6aed566Sopenharmony_ci    (void)cntlr;
493d6aed566Sopenharmony_ci    return false;
494d6aed566Sopenharmony_ci}
495d6aed566Sopenharmony_ci
496d6aed566Sopenharmony_cistatic struct MmcCntlrOps g_virtblkOps = {
497d6aed566Sopenharmony_ci    .request = VirtMmcDoRequest,
498d6aed566Sopenharmony_ci    .devPlugged = VirtMmcPlugged,
499d6aed566Sopenharmony_ci    .devBusy = VirtMmcBusy,
500d6aed566Sopenharmony_ci};
501d6aed566Sopenharmony_ci
502d6aed566Sopenharmony_ci
503d6aed566Sopenharmony_ci/*
504d6aed566Sopenharmony_ci * HDF entry
505d6aed566Sopenharmony_ci */
506d6aed566Sopenharmony_ci
507d6aed566Sopenharmony_cistatic void HdfVirtblkRelease(struct HdfDeviceObject *deviceObject)
508d6aed566Sopenharmony_ci{
509d6aed566Sopenharmony_ci    struct MmcCntlr *cntlr = deviceObject->priv;
510d6aed566Sopenharmony_ci    struct Virtblk *blk = cntlr->priv;
511d6aed566Sopenharmony_ci
512d6aed566Sopenharmony_ci    if (blk) {
513d6aed566Sopenharmony_ci        VirtblkDeInit(blk);
514d6aed566Sopenharmony_ci    }
515d6aed566Sopenharmony_ci    if (cntlr->curDev != NULL) {
516d6aed566Sopenharmony_ci        MmcDeviceRemove(cntlr->curDev);
517d6aed566Sopenharmony_ci        OsalMemFree(cntlr->curDev);
518d6aed566Sopenharmony_ci        cntlr->curDev = NULL;
519d6aed566Sopenharmony_ci    }
520d6aed566Sopenharmony_ci    MmcCntlrRemove(cntlr);
521d6aed566Sopenharmony_ci    OsalMemFree(cntlr);
522d6aed566Sopenharmony_ci}
523d6aed566Sopenharmony_ci
524d6aed566Sopenharmony_cistatic int32_t HdfVirtblkBind(struct HdfDeviceObject *obj)
525d6aed566Sopenharmony_ci{
526d6aed566Sopenharmony_ci    struct MmcCntlr *cntlr = NULL;
527d6aed566Sopenharmony_ci    struct Virtblk *blk = NULL;
528d6aed566Sopenharmony_ci    int32_t ret;
529d6aed566Sopenharmony_ci
530d6aed566Sopenharmony_ci    if (obj == NULL) {
531d6aed566Sopenharmony_ci        HDF_LOGE("[%s]HdfDeviceObject is NULL", __func__);
532d6aed566Sopenharmony_ci        return HDF_ERR_INVALID_OBJECT;
533d6aed566Sopenharmony_ci    }
534d6aed566Sopenharmony_ci
535d6aed566Sopenharmony_ci    cntlr = OsalMemCalloc(sizeof(struct MmcCntlr));
536d6aed566Sopenharmony_ci    if (cntlr == NULL) {
537d6aed566Sopenharmony_ci        HDF_LOGE("[%s]alloc MmcCntlr memory failed", __func__);
538d6aed566Sopenharmony_ci        return HDF_ERR_MALLOC_FAIL;
539d6aed566Sopenharmony_ci    }
540d6aed566Sopenharmony_ci
541d6aed566Sopenharmony_ci    if ((blk = VirtblkInitDev()) == NULL) {
542d6aed566Sopenharmony_ci        OsalMemFree(cntlr);
543d6aed566Sopenharmony_ci        return HDF_FAILURE;
544d6aed566Sopenharmony_ci    }
545d6aed566Sopenharmony_ci
546d6aed566Sopenharmony_ci    obj->service = &cntlr->service;
547d6aed566Sopenharmony_ci    obj->priv = cntlr;
548d6aed566Sopenharmony_ci    cntlr->priv = blk;
549d6aed566Sopenharmony_ci    cntlr->ops = &g_virtblkOps;
550d6aed566Sopenharmony_ci    cntlr->hdfDevObj = obj;
551d6aed566Sopenharmony_ci    if ((ret = MmcCntlrParse(cntlr, obj)) != HDF_SUCCESS) {
552d6aed566Sopenharmony_ci        goto _ERR;
553d6aed566Sopenharmony_ci    }
554d6aed566Sopenharmony_ci
555d6aed566Sopenharmony_ci    if ((ret = MmcCntlrAdd(cntlr, true)) != HDF_SUCCESS) {
556d6aed566Sopenharmony_ci        goto _ERR;
557d6aed566Sopenharmony_ci    }
558d6aed566Sopenharmony_ci    (void)MmcCntlrAddDetectMsgToQueue(cntlr);
559d6aed566Sopenharmony_ci
560d6aed566Sopenharmony_ci    return HDF_SUCCESS;
561d6aed566Sopenharmony_ci
562d6aed566Sopenharmony_ci_ERR:   /* Bind failure, so we must call release manually. */
563d6aed566Sopenharmony_ci    HdfVirtblkRelease(obj);
564d6aed566Sopenharmony_ci    return ret;
565d6aed566Sopenharmony_ci}
566d6aed566Sopenharmony_ci
567d6aed566Sopenharmony_cistatic int32_t HdfVirtblkInit(struct HdfDeviceObject *device)
568d6aed566Sopenharmony_ci{
569d6aed566Sopenharmony_ci    if (device == NULL) {
570d6aed566Sopenharmony_ci        HDF_LOGE("[%s]device is null", __func__);
571d6aed566Sopenharmony_ci        return HDF_ERR_INVALID_PARAM;
572d6aed566Sopenharmony_ci    }
573d6aed566Sopenharmony_ci
574d6aed566Sopenharmony_ci    return HDF_SUCCESS;
575d6aed566Sopenharmony_ci}
576d6aed566Sopenharmony_ci
577d6aed566Sopenharmony_cistruct HdfDriverEntry g_virtBlockEntry = {
578d6aed566Sopenharmony_ci    .moduleVersion = 1,
579d6aed566Sopenharmony_ci    .moduleName = "HDF_VIRTIO_BLOCK",
580d6aed566Sopenharmony_ci    .Bind = HdfVirtblkBind,
581d6aed566Sopenharmony_ci    .Init = HdfVirtblkInit,
582d6aed566Sopenharmony_ci    .Release = HdfVirtblkRelease,
583d6aed566Sopenharmony_ci};
584d6aed566Sopenharmony_ci
585d6aed566Sopenharmony_ciHDF_INIT(g_virtBlockEntry);
586