1a8fb0a50SBin Meng /* 2a8fb0a50SBin Meng * Microchip PolarFire SoC MMUART emulation 3a8fb0a50SBin Meng * 4a8fb0a50SBin Meng * Copyright (c) 2020 Wind River Systems, Inc. 5a8fb0a50SBin Meng * 6a8fb0a50SBin Meng * Author: 7a8fb0a50SBin Meng * Bin Meng <bin.meng@windriver.com> 8a8fb0a50SBin Meng * 9a8fb0a50SBin Meng * This program is free software; you can redistribute it and/or 10a8fb0a50SBin Meng * modify it under the terms of the GNU General Public License as 11a8fb0a50SBin Meng * published by the Free Software Foundation; either version 2 or 12a8fb0a50SBin Meng * (at your option) version 3 of the License. 13a8fb0a50SBin Meng * 14a8fb0a50SBin Meng * This program is distributed in the hope that it will be useful, 15a8fb0a50SBin Meng * but WITHOUT ANY WARRANTY; without even the implied warranty of 16a8fb0a50SBin Meng * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17a8fb0a50SBin Meng * GNU General Public License for more details. 18a8fb0a50SBin Meng * 19a8fb0a50SBin Meng * You should have received a copy of the GNU General Public License along 20a8fb0a50SBin Meng * with this program; if not, see <http://www.gnu.org/licenses/>. 21a8fb0a50SBin Meng */ 22a8fb0a50SBin Meng 23a8fb0a50SBin Meng #include "qemu/osdep.h" 24a8fb0a50SBin Meng #include "qemu/log.h" 25a8fb0a50SBin Meng #include "chardev/char.h" 26a8fb0a50SBin Meng #include "hw/char/mchp_pfsoc_mmuart.h" 27a8fb0a50SBin Meng 28*24ce762dSPhilippe Mathieu-Daudé #define REGS_OFFSET 0x20 29*24ce762dSPhilippe Mathieu-Daudé 30a8fb0a50SBin Meng static uint64_t mchp_pfsoc_mmuart_read(void *opaque, hwaddr addr, unsigned size) 31a8fb0a50SBin Meng { 32a8fb0a50SBin Meng MchpPfSoCMMUartState *s = opaque; 33a8fb0a50SBin Meng 34284a66a8SPhilippe Mathieu-Daudé addr >>= 2; 35284a66a8SPhilippe Mathieu-Daudé if (addr >= MCHP_PFSOC_MMUART_REG_COUNT) { 36a8fb0a50SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 37284a66a8SPhilippe Mathieu-Daudé __func__, addr << 2); 38a8fb0a50SBin Meng return 0; 39a8fb0a50SBin Meng } 40a8fb0a50SBin Meng 41284a66a8SPhilippe Mathieu-Daudé return s->reg[addr]; 42a8fb0a50SBin Meng } 43a8fb0a50SBin Meng 44a8fb0a50SBin Meng static void mchp_pfsoc_mmuart_write(void *opaque, hwaddr addr, 45a8fb0a50SBin Meng uint64_t value, unsigned size) 46a8fb0a50SBin Meng { 47a8fb0a50SBin Meng MchpPfSoCMMUartState *s = opaque; 48a8fb0a50SBin Meng uint32_t val32 = (uint32_t)value; 49a8fb0a50SBin Meng 50284a66a8SPhilippe Mathieu-Daudé addr >>= 2; 51284a66a8SPhilippe Mathieu-Daudé if (addr >= MCHP_PFSOC_MMUART_REG_COUNT) { 52a8fb0a50SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 53284a66a8SPhilippe Mathieu-Daudé " v=0x%x\n", __func__, addr << 2, val32); 54a8fb0a50SBin Meng return; 55a8fb0a50SBin Meng } 56a8fb0a50SBin Meng 57284a66a8SPhilippe Mathieu-Daudé s->reg[addr] = val32; 58a8fb0a50SBin Meng } 59a8fb0a50SBin Meng 60a8fb0a50SBin Meng static const MemoryRegionOps mchp_pfsoc_mmuart_ops = { 61a8fb0a50SBin Meng .read = mchp_pfsoc_mmuart_read, 62a8fb0a50SBin Meng .write = mchp_pfsoc_mmuart_write, 63a8fb0a50SBin Meng .endianness = DEVICE_LITTLE_ENDIAN, 64a8fb0a50SBin Meng .impl = { 65a8fb0a50SBin Meng .min_access_size = 4, 66a8fb0a50SBin Meng .max_access_size = 4, 67a8fb0a50SBin Meng }, 68a8fb0a50SBin Meng }; 69a8fb0a50SBin Meng 70a8fb0a50SBin Meng MchpPfSoCMMUartState *mchp_pfsoc_mmuart_create(MemoryRegion *sysmem, 71a8fb0a50SBin Meng hwaddr base, qemu_irq irq, Chardev *chr) 72a8fb0a50SBin Meng { 73a8fb0a50SBin Meng MchpPfSoCMMUartState *s; 74a8fb0a50SBin Meng 75a8fb0a50SBin Meng s = g_new0(MchpPfSoCMMUartState, 1); 76a8fb0a50SBin Meng 77*24ce762dSPhilippe Mathieu-Daudé memory_region_init(&s->container, NULL, "mchp.pfsoc.mmuart", 0x1000); 78*24ce762dSPhilippe Mathieu-Daudé 79a8fb0a50SBin Meng memory_region_init_io(&s->iomem, NULL, &mchp_pfsoc_mmuart_ops, s, 80*24ce762dSPhilippe Mathieu-Daudé "mchp.pfsoc.mmuart.regs", 0x1000 - REGS_OFFSET); 81*24ce762dSPhilippe Mathieu-Daudé memory_region_add_subregion(&s->container, REGS_OFFSET, &s->iomem); 82a8fb0a50SBin Meng 83a8fb0a50SBin Meng s->base = base; 84a8fb0a50SBin Meng s->irq = irq; 85a8fb0a50SBin Meng 86*24ce762dSPhilippe Mathieu-Daudé s->serial = serial_mm_init(&s->container, 0, 2, irq, 399193, chr, 87a8fb0a50SBin Meng DEVICE_LITTLE_ENDIAN); 88a8fb0a50SBin Meng 89*24ce762dSPhilippe Mathieu-Daudé memory_region_add_subregion(sysmem, base, &s->container); 90a8fb0a50SBin Meng 91a8fb0a50SBin Meng return s; 92a8fb0a50SBin Meng } 93