1*0ee1e1f4SSubbaraya Sundeep /* 2*0ee1e1f4SSubbaraya Sundeep * System Register block model of Microsemi SmartFusion2. 3*0ee1e1f4SSubbaraya Sundeep * 4*0ee1e1f4SSubbaraya Sundeep * Copyright (c) 2017 Subbaraya Sundeep <sundeep.lkml@gmail.com> 5*0ee1e1f4SSubbaraya Sundeep * 6*0ee1e1f4SSubbaraya Sundeep * This program is free software; you can redistribute it and/or 7*0ee1e1f4SSubbaraya Sundeep * modify it under the terms of the GNU General Public License 8*0ee1e1f4SSubbaraya Sundeep * as published by the Free Software Foundation; either version 9*0ee1e1f4SSubbaraya Sundeep * 2 of the License, or (at your option) any later version. 10*0ee1e1f4SSubbaraya Sundeep * 11*0ee1e1f4SSubbaraya Sundeep * You should have received a copy of the GNU General Public License along 12*0ee1e1f4SSubbaraya Sundeep * with this program; if not, see <http://www.gnu.org/licenses/>. 13*0ee1e1f4SSubbaraya Sundeep */ 14*0ee1e1f4SSubbaraya Sundeep 15*0ee1e1f4SSubbaraya Sundeep #include "qemu/osdep.h" 16*0ee1e1f4SSubbaraya Sundeep #include "qapi/error.h" 17*0ee1e1f4SSubbaraya Sundeep #include "qemu/log.h" 18*0ee1e1f4SSubbaraya Sundeep #include "hw/misc/msf2-sysreg.h" 19*0ee1e1f4SSubbaraya Sundeep #include "qemu/error-report.h" 20*0ee1e1f4SSubbaraya Sundeep #include "trace.h" 21*0ee1e1f4SSubbaraya Sundeep 22*0ee1e1f4SSubbaraya Sundeep static inline int msf2_divbits(uint32_t div) 23*0ee1e1f4SSubbaraya Sundeep { 24*0ee1e1f4SSubbaraya Sundeep int r = ctz32(div); 25*0ee1e1f4SSubbaraya Sundeep 26*0ee1e1f4SSubbaraya Sundeep return (div < 8) ? r : r + 1; 27*0ee1e1f4SSubbaraya Sundeep } 28*0ee1e1f4SSubbaraya Sundeep 29*0ee1e1f4SSubbaraya Sundeep static void msf2_sysreg_reset(DeviceState *d) 30*0ee1e1f4SSubbaraya Sundeep { 31*0ee1e1f4SSubbaraya Sundeep MSF2SysregState *s = MSF2_SYSREG(d); 32*0ee1e1f4SSubbaraya Sundeep 33*0ee1e1f4SSubbaraya Sundeep s->regs[MSSDDR_PLL_STATUS_LOW_CR] = 0x021A2358; 34*0ee1e1f4SSubbaraya Sundeep s->regs[MSSDDR_PLL_STATUS] = 0x3; 35*0ee1e1f4SSubbaraya Sundeep s->regs[MSSDDR_FACC1_CR] = msf2_divbits(s->apb0div) << 5 | 36*0ee1e1f4SSubbaraya Sundeep msf2_divbits(s->apb1div) << 2; 37*0ee1e1f4SSubbaraya Sundeep } 38*0ee1e1f4SSubbaraya Sundeep 39*0ee1e1f4SSubbaraya Sundeep static uint64_t msf2_sysreg_read(void *opaque, hwaddr offset, 40*0ee1e1f4SSubbaraya Sundeep unsigned size) 41*0ee1e1f4SSubbaraya Sundeep { 42*0ee1e1f4SSubbaraya Sundeep MSF2SysregState *s = opaque; 43*0ee1e1f4SSubbaraya Sundeep uint32_t ret = 0; 44*0ee1e1f4SSubbaraya Sundeep 45*0ee1e1f4SSubbaraya Sundeep offset >>= 2; 46*0ee1e1f4SSubbaraya Sundeep if (offset < ARRAY_SIZE(s->regs)) { 47*0ee1e1f4SSubbaraya Sundeep ret = s->regs[offset]; 48*0ee1e1f4SSubbaraya Sundeep trace_msf2_sysreg_read(offset << 2, ret); 49*0ee1e1f4SSubbaraya Sundeep } else { 50*0ee1e1f4SSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, 51*0ee1e1f4SSubbaraya Sundeep "%s: Bad offset 0x%08" HWADDR_PRIx "\n", __func__, 52*0ee1e1f4SSubbaraya Sundeep offset << 2); 53*0ee1e1f4SSubbaraya Sundeep } 54*0ee1e1f4SSubbaraya Sundeep 55*0ee1e1f4SSubbaraya Sundeep return ret; 56*0ee1e1f4SSubbaraya Sundeep } 57*0ee1e1f4SSubbaraya Sundeep 58*0ee1e1f4SSubbaraya Sundeep static void msf2_sysreg_write(void *opaque, hwaddr offset, 59*0ee1e1f4SSubbaraya Sundeep uint64_t val, unsigned size) 60*0ee1e1f4SSubbaraya Sundeep { 61*0ee1e1f4SSubbaraya Sundeep MSF2SysregState *s = opaque; 62*0ee1e1f4SSubbaraya Sundeep uint32_t newval = val; 63*0ee1e1f4SSubbaraya Sundeep 64*0ee1e1f4SSubbaraya Sundeep offset >>= 2; 65*0ee1e1f4SSubbaraya Sundeep 66*0ee1e1f4SSubbaraya Sundeep switch (offset) { 67*0ee1e1f4SSubbaraya Sundeep case MSSDDR_PLL_STATUS: 68*0ee1e1f4SSubbaraya Sundeep trace_msf2_sysreg_write_pll_status(); 69*0ee1e1f4SSubbaraya Sundeep break; 70*0ee1e1f4SSubbaraya Sundeep 71*0ee1e1f4SSubbaraya Sundeep case ESRAM_CR: 72*0ee1e1f4SSubbaraya Sundeep case DDR_CR: 73*0ee1e1f4SSubbaraya Sundeep case ENVM_REMAP_BASE_CR: 74*0ee1e1f4SSubbaraya Sundeep if (newval != s->regs[offset]) { 75*0ee1e1f4SSubbaraya Sundeep qemu_log_mask(LOG_UNIMP, 76*0ee1e1f4SSubbaraya Sundeep TYPE_MSF2_SYSREG": remapping not supported\n"); 77*0ee1e1f4SSubbaraya Sundeep } 78*0ee1e1f4SSubbaraya Sundeep break; 79*0ee1e1f4SSubbaraya Sundeep 80*0ee1e1f4SSubbaraya Sundeep default: 81*0ee1e1f4SSubbaraya Sundeep if (offset < ARRAY_SIZE(s->regs)) { 82*0ee1e1f4SSubbaraya Sundeep trace_msf2_sysreg_write(offset << 2, newval, s->regs[offset]); 83*0ee1e1f4SSubbaraya Sundeep s->regs[offset] = newval; 84*0ee1e1f4SSubbaraya Sundeep } else { 85*0ee1e1f4SSubbaraya Sundeep qemu_log_mask(LOG_GUEST_ERROR, 86*0ee1e1f4SSubbaraya Sundeep "%s: Bad offset 0x%08" HWADDR_PRIx "\n", __func__, 87*0ee1e1f4SSubbaraya Sundeep offset << 2); 88*0ee1e1f4SSubbaraya Sundeep } 89*0ee1e1f4SSubbaraya Sundeep break; 90*0ee1e1f4SSubbaraya Sundeep } 91*0ee1e1f4SSubbaraya Sundeep } 92*0ee1e1f4SSubbaraya Sundeep 93*0ee1e1f4SSubbaraya Sundeep static const MemoryRegionOps sysreg_ops = { 94*0ee1e1f4SSubbaraya Sundeep .read = msf2_sysreg_read, 95*0ee1e1f4SSubbaraya Sundeep .write = msf2_sysreg_write, 96*0ee1e1f4SSubbaraya Sundeep .endianness = DEVICE_NATIVE_ENDIAN, 97*0ee1e1f4SSubbaraya Sundeep }; 98*0ee1e1f4SSubbaraya Sundeep 99*0ee1e1f4SSubbaraya Sundeep static void msf2_sysreg_init(Object *obj) 100*0ee1e1f4SSubbaraya Sundeep { 101*0ee1e1f4SSubbaraya Sundeep MSF2SysregState *s = MSF2_SYSREG(obj); 102*0ee1e1f4SSubbaraya Sundeep 103*0ee1e1f4SSubbaraya Sundeep memory_region_init_io(&s->iomem, obj, &sysreg_ops, s, TYPE_MSF2_SYSREG, 104*0ee1e1f4SSubbaraya Sundeep MSF2_SYSREG_MMIO_SIZE); 105*0ee1e1f4SSubbaraya Sundeep sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem); 106*0ee1e1f4SSubbaraya Sundeep } 107*0ee1e1f4SSubbaraya Sundeep 108*0ee1e1f4SSubbaraya Sundeep static const VMStateDescription vmstate_msf2_sysreg = { 109*0ee1e1f4SSubbaraya Sundeep .name = TYPE_MSF2_SYSREG, 110*0ee1e1f4SSubbaraya Sundeep .version_id = 1, 111*0ee1e1f4SSubbaraya Sundeep .minimum_version_id = 1, 112*0ee1e1f4SSubbaraya Sundeep .fields = (VMStateField[]) { 113*0ee1e1f4SSubbaraya Sundeep VMSTATE_UINT32_ARRAY(regs, MSF2SysregState, MSF2_SYSREG_MMIO_SIZE / 4), 114*0ee1e1f4SSubbaraya Sundeep VMSTATE_END_OF_LIST() 115*0ee1e1f4SSubbaraya Sundeep } 116*0ee1e1f4SSubbaraya Sundeep }; 117*0ee1e1f4SSubbaraya Sundeep 118*0ee1e1f4SSubbaraya Sundeep static Property msf2_sysreg_properties[] = { 119*0ee1e1f4SSubbaraya Sundeep /* default divisors in Libero GUI */ 120*0ee1e1f4SSubbaraya Sundeep DEFINE_PROP_UINT8("apb0divisor", MSF2SysregState, apb0div, 2), 121*0ee1e1f4SSubbaraya Sundeep DEFINE_PROP_UINT8("apb1divisor", MSF2SysregState, apb1div, 2), 122*0ee1e1f4SSubbaraya Sundeep DEFINE_PROP_END_OF_LIST(), 123*0ee1e1f4SSubbaraya Sundeep }; 124*0ee1e1f4SSubbaraya Sundeep 125*0ee1e1f4SSubbaraya Sundeep static void msf2_sysreg_realize(DeviceState *dev, Error **errp) 126*0ee1e1f4SSubbaraya Sundeep { 127*0ee1e1f4SSubbaraya Sundeep MSF2SysregState *s = MSF2_SYSREG(dev); 128*0ee1e1f4SSubbaraya Sundeep 129*0ee1e1f4SSubbaraya Sundeep if ((s->apb0div > 32 || !is_power_of_2(s->apb0div)) 130*0ee1e1f4SSubbaraya Sundeep || (s->apb1div > 32 || !is_power_of_2(s->apb1div))) { 131*0ee1e1f4SSubbaraya Sundeep error_setg(errp, "Invalid apb divisor value"); 132*0ee1e1f4SSubbaraya Sundeep error_append_hint(errp, "apb divisor must be a power of 2" 133*0ee1e1f4SSubbaraya Sundeep " and maximum value is 32\n"); 134*0ee1e1f4SSubbaraya Sundeep } 135*0ee1e1f4SSubbaraya Sundeep } 136*0ee1e1f4SSubbaraya Sundeep 137*0ee1e1f4SSubbaraya Sundeep static void msf2_sysreg_class_init(ObjectClass *klass, void *data) 138*0ee1e1f4SSubbaraya Sundeep { 139*0ee1e1f4SSubbaraya Sundeep DeviceClass *dc = DEVICE_CLASS(klass); 140*0ee1e1f4SSubbaraya Sundeep 141*0ee1e1f4SSubbaraya Sundeep dc->vmsd = &vmstate_msf2_sysreg; 142*0ee1e1f4SSubbaraya Sundeep dc->reset = msf2_sysreg_reset; 143*0ee1e1f4SSubbaraya Sundeep dc->props = msf2_sysreg_properties; 144*0ee1e1f4SSubbaraya Sundeep dc->realize = msf2_sysreg_realize; 145*0ee1e1f4SSubbaraya Sundeep } 146*0ee1e1f4SSubbaraya Sundeep 147*0ee1e1f4SSubbaraya Sundeep static const TypeInfo msf2_sysreg_info = { 148*0ee1e1f4SSubbaraya Sundeep .name = TYPE_MSF2_SYSREG, 149*0ee1e1f4SSubbaraya Sundeep .parent = TYPE_SYS_BUS_DEVICE, 150*0ee1e1f4SSubbaraya Sundeep .class_init = msf2_sysreg_class_init, 151*0ee1e1f4SSubbaraya Sundeep .instance_size = sizeof(MSF2SysregState), 152*0ee1e1f4SSubbaraya Sundeep .instance_init = msf2_sysreg_init, 153*0ee1e1f4SSubbaraya Sundeep }; 154*0ee1e1f4SSubbaraya Sundeep 155*0ee1e1f4SSubbaraya Sundeep static void msf2_sysreg_register_types(void) 156*0ee1e1f4SSubbaraya Sundeep { 157*0ee1e1f4SSubbaraya Sundeep type_register_static(&msf2_sysreg_info); 158*0ee1e1f4SSubbaraya Sundeep } 159*0ee1e1f4SSubbaraya Sundeep 160*0ee1e1f4SSubbaraya Sundeep type_init(msf2_sysreg_register_types) 161