mirror of https://gitee.com/openkylin/qemu.git
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:
commit
f00f57f344
|
@ -1316,6 +1316,15 @@ F: include/hw/riscv/opentitan.h
|
|||
F: include/hw/char/ibex_uart.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-gdbsim
|
||||
|
|
|
@ -10,3 +10,4 @@ CONFIG_SPIKE=y
|
|||
CONFIG_SIFIVE_E=y
|
||||
CONFIG_SIFIVE_U=y
|
||||
CONFIG_RISCV_VIRT=y
|
||||
CONFIG_MICROCHIP_PFSOC=y
|
||||
|
|
|
@ -121,6 +121,7 @@ static void gem_init(NICInfo *nd, uint32_t base, qemu_irq irq)
|
|||
qemu_check_nic_model(nd, TYPE_CADENCE_GEM);
|
||||
qdev_set_nic_properties(dev, nd);
|
||||
}
|
||||
object_property_set_int(OBJECT(dev), "phy-addr", 23, &error_abort);
|
||||
s = SYS_BUS_DEVICE(dev);
|
||||
sysbus_realize_and_unref(s, &error_fatal);
|
||||
sysbus_mmio_map(s, 0, base);
|
||||
|
|
|
@ -165,6 +165,7 @@ static void versal_create_gems(Versal *s, qemu_irq *pic)
|
|||
qemu_check_nic_model(nd, "cadence_gem");
|
||||
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,
|
||||
&error_abort);
|
||||
object_property_set_link(OBJECT(dev), "dma", OBJECT(&s->mr_ps),
|
||||
|
|
|
@ -460,6 +460,8 @@ static void xlnx_zynqmp_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
object_property_set_int(OBJECT(&s->gem[i]), "revision", GEM_REVISION,
|
||||
&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,
|
||||
&error_abort);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->gem[i]), errp)) {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
config ESCC
|
||||
bool
|
||||
|
||||
config HTIF
|
||||
bool
|
||||
|
||||
config PARALLEL
|
||||
bool
|
||||
default y
|
||||
|
@ -52,3 +55,9 @@ config RENESAS_SCI
|
|||
|
||||
config AVR_USART
|
||||
bool
|
||||
|
||||
config MCHP_PFSOC_MMUART
|
||||
bool
|
||||
|
||||
config SIFIVE_UART
|
||||
bool
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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_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_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_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_VIRTIO', if_true: files('virtio-serial-bus.c'))
|
||||
specific_ss.add(when: 'CONFIG_PSERIES', if_true: files('spapr_vty.c'))
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "hw/char/riscv_htif.h"
|
||||
#include "hw/char/serial.h"
|
||||
#include "chardev/char.h"
|
||||
#include "chardev/char-fe.h"
|
||||
#include "hw/riscv/riscv_htif.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/error-report.h"
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
#include "chardev/char-fe.h"
|
||||
#include "hw/hw.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/riscv/sifive_uart.h"
|
||||
#include "hw/char/sifive_uart.h"
|
||||
|
||||
/*
|
||||
* Not yet implemented:
|
|
@ -20,3 +20,6 @@ config ZYNQ_DEVCFG
|
|||
|
||||
config STP2000
|
||||
bool
|
||||
|
||||
config SIFIVE_PDMA
|
||||
bool
|
||||
|
|
|
@ -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_PXA2XX', if_true: files('pxa2xx_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'))
|
||||
|
|
|
@ -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)
|
|
@ -7,3 +7,6 @@ config PL061
|
|||
|
||||
config GPIO_KEY
|
||||
bool
|
||||
|
||||
config SIFIVE_GPIO
|
||||
bool
|
||||
|
|
|
@ -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_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_SIFIVE_GPIO', if_true: files('sifive_gpio.c'))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/riscv/sifive_gpio.h"
|
||||
#include "hw/gpio/sifive_gpio.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
|
@ -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_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
|
||||
|
||||
# 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
|
||||
|
|
|
@ -67,3 +67,9 @@ config RX_ICU
|
|||
|
||||
config LOONGSON_LIOINTC
|
||||
bool
|
||||
|
||||
config SIFIVE_CLINT
|
||||
bool
|
||||
|
||||
config SIFIVE_PLIC
|
||||
bool
|
||||
|
|
|
@ -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_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_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_KVM', if_true: files('xics_kvm.c'))
|
||||
specific_ss.add(when: 'CONFIG_XICS_SPAPR', if_true: files('xics_spapr.c'))
|
||||
|
|
|
@ -26,25 +26,26 @@
|
|||
#include "hw/sysbus.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/riscv/sifive_clint.h"
|
||||
#include "hw/intc/sifive_clint.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),
|
||||
SIFIVE_CLINT_TIMEBASE_FREQ, NANOSECONDS_PER_SECOND);
|
||||
timebase_freq, NANOSECONDS_PER_SECOND);
|
||||
}
|
||||
|
||||
/*
|
||||
* Called when timecmp is written to update the QEMU timer or immediately
|
||||
* 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 diff;
|
||||
|
||||
uint64_t rtc_r = cpu_riscv_read_rtc();
|
||||
uint64_t rtc_r = cpu_riscv_read_rtc(timebase_freq);
|
||||
|
||||
cpu->env.timecmp = value;
|
||||
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;
|
||||
/* back to ns (note args switched in muldiv64) */
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -112,10 +113,10 @@ static uint64_t sifive_clint_read(void *opaque, hwaddr addr, unsigned size)
|
|||
}
|
||||
} else if (addr == clint->time_base) {
|
||||
/* time_lo */
|
||||
return cpu_riscv_read_rtc() & 0xFFFFFFFF;
|
||||
return cpu_riscv_read_rtc(clint->timebase_freq) & 0xFFFFFFFF;
|
||||
} else if (addr == clint->time_base + 4) {
|
||||
/* 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);
|
||||
|
@ -153,13 +154,13 @@ static void sifive_clint_write(void *opaque, hwaddr addr, uint64_t value,
|
|||
/* timecmp_lo */
|
||||
uint64_t timecmp_hi = env->timecmp >> 32;
|
||||
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
||||
timecmp_hi << 32 | (value & 0xFFFFFFFF));
|
||||
timecmp_hi << 32 | (value & 0xFFFFFFFF), clint->timebase_freq);
|
||||
return;
|
||||
} else if ((addr & 0x7) == 4) {
|
||||
/* timecmp_hi */
|
||||
uint64_t timecmp_lo = env->timecmp;
|
||||
sifive_clint_write_timecmp(RISCV_CPU(cpu),
|
||||
value << 32 | (timecmp_lo & 0xFFFFFFFF));
|
||||
value << 32 | (timecmp_lo & 0xFFFFFFFF), clint->timebase_freq);
|
||||
} else {
|
||||
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("time-base", SiFiveCLINTState, time_base, 0),
|
||||
DEFINE_PROP_UINT32("aperture-size", SiFiveCLINTState, aperture_size, 0),
|
||||
DEFINE_PROP_UINT32("timebase-freq", SiFiveCLINTState, timebase_freq, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -232,7 +234,8 @@ type_init(sifive_clint_register_types)
|
|||
*/
|
||||
DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
|
||||
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;
|
||||
for (i = 0; i < num_harts; i++) {
|
||||
|
@ -242,7 +245,7 @@ DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
|
|||
continue;
|
||||
}
|
||||
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,
|
||||
&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, "time-base", time_base);
|
||||
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_mmio_map(SYS_BUS_DEVICE(dev), 0, addr);
|
||||
return dev;
|
|
@ -27,9 +27,9 @@
|
|||
#include "hw/pci/msi.h"
|
||||
#include "hw/boards.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/intc/sifive_plic.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "hw/riscv/sifive_plic.h"
|
||||
|
||||
#define RISCV_DEBUG_PLIC 0
|
||||
|
|
@ -134,4 +134,16 @@ config MAC_VIA
|
|||
config AVR_POWER
|
||||
bool
|
||||
|
||||
config SIFIVE_TEST
|
||||
bool
|
||||
|
||||
config SIFIVE_E_PRCI
|
||||
bool
|
||||
|
||||
config SIFIVE_U_OTP
|
||||
bool
|
||||
|
||||
config SIFIVE_U_PRCI
|
||||
bool
|
||||
|
||||
source macio/Kconfig
|
||||
|
|
|
@ -21,6 +21,12 @@ softmmu_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c'))
|
|||
# Mac devices
|
||||
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
|
||||
softmmu_ss.add(when: 'CONFIG_PUV3', if_true: files('puv3_pm.c'))
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "qemu/log.h"
|
||||
#include "qemu/module.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)
|
||||
{
|
|
@ -25,7 +25,7 @@
|
|||
#include "qemu/module.h"
|
||||
#include "sysemu/runstate.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)
|
||||
{
|
||||
|
@ -59,7 +59,7 @@ static const MemoryRegionOps sifive_test_ops = {
|
|||
.write = sifive_test_write,
|
||||
.endianness = DEVICE_NATIVE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.min_access_size = 2,
|
||||
.max_access_size = 4
|
||||
}
|
||||
};
|
|
@ -23,7 +23,7 @@
|
|||
#include "hw/sysbus.h"
|
||||
#include "qemu/log.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)
|
||||
{
|
|
@ -22,7 +22,7 @@
|
|||
#include "hw/sysbus.h"
|
||||
#include "qemu/log.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)
|
||||
{
|
|
@ -250,7 +250,7 @@
|
|||
#define GEM_PHYMNTNC_REG_SHIFT 18
|
||||
|
||||
/* 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_STATUS 1
|
||||
|
@ -1446,7 +1446,7 @@ static uint64_t gem_read(void *opaque, hwaddr offset, unsigned size)
|
|||
uint32_t phy_addr, reg_num;
|
||||
|
||||
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;
|
||||
retval &= 0xFFFF0000;
|
||||
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;
|
||||
|
||||
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;
|
||||
gem_phy_write(s, reg_num, val);
|
||||
}
|
||||
|
@ -1682,6 +1682,7 @@ static Property gem_properties[] = {
|
|||
DEFINE_NIC_PROPERTIES(CadenceGEMState, conf),
|
||||
DEFINE_PROP_UINT32("revision", CadenceGEMState, revision,
|
||||
GEM_MODID_VALUE),
|
||||
DEFINE_PROP_UINT8("phy-addr", CadenceGEMState, phy_addr, BOARD_PHY_ADDRESS),
|
||||
DEFINE_PROP_UINT8("num-priority-queues", CadenceGEMState,
|
||||
num_priority_queues, 1),
|
||||
DEFINE_PROP_UINT8("num-type1-screeners", CadenceGEMState,
|
||||
|
|
|
@ -1,50 +1,62 @@
|
|||
config HTIF
|
||||
bool
|
||||
|
||||
config HART
|
||||
bool
|
||||
|
||||
config IBEX
|
||||
bool
|
||||
|
||||
config SIFIVE
|
||||
config MICROCHIP_PFSOC
|
||||
bool
|
||||
select CADENCE_SDHCI
|
||||
select MCHP_PFSOC_MMUART
|
||||
select MSI_NONBROKEN
|
||||
|
||||
config SIFIVE_E
|
||||
bool
|
||||
select HART
|
||||
select SIFIVE
|
||||
select SIFIVE_CLINT
|
||||
select SIFIVE_PDMA
|
||||
select SIFIVE_PLIC
|
||||
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
|
||||
bool
|
||||
select IBEX
|
||||
select HART
|
||||
select UNIMP
|
||||
|
||||
config RISCV_VIRT
|
||||
bool
|
||||
imply PCI_DEVICES
|
||||
imply TEST_DEVICES
|
||||
select PCI
|
||||
select HART
|
||||
select SERIAL
|
||||
select GOLDFISH_RTC
|
||||
select VIRTIO_MMIO
|
||||
select MSI_NONBROKEN
|
||||
select PCI
|
||||
select PCI_EXPRESS_GENERIC_BRIDGE
|
||||
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
|
||||
|
|
|
@ -1,20 +1,12 @@
|
|||
riscv_ss = ss.source_set()
|
||||
riscv_ss.add(files('boot.c'), fdt)
|
||||
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_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_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_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_MICROCHIP_PFSOC', if_true: files('microchip_pfsoc.c'))
|
||||
|
||||
hw_arch += {'riscv': riscv_ss}
|
||||
|
|
|
@ -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(µchip_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(µchip_icicle_kit_machine_typeinfo);
|
||||
}
|
||||
|
||||
type_init(microchip_icicle_kit_machine_init_register_types)
|
|
@ -111,6 +111,7 @@ static void lowrisc_ibex_soc_realize(DeviceState *dev_soc, Error **errp)
|
|||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x8090, &error_abort);
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->cpus), &error_abort);
|
||||
|
||||
/* Boot ROM */
|
||||
|
|
|
@ -31,6 +31,8 @@ static Property riscv_harts_props[] = {
|
|||
DEFINE_PROP_UINT32("num-harts", RISCVHartArrayState, num_harts, 1),
|
||||
DEFINE_PROP_UINT32("hartid-base", RISCVHartArrayState, hartid_base, 0),
|
||||
DEFINE_PROP_STRING("cpu-type", RISCVHartArrayState, cpu_type),
|
||||
DEFINE_PROP_UINT64("resetvec", RISCVHartArrayState, resetvec,
|
||||
DEFAULT_RSTVEC),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
@ -44,6 +46,7 @@ static bool riscv_hart_realize(RISCVHartArrayState *s, int idx,
|
|||
char *cpu_type, Error **errp)
|
||||
{
|
||||
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;
|
||||
qemu_register_reset(riscv_harts_cpu_reset, &s->harts[idx]);
|
||||
return qdev_realize(DEVICE(&s->harts[idx]), NULL, errp);
|
||||
|
|
|
@ -39,12 +39,12 @@
|
|||
#include "hw/misc/unimp.h"
|
||||
#include "target/riscv/cpu.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_prci.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 "sysemu/arch_init.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_property_set_int(OBJECT(&s->cpus), "num-harts", ms->smp.cpus,
|
||||
&error_abort);
|
||||
object_property_set_int(OBJECT(&s->cpus), "resetvec", 0x1004, &error_abort);
|
||||
object_initialize_child(obj, "riscv.sifive.e.gpio0", &s->gpio,
|
||||
TYPE_SIFIVE_GPIO);
|
||||
}
|
||||
|
@ -212,7 +213,8 @@ static void sifive_e_soc_realize(DeviceState *dev, Error **errp)
|
|||
memmap[SIFIVE_E_PLIC].size);
|
||||
sifive_clint_create(memmap[SIFIVE_E_CLINT].base,
|
||||
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",
|
||||
memmap[SIFIVE_E_AON].base, memmap[SIFIVE_E_AON].size);
|
||||
sifive_e_prci_create(memmap[SIFIVE_E_PRCI].base);
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
* 4) GPIO (General Purpose Input/Output Controller)
|
||||
* 5) OTP (One-Time Programmable) memory with stored serial number
|
||||
* 6) GEM (Gigabit Ethernet Controller) and management block
|
||||
* 7) DMA (Direct Memory Access Controller)
|
||||
*
|
||||
* This board currently generates devicetree dynamically that indicates at least
|
||||
* two harts and up to five harts.
|
||||
|
@ -45,11 +46,11 @@
|
|||
#include "hw/misc/unimp.h"
|
||||
#include "target/riscv/cpu.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/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 "net/eth.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
|
@ -73,6 +74,7 @@ static const struct MemmapEntry {
|
|||
[SIFIVE_U_MROM] = { 0x1000, 0xf000 },
|
||||
[SIFIVE_U_CLINT] = { 0x2000000, 0x10000 },
|
||||
[SIFIVE_U_L2CC] = { 0x2010000, 0x1000 },
|
||||
[SIFIVE_U_PDMA] = { 0x3000000, 0x100000 },
|
||||
[SIFIVE_U_L2LIM] = { 0x8000000, 0x2000000 },
|
||||
[SIFIVE_U_PLIC] = { 0xc000000, 0x4000000 },
|
||||
[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");
|
||||
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",
|
||||
(long)memmap[SIFIVE_U_L2CC].base);
|
||||
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), "hartid-base", 0);
|
||||
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);
|
||||
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), "hartid-base", 1);
|
||||
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, "otp", &s->otp, TYPE_SIFIVE_U_OTP);
|
||||
object_initialize_child(obj, "gem", &s->gem, TYPE_CADENCE_GEM);
|
||||
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)
|
||||
|
@ -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));
|
||||
sifive_clint_create(memmap[SIFIVE_U_CLINT].base,
|
||||
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)) {
|
||||
return;
|
||||
|
@ -727,6 +749,17 @@ static void sifive_u_soc_realize(DeviceState *dev, Error **errp)
|
|||
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);
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->otp), errp)) {
|
||||
return;
|
||||
|
|
|
@ -31,12 +31,12 @@
|
|||
#include "hw/loader.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "target/riscv/cpu.h"
|
||||
#include "hw/riscv/riscv_htif.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/sifive_clint.h"
|
||||
#include "hw/riscv/spike.h"
|
||||
#include "hw/riscv/boot.h"
|
||||
#include "hw/riscv/numa.h"
|
||||
#include "hw/char/riscv_htif.h"
|
||||
#include "hw/intc/sifive_clint.h"
|
||||
#include "chardev/char.h"
|
||||
#include "sysemu/arch_init.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
|
@ -242,7 +242,8 @@ static void spike_board_init(MachineState *machine)
|
|||
sifive_clint_create(
|
||||
memmap[SPIKE_CLINT].base + i * memmap[SPIKE_CLINT].size,
|
||||
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) */
|
||||
|
|
|
@ -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
|
|
@ -1 +0,0 @@
|
|||
#include "trace/trace-hw_riscv.h"
|
|
@ -30,12 +30,12 @@
|
|||
#include "hw/char/serial.h"
|
||||
#include "target/riscv/cpu.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/boot.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 "sysemu/arch_init.h"
|
||||
#include "sysemu/device_tree.h"
|
||||
|
@ -541,7 +541,8 @@ static void virt_machine_init(MachineState *machine)
|
|||
sifive_clint_create(
|
||||
memmap[VIRT_CLINT].base + i * memmap[VIRT_CLINT].size,
|
||||
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 */
|
||||
plic_hart_config_len =
|
||||
|
|
|
@ -19,3 +19,7 @@ config SDHCI_PCI
|
|||
default y if PCI_DEVICES
|
||||
depends on PCI
|
||||
select SDHCI
|
||||
|
||||
config CADENCE_SDHCI
|
||||
bool
|
||||
select SDHCI
|
||||
|
|
|
@ -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)
|
|
@ -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_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_CADENCE_SDHCI', if_true: files('cadence_sdhci.c'))
|
||||
|
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -39,11 +39,13 @@ typedef struct SiFiveCLINTState {
|
|||
uint32_t timecmp_base;
|
||||
uint32_t time_base;
|
||||
uint32_t aperture_size;
|
||||
uint32_t timebase_freq;
|
||||
} SiFiveCLINTState;
|
||||
|
||||
DeviceState *sifive_clint_create(hwaddr addr, hwaddr size,
|
||||
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 {
|
||||
SIFIVE_SIP_BASE = 0x0,
|
|
@ -76,6 +76,8 @@ struct CadenceGEMState {
|
|||
/* Mask of register bits which are write 1 to clear */
|
||||
uint32_t regs_w1c[CADENCE_GEM_MAXREG];
|
||||
|
||||
/* PHY address */
|
||||
uint8_t phy_addr;
|
||||
/* PHY registers backing store */
|
||||
uint16_t phy_regs[32];
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -39,6 +39,7 @@ struct RISCVHartArrayState {
|
|||
uint32_t num_harts;
|
||||
uint32_t hartid_base;
|
||||
char *cpu_type;
|
||||
uint64_t resetvec;
|
||||
RISCVCPU *harts;
|
||||
};
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
#include "hw/riscv/riscv_hart.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 RISCV_E_SOC(obj) \
|
||||
|
|
|
@ -19,12 +19,13 @@
|
|||
#ifndef HW_SIFIVE_U_H
|
||||
#define HW_SIFIVE_U_H
|
||||
|
||||
#include "hw/dma/sifive_pdma.h"
|
||||
#include "hw/net/cadence_gem.h"
|
||||
#include "hw/riscv/riscv_hart.h"
|
||||
#include "hw/riscv/sifive_cpu.h"
|
||||
#include "hw/riscv/sifive_gpio.h"
|
||||
#include "hw/riscv/sifive_u_prci.h"
|
||||
#include "hw/riscv/sifive_u_otp.h"
|
||||
#include "hw/gpio/sifive_gpio.h"
|
||||
#include "hw/misc/sifive_u_otp.h"
|
||||
#include "hw/misc/sifive_u_prci.h"
|
||||
|
||||
#define TYPE_RISCV_U_SOC "riscv.sifive.u.soc"
|
||||
#define RISCV_U_SOC(obj) \
|
||||
|
@ -43,6 +44,7 @@ typedef struct SiFiveUSoCState {
|
|||
SiFiveUPRCIState prci;
|
||||
SIFIVEGPIOState gpio;
|
||||
SiFiveUOTPState otp;
|
||||
SiFivePDMAState dma;
|
||||
CadenceGEMState gem;
|
||||
|
||||
uint32_t serial;
|
||||
|
@ -72,6 +74,7 @@ enum {
|
|||
SIFIVE_U_MROM,
|
||||
SIFIVE_U_CLINT,
|
||||
SIFIVE_U_L2CC,
|
||||
SIFIVE_U_PDMA,
|
||||
SIFIVE_U_L2LIM,
|
||||
SIFIVE_U_PLIC,
|
||||
SIFIVE_U_PRCI,
|
||||
|
@ -108,6 +111,14 @@ enum {
|
|||
SIFIVE_U_GPIO_IRQ13 = 20,
|
||||
SIFIVE_U_GPIO_IRQ14 = 21,
|
||||
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
|
||||
};
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -773,7 +773,6 @@ if have_system
|
|||
'hw/watchdog',
|
||||
'hw/xen',
|
||||
'hw/gpio',
|
||||
'hw/riscv',
|
||||
'migration',
|
||||
'net',
|
||||
'softmmu',
|
||||
|
|
|
@ -96,6 +96,17 @@ const char * const riscv_intr_names[] = {
|
|||
"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)
|
||||
{
|
||||
env->misa_mask = env->misa = misa;
|
||||
|
@ -128,7 +139,6 @@ static void riscv_any_cpu_init(Object *obj)
|
|||
CPURISCVState *env = &RISCV_CPU(obj)->env;
|
||||
set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVU);
|
||||
set_priv_version(env, PRIV_VERSION_1_11_0);
|
||||
set_resetvec(env, DEFAULT_RSTVEC);
|
||||
}
|
||||
|
||||
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;
|
||||
/* We set this in the realise function */
|
||||
set_misa(env, 0);
|
||||
set_resetvec(env, DEFAULT_RSTVEC);
|
||||
}
|
||||
|
||||
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;
|
||||
set_misa(env, RVXLEN | RVI | RVM | RVA | RVF | RVD | RVC | RVS | RVU);
|
||||
set_priv_version(env, PRIV_VERSION_1_10_0);
|
||||
set_resetvec(env, 0x1004);
|
||||
}
|
||||
|
||||
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;
|
||||
set_misa(env, RVXLEN | RVI | RVM | RVA | RVC | RVU);
|
||||
set_priv_version(env, PRIV_VERSION_1_10_0);
|
||||
set_resetvec(env, 0x1004);
|
||||
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;
|
||||
set_misa(env, RV32 | RVI | RVM | RVC | RVU);
|
||||
set_priv_version(env, PRIV_VERSION_1_10_0);
|
||||
set_resetvec(env, 0x8090);
|
||||
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_resetvec(env, cpu->cfg.resetvec);
|
||||
|
||||
/* If misa isn't set (rv32 and rv64 machines) set it here */
|
||||
if (!env->misa) {
|
||||
/* 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_BOOL("mmu", RISCVCPU, cfg.mmu, true),
|
||||
DEFINE_PROP_BOOL("pmp", RISCVCPU, cfg.pmp, true),
|
||||
DEFINE_PROP_UINT64("resetvec", RISCVCPU, cfg.resetvec, DEFAULT_RSTVEC),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
|
|
|
@ -220,7 +220,8 @@ struct CPURISCVState {
|
|||
pmp_table_t pmp_state;
|
||||
|
||||
/* 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. */
|
||||
bool debugger;
|
||||
|
@ -288,6 +289,7 @@ struct RISCVCPU {
|
|||
uint16_t elen;
|
||||
bool mmu;
|
||||
bool pmp;
|
||||
uint64_t resetvec;
|
||||
} cfg;
|
||||
};
|
||||
|
||||
|
@ -309,6 +311,7 @@ extern const char * const riscv_fpr_regnames[];
|
|||
extern const char * const riscv_excp_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);
|
||||
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);
|
||||
|
@ -345,7 +348,8 @@ void riscv_cpu_swap_hypervisor_regs(CPURISCVState *env);
|
|||
int riscv_cpu_claim_interrupts(RISCVCPU *cpu, uint32_t interrupts);
|
||||
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 */
|
||||
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
|
||||
void riscv_cpu_set_mode(CPURISCVState *env, target_ulong newpriv);
|
||||
|
||||
|
|
|
@ -276,9 +276,11 @@ uint32_t riscv_cpu_update_mip(RISCVCPU *cpu, uint32_t mask, uint32_t value)
|
|||
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_arg = arg;
|
||||
}
|
||||
|
||||
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 ?
|
||||
(async ? riscv_intr_names : riscv_excp_names)[cause] : "(unknown)");
|
||||
trace_riscv_trap(env->mhartid, async, cause, env->pc, tval,
|
||||
riscv_cpu_get_trap_name(cause, async));
|
||||
|
||||
if (env->priv <= PRV_S &&
|
||||
cause < TARGET_LONG_BITS && ((deleg >> cause) & 1)) {
|
||||
|
|
|
@ -351,7 +351,7 @@ static int read_time(CPURISCVState *env, int csrno, target_ulong *val)
|
|||
return -RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
|
||||
*val = env->rdtime_fn() + delta;
|
||||
*val = env->rdtime_fn(env->rdtime_fn_arg) + delta;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -364,7 +364,7 @@ static int read_timeh(CPURISCVState *env, int csrno, target_ulong *val)
|
|||
return -RISCV_EXCP_ILLEGAL_INST;
|
||||
}
|
||||
|
||||
*val = (env->rdtime_fn() + delta) >> 32;
|
||||
*val = (env->rdtime_fn(env->rdtime_fn_arg) + delta) >> 32;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue