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