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 28a8fb0a50SBin Meng static uint64_t mchp_pfsoc_mmuart_read(void *opaque, hwaddr addr, unsigned size) 29a8fb0a50SBin Meng { 30a8fb0a50SBin Meng MchpPfSoCMMUartState *s = opaque; 31a8fb0a50SBin Meng 32*284a66a8SPhilippe Mathieu-Daudé addr >>= 2; 33*284a66a8SPhilippe Mathieu-Daudé if (addr >= MCHP_PFSOC_MMUART_REG_COUNT) { 34a8fb0a50SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", 35*284a66a8SPhilippe Mathieu-Daudé __func__, addr << 2); 36a8fb0a50SBin Meng return 0; 37a8fb0a50SBin Meng } 38a8fb0a50SBin Meng 39*284a66a8SPhilippe Mathieu-Daudé return s->reg[addr]; 40a8fb0a50SBin Meng } 41a8fb0a50SBin Meng 42a8fb0a50SBin Meng static void mchp_pfsoc_mmuart_write(void *opaque, hwaddr addr, 43a8fb0a50SBin Meng uint64_t value, unsigned size) 44a8fb0a50SBin Meng { 45a8fb0a50SBin Meng MchpPfSoCMMUartState *s = opaque; 46a8fb0a50SBin Meng uint32_t val32 = (uint32_t)value; 47a8fb0a50SBin Meng 48*284a66a8SPhilippe Mathieu-Daudé addr >>= 2; 49*284a66a8SPhilippe Mathieu-Daudé if (addr >= MCHP_PFSOC_MMUART_REG_COUNT) { 50a8fb0a50SBin Meng qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx 51*284a66a8SPhilippe Mathieu-Daudé " v=0x%x\n", __func__, addr << 2, val32); 52a8fb0a50SBin Meng return; 53a8fb0a50SBin Meng } 54a8fb0a50SBin Meng 55*284a66a8SPhilippe Mathieu-Daudé s->reg[addr] = val32; 56a8fb0a50SBin Meng } 57a8fb0a50SBin Meng 58a8fb0a50SBin Meng static const MemoryRegionOps mchp_pfsoc_mmuart_ops = { 59a8fb0a50SBin Meng .read = mchp_pfsoc_mmuart_read, 60a8fb0a50SBin Meng .write = mchp_pfsoc_mmuart_write, 61a8fb0a50SBin Meng .endianness = DEVICE_LITTLE_ENDIAN, 62a8fb0a50SBin Meng .impl = { 63a8fb0a50SBin Meng .min_access_size = 4, 64a8fb0a50SBin Meng .max_access_size = 4, 65a8fb0a50SBin Meng }, 66a8fb0a50SBin Meng }; 67a8fb0a50SBin Meng 68a8fb0a50SBin Meng MchpPfSoCMMUartState *mchp_pfsoc_mmuart_create(MemoryRegion *sysmem, 69a8fb0a50SBin Meng hwaddr base, qemu_irq irq, Chardev *chr) 70a8fb0a50SBin Meng { 71a8fb0a50SBin Meng MchpPfSoCMMUartState *s; 72a8fb0a50SBin Meng 73a8fb0a50SBin Meng s = g_new0(MchpPfSoCMMUartState, 1); 74a8fb0a50SBin Meng 75a8fb0a50SBin Meng memory_region_init_io(&s->iomem, NULL, &mchp_pfsoc_mmuart_ops, s, 76a8fb0a50SBin Meng "mchp.pfsoc.mmuart", 0x1000); 77a8fb0a50SBin Meng 78a8fb0a50SBin Meng s->base = base; 79a8fb0a50SBin Meng s->irq = irq; 80a8fb0a50SBin Meng 81a8fb0a50SBin Meng s->serial = serial_mm_init(sysmem, base, 2, irq, 399193, chr, 82a8fb0a50SBin Meng DEVICE_LITTLE_ENDIAN); 83a8fb0a50SBin Meng 84a8fb0a50SBin Meng memory_region_add_subregion(sysmem, base + 0x20, &s->iomem); 85a8fb0a50SBin Meng 86a8fb0a50SBin Meng return s; 87a8fb0a50SBin Meng } 88