This PR includes multiple fixes and features for RISC-V:

- Fixes a bug in printing trap causes
  - Allows 16-bit writes to the SiFive test device. This fixes the
    failure to reboot the RISC-V virt machine
  - Support for the Microchip PolarFire SoC and Icicle Kit
  - A reafactor of RISC-V code out of hw/riscv
 -----BEGIN PGP SIGNATURE-----
 
 iQEzBAABCAAdFiEE9sSsRtSTSGjTuM6PIeENKd+XcFQFAl9aa4YACgkQIeENKd+X
 cFTJjgf5ASfFIO5HqP1l80/UM5Pswyq0IROZDq0ItZa6U4EPzLXoE2N0POriIj4h
 Ds2JbMg0ORDqY0VbSxHlgYHMgJ9S6cuVOMnATsPG0d2jaJ3gSxLBu5k/1ENqe+Vw
 sSYXZv5uEAUfOFz99zbuhKHct5HzlmBFW9dVHdflUQS+cRgsSXq27mz1BvZ8xMWl
 lMhwubqdoNx0rOD3vKnlwrxaf54DcJ2IQT3BtTCjEar3tukdNaLijAuwt2hrFyr+
 IwpeFXA/NWar+mXP3M+BvcLaI33j73/ac2+S5SJuzHGp/ot5nT5gAuq3PDEjHMeS
 t6z9Exp776VXxNE2iUA5NB65Yp3/6w==
 =07oA
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/alistair/tags/pull-riscv-to-apply-20200910' into staging

This PR includes multiple fixes and features for RISC-V:
 - Fixes a bug in printing trap causes
 - Allows 16-bit writes to the SiFive test device. This fixes the
   failure to reboot the RISC-V virt machine
 - Support for the Microchip PolarFire SoC and Icicle Kit
 - A reafactor of RISC-V code out of hw/riscv

# gpg: Signature made Thu 10 Sep 2020 19:08:06 BST
# gpg:                using RSA key F6C4AC46D4934868D3B8CE8F21E10D29DF977054
# gpg: Good signature from "Alistair Francis <alistair@alistair23.me>" [full]
# Primary key fingerprint: F6C4 AC46 D493 4868 D3B8  CE8F 21E1 0D29 DF97 7054

* remotes/alistair/tags/pull-riscv-to-apply-20200910: (30 commits)
  hw/riscv: Sort the Kconfig options in alphabetical order
  hw/riscv: Drop CONFIG_SIFIVE
  hw/riscv: Always build riscv_hart.c
  hw/riscv: Move sifive_test model to hw/misc
  hw/riscv: Move sifive_uart model to hw/char
  hw/riscv: Move riscv_htif model to hw/char
  hw/riscv: Move sifive_plic model to hw/intc
  hw/riscv: Move sifive_clint model to hw/intc
  hw/riscv: Move sifive_gpio model to hw/gpio
  hw/riscv: Move sifive_u_otp model to hw/misc
  hw/riscv: Move sifive_u_prci model to hw/misc
  hw/riscv: Move sifive_e_prci model to hw/misc
  hw/riscv: sifive_u: Connect a DMA controller
  hw/riscv: clint: Avoid using hard-coded timebase frequency
  hw/riscv: microchip_pfsoc: Hook GPIO controllers
  hw/riscv: microchip_pfsoc: Connect 2 Cadence GEMs
  hw/arm: xlnx: Set all boards' GEM 'phy-addr' property value to 23
  hw/net: cadence_gem: Add a new 'phy-addr' property
  hw/riscv: microchip_pfsoc: Connect a DMA controller
  hw/dma: Add SiFive platform DMA controller emulation
  ...

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

# Conflicts:
#	hw/riscv/trace-events
This commit is contained in:
Peter Maydell 2020-09-13 20:29:35 +01:00
commit f00f57f344
64 changed files with 1577 additions and 107 deletions

View File

@ -1316,6 +1316,15 @@ F: include/hw/riscv/opentitan.h
F: include/hw/char/ibex_uart.h F: include/hw/char/ibex_uart.h
F: include/hw/intc/ibex_plic.h F: include/hw/intc/ibex_plic.h
Microchip PolarFire SoC Icicle Kit
M: Bin Meng <bin.meng@windriver.com>
L: qemu-riscv@nongnu.org
S: Supported
F: hw/riscv/microchip_pfsoc.c
F: hw/char/mchp_pfsoc_mmuart.c
F: include/hw/riscv/microchip_pfsoc.h
F: include/hw/char/mchp_pfsoc_mmuart.h
RX Machines RX Machines
----------- -----------
rx-gdbsim rx-gdbsim

View File

@ -10,3 +10,4 @@ CONFIG_SPIKE=y
CONFIG_SIFIVE_E=y CONFIG_SIFIVE_E=y
CONFIG_SIFIVE_U=y CONFIG_SIFIVE_U=y
CONFIG_RISCV_VIRT=y CONFIG_RISCV_VIRT=y
CONFIG_MICROCHIP_PFSOC=y

View File

@ -121,6 +121,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
qemu_check_nic_model(nd, TYPE_CADENCE_GEM); qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(dev, nd); qdev_set_nic_properties(dev, nd);
} }
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
s = SYS_BUS_DEVICE(dev); s = SYS_BUS_DEVICE(dev);
sysbus_realize_and_unref(s, &error_fatal); sysbus_realize_and_unref(s, &error_fatal);
sysbus_mmio_map(s, 0, base); sysbus_mmio_map(s, 0, base);

View File

@ -165,6 +165,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
qemu_check_nic_model(nd, "cadence_gem"); qemu_check_nic_model(nd, "cadence_gem");
qdev_set_nic_properties(dev, nd); qdev_set_nic_properties(dev, nd);
} }
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
object_property_set_int(OBJECT(dev), "num-priority-queues", 2, object_property_set_int(OBJECT(dev), "num-priority-queues", 2,
&error_abort); &error_abort);
object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps), object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),

View File

@ -460,6 +460,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
} }
object_property_set_int(OBJECT(&s->gem[i]), "revision", GEM_REVISION, object_property_set_int(OBJECT(&s->gem[i]), "revision", GEM_REVISION,
&error_abort); &error_abort);
object_property_set_int(OBJECT(&s->gem[i]), "phy-addr", 23,
&error_abort);
object_property_set_int(OBJECT(&s->gem[i]), "num-priority-queues", 2, object_property_set_int(OBJECT(&s->gem[i]), "num-priority-queues", 2,
&error_abort); &error_abort);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), errp)) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), errp)) {

View File

@ -1,6 +1,9 @@
config ESCC config ESCC
bool bool
config HTIF
bool
config PARALLEL config PARALLEL
bool bool
default y default y
@ -52,3 +55,9 @@ config RENESAS_SCI
config AVR_USART config AVR_USART
bool bool
config MCHP_PFSOC_MMUART
bool
config SIFIVE_UART
bool

View File

@ -0,0 +1,86 @@
/*
* Microchip PolarFire SoC MMUART emulation
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/log.h"
#include "chardev/char.h"
#include "exec/address-spaces.h"
#include "hw/char/mchp_pfsoc_mmuart.h"
static uint64_t mchp_pfsoc_mmuart_read(void *opaque, hwaddr addr, unsigned size)
{
MchpPfSoCMMUartState *s = opaque;
if (addr >= MCHP_PFSOC_MMUART_REG_SIZE) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n",
__func__, addr);
return 0;
}
return s->reg[addr / sizeof(uint32_t)];
}
static void mchp_pfsoc_mmuart_write(void *opaque, hwaddr addr,
uint64_t value, unsigned size)
{
MchpPfSoCMMUartState *s = opaque;
uint32_t val32 = (uint32_t)value;
if (addr >= MCHP_PFSOC_MMUART_REG_SIZE) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx
" v=0x%x\n", __func__, addr, val32);
return;
}
s->reg[addr / sizeof(uint32_t)] = val32;
}
static const MemoryRegionOps mchp_pfsoc_mmuart_ops = {
.read = mchp_pfsoc_mmuart_read,
.write = mchp_pfsoc_mmuart_write,
.endianness = DEVICE_LITTLE_ENDIAN,
.impl = {
.min_access_size = 4,
.max_access_size = 4,
},
};
MchpPfSoCMMUartState *mchp_pfsoc_mmuart_create(MemoryRegion *sysmem,
hwaddr base, qemu_irq irq, Chardev *chr)
{
MchpPfSoCMMUartState *s;
s = g_new0(MchpPfSoCMMUartState, 1);
memory_region_init_io(&s->iomem, NULL, &mchp_pfsoc_mmuart_ops, s,
"mchp.pfsoc.mmuart", 0x1000);
s->base = base;
s->irq = irq;
s->serial = serial_mm_init(sysmem, base, 2, irq, 399193, chr,
DEVICE_LITTLE_ENDIAN);
memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
return s;
}

View File

@ -30,9 +30,12 @@ softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_uart.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_uart.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_uart.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_aux.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_aux.c'))
softmmu_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c')) softmmu_ss.add(when: 'CONFIG_RENESAS_SCI', if_true: files('renesas_sci.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_UART', if_true: files('sifive_uart.c'))
softmmu_ss.add(when: 'CONFIG_SH4', if_true: files('sh_serial.c')) softmmu_ss.add(when: 'CONFIG_SH4', if_true: files('sh_serial.c'))
softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c')) softmmu_ss.add(when: 'CONFIG_STM32F2XX_USART', if_true: files('stm32f2xx_usart.c'))
softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_MMUART', if_true: files('mchp_pfsoc_mmuart.c'))
specific_ss.add(when: 'CONFIG_HTIF', if_true: files('riscv_htif.c'))
specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c')) specific_ss.add(when: 'CONFIG_TERMINAL3270', if_true: files('terminal3270.c'))
specific_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-serial-bus.c')) specific_ss.add(when: 'CONFIG_VIRTIO', if_true: files('virtio-serial-bus.c'))
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_vty.c')) specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_vty.c'))

View File

@ -24,10 +24,10 @@
#include "qapi/error.h" #include "qapi/error.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "hw/char/riscv_htif.h"
#include "hw/char/serial.h" #include "hw/char/serial.h"
#include "chardev/char.h" #include "chardev/char.h"
#include "chardev/char-fe.h" #include "chardev/char-fe.h"
#include "hw/riscv/riscv_htif.h"
#include "qemu/timer.h" #include "qemu/timer.h"
#include "qemu/error-report.h" #include "qemu/error-report.h"

View File

@ -24,7 +24,7 @@
#include "chardev/char-fe.h" #include "chardev/char-fe.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "hw/riscv/sifive_uart.h" #include "hw/char/sifive_uart.h"
/* /*
* Not yet implemented: * Not yet implemented:

View File

@ -20,3 +20,6 @@ config ZYNQ_DEVCFG
config STP2000 config STP2000
bool bool
config SIFIVE_PDMA
bool

View File

@ -13,3 +13,4 @@ softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zdma.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_dma.c', 'soc_dma.c'))
softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c')) softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_dma.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_dma.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_PDMA', if_true: files('sifive_pdma.c'))

313
hw/dma/sifive_pdma.c Normal file
View File

@ -0,0 +1,313 @@
/*
* SiFive Platform DMA emulation
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "hw/hw.h"
#include "hw/irq.h"
#include "hw/qdev-properties.h"
#include "hw/sysbus.h"
#include "migration/vmstate.h"
#include "sysemu/dma.h"
#include "hw/dma/sifive_pdma.h"
#define DMA_CONTROL 0x000
#define CONTROL_CLAIM BIT(0)
#define CONTROL_RUN BIT(1)
#define CONTROL_DONE_IE BIT(14)
#define CONTROL_ERR_IE BIT(15)
#define CONTROL_DONE BIT(30)
#define CONTROL_ERR BIT(31)
#define DMA_NEXT_CONFIG 0x004
#define CONFIG_REPEAT BIT(2)
#define CONFIG_ORDER BIT(3)
#define CONFIG_WRSZ_SHIFT 24
#define CONFIG_RDSZ_SHIFT 28
#define CONFIG_SZ_MASK 0xf
#define DMA_NEXT_BYTES 0x008
#define DMA_NEXT_DST 0x010
#define DMA_NEXT_SRC 0x018
#define DMA_EXEC_CONFIG 0x104
#define DMA_EXEC_BYTES 0x108
#define DMA_EXEC_DST 0x110
#define DMA_EXEC_SRC 0x118
enum dma_chan_state {
DMA_CHAN_STATE_IDLE,
DMA_CHAN_STATE_STARTED,
DMA_CHAN_STATE_ERROR,
DMA_CHAN_STATE_DONE
};
static void sifive_pdma_run(SiFivePDMAState *s, int ch)
{
uint64_t bytes = s->chan[ch].next_bytes;
uint64_t dst = s->chan[ch].next_dst;
uint64_t src = s->chan[ch].next_src;
uint32_t config = s->chan[ch].next_config;
int wsize, rsize, size;
uint8_t buf[64];
int n;
/* do nothing if bytes to transfer is zero */
if (!bytes) {
goto error;
}
/*
* The manual does not describe how the hardware behaviors when
* config.wsize and config.rsize are given different values.
* A common case is memory to memory DMA, and in this case they
* are normally the same. Abort if this expectation fails.
*/
wsize = (config >> CONFIG_WRSZ_SHIFT) & CONFIG_SZ_MASK;
rsize = (config >> CONFIG_RDSZ_SHIFT) & CONFIG_SZ_MASK;
if (wsize != rsize) {
goto error;
}
/*
* Calculate the transaction size
*
* size field is base 2 logarithm of DMA transaction size,
* but there is an upper limit of 64 bytes per transaction.
*/
size = wsize;
if (size > 6) {
size = 6;
}
size = 1 << size;
/* the bytes to transfer should be multiple of transaction size */
if (bytes % size) {
goto error;
}
/* indicate a DMA transfer is started */
s->chan[ch].state = DMA_CHAN_STATE_STARTED;
s->chan[ch].control &= ~CONTROL_DONE;
s->chan[ch].control &= ~CONTROL_ERR;
/* load the next_ registers into their exec_ counterparts */
s->chan[ch].exec_config = config;
s->chan[ch].exec_bytes = bytes;
s->chan[ch].exec_dst = dst;
s->chan[ch].exec_src = src;
for (n = 0; n < bytes / size; n++) {
cpu_physical_memory_read(s->chan[ch].exec_src, buf, size);
cpu_physical_memory_write(s->chan[ch].exec_dst, buf, size);
s->chan[ch].exec_src += size;
s->chan[ch].exec_dst += size;
s->chan[ch].exec_bytes -= size;
}
/* indicate a DMA transfer is done */
s->chan[ch].state = DMA_CHAN_STATE_DONE;
s->chan[ch].control &= ~CONTROL_RUN;
s->chan[ch].control |= CONTROL_DONE;
/* reload exec_ registers if repeat is required */
if (s->chan[ch].next_config & CONFIG_REPEAT) {
s->chan[ch].exec_bytes = bytes;
s->chan[ch].exec_dst = dst;
s->chan[ch].exec_src = src;
}
return;
error:
s->chan[ch].state = DMA_CHAN_STATE_ERROR;
s->chan[ch].control |= CONTROL_ERR;
return;
}
static inline void sifive_pdma_update_irq(SiFivePDMAState *s, int ch)
{
bool done_ie, err_ie;
done_ie = !!(s->chan[ch].control & CONTROL_DONE_IE);
err_ie = !!(s->chan[ch].control & CONTROL_ERR_IE);
if (done_ie && (s->chan[ch].control & CONTROL_DONE)) {
qemu_irq_raise(s->irq[ch * 2]);
} else {
qemu_irq_lower(s->irq[ch * 2]);
}
if (err_ie && (s->chan[ch].control & CONTROL_ERR)) {
qemu_irq_raise(s->irq[ch * 2 + 1]);
} else {
qemu_irq_lower(s->irq[ch * 2 + 1]);
}
s->chan[ch].state = DMA_CHAN_STATE_IDLE;
}
static uint64_t sifive_pdma_read(void *opaque, hwaddr offset, unsigned size)
{
SiFivePDMAState *s = opaque;
int ch = SIFIVE_PDMA_CHAN_NO(offset);
uint64_t val = 0;
if (ch >= SIFIVE_PDMA_CHANS) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
__func__, ch);
return 0;
}
offset &= 0xfff;
switch (offset) {
case DMA_CONTROL:
val = s->chan[ch].control;
break;
case DMA_NEXT_CONFIG:
val = s->chan[ch].next_config;
break;
case DMA_NEXT_BYTES:
val = s->chan[ch].next_bytes;
break;
case DMA_NEXT_DST:
val = s->chan[ch].next_dst;
break;
case DMA_NEXT_SRC:
val = s->chan[ch].next_src;
break;
case DMA_EXEC_CONFIG:
val = s->chan[ch].exec_config;
break;
case DMA_EXEC_BYTES:
val = s->chan[ch].exec_bytes;
break;
case DMA_EXEC_DST:
val = s->chan[ch].exec_dst;
break;
case DMA_EXEC_SRC:
val = s->chan[ch].exec_src;
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
__func__, offset);
break;
}
return val;
}
static void sifive_pdma_write(void *opaque, hwaddr offset,
uint64_t value, unsigned size)
{
SiFivePDMAState *s = opaque;
int ch = SIFIVE_PDMA_CHAN_NO(offset);
if (ch >= SIFIVE_PDMA_CHANS) {
qemu_log_mask(LOG_GUEST_ERROR, "%s: Invalid channel no %d\n",
__func__, ch);
return;
}
offset &= 0xfff;
switch (offset) {
case DMA_CONTROL:
s->chan[ch].control = value;
if (value & CONTROL_RUN) {
sifive_pdma_run(s, ch);
}
sifive_pdma_update_irq(s, ch);
break;
case DMA_NEXT_CONFIG:
s->chan[ch].next_config = value;
break;
case DMA_NEXT_BYTES:
s->chan[ch].next_bytes = value;
break;
case DMA_NEXT_DST:
s->chan[ch].next_dst = value;
break;
case DMA_NEXT_SRC:
s->chan[ch].next_src = value;
break;
case DMA_EXEC_CONFIG:
case DMA_EXEC_BYTES:
case DMA_EXEC_DST:
case DMA_EXEC_SRC:
/* these are read-only registers */
break;
default:
qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset 0x%" HWADDR_PRIX "\n",
__func__, offset);
break;
}
}
static const MemoryRegionOps sifive_pdma_ops = {
.read = sifive_pdma_read,
.write = sifive_pdma_write,
.endianness = DEVICE_LITTLE_ENDIAN,
/* there are 32-bit and 64-bit wide registers */
.impl = {
.min_access_size = 4,
.max_access_size = 8,
}
};
static void sifive_pdma_realize(DeviceState *dev, Error **errp)
{
SiFivePDMAState *s = SIFIVE_PDMA(dev);
int i;
memory_region_init_io(&s->iomem, OBJECT(dev), &sifive_pdma_ops, s,
TYPE_SIFIVE_PDMA, SIFIVE_PDMA_REG_SIZE);
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->iomem);
for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]);
}
}
static void sifive_pdma_class_init(ObjectClass *klass, void *data)
{
DeviceClass *dc = DEVICE_CLASS(klass);
dc->desc = "SiFive Platform DMA controller";
dc->realize = sifive_pdma_realize;
}
static const TypeInfo sifive_pdma_info = {
.name = TYPE_SIFIVE_PDMA,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(SiFivePDMAState),
.class_init = sifive_pdma_class_init,
};
static void sifive_pdma_register_types(void)
{
type_register_static(&sifive_pdma_info);
}
type_init(sifive_pdma_register_types)

View File

@ -7,3 +7,6 @@ config PL061
config GPIO_KEY config GPIO_KEY
bool bool
config SIFIVE_GPIO
bool

View File

@ -10,3 +10,4 @@ softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_gpio.c'))
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c')) softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files('omap_gpio.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_gpio.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c')) softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_gpio.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_GPIO', if_true: files('sifive_gpio.c'))

View File

@ -15,7 +15,7 @@
#include "qemu/log.h" #include "qemu/log.h"
#include "hw/irq.h" #include "hw/irq.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "hw/riscv/sifive_gpio.h" #include "hw/gpio/sifive_gpio.h"
#include "migration/vmstate.h" #include "migration/vmstate.h"
#include "trace.h" #include "trace.h"

View File

@ -5,3 +5,9 @@ nrf51_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PR
nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64 nrf51_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 nrf51_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64 nrf51_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
# sifive_gpio.c
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64

View File

@ -67,3 +67,9 @@ config RX_ICU
config LOONGSON_LIOINTC config LOONGSON_LIOINTC
bool bool
config SIFIVE_CLINT
bool
config SIFIVE_PLIC
bool

View File

@ -47,6 +47,8 @@ specific_ss.add(when: 'CONFIG_RX_ICU', if_true: files('rx_icu.c'))
specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c')) specific_ss.add(when: 'CONFIG_S390_FLIC', if_true: files('s390_flic.c'))
specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c')) specific_ss.add(when: 'CONFIG_S390_FLIC_KVM', if_true: files('s390_flic_kvm.c'))
specific_ss.add(when: 'CONFIG_SH4', if_true: files('sh_intc.c')) specific_ss.add(when: 'CONFIG_SH4', if_true: files('sh_intc.c'))
specific_ss.add(when: 'CONFIG_SIFIVE_CLINT', if_true: files('sifive_clint.c'))
specific_ss.add(when: 'CONFIG_SIFIVE_PLIC', if_true: files('sifive_plic.c'))
specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c')) specific_ss.add(when: 'CONFIG_XICS', if_true: files('xics.c'))
specific_ss.add(when: 'CONFIG_XICS_KVM', if_true: files('xics_kvm.c')) specific_ss.add(when: 'CONFIG_XICS_KVM', if_true: files('xics_kvm.c'))
specific_ss.add(when: 'CONFIG_XICS_SPAPR', if_true: files('xics_spapr.c')) specific_ss.add(when: 'CONFIG_XICS_SPAPR', if_true: files('xics_spapr.c'))

View File

@ -26,25 +26,26 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "target/riscv/cpu.h" #include "target/riscv/cpu.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "hw/riscv/sifive_clint.h" #include "hw/intc/sifive_clint.h"
#include "qemu/timer.h" #include "qemu/timer.h"
static uint64_t cpu_riscv_read_rtc(void) static uint64_t cpu_riscv_read_rtc(uint32_t timebase_freq)
{ {
return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL), return muldiv64(qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL),
SIFIVE_CLINT_TIMEBASE_FREQ, NANOSECONDS_PER_SECOND); timebase_freq, NANOSECONDS_PER_SECOND);
} }
/* /*
* Called when timecmp is written to update the QEMU timer or immediately * Called when timecmp is written to update the QEMU timer or immediately
* trigger timer interrupt if mtimecmp <= current timer value. * trigger timer interrupt if mtimecmp <= current timer value.
*/ */
static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value) static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value,
uint32_t timebase_freq)
{ {
uint64_t next; uint64_t next;
uint64_t diff; uint64_t diff;
uint64_t rtc_r = cpu_riscv_read_rtc(); uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
cpu->env.timecmp = value; cpu->env.timecmp = value;
if (cpu->env.timecmp <= rtc_r) { if (cpu->env.timecmp <= rtc_r) {
@ -59,7 +60,7 @@ static void sifive_clint_write_timecmp(RISCVCPU *cpu, uint64_t value)
diff = cpu->env.timecmp - rtc_r; diff = cpu->env.timecmp - rtc_r;
/* back to ns (note args switched in muldiv64) */ /* back to ns (note args switched in muldiv64) */
next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + next = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
muldiv64(diff, NANOSECONDS_PER_SECOND, SIFIVE_CLINT_TIMEBASE_FREQ); muldiv64(diff, NANOSECONDS_PER_SECOND, timebase_freq);
timer_mod(cpu->env.timer, next); timer_mod(cpu->env.timer, next);
} }
@ -112,10 +113,10 @@ static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
} }
} else if (addr == clint->time_base) { } else if (addr == clint->time_base) {
/* time_lo */ /* time_lo */
return cpu_riscv_read_rtc() & 0xFFFFFFFF; return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
} else if (addr == clint->time_base + 4) { } else if (addr == clint->time_base + 4) {
/* time_hi */ /* time_hi */
return (cpu_riscv_read_rtc() >> 32) & 0xFFFFFFFF; return (cpu_riscv_read_rtc(clint->timebase_freq) >> 32) & 0xFFFFFFFF;
} }
error_report("clint: invalid read: %08x", (uint32_t)addr); error_report("clint: invalid read: %08x", (uint32_t)addr);
@ -153,13 +154,13 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
/* timecmp_lo */ /* timecmp_lo */
uint64_t timecmp_hi = env->timecmp >> 32; uint64_t timecmp_hi = env->timecmp >> 32;
sifive_clint_write_timecmp(RISCV_CPU(cpu), sifive_clint_write_timecmp(RISCV_CPU(cpu),
timecmp_hi << 32 | (value & 0xFFFFFFFF)); timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
return; return;
} else if ((addr & 0x7) == 4) { } else if ((addr & 0x7) == 4) {
/* timecmp_hi */ /* timecmp_hi */
uint64_t timecmp_lo = env->timecmp; uint64_t timecmp_lo = env->timecmp;
sifive_clint_write_timecmp(RISCV_CPU(cpu), sifive_clint_write_timecmp(RISCV_CPU(cpu),
value << 32 | (timecmp_lo & 0xFFFFFFFF)); value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
} else { } else {
error_report("clint: invalid timecmp write: %08x", (uint32_t)addr); error_report("clint: invalid timecmp write: %08x", (uint32_t)addr);
} }
@ -194,6 +195,7 @@ static Property sifive_clint_properties[] = {
DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0), DEFINE_PROP_UINT32("timecmp-base", SiFiveCLINTState, timecmp_base, 0),
DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0), DEFINE_PROP_UINT32("time-base", SiFiveCLINTState, time_base, 0),
DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0), DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -232,7 +234,8 @@ type_init(sifive_clint_register_types)
*/ */
DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
uint32_t timecmp_base, uint32_t time_base, bool provide_rdtime) uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
bool provide_rdtime)
{ {
int i; int i;
for (i = 0; i < num_harts; i++) { for (i = 0; i < num_harts; i++) {
@ -242,7 +245,7 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
continue; continue;
} }
if (provide_rdtime) { if (provide_rdtime) {
riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc); riscv_cpu_set_rdtime_fn(env, cpu_riscv_read_rtc, timebase_freq);
} }
env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, env->timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
&sifive_clint_timer_cb, cpu); &sifive_clint_timer_cb, cpu);
@ -256,6 +259,7 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base); qdev_prop_set_uint32(dev, "timecmp-base", timecmp_base);
qdev_prop_set_uint32(dev, "time-base", time_base); qdev_prop_set_uint32(dev, "time-base", time_base);
qdev_prop_set_uint32(dev, "aperture-size", size); qdev_prop_set_uint32(dev, "aperture-size", size);
qdev_prop_set_uint32(dev, "timebase-freq", timebase_freq);
sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal); sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr); sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
return dev; return dev;

View File

@ -27,9 +27,9 @@
#include "hw/pci/msi.h" #include "hw/pci/msi.h"
#include "hw/boards.h" #include "hw/boards.h"
#include "hw/qdev-properties.h" #include "hw/qdev-properties.h"
#include "hw/intc/sifive_plic.h"
#include "target/riscv/cpu.h" #include "target/riscv/cpu.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
#include "hw/riscv/sifive_plic.h"
#define RISCV_DEBUG_PLIC 0 #define RISCV_DEBUG_PLIC 0

View File

@ -134,4 +134,16 @@ config MAC_VIA
config AVR_POWER config AVR_POWER
bool bool
config SIFIVE_TEST
bool
config SIFIVE_E_PRCI
bool
config SIFIVE_U_OTP
bool
config SIFIVE_U_PRCI
bool
source macio/Kconfig source macio/Kconfig

View File

@ -21,6 +21,12 @@ softmmu_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c'))
# Mac devices # Mac devices
softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c'))
# RISC-V devices
softmmu_ss.add(when: 'CONFIG_SIFIVE_TEST', if_true: files('sifive_test.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c'))
softmmu_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c'))
# PKUnity SoC devices # PKUnity SoC devices
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_pm.c')) softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_pm.c'))

View File

@ -24,7 +24,7 @@
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/riscv/sifive_e_prci.h" #include "hw/misc/sifive_e_prci.h"
static uint64_t sifive_e_prci_read(void *opaque, hwaddr addr, unsigned int size) static uint64_t sifive_e_prci_read(void *opaque, hwaddr addr, unsigned int size)
{ {

View File

@ -25,7 +25,7 @@
#include "qemu/module.h" #include "qemu/module.h"
#include "sysemu/runstate.h" #include "sysemu/runstate.h"
#include "hw/hw.h" #include "hw/hw.h"
#include "hw/riscv/sifive_test.h" #include "hw/misc/sifive_test.h"
static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size) static uint64_t sifive_test_read(void *opaque, hwaddr addr, unsigned int size)
{ {
@ -59,7 +59,7 @@ static const MemoryRegionOps sifive_test_ops = {
.write = sifive_test_write, .write = sifive_test_write,
.endianness = DEVICE_NATIVE_ENDIAN, .endianness = DEVICE_NATIVE_ENDIAN,
.valid = { .valid = {
.min_access_size = 4, .min_access_size = 2,
.max_access_size = 4 .max_access_size = 4
} }
}; };

View File

@ -23,7 +23,7 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "hw/riscv/sifive_u_otp.h" #include "hw/misc/sifive_u_otp.h"
static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size)
{ {

View File

@ -22,7 +22,7 @@
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "qemu/log.h" #include "qemu/log.h"
#include "qemu/module.h" #include "qemu/module.h"
#include "hw/riscv/sifive_u_prci.h" #include "hw/misc/sifive_u_prci.h"
static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size) static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size)
{ {

View File

@ -250,7 +250,7 @@
#define GEM_PHYMNTNC_REG_SHIFT 18 #define GEM_PHYMNTNC_REG_SHIFT 18
/* Marvell PHY definitions */ /* Marvell PHY definitions */
#define BOARD_PHY_ADDRESS 23 /* PHY address we will emulate a device at */ #define BOARD_PHY_ADDRESS 0 /* PHY address we will emulate a device at */
#define PHY_REG_CONTROL 0 #define PHY_REG_CONTROL 0
#define PHY_REG_STATUS 1 #define PHY_REG_STATUS 1
@ -1446,7 +1446,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
uint32_t phy_addr, reg_num; uint32_t phy_addr, reg_num;
phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT; phy_addr = (retval & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) { if (phy_addr == s->phy_addr) {
reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT; reg_num = (retval & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
retval &= 0xFFFF0000; retval &= 0xFFFF0000;
retval |= gem_phy_read(s, reg_num); retval |= gem_phy_read(s, reg_num);
@ -1569,7 +1569,7 @@ static void gem_write(void *opaque, hwaddr offset, uint64_t val,
uint32_t phy_addr, reg_num; uint32_t phy_addr, reg_num;
phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT; phy_addr = (val & GEM_PHYMNTNC_ADDR) >> GEM_PHYMNTNC_ADDR_SHFT;
if (phy_addr == BOARD_PHY_ADDRESS || phy_addr == 0) { if (phy_addr == s->phy_addr) {
reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT; reg_num = (val & GEM_PHYMNTNC_REG) >> GEM_PHYMNTNC_REG_SHIFT;
gem_phy_write(s, reg_num, val); gem_phy_write(s, reg_num, val);
} }
@ -1682,6 +1682,7 @@ static Property gem_properties[] = {
DEFINE_NIC_PROPERTIES(CadenceGEMState, conf), DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
DEFINE_PROP_UINT32("revision", CadenceGEMState, revision, DEFINE_PROP_UINT32("revision", CadenceGEMState, revision,
GEM_MODID_VALUE), GEM_MODID_VALUE),
DEFINE_PROP_UINT8("phy-addr", CadenceGEMState, phy_addr, BOARD_PHY_ADDRESS),
DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState, DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState,
num_priority_queues, 1), num_priority_queues, 1),
DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState, DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState,

View File

@ -1,50 +1,62 @@
config HTIF
bool
config HART
bool
config IBEX config IBEX
bool bool
config SIFIVE config MICROCHIP_PFSOC
bool bool
select CADENCE_SDHCI
select MCHP_PFSOC_MMUART
select MSI_NONBROKEN select MSI_NONBROKEN
select SIFIVE_CLINT
config SIFIVE_E select SIFIVE_PDMA
bool select SIFIVE_PLIC
select HART
select SIFIVE
select UNIMP select UNIMP
config SIFIVE_U
bool
select CADENCE
select HART
select SIFIVE
select UNIMP
config SPIKE
bool
select HART
select HTIF
select SIFIVE
config OPENTITAN config OPENTITAN
bool bool
select IBEX select IBEX
select HART
select UNIMP select UNIMP
config RISCV_VIRT config RISCV_VIRT
bool bool
imply PCI_DEVICES imply PCI_DEVICES
imply TEST_DEVICES imply TEST_DEVICES
select PCI
select HART
select SERIAL
select GOLDFISH_RTC select GOLDFISH_RTC
select VIRTIO_MMIO select MSI_NONBROKEN
select PCI
select PCI_EXPRESS_GENERIC_BRIDGE select PCI_EXPRESS_GENERIC_BRIDGE
select PFLASH_CFI01 select PFLASH_CFI01
select SIFIVE select SERIAL
select SIFIVE_CLINT
select SIFIVE_PLIC
select SIFIVE_TEST
select VIRTIO_MMIO
config SIFIVE_E
bool
select MSI_NONBROKEN
select SIFIVE_CLINT
select SIFIVE_GPIO
select SIFIVE_PLIC
select SIFIVE_UART
select SIFIVE_E_PRCI
select UNIMP
config SIFIVE_U
bool
select CADENCE
select MSI_NONBROKEN
select SIFIVE_CLINT
select SIFIVE_GPIO
select SIFIVE_PDMA
select SIFIVE_PLIC
select SIFIVE_UART
select SIFIVE_U_OTP
select SIFIVE_U_PRCI
select UNIMP
config SPIKE
bool
select HTIF
select MSI_NONBROKEN
select SIFIVE_CLINT
select SIFIVE_PLIC

View File

@ -1,20 +1,12 @@
riscv_ss = ss.source_set() riscv_ss = ss.source_set()
riscv_ss.add(files('boot.c'), fdt) riscv_ss.add(files('boot.c'), fdt)
riscv_ss.add(files('numa.c')) riscv_ss.add(files('numa.c'))
riscv_ss.add(when: 'CONFIG_HART', if_true: files('riscv_hart.c')) riscv_ss.add(files('riscv_hart.c'))
riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c')) riscv_ss.add(when: 'CONFIG_OPENTITAN', if_true: files('opentitan.c'))
riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c')) riscv_ss.add(when: 'CONFIG_RISCV_VIRT', if_true: files('virt.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_clint.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_gpio.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_plic.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_test.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE', if_true: files('sifive_uart.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE_E', if_true: files('sifive_e_prci.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c')) riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u_otp.c'))
riscv_ss.add(when: 'CONFIG_SIFIVE_U', if_true: files('sifive_u_prci.c'))
riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('riscv_htif.c'))
riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c')) riscv_ss.add(when: 'CONFIG_SPIKE', if_true: files('spike.c'))
riscv_ss.add(when: 'CONFIG_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
hw_arch += {'riscv': riscv_ss} hw_arch += {'riscv': riscv_ss}

437
hw/riscv/microchip_pfsoc.c Normal file
View File

@ -0,0 +1,437 @@
/*
* QEMU RISC-V Board Compatible with Microchip PolarFire SoC Icicle Kit
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* Provides a board compatible with the Microchip PolarFire SoC Icicle Kit
*
* 0) CLINT (Core Level Interruptor)
* 1) PLIC (Platform Level Interrupt Controller)
* 2) eNVM (Embedded Non-Volatile Memory)
* 3) MMUARTs (Multi-Mode UART)
* 4) Cadence eMMC/SDHC controller and an SD card connected to it
* 5) SiFive Platform DMA (Direct Memory Access Controller)
* 6) GEM (Gigabit Ethernet MAC Controller)
*
* This board currently generates devicetree dynamically that indicates at least
* two harts and up to five harts.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qemu/units.h"
#include "qemu/cutils.h"
#include "qapi/error.h"
#include "hw/boards.h"
#include "hw/irq.h"
#include "hw/loader.h"
#include "hw/sysbus.h"
#include "chardev/char.h"
#include "hw/cpu/cluster.h"
#include "target/riscv/cpu.h"
#include "hw/misc/unimp.h"
#include "hw/riscv/boot.h"
#include "hw/riscv/riscv_hart.h"
#include "hw/riscv/microchip_pfsoc.h"
#include "hw/intc/sifive_clint.h"
#include "hw/intc/sifive_plic.h"
#include "sysemu/sysemu.h"
/*
* The BIOS image used by this machine is called Hart Software Services (HSS).
* See https://github.com/polarfire-soc/hart-software-services
*/
#define BIOS_FILENAME "hss.bin"
#define RESET_VECTOR 0x20220000
/* CLINT timebase frequency */
#define CLINT_TIMEBASE_FREQ 1000000
/* GEM version */
#define GEM_REVISION 0x0107010c
static const struct MemmapEntry {
hwaddr base;
hwaddr size;
} microchip_pfsoc_memmap[] = {
[MICROCHIP_PFSOC_DEBUG] = { 0x0, 0x1000 },
[MICROCHIP_PFSOC_E51_DTIM] = { 0x1000000, 0x2000 },
[MICROCHIP_PFSOC_BUSERR_UNIT0] = { 0x1700000, 0x1000 },
[MICROCHIP_PFSOC_BUSERR_UNIT1] = { 0x1701000, 0x1000 },
[MICROCHIP_PFSOC_BUSERR_UNIT2] = { 0x1702000, 0x1000 },
[MICROCHIP_PFSOC_BUSERR_UNIT3] = { 0x1703000, 0x1000 },
[MICROCHIP_PFSOC_BUSERR_UNIT4] = { 0x1704000, 0x1000 },
[MICROCHIP_PFSOC_CLINT] = { 0x2000000, 0x10000 },
[MICROCHIP_PFSOC_L2CC] = { 0x2010000, 0x1000 },
[MICROCHIP_PFSOC_DMA] = { 0x3000000, 0x100000 },
[MICROCHIP_PFSOC_L2LIM] = { 0x8000000, 0x2000000 },
[MICROCHIP_PFSOC_PLIC] = { 0xc000000, 0x4000000 },
[MICROCHIP_PFSOC_MMUART0] = { 0x20000000, 0x1000 },
[MICROCHIP_PFSOC_SYSREG] = { 0x20002000, 0x2000 },
[MICROCHIP_PFSOC_MPUCFG] = { 0x20005000, 0x1000 },
[MICROCHIP_PFSOC_EMMC_SD] = { 0x20008000, 0x1000 },
[MICROCHIP_PFSOC_MMUART1] = { 0x20100000, 0x1000 },
[MICROCHIP_PFSOC_MMUART2] = { 0x20102000, 0x1000 },
[MICROCHIP_PFSOC_MMUART3] = { 0x20104000, 0x1000 },
[MICROCHIP_PFSOC_MMUART4] = { 0x20106000, 0x1000 },
[MICROCHIP_PFSOC_GEM0] = { 0x20110000, 0x2000 },
[MICROCHIP_PFSOC_GEM1] = { 0x20112000, 0x2000 },
[MICROCHIP_PFSOC_GPIO0] = { 0x20120000, 0x1000 },
[MICROCHIP_PFSOC_GPIO1] = { 0x20121000, 0x1000 },
[MICROCHIP_PFSOC_GPIO2] = { 0x20122000, 0x1000 },
[MICROCHIP_PFSOC_ENVM_CFG] = { 0x20200000, 0x1000 },
[MICROCHIP_PFSOC_ENVM_DATA] = { 0x20220000, 0x20000 },
[MICROCHIP_PFSOC_IOSCB_CFG] = { 0x37080000, 0x1000 },
[MICROCHIP_PFSOC_DRAM] = { 0x80000000, 0x0 },
};
static void microchip_pfsoc_soc_instance_init(Object *obj)
{
MachineState *ms = MACHINE(qdev_get_machine());
MicrochipPFSoCState *s = MICROCHIP_PFSOC(obj);
object_initialize_child(obj, "e-cluster", &s->e_cluster, TYPE_CPU_CLUSTER);
qdev_prop_set_uint32(DEVICE(&s->e_cluster), "cluster-id", 0);
object_initialize_child(OBJECT(&s->e_cluster), "e-cpus", &s->e_cpus,
TYPE_RISCV_HART_ARRAY);
qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1);
qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0);
qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type",
TYPE_RISCV_CPU_SIFIVE_E51);
qdev_prop_set_uint64(DEVICE(&s->e_cpus), "resetvec", RESET_VECTOR);
object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER);
qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);
object_initialize_child(OBJECT(&s->u_cluster), "u-cpus", &s->u_cpus,
TYPE_RISCV_HART_ARRAY);
qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1);
qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1);
qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type",
TYPE_RISCV_CPU_SIFIVE_U54);
qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", RESET_VECTOR);
object_initialize_child(obj, "dma-controller", &s->dma,
TYPE_SIFIVE_PDMA);
object_initialize_child(obj, "gem0", &s->gem0, TYPE_CADENCE_GEM);
object_initialize_child(obj, "gem1", &s->gem1, TYPE_CADENCE_GEM);
object_initialize_child(obj, "sd-controller", &s->sdhci,
TYPE_CADENCE_SDHCI);
}
static void microchip_pfsoc_soc_realize(DeviceState *dev, Error **errp)
{
MachineState *ms = MACHINE(qdev_get_machine());
MicrochipPFSoCState *s = MICROCHIP_PFSOC(dev);
const struct MemmapEntry *memmap = microchip_pfsoc_memmap;
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *e51_dtim_mem = g_new(MemoryRegion, 1);
MemoryRegion *l2lim_mem = g_new(MemoryRegion, 1);
MemoryRegion *envm_data = g_new(MemoryRegion, 1);
char *plic_hart_config;
size_t plic_hart_config_len;
NICInfo *nd;
int i;
sysbus_realize(SYS_BUS_DEVICE(&s->e_cpus), &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->u_cpus), &error_abort);
/*
* The cluster must be realized after the RISC-V hart array container,
* as the container's CPU object is only created on realize, and the
* CPU must exist and have been parented into the cluster before the
* cluster is realized.
*/
qdev_realize(DEVICE(&s->e_cluster), NULL, &error_abort);
qdev_realize(DEVICE(&s->u_cluster), NULL, &error_abort);
/* E51 DTIM */
memory_region_init_ram(e51_dtim_mem, NULL, "microchip.pfsoc.e51_dtim_mem",
memmap[MICROCHIP_PFSOC_E51_DTIM].size, &error_fatal);
memory_region_add_subregion(system_memory,
memmap[MICROCHIP_PFSOC_E51_DTIM].base,
e51_dtim_mem);
/* Bus Error Units */
create_unimplemented_device("microchip.pfsoc.buserr_unit0_mem",
memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].base,
memmap[MICROCHIP_PFSOC_BUSERR_UNIT0].size);
create_unimplemented_device("microchip.pfsoc.buserr_unit1_mem",
memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].base,
memmap[MICROCHIP_PFSOC_BUSERR_UNIT1].size);
create_unimplemented_device("microchip.pfsoc.buserr_unit2_mem",
memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].base,
memmap[MICROCHIP_PFSOC_BUSERR_UNIT2].size);
create_unimplemented_device("microchip.pfsoc.buserr_unit3_mem",
memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].base,
memmap[MICROCHIP_PFSOC_BUSERR_UNIT3].size);
create_unimplemented_device("microchip.pfsoc.buserr_unit4_mem",
memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].base,
memmap[MICROCHIP_PFSOC_BUSERR_UNIT4].size);
/* CLINT */
sifive_clint_create(memmap[MICROCHIP_PFSOC_CLINT].base,
memmap[MICROCHIP_PFSOC_CLINT].size, 0, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
CLINT_TIMEBASE_FREQ, false);
/* L2 cache controller */
create_unimplemented_device("microchip.pfsoc.l2cc",
memmap[MICROCHIP_PFSOC_L2CC].base, memmap[MICROCHIP_PFSOC_L2CC].size);
/*
* Add L2-LIM at reset size.
* This should be reduced in size as the L2 Cache Controller WayEnable
* register is incremented. Unfortunately I don't see a nice (or any) way
* to handle reducing or blocking out the L2 LIM while still allowing it
* be re returned to all enabled after a reset. For the time being, just
* leave it enabled all the time. This won't break anything, but will be
* too generous to misbehaving guests.
*/
memory_region_init_ram(l2lim_mem, NULL, "microchip.pfsoc.l2lim",
memmap[MICROCHIP_PFSOC_L2LIM].size, &error_fatal);
memory_region_add_subregion(system_memory,
memmap[MICROCHIP_PFSOC_L2LIM].base,
l2lim_mem);
/* create PLIC hart topology configuration string */
plic_hart_config_len = (strlen(MICROCHIP_PFSOC_PLIC_HART_CONFIG) + 1) *
ms->smp.cpus;
plic_hart_config = g_malloc0(plic_hart_config_len);
for (i = 0; i < ms->smp.cpus; i++) {
if (i != 0) {
strncat(plic_hart_config, "," MICROCHIP_PFSOC_PLIC_HART_CONFIG,
plic_hart_config_len);
} else {
strncat(plic_hart_config, "M", plic_hart_config_len);
}
plic_hart_config_len -= (strlen(MICROCHIP_PFSOC_PLIC_HART_CONFIG) + 1);
}
/* PLIC */
s->plic = sifive_plic_create(memmap[MICROCHIP_PFSOC_PLIC].base,
plic_hart_config, 0,
MICROCHIP_PFSOC_PLIC_NUM_SOURCES,
MICROCHIP_PFSOC_PLIC_NUM_PRIORITIES,
MICROCHIP_PFSOC_PLIC_PRIORITY_BASE,
MICROCHIP_PFSOC_PLIC_PENDING_BASE,
MICROCHIP_PFSOC_PLIC_ENABLE_BASE,
MICROCHIP_PFSOC_PLIC_ENABLE_STRIDE,
MICROCHIP_PFSOC_PLIC_CONTEXT_BASE,
MICROCHIP_PFSOC_PLIC_CONTEXT_STRIDE,
memmap[MICROCHIP_PFSOC_PLIC].size);
g_free(plic_hart_config);
/* DMA */
sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->dma), 0,
memmap[MICROCHIP_PFSOC_DMA].base);
for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), i,
qdev_get_gpio_in(DEVICE(s->plic),
MICROCHIP_PFSOC_DMA_IRQ0 + i));
}
/* SYSREG */
create_unimplemented_device("microchip.pfsoc.sysreg",
memmap[MICROCHIP_PFSOC_SYSREG].base,
memmap[MICROCHIP_PFSOC_SYSREG].size);
/* MPUCFG */
create_unimplemented_device("microchip.pfsoc.mpucfg",
memmap[MICROCHIP_PFSOC_MPUCFG].base,
memmap[MICROCHIP_PFSOC_MPUCFG].size);
/* SDHCI */
sysbus_realize(SYS_BUS_DEVICE(&s->sdhci), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->sdhci), 0,
memmap[MICROCHIP_PFSOC_EMMC_SD].base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->sdhci), 0,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_EMMC_SD_IRQ));
/* MMUARTs */
s->serial0 = mchp_pfsoc_mmuart_create(system_memory,
memmap[MICROCHIP_PFSOC_MMUART0].base,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART0_IRQ),
serial_hd(0));
s->serial1 = mchp_pfsoc_mmuart_create(system_memory,
memmap[MICROCHIP_PFSOC_MMUART1].base,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART1_IRQ),
serial_hd(1));
s->serial2 = mchp_pfsoc_mmuart_create(system_memory,
memmap[MICROCHIP_PFSOC_MMUART2].base,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART2_IRQ),
serial_hd(2));
s->serial3 = mchp_pfsoc_mmuart_create(system_memory,
memmap[MICROCHIP_PFSOC_MMUART3].base,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART3_IRQ),
serial_hd(3));
s->serial4 = mchp_pfsoc_mmuart_create(system_memory,
memmap[MICROCHIP_PFSOC_MMUART4].base,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_MMUART4_IRQ),
serial_hd(4));
/* GEMs */
nd = &nd_table[0];
if (nd->used) {
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(DEVICE(&s->gem0), nd);
}
nd = &nd_table[1];
if (nd->used) {
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
qdev_set_nic_properties(DEVICE(&s->gem1), nd);
}
object_property_set_int(OBJECT(&s->gem0), "revision", GEM_REVISION, errp);
object_property_set_int(OBJECT(&s->gem0), "phy-addr", 8, errp);
sysbus_realize(SYS_BUS_DEVICE(&s->gem0), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem0), 0,
memmap[MICROCHIP_PFSOC_GEM0].base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem0), 0,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM0_IRQ));
object_property_set_int(OBJECT(&s->gem1), "revision", GEM_REVISION, errp);
object_property_set_int(OBJECT(&s->gem1), "phy-addr", 9, errp);
sysbus_realize(SYS_BUS_DEVICE(&s->gem1), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->gem1), 0,
memmap[MICROCHIP_PFSOC_GEM1].base);
sysbus_connect_irq(SYS_BUS_DEVICE(&s->gem1), 0,
qdev_get_gpio_in(DEVICE(s->plic), MICROCHIP_PFSOC_GEM1_IRQ));
/* GPIOs */
create_unimplemented_device("microchip.pfsoc.gpio0",
memmap[MICROCHIP_PFSOC_GPIO0].base,
memmap[MICROCHIP_PFSOC_GPIO0].size);
create_unimplemented_device("microchip.pfsoc.gpio1",
memmap[MICROCHIP_PFSOC_GPIO1].base,
memmap[MICROCHIP_PFSOC_GPIO1].size);
create_unimplemented_device("microchip.pfsoc.gpio2",
memmap[MICROCHIP_PFSOC_GPIO2].base,
memmap[MICROCHIP_PFSOC_GPIO2].size);
/* eNVM */
memory_region_init_rom(envm_data, OBJECT(dev), "microchip.pfsoc.envm.data",
memmap[MICROCHIP_PFSOC_ENVM_DATA].size,
&error_fatal);
memory_region_add_subregion(system_memory,
memmap[MICROCHIP_PFSOC_ENVM_DATA].base,
envm_data);
/* IOSCBCFG */
create_unimplemented_device("microchip.pfsoc.ioscb.cfg",
memmap[MICROCHIP_PFSOC_IOSCB_CFG].base,
memmap[MICROCHIP_PFSOC_IOSCB_CFG].size);
}
static void microchip_pfsoc_soc_class_init(ObjectClass *oc, void *data)
{
DeviceClass *dc = DEVICE_CLASS(oc);
dc->realize = microchip_pfsoc_soc_realize;
/* Reason: Uses serial_hds in realize function, thus can't be used twice */
dc->user_creatable = false;
}
static const TypeInfo microchip_pfsoc_soc_type_info = {
.name = TYPE_MICROCHIP_PFSOC,
.parent = TYPE_DEVICE,
.instance_size = sizeof(MicrochipPFSoCState),
.instance_init = microchip_pfsoc_soc_instance_init,
.class_init = microchip_pfsoc_soc_class_init,
};
static void microchip_pfsoc_soc_register_types(void)
{
type_register_static(&microchip_pfsoc_soc_type_info);
}
type_init(microchip_pfsoc_soc_register_types)
static void microchip_icicle_kit_machine_init(MachineState *machine)
{
MachineClass *mc = MACHINE_GET_CLASS(machine);
const struct MemmapEntry *memmap = microchip_pfsoc_memmap;
MicrochipIcicleKitState *s = MICROCHIP_ICICLE_KIT_MACHINE(machine);
MemoryRegion *system_memory = get_system_memory();
MemoryRegion *main_mem = g_new(MemoryRegion, 1);
DriveInfo *dinfo = drive_get_next(IF_SD);
/* Sanity check on RAM size */
if (machine->ram_size < mc->default_ram_size) {
char *sz = size_to_str(mc->default_ram_size);
error_report("Invalid RAM size, should be bigger than %s", sz);
g_free(sz);
exit(EXIT_FAILURE);
}
/* Initialize SoC */
object_initialize_child(OBJECT(machine), "soc", &s->soc,
TYPE_MICROCHIP_PFSOC);
qdev_realize(DEVICE(&s->soc), NULL, &error_abort);
/* Register RAM */
memory_region_init_ram(main_mem, NULL, "microchip.icicle.kit.ram",
machine->ram_size, &error_fatal);
memory_region_add_subregion(system_memory,
memmap[MICROCHIP_PFSOC_DRAM].base, main_mem);
/* Load the firmware */
riscv_find_and_load_firmware(machine, BIOS_FILENAME, RESET_VECTOR, NULL);
/* Attach an SD card */
if (dinfo) {
CadenceSDHCIState *sdhci = &(s->soc.sdhci);
DeviceState *card = qdev_new(TYPE_SD_CARD);
qdev_prop_set_drive_err(card, "drive", blk_by_legacy_dinfo(dinfo),
&error_fatal);
qdev_realize_and_unref(card, sdhci->bus, &error_fatal);
}
}
static void microchip_icicle_kit_machine_class_init(ObjectClass *oc, void *data)
{
MachineClass *mc = MACHINE_CLASS(oc);
mc->desc = "Microchip PolarFire SoC Icicle Kit";
mc->init = microchip_icicle_kit_machine_init;
mc->max_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT +
MICROCHIP_PFSOC_COMPUTE_CPU_COUNT;
mc->min_cpus = MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT + 1;
mc->default_cpus = mc->min_cpus;
mc->default_ram_size = 1 * GiB;
}
static const TypeInfo microchip_icicle_kit_machine_typeinfo = {
.name = MACHINE_TYPE_NAME("microchip-icicle-kit"),
.parent = TYPE_MACHINE,
.class_init = microchip_icicle_kit_machine_class_init,
.instance_size = sizeof(MicrochipIcicleKitState),
};
static void microchip_icicle_kit_machine_init_register_types(void)
{
type_register_static(&microchip_icicle_kit_machine_typeinfo);
}
type_init(microchip_icicle_kit_machine_init_register_types)

View File

@ -111,6 +111,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
&error_abort); &error_abort);
object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
&error_abort); &error_abort);
object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8090, &error_abort);
sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort); sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort);
/* Boot ROM */ /* Boot ROM */

View File

@ -31,6 +31,8 @@ static Property riscv_harts_props[] = {
DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1), DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1),
DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0), DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0),
DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type), DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
DEFINE_PROP_UINT64("resetvec", RISCVHartArrayState, resetvec,
DEFAULT_RSTVEC),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };
@ -44,6 +46,7 @@ static bool riscv_hart_realize(RISCVHartArrayState *s, int idx,
char *cpu_type, Error **errp) char *cpu_type, Error **errp)
{ {
object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type); object_initialize_child(OBJECT(s), "harts[*]", &s->harts[idx], cpu_type);
qdev_prop_set_uint64(DEVICE(&s->harts[idx]), "resetvec", s->resetvec);
s->harts[idx].env.mhartid = s->hartid_base + idx; s->harts[idx].env.mhartid = s->hartid_base + idx;
qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]); qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp); return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp);

View File

@ -39,12 +39,12 @@
#include "hw/misc/unimp.h" #include "hw/misc/unimp.h"
#include "target/riscv/cpu.h" #include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_plic.h"
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/sifive_uart.h"
#include "hw/riscv/sifive_e.h" #include "hw/riscv/sifive_e.h"
#include "hw/riscv/sifive_e_prci.h"
#include "hw/riscv/boot.h" #include "hw/riscv/boot.h"
#include "hw/char/sifive_uart.h"
#include "hw/intc/sifive_clint.h"
#include "hw/intc/sifive_plic.h"
#include "hw/misc/sifive_e_prci.h"
#include "chardev/char.h" #include "chardev/char.h"
#include "sysemu/arch_init.h" #include "sysemu/arch_init.h"
#include "sysemu/sysemu.h" #include "sysemu/sysemu.h"
@ -177,6 +177,7 @@ static void sifive_e_soc_init(Object *obj)
object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY); object_initialize_child(obj, "cpus", &s->cpus, TYPE_RISCV_HART_ARRAY);
object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus, object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
&error_abort); &error_abort);
object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x1004, &error_abort);
object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio, object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio,
TYPE_SIFIVE_GPIO); TYPE_SIFIVE_GPIO);
} }
@ -212,7 +213,8 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
memmap[SIFIVE_E_PLIC].size); memmap[SIFIVE_E_PLIC].size);
sifive_clint_create(memmap[SIFIVE_E_CLINT].base, sifive_clint_create(memmap[SIFIVE_E_CLINT].base,
memmap[SIFIVE_E_CLINT].size, 0, ms->smp.cpus, memmap[SIFIVE_E_CLINT].size, 0, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, false);
create_unimplemented_device("riscv.sifive.e.aon", create_unimplemented_device("riscv.sifive.e.aon",
memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size); memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size);
sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base); sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base);

View File

@ -14,6 +14,7 @@
* 4) GPIO (General Purpose Input/Output Controller) * 4) GPIO (General Purpose Input/Output Controller)
* 5) OTP (One-Time Programmable) memory with stored serial number * 5) OTP (One-Time Programmable) memory with stored serial number
* 6) GEM (Gigabit Ethernet Controller) and management block * 6) GEM (Gigabit Ethernet Controller) and management block
* 7) DMA (Direct Memory Access Controller)
* *
* This board currently generates devicetree dynamically that indicates at least * This board currently generates devicetree dynamically that indicates at least
* two harts and up to five harts. * two harts and up to five harts.
@ -45,11 +46,11 @@
#include "hw/misc/unimp.h" #include "hw/misc/unimp.h"
#include "target/riscv/cpu.h" #include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_plic.h"
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/sifive_uart.h"
#include "hw/riscv/sifive_u.h" #include "hw/riscv/sifive_u.h"
#include "hw/riscv/boot.h" #include "hw/riscv/boot.h"
#include "hw/char/sifive_uart.h"
#include "hw/intc/sifive_clint.h"
#include "hw/intc/sifive_plic.h"
#include "chardev/char.h" #include "chardev/char.h"
#include "net/eth.h" #include "net/eth.h"
#include "sysemu/arch_init.h" #include "sysemu/arch_init.h"
@ -73,6 +74,7 @@ static const struct MemmapEntry {
[SIFIVE_U_MROM] = { 0x1000, 0xf000 }, [SIFIVE_U_MROM] = { 0x1000, 0xf000 },
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 }, [SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
[SIFIVE_U_L2CC] = { 0x2010000, 0x1000 }, [SIFIVE_U_L2CC] = { 0x2010000, 0x1000 },
[SIFIVE_U_PDMA] = { 0x3000000, 0x100000 },
[SIFIVE_U_L2LIM] = { 0x8000000, 0x2000000 }, [SIFIVE_U_L2LIM] = { 0x8000000, 0x2000000 },
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 }, [SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
[SIFIVE_U_PRCI] = { 0x10000000, 0x1000 }, [SIFIVE_U_PRCI] = { 0x10000000, 0x1000 },
@ -303,6 +305,22 @@ static void create_fdt(SiFiveUState *s, const struct MemmapEntry *memmap,
qemu_fdt_setprop_string(fdt, nodename, "compatible", "gpio-restart"); qemu_fdt_setprop_string(fdt, nodename, "compatible", "gpio-restart");
g_free(nodename); g_free(nodename);
nodename = g_strdup_printf("/soc/dma@%lx",
(long)memmap[SIFIVE_U_PDMA].base);
qemu_fdt_add_subnode(fdt, nodename);
qemu_fdt_setprop_cell(fdt, nodename, "#dma-cells", 1);
qemu_fdt_setprop_cells(fdt, nodename, "interrupts",
SIFIVE_U_PDMA_IRQ0, SIFIVE_U_PDMA_IRQ1, SIFIVE_U_PDMA_IRQ2,
SIFIVE_U_PDMA_IRQ3, SIFIVE_U_PDMA_IRQ4, SIFIVE_U_PDMA_IRQ5,
SIFIVE_U_PDMA_IRQ6, SIFIVE_U_PDMA_IRQ7);
qemu_fdt_setprop_cell(fdt, nodename, "interrupt-parent", plic_phandle);
qemu_fdt_setprop_cells(fdt, nodename, "reg",
0x0, memmap[SIFIVE_U_PDMA].base,
0x0, memmap[SIFIVE_U_PDMA].size);
qemu_fdt_setprop_string(fdt, nodename, "compatible",
"sifive,fu540-c000-pdma");
g_free(nodename);
nodename = g_strdup_printf("/soc/cache-controller@%lx", nodename = g_strdup_printf("/soc/cache-controller@%lx",
(long)memmap[SIFIVE_U_L2CC].base); (long)memmap[SIFIVE_U_L2CC].base);
qemu_fdt_add_subnode(fdt, nodename); qemu_fdt_add_subnode(fdt, nodename);
@ -611,6 +629,7 @@ static void sifive_u_soc_instance_init(Object *obj)
qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1); qdev_prop_set_uint32(DEVICE(&s->e_cpus), "num-harts", 1);
qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0); qdev_prop_set_uint32(DEVICE(&s->e_cpus), "hartid-base", 0);
qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU); qdev_prop_set_string(DEVICE(&s->e_cpus), "cpu-type", SIFIVE_E_CPU);
qdev_prop_set_uint64(DEVICE(&s->e_cpus), "resetvec", 0x1004);
object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER); object_initialize_child(obj, "u-cluster", &s->u_cluster, TYPE_CPU_CLUSTER);
qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1); qdev_prop_set_uint32(DEVICE(&s->u_cluster), "cluster-id", 1);
@ -620,11 +639,13 @@ static void sifive_u_soc_instance_init(Object *obj)
qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1); qdev_prop_set_uint32(DEVICE(&s->u_cpus), "num-harts", ms->smp.cpus - 1);
qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1); qdev_prop_set_uint32(DEVICE(&s->u_cpus), "hartid-base", 1);
qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU); qdev_prop_set_string(DEVICE(&s->u_cpus), "cpu-type", SIFIVE_U_CPU);
qdev_prop_set_uint64(DEVICE(&s->u_cpus), "resetvec", 0x1004);
object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI); object_initialize_child(obj, "prci", &s->prci, TYPE_SIFIVE_U_PRCI);
object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP); object_initialize_child(obj, "otp", &s->otp, TYPE_SIFIVE_U_OTP);
object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM); object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM);
object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO); object_initialize_child(obj, "gpio", &s->gpio, TYPE_SIFIVE_GPIO);
object_initialize_child(obj, "pdma", &s->dma, TYPE_SIFIVE_PDMA);
} }
static void sifive_u_soc_realize(DeviceState *dev, Error **errp) static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
@ -704,7 +725,8 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ)); serial_hd(1), qdev_get_gpio_in(DEVICE(s->plic), SIFIVE_U_UART1_IRQ));
sifive_clint_create(memmap[SIFIVE_U_CLINT].base, sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
memmap[SIFIVE_U_CLINT].size, 0, ms->smp.cpus, memmap[SIFIVE_U_CLINT].size, 0, ms->smp.cpus,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, false);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->prci), errp)) {
return; return;
@ -727,6 +749,17 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
SIFIVE_U_GPIO_IRQ0 + i)); SIFIVE_U_GPIO_IRQ0 + i));
} }
/* PDMA */
sysbus_realize(SYS_BUS_DEVICE(&s->dma), errp);
sysbus_mmio_map(SYS_BUS_DEVICE(&s->dma), 0, memmap[SIFIVE_U_PDMA].base);
/* Connect PDMA interrupts to the PLIC */
for (i = 0; i < SIFIVE_PDMA_IRQS; i++) {
sysbus_connect_irq(SYS_BUS_DEVICE(&s->dma), i,
qdev_get_gpio_in(DEVICE(s->plic),
SIFIVE_U_PDMA_IRQ0 + i));
}
qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial); qdev_prop_set_uint32(DEVICE(&s->otp), "serial", s->serial);
if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) { if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) {
return; return;

View File

@ -31,12 +31,12 @@
#include "hw/loader.h" #include "hw/loader.h"
#include "hw/sysbus.h" #include "hw/sysbus.h"
#include "target/riscv/cpu.h" #include "target/riscv/cpu.h"
#include "hw/riscv/riscv_htif.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/spike.h" #include "hw/riscv/spike.h"
#include "hw/riscv/boot.h" #include "hw/riscv/boot.h"
#include "hw/riscv/numa.h" #include "hw/riscv/numa.h"
#include "hw/char/riscv_htif.h"
#include "hw/intc/sifive_clint.h"
#include "chardev/char.h" #include "chardev/char.h"
#include "sysemu/arch_init.h" #include "sysemu/arch_init.h"
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
@ -242,7 +242,8 @@ static void spike_board_init(MachineState *machine)
sifive_clint_create( sifive_clint_create(
memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size, memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
memmap[SPIKE_CLINT].size, base_hartid, hart_count, memmap[SPIKE_CLINT].size, base_hartid, hart_count,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, false); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, false);
} }
/* register system main memory (actual RAM) */ /* register system main memory (actual RAM) */

View File

@ -1,7 +0,0 @@
# See docs/devel/tracing.txt for syntax documentation.
# sifive_gpio.c
sifive_gpio_read(uint64_t offset, uint64_t r) "offset 0x%" PRIx64 " value 0x%" PRIx64
sifive_gpio_write(uint64_t offset, uint64_t value) "offset 0x%" PRIx64 " value 0x%" PRIx64
sifive_gpio_set(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64
sifive_gpio_update_output_irq(int64_t line, int64_t value) "line %" PRIi64 " value %" PRIi64

View File

@ -1 +0,0 @@
#include "trace/trace-hw_riscv.h"

View File

@ -30,12 +30,12 @@
#include "hw/char/serial.h" #include "hw/char/serial.h"
#include "target/riscv/cpu.h" #include "target/riscv/cpu.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_plic.h"
#include "hw/riscv/sifive_clint.h"
#include "hw/riscv/sifive_test.h"
#include "hw/riscv/virt.h" #include "hw/riscv/virt.h"
#include "hw/riscv/boot.h" #include "hw/riscv/boot.h"
#include "hw/riscv/numa.h" #include "hw/riscv/numa.h"
#include "hw/intc/sifive_clint.h"
#include "hw/intc/sifive_plic.h"
#include "hw/misc/sifive_test.h"
#include "chardev/char.h" #include "chardev/char.h"
#include "sysemu/arch_init.h" #include "sysemu/arch_init.h"
#include "sysemu/device_tree.h" #include "sysemu/device_tree.h"
@ -541,7 +541,8 @@ static void virt_machine_init(MachineState *machine)
sifive_clint_create( sifive_clint_create(
memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size, memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
memmap[VIRT_CLINT].size, base_hartid, hart_count, memmap[VIRT_CLINT].size, base_hartid, hart_count,
SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE, true); SIFIVE_SIP_BASE, SIFIVE_TIMECMP_BASE, SIFIVE_TIME_BASE,
SIFIVE_CLINT_TIMEBASE_FREQ, true);
/* Per-socket PLIC hart topology configuration string */ /* Per-socket PLIC hart topology configuration string */
plic_hart_config_len = plic_hart_config_len =

View File

@ -19,3 +19,7 @@ config SDHCI_PCI
default y if PCI_DEVICES default y if PCI_DEVICES
depends on PCI depends on PCI
select SDHCI select SDHCI
config CADENCE_SDHCI
bool
select SDHCI

193
hw/sd/cadence_sdhci.c Normal file
View File

@ -0,0 +1,193 @@
/*
* Cadence SDHCI emulation
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "qemu/osdep.h"
#include "qemu/bitops.h"
#include "qemu/error-report.h"
#include "qemu/log.h"
#include "qapi/error.h"
#include "migration/vmstate.h"
#include "hw/irq.h"
#include "hw/sd/cadence_sdhci.h"
#include "sdhci-internal.h"
/* HRS - Host Register Set (specific to Cadence) */
#define CADENCE_SDHCI_HRS00 0x00 /* general information */
#define CADENCE_SDHCI_HRS00_SWR BIT(0)
#define CADENCE_SDHCI_HRS00_POR_VAL 0x00010000
#define CADENCE_SDHCI_HRS04 0x10 /* PHY access port */
#define CADENCE_SDHCI_HRS04_WR BIT(24)
#define CADENCE_SDHCI_HRS04_RD BIT(25)
#define CADENCE_SDHCI_HRS04_ACK BIT(26)
#define CADENCE_SDHCI_HRS06 0x18 /* eMMC control */
#define CADENCE_SDHCI_HRS06_TUNE_UP BIT(15)
/* SRS - Slot Register Set (SDHCI-compatible) */
#define CADENCE_SDHCI_SRS_BASE 0x200
#define TO_REG(addr) ((addr) / sizeof(uint32_t))
static void cadence_sdhci_instance_init(Object *obj)
{
CadenceSDHCIState *s = CADENCE_SDHCI(obj);
object_initialize_child(OBJECT(s), "generic-sdhci",
&s->sdhci, TYPE_SYSBUS_SDHCI);
}
static void cadence_sdhci_reset(DeviceState *dev)
{
CadenceSDHCIState *s = CADENCE_SDHCI(dev);
memset(s->regs, 0, CADENCE_SDHCI_REG_SIZE);
s->regs[TO_REG(CADENCE_SDHCI_HRS00)] = CADENCE_SDHCI_HRS00_POR_VAL;
device_cold_reset(DEVICE(&s->sdhci));
}
static uint64_t cadence_sdhci_read(void *opaque, hwaddr addr, unsigned int size)
{
CadenceSDHCIState *s = opaque;
uint32_t val;
val = s->regs[TO_REG(addr)];
return (uint64_t)val;
}
static void cadence_sdhci_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
{
CadenceSDHCIState *s = opaque;
uint32_t val32 = (uint32_t)val;
switch (addr) {
case CADENCE_SDHCI_HRS00:
/*
* The only writable bit is SWR (software reset) and it automatically
* clears to zero, so essentially this register remains unchanged.
*/
if (val32 & CADENCE_SDHCI_HRS00_SWR) {
cadence_sdhci_reset(DEVICE(s));
}
break;
case CADENCE_SDHCI_HRS04:
/*
* Only emulate the ACK bit behavior when read or write transaction
* are requested.
*/
if (val32 & (CADENCE_SDHCI_HRS04_WR | CADENCE_SDHCI_HRS04_RD)) {
val32 |= CADENCE_SDHCI_HRS04_ACK;
} else {
val32 &= ~CADENCE_SDHCI_HRS04_ACK;
}
s->regs[TO_REG(addr)] = val32;
break;
case CADENCE_SDHCI_HRS06:
if (val32 & CADENCE_SDHCI_HRS06_TUNE_UP) {
val32 &= ~CADENCE_SDHCI_HRS06_TUNE_UP;
}
s->regs[TO_REG(addr)] = val32;
break;
default:
s->regs[TO_REG(addr)] = val32;
break;
}
}
static const MemoryRegionOps cadence_sdhci_ops = {
.read = cadence_sdhci_read,
.write = cadence_sdhci_write,
.endianness = DEVICE_NATIVE_ENDIAN,
.impl = {
.min_access_size = 4,
.max_access_size = 4,
},
.valid = {
.min_access_size = 4,
.max_access_size = 4,
}
};
static void cadence_sdhci_realize(DeviceState *dev, Error **errp)
{
CadenceSDHCIState *s = CADENCE_SDHCI(dev);
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
SysBusDevice *sbd_sdhci = SYS_BUS_DEVICE(&s->sdhci);
memory_region_init(&s->container, OBJECT(s),
"cadence.sdhci-container", 0x1000);
sysbus_init_mmio(sbd, &s->container);
memory_region_init_io(&s->iomem, OBJECT(s), &cadence_sdhci_ops,
s, TYPE_CADENCE_SDHCI, CADENCE_SDHCI_REG_SIZE);
memory_region_add_subregion(&s->container, 0, &s->iomem);
sysbus_realize(sbd_sdhci, errp);
memory_region_add_subregion(&s->container, CADENCE_SDHCI_SRS_BASE,
sysbus_mmio_get_region(sbd_sdhci, 0));
/* propagate irq and "sd-bus" from generic-sdhci */
sysbus_pass_irq(sbd, sbd_sdhci);
s->bus = qdev_get_child_bus(DEVICE(sbd_sdhci), "sd-bus");
}
static const VMStateDescription vmstate_cadence_sdhci = {
.name = TYPE_CADENCE_SDHCI,
.version_id = 1,
.fields = (VMStateField[]) {
VMSTATE_UINT32_ARRAY(regs, CadenceSDHCIState, CADENCE_SDHCI_NUM_REGS),
VMSTATE_END_OF_LIST(),
},
};
static void cadence_sdhci_class_init(ObjectClass *classp, void *data)
{
DeviceClass *dc = DEVICE_CLASS(classp);
dc->desc = "Cadence SD/SDIO/eMMC Host Controller (SD4HC)";
dc->realize = cadence_sdhci_realize;
dc->reset = cadence_sdhci_reset;
dc->vmsd = &vmstate_cadence_sdhci;
}
static TypeInfo cadence_sdhci_info = {
.name = TYPE_CADENCE_SDHCI,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(CadenceSDHCIState),
.instance_init = cadence_sdhci_instance_init,
.class_init = cadence_sdhci_class_init,
};
static void cadence_sdhci_register_types(void)
{
type_register_static(&cadence_sdhci_info);
}
type_init(cadence_sdhci_register_types)

View File

@ -10,3 +10,4 @@ softmmu_ss.add(when: 'CONFIG_PXA2XX', if_true: files('pxa2xx_mmci.c'))
softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c')) softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files('bcm2835_sdhost.c'))
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c')) softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_sdhci.c'))
softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c')) softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sdhost.c'))
softmmu_ss.add(when: 'CONFIG_CADENCE_SDHCI', if_true: files('cadence_sdhci.c'))

View File

@ -0,0 +1,61 @@
/*
* Microchip PolarFire SoC MMUART emulation
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef HW_MCHP_PFSOC_MMUART_H
#define HW_MCHP_PFSOC_MMUART_H
#include "hw/char/serial.h"
#define MCHP_PFSOC_MMUART_REG_SIZE 52
typedef struct MchpPfSoCMMUartState {
MemoryRegion iomem;
hwaddr base;
qemu_irq irq;
SerialMM *serial;
uint32_t reg[MCHP_PFSOC_MMUART_REG_SIZE / sizeof(uint32_t)];
} MchpPfSoCMMUartState;
/**
* mchp_pfsoc_mmuart_create - Create a Microchip PolarFire SoC MMUART
*
* This is a helper routine for board to create a MMUART device that is
* compatible with Microchip PolarFire SoC.
*
* @sysmem: system memory region to map
* @base: base address of the MMUART registers
* @irq: IRQ number of the MMUART device
* @chr: character device to associate to
*
* @return: a pointer to the device specific control structure
*/
MchpPfSoCMMUartState *mchp_pfsoc_mmuart_create(MemoryRegion *sysmem,
hwaddr base, qemu_irq irq, Chardev *chr);
#endif /* HW_MCHP_PFSOC_MMUART_H */

View File

@ -0,0 +1,57 @@
/*
* SiFive Platform DMA emulation
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef SIFIVE_PDMA_H
#define SIFIVE_PDMA_H
struct sifive_pdma_chan {
uint32_t control;
uint32_t next_config;
uint64_t next_bytes;
uint64_t next_dst;
uint64_t next_src;
uint32_t exec_config;
uint64_t exec_bytes;
uint64_t exec_dst;
uint64_t exec_src;
int state;
};
#define SIFIVE_PDMA_CHANS 4
#define SIFIVE_PDMA_IRQS (SIFIVE_PDMA_CHANS * 2)
#define SIFIVE_PDMA_REG_SIZE 0x100000
#define SIFIVE_PDMA_CHAN_NO(reg) ((reg & (SIFIVE_PDMA_REG_SIZE - 1)) >> 12)
typedef struct SiFivePDMAState {
SysBusDevice parent;
MemoryRegion iomem;
qemu_irq irq[SIFIVE_PDMA_IRQS];
struct sifive_pdma_chan chan[SIFIVE_PDMA_CHANS];
} SiFivePDMAState;
#define TYPE_SIFIVE_PDMA "sifive.pdma"
#define SIFIVE_PDMA(obj) \
OBJECT_CHECK(SiFivePDMAState, (obj), TYPE_SIFIVE_PDMA)
#endif /* SIFIVE_PDMA_H */

View File

@ -39,11 +39,13 @@ typedef struct SiFiveCLINTState {
uint32_t timecmp_base; uint32_t timecmp_base;
uint32_t time_base; uint32_t time_base;
uint32_t aperture_size; uint32_t aperture_size;
uint32_t timebase_freq;
} SiFiveCLINTState; } SiFiveCLINTState;
DeviceState *sifive_clint_create(hwaddr addr, hwaddr size, DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base, uint32_t hartid_base, uint32_t num_harts, uint32_t sip_base,
uint32_t timecmp_base, uint32_t time_base, bool provide_rdtime); uint32_t timecmp_base, uint32_t time_base, uint32_t timebase_freq,
bool provide_rdtime);
enum { enum {
SIFIVE_SIP_BASE = 0x0, SIFIVE_SIP_BASE = 0x0,

View File

@ -76,6 +76,8 @@ struct CadenceGEMState {
/* Mask of register bits which are write 1 to clear */ /* Mask of register bits which are write 1 to clear */
uint32_t regs_w1c[CADENCE_GEM_MAXREG]; uint32_t regs_w1c[CADENCE_GEM_MAXREG];
/* PHY address */
uint8_t phy_addr;
/* PHY registers backing store */ /* PHY registers backing store */
uint16_t phy_regs[32]; uint16_t phy_regs[32];

View File

@ -0,0 +1,133 @@
/*
* Microchip PolarFire SoC machine interface
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef HW_MICROCHIP_PFSOC_H
#define HW_MICROCHIP_PFSOC_H
#include "hw/char/mchp_pfsoc_mmuart.h"
#include "hw/dma/sifive_pdma.h"
#include "hw/net/cadence_gem.h"
#include "hw/sd/cadence_sdhci.h"
typedef struct MicrochipPFSoCState {
/*< private >*/
DeviceState parent_obj;
/*< public >*/
CPUClusterState e_cluster;
CPUClusterState u_cluster;
RISCVHartArrayState e_cpus;
RISCVHartArrayState u_cpus;
DeviceState *plic;
MchpPfSoCMMUartState *serial0;
MchpPfSoCMMUartState *serial1;
MchpPfSoCMMUartState *serial2;
MchpPfSoCMMUartState *serial3;
MchpPfSoCMMUartState *serial4;
SiFivePDMAState dma;
CadenceGEMState gem0;
CadenceGEMState gem1;
CadenceSDHCIState sdhci;
} MicrochipPFSoCState;
#define TYPE_MICROCHIP_PFSOC "microchip.pfsoc"
#define MICROCHIP_PFSOC(obj) \
OBJECT_CHECK(MicrochipPFSoCState, (obj), TYPE_MICROCHIP_PFSOC)
typedef struct MicrochipIcicleKitState {
/*< private >*/
MachineState parent_obj;
/*< public >*/
MicrochipPFSoCState soc;
} MicrochipIcicleKitState;
#define TYPE_MICROCHIP_ICICLE_KIT_MACHINE \
MACHINE_TYPE_NAME("microchip-icicle-kit")
#define MICROCHIP_ICICLE_KIT_MACHINE(obj) \
OBJECT_CHECK(MicrochipIcicleKitState, (obj), \
TYPE_MICROCHIP_ICICLE_KIT_MACHINE)
enum {
MICROCHIP_PFSOC_DEBUG,
MICROCHIP_PFSOC_E51_DTIM,
MICROCHIP_PFSOC_BUSERR_UNIT0,
MICROCHIP_PFSOC_BUSERR_UNIT1,
MICROCHIP_PFSOC_BUSERR_UNIT2,
MICROCHIP_PFSOC_BUSERR_UNIT3,
MICROCHIP_PFSOC_BUSERR_UNIT4,
MICROCHIP_PFSOC_CLINT,
MICROCHIP_PFSOC_L2CC,
MICROCHIP_PFSOC_DMA,
MICROCHIP_PFSOC_L2LIM,
MICROCHIP_PFSOC_PLIC,
MICROCHIP_PFSOC_MMUART0,
MICROCHIP_PFSOC_SYSREG,
MICROCHIP_PFSOC_MPUCFG,
MICROCHIP_PFSOC_EMMC_SD,
MICROCHIP_PFSOC_MMUART1,
MICROCHIP_PFSOC_MMUART2,
MICROCHIP_PFSOC_MMUART3,
MICROCHIP_PFSOC_MMUART4,
MICROCHIP_PFSOC_GEM0,
MICROCHIP_PFSOC_GEM1,
MICROCHIP_PFSOC_GPIO0,
MICROCHIP_PFSOC_GPIO1,
MICROCHIP_PFSOC_GPIO2,
MICROCHIP_PFSOC_ENVM_CFG,
MICROCHIP_PFSOC_ENVM_DATA,
MICROCHIP_PFSOC_IOSCB_CFG,
MICROCHIP_PFSOC_DRAM,
};
enum {
MICROCHIP_PFSOC_DMA_IRQ0 = 5,
MICROCHIP_PFSOC_DMA_IRQ1 = 6,
MICROCHIP_PFSOC_DMA_IRQ2 = 7,
MICROCHIP_PFSOC_DMA_IRQ3 = 8,
MICROCHIP_PFSOC_DMA_IRQ4 = 9,
MICROCHIP_PFSOC_DMA_IRQ5 = 10,
MICROCHIP_PFSOC_DMA_IRQ6 = 11,
MICROCHIP_PFSOC_DMA_IRQ7 = 12,
MICROCHIP_PFSOC_GEM0_IRQ = 64,
MICROCHIP_PFSOC_GEM1_IRQ = 70,
MICROCHIP_PFSOC_EMMC_SD_IRQ = 88,
MICROCHIP_PFSOC_MMUART0_IRQ = 90,
MICROCHIP_PFSOC_MMUART1_IRQ = 91,
MICROCHIP_PFSOC_MMUART2_IRQ = 92,
MICROCHIP_PFSOC_MMUART3_IRQ = 93,
MICROCHIP_PFSOC_MMUART4_IRQ = 94,
};
#define MICROCHIP_PFSOC_MANAGEMENT_CPU_COUNT 1
#define MICROCHIP_PFSOC_COMPUTE_CPU_COUNT 4
#define MICROCHIP_PFSOC_PLIC_HART_CONFIG "MS"
#define MICROCHIP_PFSOC_PLIC_NUM_SOURCES 185
#define MICROCHIP_PFSOC_PLIC_NUM_PRIORITIES 7
#define MICROCHIP_PFSOC_PLIC_PRIORITY_BASE 0x04
#define MICROCHIP_PFSOC_PLIC_PENDING_BASE 0x1000
#define MICROCHIP_PFSOC_PLIC_ENABLE_BASE 0x2000
#define MICROCHIP_PFSOC_PLIC_ENABLE_STRIDE 0x80
#define MICROCHIP_PFSOC_PLIC_CONTEXT_BASE 0x200000
#define MICROCHIP_PFSOC_PLIC_CONTEXT_STRIDE 0x1000
#endif /* HW_MICROCHIP_PFSOC_H */

View File

@ -39,6 +39,7 @@ struct RISCVHartArrayState {
uint32_t num_harts; uint32_t num_harts;
uint32_t hartid_base; uint32_t hartid_base;
char *cpu_type; char *cpu_type;
uint64_t resetvec;
RISCVCPU *harts; RISCVCPU *harts;
}; };

View File

@ -21,7 +21,7 @@
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_cpu.h" #include "hw/riscv/sifive_cpu.h"
#include "hw/riscv/sifive_gpio.h" #include "hw/gpio/sifive_gpio.h"
#define TYPE_RISCV_E_SOC "riscv.sifive.e.soc" #define TYPE_RISCV_E_SOC "riscv.sifive.e.soc"
#define RISCV_E_SOC(obj) \ #define RISCV_E_SOC(obj) \

View File

@ -19,12 +19,13 @@
#ifndef HW_SIFIVE_U_H #ifndef HW_SIFIVE_U_H
#define HW_SIFIVE_U_H #define HW_SIFIVE_U_H
#include "hw/dma/sifive_pdma.h"
#include "hw/net/cadence_gem.h" #include "hw/net/cadence_gem.h"
#include "hw/riscv/riscv_hart.h" #include "hw/riscv/riscv_hart.h"
#include "hw/riscv/sifive_cpu.h" #include "hw/riscv/sifive_cpu.h"
#include "hw/riscv/sifive_gpio.h" #include "hw/gpio/sifive_gpio.h"
#include "hw/riscv/sifive_u_prci.h" #include "hw/misc/sifive_u_otp.h"
#include "hw/riscv/sifive_u_otp.h" #include "hw/misc/sifive_u_prci.h"
#define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc"
#define RISCV_U_SOC(obj) \ #define RISCV_U_SOC(obj) \
@ -43,6 +44,7 @@ typedef struct SiFiveUSoCState {
SiFiveUPRCIState prci; SiFiveUPRCIState prci;
SIFIVEGPIOState gpio; SIFIVEGPIOState gpio;
SiFiveUOTPState otp; SiFiveUOTPState otp;
SiFivePDMAState dma;
CadenceGEMState gem; CadenceGEMState gem;
uint32_t serial; uint32_t serial;
@ -72,6 +74,7 @@ enum {
SIFIVE_U_MROM, SIFIVE_U_MROM,
SIFIVE_U_CLINT, SIFIVE_U_CLINT,
SIFIVE_U_L2CC, SIFIVE_U_L2CC,
SIFIVE_U_PDMA,
SIFIVE_U_L2LIM, SIFIVE_U_L2LIM,
SIFIVE_U_PLIC, SIFIVE_U_PLIC,
SIFIVE_U_PRCI, SIFIVE_U_PRCI,
@ -108,6 +111,14 @@ enum {
SIFIVE_U_GPIO_IRQ13 = 20, SIFIVE_U_GPIO_IRQ13 = 20,
SIFIVE_U_GPIO_IRQ14 = 21, SIFIVE_U_GPIO_IRQ14 = 21,
SIFIVE_U_GPIO_IRQ15 = 22, SIFIVE_U_GPIO_IRQ15 = 22,
SIFIVE_U_PDMA_IRQ0 = 23,
SIFIVE_U_PDMA_IRQ1 = 24,
SIFIVE_U_PDMA_IRQ2 = 25,
SIFIVE_U_PDMA_IRQ3 = 26,
SIFIVE_U_PDMA_IRQ4 = 27,
SIFIVE_U_PDMA_IRQ5 = 28,
SIFIVE_U_PDMA_IRQ6 = 29,
SIFIVE_U_PDMA_IRQ7 = 30,
SIFIVE_U_GEM_IRQ = 0x35 SIFIVE_U_GEM_IRQ = 0x35
}; };

View File

@ -0,0 +1,47 @@
/*
* Cadence SDHCI emulation
*
* Copyright (c) 2020 Wind River Systems, Inc.
*
* Author:
* Bin Meng <bin.meng@windriver.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 or
* (at your option) version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef CADENCE_SDHCI_H
#define CADENCE_SDHCI_H
#include "hw/sd/sdhci.h"
#define CADENCE_SDHCI_REG_SIZE 0x100
#define CADENCE_SDHCI_NUM_REGS (CADENCE_SDHCI_REG_SIZE / sizeof(uint32_t))
typedef struct CadenceSDHCIState {
SysBusDevice parent;
MemoryRegion container;
MemoryRegion iomem;
BusState *bus;
uint32_t regs[CADENCE_SDHCI_NUM_REGS];
SDHCIState sdhci;
} CadenceSDHCIState;
#define TYPE_CADENCE_SDHCI "cadence.sdhci"
#define CADENCE_SDHCI(obj) OBJECT_CHECK(CadenceSDHCIState, (obj), \
TYPE_CADENCE_SDHCI)
#endif /* CADENCE_SDHCI_H */

View File

@ -773,7 +773,6 @@ if have_system
'hw/watchdog', 'hw/watchdog',
'hw/xen', 'hw/xen',
'hw/gpio', 'hw/gpio',
'hw/riscv',
'migration', 'migration',
'net', 'net',
'softmmu', 'softmmu',

View File

@ -96,6 +96,17 @@ const char * const riscv_intr_names[] = {
"reserved" "reserved"
}; };
const char *riscv_cpu_get_trap_name(target_ulong cause, bool async)
{
if (async) {
return (cause < ARRAY_SIZE(riscv_intr_names)) ?
riscv_intr_names[cause] : "(unknown)";
} else {
return (cause < ARRAY_SIZE(riscv_excp_names)) ?
riscv_excp_names[cause] : "(unknown)";
}
}
static void set_misa(CPURISCVState *env, target_ulong misa) static void set_misa(CPURISCVState *env, target_ulong misa)
{ {
env->misa_mask = env->misa = misa; env->misa_mask = env->misa = misa;
@ -128,7 +139,6 @@ static void riscv_any_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU); set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_11_0); set_priv_version(env, PRIV_VERSION_1_11_0);
set_resetvec(env, DEFAULT_RSTVEC);
} }
static void riscv_base_cpu_init(Object *obj) static void riscv_base_cpu_init(Object *obj)
@ -136,7 +146,6 @@ static void riscv_base_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
/* We set this in the realise function */ /* We set this in the realise function */
set_misa(env, 0); set_misa(env, 0);
set_resetvec(env, DEFAULT_RSTVEC);
} }
static void rvxx_sifive_u_cpu_init(Object *obj) static void rvxx_sifive_u_cpu_init(Object *obj)
@ -144,7 +153,6 @@ static void rvxx_sifive_u_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU); set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0); set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, 0x1004);
} }
static void rvxx_sifive_e_cpu_init(Object *obj) static void rvxx_sifive_e_cpu_init(Object *obj)
@ -152,7 +160,6 @@ static void rvxx_sifive_e_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RVXLEN | RVI | RVM | RVA | RVC | RVU); set_misa(env, RVXLEN | RVI | RVM | RVA | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0); set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, 0x1004);
qdev_prop_set_bit(DEVICE(obj), "mmu", false); qdev_prop_set_bit(DEVICE(obj), "mmu", false);
} }
@ -163,7 +170,6 @@ static void rv32_ibex_cpu_init(Object *obj)
CPURISCVState *env = &RISCV_CPU(obj)->env; CPURISCVState *env = &RISCV_CPU(obj)->env;
set_misa(env, RV32 | RVI | RVM | RVC | RVU); set_misa(env, RV32 | RVI | RVM | RVC | RVU);
set_priv_version(env, PRIV_VERSION_1_10_0); set_priv_version(env, PRIV_VERSION_1_10_0);
set_resetvec(env, 0x8090);
qdev_prop_set_bit(DEVICE(obj), "mmu", false); qdev_prop_set_bit(DEVICE(obj), "mmu", false);
} }
@ -373,6 +379,8 @@ static void riscv_cpu_realize(DeviceState *dev, Error **errp)
set_feature(env, RISCV_FEATURE_PMP); set_feature(env, RISCV_FEATURE_PMP);
} }
set_resetvec(env, cpu->cfg.resetvec);
/* If misa isn't set (rv32 and rv64 machines) set it here */ /* If misa isn't set (rv32 and rv64 machines) set it here */
if (!env->misa) { if (!env->misa) {
/* Do some ISA extension error checking */ /* Do some ISA extension error checking */
@ -518,6 +526,7 @@ static Property riscv_cpu_properties[] = {
DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64), DEFINE_PROP_UINT16("elen", RISCVCPU, cfg.elen, 64),
DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true), DEFINE_PROP_BOOL("mmu", RISCVCPU, cfg.mmu, true),
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true), DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
DEFINE_PROP_END_OF_LIST(), DEFINE_PROP_END_OF_LIST(),
}; };

View File

@ -220,7 +220,8 @@ struct CPURISCVState {
pmp_table_t pmp_state; pmp_table_t pmp_state;
/* machine specific rdtime callback */ /* machine specific rdtime callback */
uint64_t (*rdtime_fn)(void); uint64_t (*rdtime_fn)(uint32_t);
uint32_t rdtime_fn_arg;
/* True if in debugger mode. */ /* True if in debugger mode. */
bool debugger; bool debugger;
@ -288,6 +289,7 @@ struct RISCVCPU {
uint16_t elen; uint16_t elen;
bool mmu; bool mmu;
bool pmp; bool pmp;
uint64_t resetvec;
} cfg; } cfg;
}; };
@ -309,6 +311,7 @@ extern const char * const riscv_fpr_regnames[];
extern const char * const riscv_excp_names[]; extern const char * const riscv_excp_names[];
extern const char * const riscv_intr_names[]; extern const char * const riscv_intr_names[];
const char *riscv_cpu_get_trap_name(target_ulong cause, bool async);
void riscv_cpu_do_interrupt(CPUState *cpu); void riscv_cpu_do_interrupt(CPUState *cpu);
int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg); int riscv_cpu_gdb_read_register(CPUState *cpu, GByteArray *buf, int reg);
int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg); int riscv_cpu_gdb_write_register(CPUState *cpu, uint8_t *buf, int reg);
@ -345,7 +348,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts); int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value); uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value);
#define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */ #define BOOL_TO_MASK(x) (-!!(x)) /* helper for riscv_cpu_update_mip value */
void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void)); void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
uint32_t arg);
#endif #endif
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv); void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);

View File

@ -276,9 +276,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
return old; return old;
} }
void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(void)) void riscv_cpu_set_rdtime_fn(CPURISCVState *env, uint64_t (*fn)(uint32_t),
uint32_t arg)
{ {
env->rdtime_fn = fn; env->rdtime_fn = fn;
env->rdtime_fn_arg = arg;
} }
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv) void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv)
@ -892,8 +894,8 @@ void riscv_cpu_do_interrupt(CPUState *cs)
} }
} }
trace_riscv_trap(env->mhartid, async, cause, env->pc, tval, cause < 23 ? trace_riscv_trap(env->mhartid, async, cause, env->pc, tval,
(async ? riscv_intr_names : riscv_excp_names)[cause] : "(unknown)"); riscv_cpu_get_trap_name(cause, async));
if (env->priv <= PRV_S && if (env->priv <= PRV_S &&
cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) { cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {

View File

@ -351,7 +351,7 @@ static int read_time(CPURISCVState *env, int csrno, target_ulong *val)
return -RISCV_EXCP_ILLEGAL_INST; return -RISCV_EXCP_ILLEGAL_INST;
} }
*val = env->rdtime_fn() + delta; *val = env->rdtime_fn(env->rdtime_fn_arg) + delta;
return 0; return 0;
} }
@ -364,7 +364,7 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
return -RISCV_EXCP_ILLEGAL_INST; return -RISCV_EXCP_ILLEGAL_INST;
} }
*val = (env->rdtime_fn() + delta) >> 32; *val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32;
return 0; return 0;
} }
#endif #endif