qemu

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

sifive_u_prci.c (5553B)


      1 /*
      2  * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt)
      3  *
      4  * Copyright (c) 2019 Bin Meng <bmeng.cn@gmail.com>
      5  *
      6  * Simple model of the PRCI to emulate register reads made by the SDK BSP
      7  *
      8  * This program is free software; you can redistribute it and/or modify it
      9  * under the terms and conditions of the GNU General Public License,
     10  * version 2 or later, as published by the Free Software Foundation.
     11  *
     12  * This program is distributed in the hope it will be useful, but WITHOUT
     13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
     14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
     15  * more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along with
     18  * this program.  If not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "hw/sysbus.h"
     23 #include "qemu/log.h"
     24 #include "qemu/module.h"
     25 #include "hw/misc/sifive_u_prci.h"
     26 
     27 static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size)
     28 {
     29     SiFiveUPRCIState *s = opaque;
     30 
     31     switch (addr) {
     32     case SIFIVE_U_PRCI_HFXOSCCFG:
     33         return s->hfxosccfg;
     34     case SIFIVE_U_PRCI_COREPLLCFG0:
     35         return s->corepllcfg0;
     36     case SIFIVE_U_PRCI_DDRPLLCFG0:
     37         return s->ddrpllcfg0;
     38     case SIFIVE_U_PRCI_DDRPLLCFG1:
     39         return s->ddrpllcfg1;
     40     case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
     41         return s->gemgxlpllcfg0;
     42     case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
     43         return s->gemgxlpllcfg1;
     44     case SIFIVE_U_PRCI_CORECLKSEL:
     45         return s->coreclksel;
     46     case SIFIVE_U_PRCI_DEVICESRESET:
     47         return s->devicesreset;
     48     case SIFIVE_U_PRCI_CLKMUXSTATUS:
     49         return s->clkmuxstatus;
     50     }
     51 
     52     qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
     53                   __func__, addr);
     54 
     55     return 0;
     56 }
     57 
     58 static void sifive_u_prci_write(void *opaque, hwaddr addr,
     59                                 uint64_t val64, unsigned int size)
     60 {
     61     SiFiveUPRCIState *s = opaque;
     62     uint32_t val32 = (uint32_t)val64;
     63 
     64     switch (addr) {
     65     case SIFIVE_U_PRCI_HFXOSCCFG:
     66         s->hfxosccfg = val32;
     67         /* OSC stays ready */
     68         s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY;
     69         break;
     70     case SIFIVE_U_PRCI_COREPLLCFG0:
     71         s->corepllcfg0 = val32;
     72         /* internal feedback */
     73         s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
     74         /* PLL stays locked */
     75         s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
     76         break;
     77     case SIFIVE_U_PRCI_DDRPLLCFG0:
     78         s->ddrpllcfg0 = val32;
     79         /* internal feedback */
     80         s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
     81         /* PLL stays locked */
     82         s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
     83         break;
     84     case SIFIVE_U_PRCI_DDRPLLCFG1:
     85         s->ddrpllcfg1 = val32;
     86         break;
     87     case SIFIVE_U_PRCI_GEMGXLPLLCFG0:
     88         s->gemgxlpllcfg0 = val32;
     89         /* internal feedback */
     90         s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE;
     91         /* PLL stays locked */
     92         s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK;
     93         break;
     94     case SIFIVE_U_PRCI_GEMGXLPLLCFG1:
     95         s->gemgxlpllcfg1 = val32;
     96         break;
     97     case SIFIVE_U_PRCI_CORECLKSEL:
     98         s->coreclksel = val32;
     99         break;
    100     case SIFIVE_U_PRCI_DEVICESRESET:
    101         s->devicesreset = val32;
    102         break;
    103     case SIFIVE_U_PRCI_CLKMUXSTATUS:
    104         s->clkmuxstatus = val32;
    105         break;
    106     default:
    107         qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
    108                       " v=0x%x\n", __func__, addr, val32);
    109     }
    110 }
    111 
    112 static const MemoryRegionOps sifive_u_prci_ops = {
    113     .read = sifive_u_prci_read,
    114     .write = sifive_u_prci_write,
    115     .endianness = DEVICE_NATIVE_ENDIAN,
    116     .valid = {
    117         .min_access_size = 4,
    118         .max_access_size = 4
    119     }
    120 };
    121 
    122 static void sifive_u_prci_realize(DeviceState *dev, Error **errp)
    123 {
    124     SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
    125 
    126     memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s,
    127                           TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE);
    128     sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio);
    129 }
    130 
    131 static void sifive_u_prci_reset(DeviceState *dev)
    132 {
    133     SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev);
    134 
    135     /* Initialize register to power-on-reset values */
    136     s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN;
    137     s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
    138                      SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
    139                      SIFIVE_U_PRCI_PLLCFG0_LOCK;
    140     s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
    141                     SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
    142                     SIFIVE_U_PRCI_PLLCFG0_LOCK;
    143     s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF |
    144                        SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE |
    145                        SIFIVE_U_PRCI_PLLCFG0_LOCK;
    146     s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK;
    147 }
    148 
    149 static void sifive_u_prci_class_init(ObjectClass *klass, void *data)
    150 {
    151     DeviceClass *dc = DEVICE_CLASS(klass);
    152 
    153     dc->realize = sifive_u_prci_realize;
    154     dc->reset = sifive_u_prci_reset;
    155 }
    156 
    157 static const TypeInfo sifive_u_prci_info = {
    158     .name          = TYPE_SIFIVE_U_PRCI,
    159     .parent        = TYPE_SYS_BUS_DEVICE,
    160     .instance_size = sizeof(SiFiveUPRCIState),
    161     .class_init    = sifive_u_prci_class_init,
    162 };
    163 
    164 static void sifive_u_prci_register_types(void)
    165 {
    166     type_register_static(&sifive_u_prci_info);
    167 }
    168 
    169 type_init(sifive_u_prci_register_types)