xref: /openbmc/qemu/hw/misc/sifive_u_prci.c (revision 9fe640a53dd8ef33d32ab6e833fa9b6d1356cfae)
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