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