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