1a937b302SBin Meng /* 2a937b302SBin Meng * Microchip PolarFire SoC IOSCB module emulation 3a937b302SBin Meng * 4a937b302SBin Meng * Copyright (c) 2020 Wind River Systems, Inc. 5a937b302SBin Meng * 6a937b302SBin Meng * Author: 7a937b302SBin Meng * Bin Meng <bin.meng@windriver.com> 8a937b302SBin Meng * 9a937b302SBin Meng * This program is free software; you can redistribute it and/or 10a937b302SBin Meng * modify it under the terms of the GNU General Public License as 11a937b302SBin Meng * published by the Free Software Foundation; either version 2 or 12a937b302SBin Meng * (at your option) version 3 of the License. 13a937b302SBin Meng * 14a937b302SBin Meng * This program is distributed in the hope that it will be useful, 15a937b302SBin Meng * but WITHOUT ANY WARRANTY; without even the implied warranty of 16a937b302SBin Meng * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17a937b302SBin Meng * GNU General Public License for more details. 18a937b302SBin Meng * 19a937b302SBin Meng * You should have received a copy of the GNU General Public License along 20a937b302SBin Meng * with this program; if not, see <http://www.gnu.org/licenses/>. 21a937b302SBin Meng */ 22a937b302SBin Meng 23a937b302SBin Meng #include "qemu/osdep.h" 24a937b302SBin Meng #include "qemu/bitops.h" 25a937b302SBin Meng #include "qemu/log.h" 26a937b302SBin Meng #include "qapi/error.h" 27*592f0a94SConor Dooley #include "hw/irq.h" 28a937b302SBin Meng #include "hw/sysbus.h" 29a937b302SBin Meng #include "hw/misc/mchp_pfsoc_ioscb.h" 30a937b302SBin Meng 31a937b302SBin Meng /* 32a937b302SBin Meng * The whole IOSCB module registers map into the system address at 0x3000_0000, 33a937b302SBin Meng * named as "System Port 0 (AXI-D0)". 34a937b302SBin Meng */ 35a937b302SBin Meng #define IOSCB_WHOLE_REG_SIZE 0x10000000 36a937b302SBin Meng #define IOSCB_SUBMOD_REG_SIZE 0x1000 3713cd1d6eSConor Dooley #define IOSCB_CCC_REG_SIZE 0x2000000 38*592f0a94SConor Dooley #define IOSCB_CTRL_REG_SIZE 0x800 39*592f0a94SConor Dooley #define IOSCB_QSPIXIP_REG_SIZE 0x200 40*592f0a94SConor Dooley 41a937b302SBin Meng 42a937b302SBin Meng /* 43a937b302SBin Meng * There are many sub-modules in the IOSCB module. 44a937b302SBin Meng * See Microchip PolarFire SoC documentation (Register_Map.zip), 45a937b302SBin Meng * Register Map/PF_SoC_RegMap_V1_1/MPFS250T/mpfs250t_ioscb_memmap_dri.htm 46a937b302SBin Meng * 47a937b302SBin Meng * The following are sub-modules offsets that are of concern. 48a937b302SBin Meng */ 49a937b302SBin Meng #define IOSCB_LANE01_BASE 0x06500000 50a937b302SBin Meng #define IOSCB_LANE23_BASE 0x06510000 51a937b302SBin Meng #define IOSCB_CTRL_BASE 0x07020000 52*592f0a94SConor Dooley #define IOSCB_QSPIXIP_BASE 0x07020100 53*592f0a94SConor Dooley #define IOSCB_MAILBOX_BASE 0x07020800 54a937b302SBin Meng #define IOSCB_CFG_BASE 0x07080000 5513cd1d6eSConor Dooley #define IOSCB_CCC_BASE 0x08000000 56a937b302SBin Meng #define IOSCB_PLL_MSS_BASE 0x0E001000 57a937b302SBin Meng #define IOSCB_CFM_MSS_BASE 0x0E002000 58a937b302SBin Meng #define IOSCB_PLL_DDR_BASE 0x0E010000 59a937b302SBin Meng #define IOSCB_BC_DDR_BASE 0x0E020000 60a937b302SBin Meng #define IOSCB_IO_CALIB_DDR_BASE 0x0E040000 61a937b302SBin Meng #define IOSCB_PLL_SGMII_BASE 0x0E080000 62a937b302SBin Meng #define IOSCB_DLL_SGMII_BASE 0x0E100000 63a937b302SBin Meng #define IOSCB_CFM_SGMII_BASE 0x0E200000 64a937b302SBin Meng #define IOSCB_BC_SGMII_BASE 0x0E400000 65a937b302SBin Meng #define IOSCB_IO_CALIB_SGMII_BASE 0x0E800000 66a937b302SBin Meng 67a937b302SBin Meng static uint64_t mchp_pfsoc_dummy_read(void *opaque, hwaddr offset, 68a937b302SBin Meng unsigned size) 69a937b302SBin Meng { 70a937b302SBin Meng qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " 71a937b302SBin Meng "(size %d, offset 0x%" HWADDR_PRIx ")\n", 72a937b302SBin Meng __func__, size, offset); 73a937b302SBin Meng 74a937b302SBin Meng return 0; 75a937b302SBin Meng } 76a937b302SBin Meng 77a937b302SBin Meng static void mchp_pfsoc_dummy_write(void *opaque, hwaddr offset, 78a937b302SBin Meng uint64_t value, unsigned size) 79a937b302SBin Meng { 80a937b302SBin Meng qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " 81a937b302SBin Meng "(size %d, value 0x%" PRIx64 82a937b302SBin Meng ", offset 0x%" HWADDR_PRIx ")\n", 83a937b302SBin Meng __func__, size, value, offset); 84a937b302SBin Meng } 85a937b302SBin Meng 86a937b302SBin Meng static const MemoryRegionOps mchp_pfsoc_dummy_ops = { 87a937b302SBin Meng .read = mchp_pfsoc_dummy_read, 88a937b302SBin Meng .write = mchp_pfsoc_dummy_write, 89a937b302SBin Meng .endianness = DEVICE_LITTLE_ENDIAN, 90a937b302SBin Meng }; 91a937b302SBin Meng 92a937b302SBin Meng /* All PLL modules in IOSCB have the same register layout */ 93a937b302SBin Meng 94a937b302SBin Meng #define PLL_CTRL 0x04 95a937b302SBin Meng 96a937b302SBin Meng static uint64_t mchp_pfsoc_pll_read(void *opaque, hwaddr offset, 97a937b302SBin Meng unsigned size) 98a937b302SBin Meng { 99a937b302SBin Meng uint32_t val = 0; 100a937b302SBin Meng 101a937b302SBin Meng switch (offset) { 102a937b302SBin Meng case PLL_CTRL: 103a937b302SBin Meng /* PLL is locked */ 104a937b302SBin Meng val = BIT(25); 105a937b302SBin Meng break; 106a937b302SBin Meng default: 107a937b302SBin Meng qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " 108a937b302SBin Meng "(size %d, offset 0x%" HWADDR_PRIx ")\n", 109a937b302SBin Meng __func__, size, offset); 110a937b302SBin Meng break; 111a937b302SBin Meng } 112a937b302SBin Meng 113a937b302SBin Meng return val; 114a937b302SBin Meng } 115a937b302SBin Meng 116a937b302SBin Meng static const MemoryRegionOps mchp_pfsoc_pll_ops = { 117a937b302SBin Meng .read = mchp_pfsoc_pll_read, 118a937b302SBin Meng .write = mchp_pfsoc_dummy_write, 119a937b302SBin Meng .endianness = DEVICE_LITTLE_ENDIAN, 120a937b302SBin Meng }; 121a937b302SBin Meng 122a937b302SBin Meng /* IO_CALIB_DDR submodule */ 123a937b302SBin Meng 124a937b302SBin Meng #define IO_CALIB_DDR_IOC_REG1 0x08 125a937b302SBin Meng 126a937b302SBin Meng static uint64_t mchp_pfsoc_io_calib_ddr_read(void *opaque, hwaddr offset, 127a937b302SBin Meng unsigned size) 128a937b302SBin Meng { 129a937b302SBin Meng uint32_t val = 0; 130a937b302SBin Meng 131a937b302SBin Meng switch (offset) { 132a937b302SBin Meng case IO_CALIB_DDR_IOC_REG1: 133a937b302SBin Meng /* calibration completed */ 134a937b302SBin Meng val = BIT(2); 135a937b302SBin Meng break; 136a937b302SBin Meng default: 137a937b302SBin Meng qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " 138a937b302SBin Meng "(size %d, offset 0x%" HWADDR_PRIx ")\n", 139a937b302SBin Meng __func__, size, offset); 140a937b302SBin Meng break; 141a937b302SBin Meng } 142a937b302SBin Meng 143a937b302SBin Meng return val; 144a937b302SBin Meng } 145a937b302SBin Meng 146a937b302SBin Meng static const MemoryRegionOps mchp_pfsoc_io_calib_ddr_ops = { 147a937b302SBin Meng .read = mchp_pfsoc_io_calib_ddr_read, 148a937b302SBin Meng .write = mchp_pfsoc_dummy_write, 149a937b302SBin Meng .endianness = DEVICE_LITTLE_ENDIAN, 150a937b302SBin Meng }; 151a937b302SBin Meng 152*592f0a94SConor Dooley #define SERVICES_CR 0x50 153*592f0a94SConor Dooley #define SERVICES_SR 0x54 154*592f0a94SConor Dooley #define SERVICES_STATUS_SHIFT 16 155*592f0a94SConor Dooley 156*592f0a94SConor Dooley static uint64_t mchp_pfsoc_ctrl_read(void *opaque, hwaddr offset, 157*592f0a94SConor Dooley unsigned size) 158*592f0a94SConor Dooley { 159*592f0a94SConor Dooley uint32_t val = 0; 160*592f0a94SConor Dooley 161*592f0a94SConor Dooley switch (offset) { 162*592f0a94SConor Dooley case SERVICES_SR: 163*592f0a94SConor Dooley /* 164*592f0a94SConor Dooley * Although some services have no error codes, most do. All services 165*592f0a94SConor Dooley * that do implement errors, begin their error codes at 1. Treat all 166*592f0a94SConor Dooley * service requests as failures & return 1. 167*592f0a94SConor Dooley * See the "PolarFire® FPGA and PolarFire SoC FPGA System Services" 168*592f0a94SConor Dooley * user guide for more information on service error codes. 169*592f0a94SConor Dooley */ 170*592f0a94SConor Dooley val = 1u << SERVICES_STATUS_SHIFT; 171*592f0a94SConor Dooley break; 172*592f0a94SConor Dooley default: 173*592f0a94SConor Dooley qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read " 174*592f0a94SConor Dooley "(size %d, offset 0x%" HWADDR_PRIx ")\n", 175*592f0a94SConor Dooley __func__, size, offset); 176*592f0a94SConor Dooley } 177*592f0a94SConor Dooley 178*592f0a94SConor Dooley return val; 179*592f0a94SConor Dooley } 180*592f0a94SConor Dooley 181*592f0a94SConor Dooley static void mchp_pfsoc_ctrl_write(void *opaque, hwaddr offset, 182*592f0a94SConor Dooley uint64_t value, unsigned size) 183*592f0a94SConor Dooley { 184*592f0a94SConor Dooley MchpPfSoCIoscbState *s = opaque; 185*592f0a94SConor Dooley 186*592f0a94SConor Dooley switch (offset) { 187*592f0a94SConor Dooley case SERVICES_CR: 188*592f0a94SConor Dooley qemu_irq_raise(s->irq); 189*592f0a94SConor Dooley break; 190*592f0a94SConor Dooley default: 191*592f0a94SConor Dooley qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write " 192*592f0a94SConor Dooley "(size %d, value 0x%" PRIx64 193*592f0a94SConor Dooley ", offset 0x%" HWADDR_PRIx ")\n", 194*592f0a94SConor Dooley __func__, size, value, offset); 195*592f0a94SConor Dooley } 196*592f0a94SConor Dooley } 197*592f0a94SConor Dooley 198*592f0a94SConor Dooley static const MemoryRegionOps mchp_pfsoc_ctrl_ops = { 199*592f0a94SConor Dooley .read = mchp_pfsoc_ctrl_read, 200*592f0a94SConor Dooley .write = mchp_pfsoc_ctrl_write, 201*592f0a94SConor Dooley .endianness = DEVICE_LITTLE_ENDIAN, 202*592f0a94SConor Dooley }; 203*592f0a94SConor Dooley 204a937b302SBin Meng static void mchp_pfsoc_ioscb_realize(DeviceState *dev, Error **errp) 205a937b302SBin Meng { 206a937b302SBin Meng MchpPfSoCIoscbState *s = MCHP_PFSOC_IOSCB(dev); 207a937b302SBin Meng SysBusDevice *sbd = SYS_BUS_DEVICE(dev); 208a937b302SBin Meng 209a937b302SBin Meng memory_region_init(&s->container, OBJECT(s), 210a937b302SBin Meng "mchp.pfsoc.ioscb", IOSCB_WHOLE_REG_SIZE); 211a937b302SBin Meng sysbus_init_mmio(sbd, &s->container); 212a937b302SBin Meng 213a937b302SBin Meng /* add subregions for all sub-modules in IOSCB */ 214a937b302SBin Meng 215a937b302SBin Meng memory_region_init_io(&s->lane01, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 216a937b302SBin Meng "mchp.pfsoc.ioscb.lane01", IOSCB_SUBMOD_REG_SIZE); 217a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_LANE01_BASE, &s->lane01); 218a937b302SBin Meng 219a937b302SBin Meng memory_region_init_io(&s->lane23, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 220a937b302SBin Meng "mchp.pfsoc.ioscb.lane23", IOSCB_SUBMOD_REG_SIZE); 221a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_LANE23_BASE, &s->lane23); 222a937b302SBin Meng 223*592f0a94SConor Dooley memory_region_init_io(&s->ctrl, OBJECT(s), &mchp_pfsoc_ctrl_ops, s, 224*592f0a94SConor Dooley "mchp.pfsoc.ioscb.ctrl", IOSCB_CTRL_REG_SIZE); 225a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_CTRL_BASE, &s->ctrl); 226a937b302SBin Meng 227*592f0a94SConor Dooley memory_region_init_io(&s->qspixip, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 228*592f0a94SConor Dooley "mchp.pfsoc.ioscb.qspixip", IOSCB_QSPIXIP_REG_SIZE); 229*592f0a94SConor Dooley memory_region_add_subregion(&s->container, IOSCB_QSPIXIP_BASE, &s->qspixip); 230*592f0a94SConor Dooley 231*592f0a94SConor Dooley memory_region_init_io(&s->mailbox, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 232*592f0a94SConor Dooley "mchp.pfsoc.ioscb.mailbox", IOSCB_SUBMOD_REG_SIZE); 233*592f0a94SConor Dooley memory_region_add_subregion(&s->container, IOSCB_MAILBOX_BASE, &s->mailbox); 234*592f0a94SConor Dooley 235a937b302SBin Meng memory_region_init_io(&s->cfg, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 236a937b302SBin Meng "mchp.pfsoc.ioscb.cfg", IOSCB_SUBMOD_REG_SIZE); 237a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_CFG_BASE, &s->cfg); 238a937b302SBin Meng 23913cd1d6eSConor Dooley memory_region_init_io(&s->ccc, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 24013cd1d6eSConor Dooley "mchp.pfsoc.ioscb.ccc", IOSCB_CCC_REG_SIZE); 24113cd1d6eSConor Dooley memory_region_add_subregion(&s->container, IOSCB_CCC_BASE, &s->ccc); 24213cd1d6eSConor Dooley 243a937b302SBin Meng memory_region_init_io(&s->pll_mss, OBJECT(s), &mchp_pfsoc_pll_ops, s, 244a937b302SBin Meng "mchp.pfsoc.ioscb.pll_mss", IOSCB_SUBMOD_REG_SIZE); 245a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_PLL_MSS_BASE, &s->pll_mss); 246a937b302SBin Meng 247a937b302SBin Meng memory_region_init_io(&s->cfm_mss, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 248a937b302SBin Meng "mchp.pfsoc.ioscb.cfm_mss", IOSCB_SUBMOD_REG_SIZE); 249a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_CFM_MSS_BASE, &s->cfm_mss); 250a937b302SBin Meng 251a937b302SBin Meng memory_region_init_io(&s->pll_ddr, OBJECT(s), &mchp_pfsoc_pll_ops, s, 252a937b302SBin Meng "mchp.pfsoc.ioscb.pll_ddr", IOSCB_SUBMOD_REG_SIZE); 253a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_PLL_DDR_BASE, &s->pll_ddr); 254a937b302SBin Meng 255a937b302SBin Meng memory_region_init_io(&s->bc_ddr, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 256a937b302SBin Meng "mchp.pfsoc.ioscb.bc_ddr", IOSCB_SUBMOD_REG_SIZE); 257a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_BC_DDR_BASE, &s->bc_ddr); 258a937b302SBin Meng 259a937b302SBin Meng memory_region_init_io(&s->io_calib_ddr, OBJECT(s), 260a937b302SBin Meng &mchp_pfsoc_io_calib_ddr_ops, s, 261a937b302SBin Meng "mchp.pfsoc.ioscb.io_calib_ddr", 262a937b302SBin Meng IOSCB_SUBMOD_REG_SIZE); 263a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_DDR_BASE, 264a937b302SBin Meng &s->io_calib_ddr); 265a937b302SBin Meng 266a937b302SBin Meng memory_region_init_io(&s->pll_sgmii, OBJECT(s), &mchp_pfsoc_pll_ops, s, 267a937b302SBin Meng "mchp.pfsoc.ioscb.pll_sgmii", IOSCB_SUBMOD_REG_SIZE); 268a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_PLL_SGMII_BASE, 269a937b302SBin Meng &s->pll_sgmii); 270a937b302SBin Meng 271a937b302SBin Meng memory_region_init_io(&s->dll_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 272a937b302SBin Meng "mchp.pfsoc.ioscb.dll_sgmii", IOSCB_SUBMOD_REG_SIZE); 273a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_DLL_SGMII_BASE, 274a937b302SBin Meng &s->dll_sgmii); 275a937b302SBin Meng 276a937b302SBin Meng memory_region_init_io(&s->cfm_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 277a937b302SBin Meng "mchp.pfsoc.ioscb.cfm_sgmii", IOSCB_SUBMOD_REG_SIZE); 278a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_CFM_SGMII_BASE, 279a937b302SBin Meng &s->cfm_sgmii); 280a937b302SBin Meng 281a937b302SBin Meng memory_region_init_io(&s->bc_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, s, 282a937b302SBin Meng "mchp.pfsoc.ioscb.bc_sgmii", IOSCB_SUBMOD_REG_SIZE); 283a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_BC_SGMII_BASE, 284a937b302SBin Meng &s->bc_sgmii); 285a937b302SBin Meng 286a937b302SBin Meng memory_region_init_io(&s->io_calib_sgmii, OBJECT(s), &mchp_pfsoc_dummy_ops, 287a937b302SBin Meng s, "mchp.pfsoc.ioscb.io_calib_sgmii", 288a937b302SBin Meng IOSCB_SUBMOD_REG_SIZE); 289a937b302SBin Meng memory_region_add_subregion(&s->container, IOSCB_IO_CALIB_SGMII_BASE, 290a937b302SBin Meng &s->io_calib_sgmii); 291*592f0a94SConor Dooley 292*592f0a94SConor Dooley sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq); 293a937b302SBin Meng } 294a937b302SBin Meng 295a937b302SBin Meng static void mchp_pfsoc_ioscb_class_init(ObjectClass *klass, void *data) 296a937b302SBin Meng { 297a937b302SBin Meng DeviceClass *dc = DEVICE_CLASS(klass); 298a937b302SBin Meng 299a937b302SBin Meng dc->desc = "Microchip PolarFire SoC IOSCB modules"; 300a937b302SBin Meng dc->realize = mchp_pfsoc_ioscb_realize; 301a937b302SBin Meng } 302a937b302SBin Meng 303a937b302SBin Meng static const TypeInfo mchp_pfsoc_ioscb_info = { 304a937b302SBin Meng .name = TYPE_MCHP_PFSOC_IOSCB, 305a937b302SBin Meng .parent = TYPE_SYS_BUS_DEVICE, 306a937b302SBin Meng .instance_size = sizeof(MchpPfSoCIoscbState), 307a937b302SBin Meng .class_init = mchp_pfsoc_ioscb_class_init, 308a937b302SBin Meng }; 309a937b302SBin Meng 310a937b302SBin Meng static void mchp_pfsoc_ioscb_register_types(void) 311a937b302SBin Meng { 312a937b302SBin Meng type_register_static(&mchp_pfsoc_ioscb_info); 313a937b302SBin Meng } 314a937b302SBin Meng 315a937b302SBin Meng type_init(mchp_pfsoc_ioscb_register_types) 316