qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

npcm7xx_sdhci.c (5469B)


      1 /*
      2  * NPCM7xx SD-3.0 / eMMC-4.51 Host Controller
      3  *
      4  * Copyright (c) 2021 Google LLC
      5  *
      6  * This program is free software; you can redistribute it and/or modify it
      7  * under the terms of the GNU General Public License as published by the
      8  * Free Software Foundation; either version 2 of the License, or
      9  * (at your option) any later version.
     10  *
     11  * This program is distributed in the hope that it will be useful, but WITHOUT
     12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
     14  * for more details.
     15  */
     16 
     17 #include "qemu/osdep.h"
     18 
     19 #include "hw/sd/npcm7xx_sdhci.h"
     20 #include "migration/vmstate.h"
     21 #include "sdhci-internal.h"
     22 #include "qemu/log.h"
     23 
     24 static uint64_t npcm7xx_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
     25 {
     26     NPCM7xxSDHCIState *s = opaque;
     27     uint64_t val = 0;
     28 
     29     switch (addr) {
     30     case NPCM7XX_PRSTVALS_0:
     31     case NPCM7XX_PRSTVALS_1:
     32     case NPCM7XX_PRSTVALS_2:
     33     case NPCM7XX_PRSTVALS_3:
     34     case NPCM7XX_PRSTVALS_4:
     35     case NPCM7XX_PRSTVALS_5:
     36         val = s->regs.prstvals[(addr - NPCM7XX_PRSTVALS_0) / 2];
     37         break;
     38     case NPCM7XX_BOOTTOCTRL:
     39         val = s->regs.boottoctrl;
     40         break;
     41     default:
     42         qemu_log_mask(LOG_GUEST_ERROR, "SDHCI read of nonexistent reg: 0x%02"
     43                       HWADDR_PRIx, addr);
     44         break;
     45     }
     46 
     47     return val;
     48 }
     49 
     50 static void npcm7xx_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
     51                                 unsigned int size)
     52 {
     53     NPCM7xxSDHCIState *s = opaque;
     54 
     55     switch (addr) {
     56     case NPCM7XX_BOOTTOCTRL:
     57         s->regs.boottoctrl = val;
     58         break;
     59     default:
     60         qemu_log_mask(LOG_GUEST_ERROR, "SDHCI write of nonexistent reg: 0x%02"
     61                       HWADDR_PRIx, addr);
     62         break;
     63     }
     64 }
     65 
     66 static bool npcm7xx_sdhci_check_mem_op(void *opaque, hwaddr addr,
     67                                        unsigned size, bool is_write,
     68                                        MemTxAttrs attrs)
     69 {
     70     switch (addr) {
     71     case NPCM7XX_PRSTVALS_0:
     72     case NPCM7XX_PRSTVALS_1:
     73     case NPCM7XX_PRSTVALS_2:
     74     case NPCM7XX_PRSTVALS_3:
     75     case NPCM7XX_PRSTVALS_4:
     76     case NPCM7XX_PRSTVALS_5:
     77         /* RO Word */
     78         return !is_write && size == 2;
     79     case NPCM7XX_BOOTTOCTRL:
     80         /* R/W Dword */
     81         return size == 4;
     82     default:
     83         return false;
     84     }
     85 }
     86 
     87 static const MemoryRegionOps npcm7xx_sdhci_ops = {
     88     .read = npcm7xx_sdhci_read,
     89     .write = npcm7xx_sdhci_write,
     90     .endianness = DEVICE_NATIVE_ENDIAN,
     91     .valid = {
     92         .min_access_size = 1,
     93         .max_access_size = 4,
     94         .unaligned = false,
     95         .accepts = npcm7xx_sdhci_check_mem_op,
     96     },
     97 };
     98 
     99 static void npcm7xx_sdhci_realize(DeviceState *dev, Error **errp)
    100 {
    101     NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
    102     SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
    103     SysBusDevice *sbd_sdhci = SYS_BUS_DEVICE(&s->sdhci);
    104 
    105     memory_region_init(&s->container, OBJECT(s),
    106                        "npcm7xx.sdhci-container", 0x1000);
    107     sysbus_init_mmio(sbd, &s->container);
    108 
    109     memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_sdhci_ops, s,
    110                           TYPE_NPCM7XX_SDHCI, NPCM7XX_SDHCI_REGSIZE);
    111     memory_region_add_subregion_overlap(&s->container, NPCM7XX_PRSTVALS,
    112                                         &s->iomem, 1);
    113 
    114     sysbus_realize(sbd_sdhci, errp);
    115     memory_region_add_subregion(&s->container, 0,
    116                                 sysbus_mmio_get_region(sbd_sdhci, 0));
    117 
    118     /* propagate irq and "sd-bus" from generic-sdhci */
    119     sysbus_pass_irq(sbd, sbd_sdhci);
    120     s->bus = qdev_get_child_bus(DEVICE(sbd_sdhci), "sd-bus");
    121 
    122     /* Set the read only preset values. */
    123     memset(s->regs.prstvals, 0, sizeof(s->regs.prstvals));
    124     s->regs.prstvals[0] = NPCM7XX_PRSTVALS_0_RESET;
    125     s->regs.prstvals[1] = NPCM7XX_PRSTVALS_1_RESET;
    126     s->regs.prstvals[3] = NPCM7XX_PRSTVALS_3_RESET;
    127 }
    128 
    129 static void npcm7xx_sdhci_reset(DeviceState *dev)
    130 {
    131     NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(dev);
    132     device_cold_reset(DEVICE(&s->sdhci));
    133     s->regs.boottoctrl = 0;
    134 
    135     s->sdhci.prnsts = NPCM7XX_PRSNTS_RESET;
    136     s->sdhci.blkgap = NPCM7XX_BLKGAP_RESET;
    137     s->sdhci.capareg = NPCM7XX_CAPAB_RESET;
    138     s->sdhci.maxcurr = NPCM7XX_MAXCURR_RESET;
    139     s->sdhci.version = NPCM7XX_HCVER_RESET;
    140 }
    141 
    142 static const VMStateDescription vmstate_npcm7xx_sdhci = {
    143     .name = TYPE_NPCM7XX_SDHCI,
    144     .version_id = 0,
    145     .fields = (VMStateField[]) {
    146         VMSTATE_UINT32(regs.boottoctrl, NPCM7xxSDHCIState),
    147         VMSTATE_END_OF_LIST(),
    148     },
    149 };
    150 
    151 static void npcm7xx_sdhci_class_init(ObjectClass *classp, void *data)
    152 {
    153     DeviceClass *dc = DEVICE_CLASS(classp);
    154 
    155     dc->desc = "NPCM7xx SD/eMMC Host Controller";
    156     dc->realize = npcm7xx_sdhci_realize;
    157     dc->reset = npcm7xx_sdhci_reset;
    158     dc->vmsd = &vmstate_npcm7xx_sdhci;
    159 }
    160 
    161 static void npcm7xx_sdhci_instance_init(Object *obj)
    162 {
    163     NPCM7xxSDHCIState *s = NPCM7XX_SDHCI(obj);
    164 
    165     object_initialize_child(OBJECT(s), "generic-sdhci", &s->sdhci,
    166                             TYPE_SYSBUS_SDHCI);
    167 }
    168 
    169 static const TypeInfo npcm7xx_sdhci_info = {
    170     .name = TYPE_NPCM7XX_SDHCI,
    171     .parent = TYPE_SYS_BUS_DEVICE,
    172     .instance_size = sizeof(NPCM7xxSDHCIState),
    173     .instance_init = npcm7xx_sdhci_instance_init,
    174     .class_init = npcm7xx_sdhci_class_init,
    175 };
    176 
    177 static void npcm7xx_sdhci_register_types(void)
    178 {
    179     type_register_static(&npcm7xx_sdhci_info);
    180 }
    181 
    182 type_init(npcm7xx_sdhci_register_types)