From 834e027a3452e1c139c5400cae550c6c5a340b28 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Tue, 1 Sep 2020 09:39:11 +0800 Subject: hw/riscv: sifive_u: Connect a DMA controller SiFive FU540 SoC integrates a platform DMA controller with 4 DMA channels. This connects the exsiting SiFive PDMA model to the SoC, and adds its device tree data as well. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1598924352-89526-17-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- include/hw/riscv/sifive_u.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'include/hw/riscv/sifive_u.h') diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index d3c0c00d10..793000a2ed 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -19,6 +19,7 @@ #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" @@ -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 }; -- cgit 1.4.1 From 9fe640a53dd8ef33d32ab6e833fa9b6d1356cfae Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 3 Sep 2020 18:40:13 +0800 Subject: hw/riscv: Move sifive_u_prci model to hw/misc This is an effort to clean up the hw/riscv directory. Ideally it should only contain the RISC-V SoC / machine codes plus generic codes. Let's move sifive_u_prci model to hw/misc directory. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1599129623-68957-3-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/sifive_u_prci.c | 169 +++++++++++++++++++++++++++++++++++++++ hw/riscv/Kconfig | 1 + hw/riscv/meson.build | 1 - hw/riscv/sifive_u_prci.c | 169 --------------------------------------- include/hw/misc/sifive_u_prci.h | 91 +++++++++++++++++++++ include/hw/riscv/sifive_u.h | 2 +- include/hw/riscv/sifive_u_prci.h | 91 --------------------- 9 files changed, 266 insertions(+), 262 deletions(-) create mode 100644 hw/misc/sifive_u_prci.c delete mode 100644 hw/riscv/sifive_u_prci.c create mode 100644 include/hw/misc/sifive_u_prci.h delete mode 100644 include/hw/riscv/sifive_u_prci.h (limited to 'include/hw/riscv/sifive_u.h') diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 507398635b..65f3fdd9e0 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -137,4 +137,7 @@ config AVR_POWER config SIFIVE_E_PRCI bool +config SIFIVE_U_PRCI + bool + source macio/Kconfig diff --git a/hw/misc/meson.build b/hw/misc/meson.build index b6b2e5797f..9e9550e30d 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -23,6 +23,7 @@ softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) # RISC-V devices softmmu_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.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')) diff --git a/hw/misc/sifive_u_prci.c b/hw/misc/sifive_u_prci.c new file mode 100644 index 0000000000..5d9d446ee8 --- /dev/null +++ b/hw/misc/sifive_u_prci.c @@ -0,0 +1,169 @@ +/* + * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) + * + * Copyright (c) 2019 Bin Meng + * + * Simple model of the PRCI to emulate register reads made by the SDK BSP + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/misc/sifive_u_prci.h" + +static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveUPRCIState *s = opaque; + + switch (addr) { + case SIFIVE_U_PRCI_HFXOSCCFG: + return s->hfxosccfg; + case SIFIVE_U_PRCI_COREPLLCFG0: + return s->corepllcfg0; + case SIFIVE_U_PRCI_DDRPLLCFG0: + return s->ddrpllcfg0; + case SIFIVE_U_PRCI_DDRPLLCFG1: + return s->ddrpllcfg1; + case SIFIVE_U_PRCI_GEMGXLPLLCFG0: + return s->gemgxlpllcfg0; + case SIFIVE_U_PRCI_GEMGXLPLLCFG1: + return s->gemgxlpllcfg1; + case SIFIVE_U_PRCI_CORECLKSEL: + return s->coreclksel; + case SIFIVE_U_PRCI_DEVICESRESET: + return s->devicesreset; + case SIFIVE_U_PRCI_CLKMUXSTATUS: + return s->clkmuxstatus; + } + + qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", + __func__, addr); + + return 0; +} + +static void sifive_u_prci_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveUPRCIState *s = opaque; + uint32_t val32 = (uint32_t)val64; + + switch (addr) { + case SIFIVE_U_PRCI_HFXOSCCFG: + s->hfxosccfg = val32; + /* OSC stays ready */ + s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY; + break; + case SIFIVE_U_PRCI_COREPLLCFG0: + s->corepllcfg0 = val32; + /* internal feedback */ + s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; + /* PLL stays locked */ + s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; + break; + case SIFIVE_U_PRCI_DDRPLLCFG0: + s->ddrpllcfg0 = val32; + /* internal feedback */ + s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; + /* PLL stays locked */ + s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; + break; + case SIFIVE_U_PRCI_DDRPLLCFG1: + s->ddrpllcfg1 = val32; + break; + case SIFIVE_U_PRCI_GEMGXLPLLCFG0: + s->gemgxlpllcfg0 = val32; + /* internal feedback */ + s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; + /* PLL stays locked */ + s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; + break; + case SIFIVE_U_PRCI_GEMGXLPLLCFG1: + s->gemgxlpllcfg1 = val32; + break; + case SIFIVE_U_PRCI_CORECLKSEL: + s->coreclksel = val32; + break; + case SIFIVE_U_PRCI_DEVICESRESET: + s->devicesreset = val32; + break; + case SIFIVE_U_PRCI_CLKMUXSTATUS: + s->clkmuxstatus = val32; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx + " v=0x%x\n", __func__, addr, val32); + } +} + +static const MemoryRegionOps sifive_u_prci_ops = { + .read = sifive_u_prci_read, + .write = sifive_u_prci_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static void sifive_u_prci_realize(DeviceState *dev, Error **errp) +{ + SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); + + memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s, + TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void sifive_u_prci_reset(DeviceState *dev) +{ + SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); + + /* Initialize register to power-on-reset values */ + s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN; + s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | + SIFIVE_U_PRCI_PLLCFG0_LOCK; + s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | + SIFIVE_U_PRCI_PLLCFG0_LOCK; + s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | + SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | + SIFIVE_U_PRCI_PLLCFG0_LOCK; + s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK; +} + +static void sifive_u_prci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->realize = sifive_u_prci_realize; + dc->reset = sifive_u_prci_reset; +} + +static const TypeInfo sifive_u_prci_info = { + .name = TYPE_SIFIVE_U_PRCI, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveUPRCIState), + .class_init = sifive_u_prci_class_init, +}; + +static void sifive_u_prci_register_types(void) +{ + type_register_static(&sifive_u_prci_info); +} + +type_init(sifive_u_prci_register_types) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 5855e99aaa..109364b814 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -24,6 +24,7 @@ config SIFIVE_U select HART select SIFIVE select SIFIVE_PDMA + select SIFIVE_U_PRCI select UNIMP config SPIKE diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 003994d1ea..3462cb5a28 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -12,7 +12,6 @@ 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_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')) diff --git a/hw/riscv/sifive_u_prci.c b/hw/riscv/sifive_u_prci.c deleted file mode 100644 index 4fa590c064..0000000000 --- a/hw/riscv/sifive_u_prci.c +++ /dev/null @@ -1,169 +0,0 @@ -/* - * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) - * - * Copyright (c) 2019 Bin Meng - * - * Simple model of the PRCI to emulate register reads made by the SDK BSP - * - * 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 . - */ - -#include "qemu/osdep.h" -#include "hw/sysbus.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "hw/riscv/sifive_u_prci.h" - -static uint64_t sifive_u_prci_read(void *opaque, hwaddr addr, unsigned int size) -{ - SiFiveUPRCIState *s = opaque; - - switch (addr) { - case SIFIVE_U_PRCI_HFXOSCCFG: - return s->hfxosccfg; - case SIFIVE_U_PRCI_COREPLLCFG0: - return s->corepllcfg0; - case SIFIVE_U_PRCI_DDRPLLCFG0: - return s->ddrpllcfg0; - case SIFIVE_U_PRCI_DDRPLLCFG1: - return s->ddrpllcfg1; - case SIFIVE_U_PRCI_GEMGXLPLLCFG0: - return s->gemgxlpllcfg0; - case SIFIVE_U_PRCI_GEMGXLPLLCFG1: - return s->gemgxlpllcfg1; - case SIFIVE_U_PRCI_CORECLKSEL: - return s->coreclksel; - case SIFIVE_U_PRCI_DEVICESRESET: - return s->devicesreset; - case SIFIVE_U_PRCI_CLKMUXSTATUS: - return s->clkmuxstatus; - } - - qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", - __func__, addr); - - return 0; -} - -static void sifive_u_prci_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - SiFiveUPRCIState *s = opaque; - uint32_t val32 = (uint32_t)val64; - - switch (addr) { - case SIFIVE_U_PRCI_HFXOSCCFG: - s->hfxosccfg = val32; - /* OSC stays ready */ - s->hfxosccfg |= SIFIVE_U_PRCI_HFXOSCCFG_RDY; - break; - case SIFIVE_U_PRCI_COREPLLCFG0: - s->corepllcfg0 = val32; - /* internal feedback */ - s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; - /* PLL stays locked */ - s->corepllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; - break; - case SIFIVE_U_PRCI_DDRPLLCFG0: - s->ddrpllcfg0 = val32; - /* internal feedback */ - s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; - /* PLL stays locked */ - s->ddrpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; - break; - case SIFIVE_U_PRCI_DDRPLLCFG1: - s->ddrpllcfg1 = val32; - break; - case SIFIVE_U_PRCI_GEMGXLPLLCFG0: - s->gemgxlpllcfg0 = val32; - /* internal feedback */ - s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_FSE; - /* PLL stays locked */ - s->gemgxlpllcfg0 |= SIFIVE_U_PRCI_PLLCFG0_LOCK; - break; - case SIFIVE_U_PRCI_GEMGXLPLLCFG1: - s->gemgxlpllcfg1 = val32; - break; - case SIFIVE_U_PRCI_CORECLKSEL: - s->coreclksel = val32; - break; - case SIFIVE_U_PRCI_DEVICESRESET: - s->devicesreset = val32; - break; - case SIFIVE_U_PRCI_CLKMUXSTATUS: - s->clkmuxstatus = val32; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx - " v=0x%x\n", __func__, addr, val32); - } -} - -static const MemoryRegionOps sifive_u_prci_ops = { - .read = sifive_u_prci_read, - .write = sifive_u_prci_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static void sifive_u_prci_realize(DeviceState *dev, Error **errp) -{ - SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); - - memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_prci_ops, s, - TYPE_SIFIVE_U_PRCI, SIFIVE_U_PRCI_REG_SIZE); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); -} - -static void sifive_u_prci_reset(DeviceState *dev) -{ - SiFiveUPRCIState *s = SIFIVE_U_PRCI(dev); - - /* Initialize register to power-on-reset values */ - s->hfxosccfg = SIFIVE_U_PRCI_HFXOSCCFG_RDY | SIFIVE_U_PRCI_HFXOSCCFG_EN; - s->corepllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | - SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | - SIFIVE_U_PRCI_PLLCFG0_LOCK; - s->ddrpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | - SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | - SIFIVE_U_PRCI_PLLCFG0_LOCK; - s->gemgxlpllcfg0 = SIFIVE_U_PRCI_PLLCFG0_DIVR | SIFIVE_U_PRCI_PLLCFG0_DIVF | - SIFIVE_U_PRCI_PLLCFG0_DIVQ | SIFIVE_U_PRCI_PLLCFG0_FSE | - SIFIVE_U_PRCI_PLLCFG0_LOCK; - s->coreclksel = SIFIVE_U_PRCI_CORECLKSEL_HFCLK; -} - -static void sifive_u_prci_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = sifive_u_prci_realize; - dc->reset = sifive_u_prci_reset; -} - -static const TypeInfo sifive_u_prci_info = { - .name = TYPE_SIFIVE_U_PRCI, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SiFiveUPRCIState), - .class_init = sifive_u_prci_class_init, -}; - -static void sifive_u_prci_register_types(void) -{ - type_register_static(&sifive_u_prci_info); -} - -type_init(sifive_u_prci_register_types) diff --git a/include/hw/misc/sifive_u_prci.h b/include/hw/misc/sifive_u_prci.h new file mode 100644 index 0000000000..0a531fdadc --- /dev/null +++ b/include/hw/misc/sifive_u_prci.h @@ -0,0 +1,91 @@ +/* + * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) interface + * + * Copyright (c) 2019 Bin Meng + * + * 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 . + */ + +#ifndef HW_SIFIVE_U_PRCI_H +#define HW_SIFIVE_U_PRCI_H + +#define SIFIVE_U_PRCI_HFXOSCCFG 0x00 +#define SIFIVE_U_PRCI_COREPLLCFG0 0x04 +#define SIFIVE_U_PRCI_DDRPLLCFG0 0x0C +#define SIFIVE_U_PRCI_DDRPLLCFG1 0x10 +#define SIFIVE_U_PRCI_GEMGXLPLLCFG0 0x1C +#define SIFIVE_U_PRCI_GEMGXLPLLCFG1 0x20 +#define SIFIVE_U_PRCI_CORECLKSEL 0x24 +#define SIFIVE_U_PRCI_DEVICESRESET 0x28 +#define SIFIVE_U_PRCI_CLKMUXSTATUS 0x2C + +/* + * Current FU540-C000 manual says ready bit is at bit 29, but + * freedom-u540-c000-bootloader codes (ux00prci.h) says it is at bit 31. + * We have to trust the actual code that works. + * + * see https://github.com/sifive/freedom-u540-c000-bootloader + */ + +#define SIFIVE_U_PRCI_HFXOSCCFG_EN (1 << 30) +#define SIFIVE_U_PRCI_HFXOSCCFG_RDY (1 << 31) + +/* xxxPLLCFG0 register bits */ +#define SIFIVE_U_PRCI_PLLCFG0_DIVR (1 << 0) +#define SIFIVE_U_PRCI_PLLCFG0_DIVF (31 << 6) +#define SIFIVE_U_PRCI_PLLCFG0_DIVQ (3 << 15) +#define SIFIVE_U_PRCI_PLLCFG0_FSE (1 << 25) +#define SIFIVE_U_PRCI_PLLCFG0_LOCK (1 << 31) + +/* xxxPLLCFG1 register bits */ +#define SIFIVE_U_PRCI_PLLCFG1_CKE (1 << 24) + +/* coreclksel register bits */ +#define SIFIVE_U_PRCI_CORECLKSEL_HFCLK (1 << 0) + + +#define SIFIVE_U_PRCI_REG_SIZE 0x1000 + +#define TYPE_SIFIVE_U_PRCI "riscv.sifive.u.prci" + +#define SIFIVE_U_PRCI(obj) \ + OBJECT_CHECK(SiFiveUPRCIState, (obj), TYPE_SIFIVE_U_PRCI) + +typedef struct SiFiveUPRCIState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion mmio; + uint32_t hfxosccfg; + uint32_t corepllcfg0; + uint32_t ddrpllcfg0; + uint32_t ddrpllcfg1; + uint32_t gemgxlpllcfg0; + uint32_t gemgxlpllcfg1; + uint32_t coreclksel; + uint32_t devicesreset; + uint32_t clkmuxstatus; +} SiFiveUPRCIState; + +/* + * Clock indexes for use by Device Tree data and the PRCI driver. + * + * These values are from sifive-fu540-prci.h in the Linux kernel. + */ +#define PRCI_CLK_COREPLL 0 +#define PRCI_CLK_DDRPLL 1 +#define PRCI_CLK_GEMGXLPLL 2 +#define PRCI_CLK_TLCLK 3 + +#endif /* HW_SIFIVE_U_PRCI_H */ diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 793000a2ed..cbeb2286d7 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -24,8 +24,8 @@ #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/misc/sifive_u_prci.h" #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" #define RISCV_U_SOC(obj) \ diff --git a/include/hw/riscv/sifive_u_prci.h b/include/hw/riscv/sifive_u_prci.h deleted file mode 100644 index 0a531fdadc..0000000000 --- a/include/hw/riscv/sifive_u_prci.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * QEMU SiFive U PRCI (Power, Reset, Clock, Interrupt) interface - * - * Copyright (c) 2019 Bin Meng - * - * 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 . - */ - -#ifndef HW_SIFIVE_U_PRCI_H -#define HW_SIFIVE_U_PRCI_H - -#define SIFIVE_U_PRCI_HFXOSCCFG 0x00 -#define SIFIVE_U_PRCI_COREPLLCFG0 0x04 -#define SIFIVE_U_PRCI_DDRPLLCFG0 0x0C -#define SIFIVE_U_PRCI_DDRPLLCFG1 0x10 -#define SIFIVE_U_PRCI_GEMGXLPLLCFG0 0x1C -#define SIFIVE_U_PRCI_GEMGXLPLLCFG1 0x20 -#define SIFIVE_U_PRCI_CORECLKSEL 0x24 -#define SIFIVE_U_PRCI_DEVICESRESET 0x28 -#define SIFIVE_U_PRCI_CLKMUXSTATUS 0x2C - -/* - * Current FU540-C000 manual says ready bit is at bit 29, but - * freedom-u540-c000-bootloader codes (ux00prci.h) says it is at bit 31. - * We have to trust the actual code that works. - * - * see https://github.com/sifive/freedom-u540-c000-bootloader - */ - -#define SIFIVE_U_PRCI_HFXOSCCFG_EN (1 << 30) -#define SIFIVE_U_PRCI_HFXOSCCFG_RDY (1 << 31) - -/* xxxPLLCFG0 register bits */ -#define SIFIVE_U_PRCI_PLLCFG0_DIVR (1 << 0) -#define SIFIVE_U_PRCI_PLLCFG0_DIVF (31 << 6) -#define SIFIVE_U_PRCI_PLLCFG0_DIVQ (3 << 15) -#define SIFIVE_U_PRCI_PLLCFG0_FSE (1 << 25) -#define SIFIVE_U_PRCI_PLLCFG0_LOCK (1 << 31) - -/* xxxPLLCFG1 register bits */ -#define SIFIVE_U_PRCI_PLLCFG1_CKE (1 << 24) - -/* coreclksel register bits */ -#define SIFIVE_U_PRCI_CORECLKSEL_HFCLK (1 << 0) - - -#define SIFIVE_U_PRCI_REG_SIZE 0x1000 - -#define TYPE_SIFIVE_U_PRCI "riscv.sifive.u.prci" - -#define SIFIVE_U_PRCI(obj) \ - OBJECT_CHECK(SiFiveUPRCIState, (obj), TYPE_SIFIVE_U_PRCI) - -typedef struct SiFiveUPRCIState { - /*< private >*/ - SysBusDevice parent_obj; - - /*< public >*/ - MemoryRegion mmio; - uint32_t hfxosccfg; - uint32_t corepllcfg0; - uint32_t ddrpllcfg0; - uint32_t ddrpllcfg1; - uint32_t gemgxlpllcfg0; - uint32_t gemgxlpllcfg1; - uint32_t coreclksel; - uint32_t devicesreset; - uint32_t clkmuxstatus; -} SiFiveUPRCIState; - -/* - * Clock indexes for use by Device Tree data and the PRCI driver. - * - * These values are from sifive-fu540-prci.h in the Linux kernel. - */ -#define PRCI_CLK_COREPLL 0 -#define PRCI_CLK_DDRPLL 1 -#define PRCI_CLK_GEMGXLPLL 2 -#define PRCI_CLK_TLCLK 3 - -#endif /* HW_SIFIVE_U_PRCI_H */ -- cgit 1.4.1 From 0fa9e329454aaccc6dbb6a4f52ad0c88a060a3b6 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 3 Sep 2020 18:40:14 +0800 Subject: hw/riscv: Move sifive_u_otp model to hw/misc This is an effort to clean up the hw/riscv directory. Ideally it should only contain the RISC-V SoC / machine codes plus generic codes. Let's move sifive_u_otp model to hw/misc directory. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1599129623-68957-4-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/misc/Kconfig | 3 + hw/misc/meson.build | 1 + hw/misc/sifive_u_otp.c | 191 ++++++++++++++++++++++++++++++++++++++++ hw/riscv/Kconfig | 1 + hw/riscv/meson.build | 1 - hw/riscv/sifive_u_otp.c | 191 ---------------------------------------- include/hw/misc/sifive_u_otp.h | 80 +++++++++++++++++ include/hw/riscv/sifive_u.h | 2 +- include/hw/riscv/sifive_u_otp.h | 80 ----------------- 9 files changed, 277 insertions(+), 273 deletions(-) create mode 100644 hw/misc/sifive_u_otp.c delete mode 100644 hw/riscv/sifive_u_otp.c create mode 100644 include/hw/misc/sifive_u_otp.h delete mode 100644 include/hw/riscv/sifive_u_otp.h (limited to 'include/hw/riscv/sifive_u.h') diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 65f3fdd9e0..fa3d0f4723 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -137,6 +137,9 @@ config AVR_POWER config SIFIVE_E_PRCI bool +config SIFIVE_U_OTP + bool + config SIFIVE_U_PRCI bool diff --git a/hw/misc/meson.build b/hw/misc/meson.build index 9e9550e30d..018a88c670 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -23,6 +23,7 @@ softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) # RISC-V devices 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 diff --git a/hw/misc/sifive_u_otp.c b/hw/misc/sifive_u_otp.c new file mode 100644 index 0000000000..c2f3c8e129 --- /dev/null +++ b/hw/misc/sifive_u_otp.c @@ -0,0 +1,191 @@ +/* + * QEMU SiFive U OTP (One-Time Programmable) Memory interface + * + * Copyright (c) 2019 Bin Meng + * + * Simple model of the OTP to emulate register reads made by the SDK BSP + * + * 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 . + */ + +#include "qemu/osdep.h" +#include "hw/qdev-properties.h" +#include "hw/sysbus.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/misc/sifive_u_otp.h" + +static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) +{ + SiFiveUOTPState *s = opaque; + + switch (addr) { + case SIFIVE_U_OTP_PA: + return s->pa; + case SIFIVE_U_OTP_PAIO: + return s->paio; + case SIFIVE_U_OTP_PAS: + return s->pas; + case SIFIVE_U_OTP_PCE: + return s->pce; + case SIFIVE_U_OTP_PCLK: + return s->pclk; + case SIFIVE_U_OTP_PDIN: + return s->pdin; + case SIFIVE_U_OTP_PDOUT: + if ((s->pce & SIFIVE_U_OTP_PCE_EN) && + (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && + (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { + return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; + } else { + return 0xff; + } + case SIFIVE_U_OTP_PDSTB: + return s->pdstb; + case SIFIVE_U_OTP_PPROG: + return s->pprog; + case SIFIVE_U_OTP_PTC: + return s->ptc; + case SIFIVE_U_OTP_PTM: + return s->ptm; + case SIFIVE_U_OTP_PTM_REP: + return s->ptm_rep; + case SIFIVE_U_OTP_PTR: + return s->ptr; + case SIFIVE_U_OTP_PTRIM: + return s->ptrim; + case SIFIVE_U_OTP_PWE: + return s->pwe; + } + + qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", + __func__, addr); + return 0; +} + +static void sifive_u_otp_write(void *opaque, hwaddr addr, + uint64_t val64, unsigned int size) +{ + SiFiveUOTPState *s = opaque; + uint32_t val32 = (uint32_t)val64; + + switch (addr) { + case SIFIVE_U_OTP_PA: + s->pa = val32 & SIFIVE_U_OTP_PA_MASK; + break; + case SIFIVE_U_OTP_PAIO: + s->paio = val32; + break; + case SIFIVE_U_OTP_PAS: + s->pas = val32; + break; + case SIFIVE_U_OTP_PCE: + s->pce = val32; + break; + case SIFIVE_U_OTP_PCLK: + s->pclk = val32; + break; + case SIFIVE_U_OTP_PDIN: + s->pdin = val32; + break; + case SIFIVE_U_OTP_PDOUT: + /* read-only */ + break; + case SIFIVE_U_OTP_PDSTB: + s->pdstb = val32; + break; + case SIFIVE_U_OTP_PPROG: + s->pprog = val32; + break; + case SIFIVE_U_OTP_PTC: + s->ptc = val32; + break; + case SIFIVE_U_OTP_PTM: + s->ptm = val32; + break; + case SIFIVE_U_OTP_PTM_REP: + s->ptm_rep = val32; + break; + case SIFIVE_U_OTP_PTR: + s->ptr = val32; + break; + case SIFIVE_U_OTP_PTRIM: + s->ptrim = val32; + break; + case SIFIVE_U_OTP_PWE: + s->pwe = val32; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx + " v=0x%x\n", __func__, addr, val32); + } +} + +static const MemoryRegionOps sifive_u_otp_ops = { + .read = sifive_u_otp_read, + .write = sifive_u_otp_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4 + } +}; + +static Property sifive_u_otp_properties[] = { + DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_u_otp_realize(DeviceState *dev, Error **errp) +{ + SiFiveUOTPState *s = SIFIVE_U_OTP(dev); + + memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, + TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); +} + +static void sifive_u_otp_reset(DeviceState *dev) +{ + SiFiveUOTPState *s = SIFIVE_U_OTP(dev); + + /* Initialize all fuses' initial value to 0xFFs */ + memset(s->fuse, 0xff, sizeof(s->fuse)); + + /* Make a valid content of serial number */ + s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; + s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); +} + +static void sifive_u_otp_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, sifive_u_otp_properties); + dc->realize = sifive_u_otp_realize; + dc->reset = sifive_u_otp_reset; +} + +static const TypeInfo sifive_u_otp_info = { + .name = TYPE_SIFIVE_U_OTP, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SiFiveUOTPState), + .class_init = sifive_u_otp_class_init, +}; + +static void sifive_u_otp_register_types(void) +{ + type_register_static(&sifive_u_otp_info); +} + +type_init(sifive_u_otp_register_types) diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 109364b814..76eaf77a80 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -24,6 +24,7 @@ config SIFIVE_U select HART select SIFIVE select SIFIVE_PDMA + select SIFIVE_U_OTP select SIFIVE_U_PRCI select UNIMP diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 3462cb5a28..74a73b2a44 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -11,7 +11,6 @@ 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_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_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')) diff --git a/hw/riscv/sifive_u_otp.c b/hw/riscv/sifive_u_otp.c deleted file mode 100644 index f6ecbaa2ca..0000000000 --- a/hw/riscv/sifive_u_otp.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * QEMU SiFive U OTP (One-Time Programmable) Memory interface - * - * Copyright (c) 2019 Bin Meng - * - * Simple model of the OTP to emulate register reads made by the SDK BSP - * - * 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 . - */ - -#include "qemu/osdep.h" -#include "hw/qdev-properties.h" -#include "hw/sysbus.h" -#include "qemu/log.h" -#include "qemu/module.h" -#include "hw/riscv/sifive_u_otp.h" - -static uint64_t sifive_u_otp_read(void *opaque, hwaddr addr, unsigned int size) -{ - SiFiveUOTPState *s = opaque; - - switch (addr) { - case SIFIVE_U_OTP_PA: - return s->pa; - case SIFIVE_U_OTP_PAIO: - return s->paio; - case SIFIVE_U_OTP_PAS: - return s->pas; - case SIFIVE_U_OTP_PCE: - return s->pce; - case SIFIVE_U_OTP_PCLK: - return s->pclk; - case SIFIVE_U_OTP_PDIN: - return s->pdin; - case SIFIVE_U_OTP_PDOUT: - if ((s->pce & SIFIVE_U_OTP_PCE_EN) && - (s->pdstb & SIFIVE_U_OTP_PDSTB_EN) && - (s->ptrim & SIFIVE_U_OTP_PTRIM_EN)) { - return s->fuse[s->pa & SIFIVE_U_OTP_PA_MASK]; - } else { - return 0xff; - } - case SIFIVE_U_OTP_PDSTB: - return s->pdstb; - case SIFIVE_U_OTP_PPROG: - return s->pprog; - case SIFIVE_U_OTP_PTC: - return s->ptc; - case SIFIVE_U_OTP_PTM: - return s->ptm; - case SIFIVE_U_OTP_PTM_REP: - return s->ptm_rep; - case SIFIVE_U_OTP_PTR: - return s->ptr; - case SIFIVE_U_OTP_PTRIM: - return s->ptrim; - case SIFIVE_U_OTP_PWE: - return s->pwe; - } - - qemu_log_mask(LOG_GUEST_ERROR, "%s: read: addr=0x%" HWADDR_PRIx "\n", - __func__, addr); - return 0; -} - -static void sifive_u_otp_write(void *opaque, hwaddr addr, - uint64_t val64, unsigned int size) -{ - SiFiveUOTPState *s = opaque; - uint32_t val32 = (uint32_t)val64; - - switch (addr) { - case SIFIVE_U_OTP_PA: - s->pa = val32 & SIFIVE_U_OTP_PA_MASK; - break; - case SIFIVE_U_OTP_PAIO: - s->paio = val32; - break; - case SIFIVE_U_OTP_PAS: - s->pas = val32; - break; - case SIFIVE_U_OTP_PCE: - s->pce = val32; - break; - case SIFIVE_U_OTP_PCLK: - s->pclk = val32; - break; - case SIFIVE_U_OTP_PDIN: - s->pdin = val32; - break; - case SIFIVE_U_OTP_PDOUT: - /* read-only */ - break; - case SIFIVE_U_OTP_PDSTB: - s->pdstb = val32; - break; - case SIFIVE_U_OTP_PPROG: - s->pprog = val32; - break; - case SIFIVE_U_OTP_PTC: - s->ptc = val32; - break; - case SIFIVE_U_OTP_PTM: - s->ptm = val32; - break; - case SIFIVE_U_OTP_PTM_REP: - s->ptm_rep = val32; - break; - case SIFIVE_U_OTP_PTR: - s->ptr = val32; - break; - case SIFIVE_U_OTP_PTRIM: - s->ptrim = val32; - break; - case SIFIVE_U_OTP_PWE: - s->pwe = val32; - break; - default: - qemu_log_mask(LOG_GUEST_ERROR, "%s: bad write: addr=0x%" HWADDR_PRIx - " v=0x%x\n", __func__, addr, val32); - } -} - -static const MemoryRegionOps sifive_u_otp_ops = { - .read = sifive_u_otp_read, - .write = sifive_u_otp_write, - .endianness = DEVICE_NATIVE_ENDIAN, - .valid = { - .min_access_size = 4, - .max_access_size = 4 - } -}; - -static Property sifive_u_otp_properties[] = { - DEFINE_PROP_UINT32("serial", SiFiveUOTPState, serial, 0), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sifive_u_otp_realize(DeviceState *dev, Error **errp) -{ - SiFiveUOTPState *s = SIFIVE_U_OTP(dev); - - memory_region_init_io(&s->mmio, OBJECT(dev), &sifive_u_otp_ops, s, - TYPE_SIFIVE_U_OTP, SIFIVE_U_OTP_REG_SIZE); - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); -} - -static void sifive_u_otp_reset(DeviceState *dev) -{ - SiFiveUOTPState *s = SIFIVE_U_OTP(dev); - - /* Initialize all fuses' initial value to 0xFFs */ - memset(s->fuse, 0xff, sizeof(s->fuse)); - - /* Make a valid content of serial number */ - s->fuse[SIFIVE_U_OTP_SERIAL_ADDR] = s->serial; - s->fuse[SIFIVE_U_OTP_SERIAL_ADDR + 1] = ~(s->serial); -} - -static void sifive_u_otp_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - device_class_set_props(dc, sifive_u_otp_properties); - dc->realize = sifive_u_otp_realize; - dc->reset = sifive_u_otp_reset; -} - -static const TypeInfo sifive_u_otp_info = { - .name = TYPE_SIFIVE_U_OTP, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SiFiveUOTPState), - .class_init = sifive_u_otp_class_init, -}; - -static void sifive_u_otp_register_types(void) -{ - type_register_static(&sifive_u_otp_info); -} - -type_init(sifive_u_otp_register_types) diff --git a/include/hw/misc/sifive_u_otp.h b/include/hw/misc/sifive_u_otp.h new file mode 100644 index 0000000000..639297564a --- /dev/null +++ b/include/hw/misc/sifive_u_otp.h @@ -0,0 +1,80 @@ +/* + * QEMU SiFive U OTP (One-Time Programmable) Memory interface + * + * Copyright (c) 2019 Bin Meng + * + * 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 . + */ + +#ifndef HW_SIFIVE_U_OTP_H +#define HW_SIFIVE_U_OTP_H + +#define SIFIVE_U_OTP_PA 0x00 +#define SIFIVE_U_OTP_PAIO 0x04 +#define SIFIVE_U_OTP_PAS 0x08 +#define SIFIVE_U_OTP_PCE 0x0C +#define SIFIVE_U_OTP_PCLK 0x10 +#define SIFIVE_U_OTP_PDIN 0x14 +#define SIFIVE_U_OTP_PDOUT 0x18 +#define SIFIVE_U_OTP_PDSTB 0x1C +#define SIFIVE_U_OTP_PPROG 0x20 +#define SIFIVE_U_OTP_PTC 0x24 +#define SIFIVE_U_OTP_PTM 0x28 +#define SIFIVE_U_OTP_PTM_REP 0x2C +#define SIFIVE_U_OTP_PTR 0x30 +#define SIFIVE_U_OTP_PTRIM 0x34 +#define SIFIVE_U_OTP_PWE 0x38 + +#define SIFIVE_U_OTP_PCE_EN (1 << 0) + +#define SIFIVE_U_OTP_PDSTB_EN (1 << 0) + +#define SIFIVE_U_OTP_PTRIM_EN (1 << 0) + +#define SIFIVE_U_OTP_PA_MASK 0xfff +#define SIFIVE_U_OTP_NUM_FUSES 0x1000 +#define SIFIVE_U_OTP_SERIAL_ADDR 0xfc + +#define SIFIVE_U_OTP_REG_SIZE 0x1000 + +#define TYPE_SIFIVE_U_OTP "riscv.sifive.u.otp" + +#define SIFIVE_U_OTP(obj) \ + OBJECT_CHECK(SiFiveUOTPState, (obj), TYPE_SIFIVE_U_OTP) + +typedef struct SiFiveUOTPState { + /*< private >*/ + SysBusDevice parent_obj; + + /*< public >*/ + MemoryRegion mmio; + uint32_t pa; + uint32_t paio; + uint32_t pas; + uint32_t pce; + uint32_t pclk; + uint32_t pdin; + uint32_t pdstb; + uint32_t pprog; + uint32_t ptc; + uint32_t ptm; + uint32_t ptm_rep; + uint32_t ptr; + uint32_t ptrim; + uint32_t pwe; + uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES]; + /* config */ + uint32_t serial; +} SiFiveUOTPState; + +#endif /* HW_SIFIVE_U_OTP_H */ diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index cbeb2286d7..936a3bd0b1 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -24,7 +24,7 @@ #include "hw/riscv/riscv_hart.h" #include "hw/riscv/sifive_cpu.h" #include "hw/riscv/sifive_gpio.h" -#include "hw/riscv/sifive_u_otp.h" +#include "hw/misc/sifive_u_otp.h" #include "hw/misc/sifive_u_prci.h" #define TYPE_RISCV_U_SOC "riscv.sifive.u.soc" diff --git a/include/hw/riscv/sifive_u_otp.h b/include/hw/riscv/sifive_u_otp.h deleted file mode 100644 index 639297564a..0000000000 --- a/include/hw/riscv/sifive_u_otp.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * QEMU SiFive U OTP (One-Time Programmable) Memory interface - * - * Copyright (c) 2019 Bin Meng - * - * 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 . - */ - -#ifndef HW_SIFIVE_U_OTP_H -#define HW_SIFIVE_U_OTP_H - -#define SIFIVE_U_OTP_PA 0x00 -#define SIFIVE_U_OTP_PAIO 0x04 -#define SIFIVE_U_OTP_PAS 0x08 -#define SIFIVE_U_OTP_PCE 0x0C -#define SIFIVE_U_OTP_PCLK 0x10 -#define SIFIVE_U_OTP_PDIN 0x14 -#define SIFIVE_U_OTP_PDOUT 0x18 -#define SIFIVE_U_OTP_PDSTB 0x1C -#define SIFIVE_U_OTP_PPROG 0x20 -#define SIFIVE_U_OTP_PTC 0x24 -#define SIFIVE_U_OTP_PTM 0x28 -#define SIFIVE_U_OTP_PTM_REP 0x2C -#define SIFIVE_U_OTP_PTR 0x30 -#define SIFIVE_U_OTP_PTRIM 0x34 -#define SIFIVE_U_OTP_PWE 0x38 - -#define SIFIVE_U_OTP_PCE_EN (1 << 0) - -#define SIFIVE_U_OTP_PDSTB_EN (1 << 0) - -#define SIFIVE_U_OTP_PTRIM_EN (1 << 0) - -#define SIFIVE_U_OTP_PA_MASK 0xfff -#define SIFIVE_U_OTP_NUM_FUSES 0x1000 -#define SIFIVE_U_OTP_SERIAL_ADDR 0xfc - -#define SIFIVE_U_OTP_REG_SIZE 0x1000 - -#define TYPE_SIFIVE_U_OTP "riscv.sifive.u.otp" - -#define SIFIVE_U_OTP(obj) \ - OBJECT_CHECK(SiFiveUOTPState, (obj), TYPE_SIFIVE_U_OTP) - -typedef struct SiFiveUOTPState { - /*< private >*/ - SysBusDevice parent_obj; - - /*< public >*/ - MemoryRegion mmio; - uint32_t pa; - uint32_t paio; - uint32_t pas; - uint32_t pce; - uint32_t pclk; - uint32_t pdin; - uint32_t pdstb; - uint32_t pprog; - uint32_t ptc; - uint32_t ptm; - uint32_t ptm_rep; - uint32_t ptr; - uint32_t ptrim; - uint32_t pwe; - uint32_t fuse[SIFIVE_U_OTP_NUM_FUSES]; - /* config */ - uint32_t serial; -} SiFiveUOTPState; - -#endif /* HW_SIFIVE_U_OTP_H */ -- cgit 1.4.1 From 4921a0ce86cecd03e6918832673db79de62e6fe1 Mon Sep 17 00:00:00 2001 From: Bin Meng Date: Thu, 3 Sep 2020 18:40:15 +0800 Subject: hw/riscv: Move sifive_gpio model to hw/gpio This is an effort to clean up the hw/riscv directory. Ideally it should only contain the RISC-V SoC / machine codes plus generic codes. Let's move sifive_gpio model to hw/gpio directory. Note this also removes the trace-events in the hw/riscv directory, since gpio is the only supported trace target in that directory. Signed-off-by: Bin Meng Reviewed-by: Alistair Francis Message-Id: <1599129623-68957-5-git-send-email-bmeng.cn@gmail.com> Signed-off-by: Alistair Francis --- hw/gpio/Kconfig | 3 + hw/gpio/meson.build | 1 + hw/gpio/sifive_gpio.c | 397 +++++++++++++++++++++++++++++++++++++++++ hw/gpio/trace-events | 6 + hw/riscv/Kconfig | 2 + hw/riscv/meson.build | 1 - hw/riscv/sifive_gpio.c | 397 ----------------------------------------- hw/riscv/trace-events | 7 - hw/riscv/trace.h | 1 - include/hw/gpio/sifive_gpio.h | 76 ++++++++ include/hw/riscv/sifive_e.h | 2 +- include/hw/riscv/sifive_gpio.h | 76 -------- include/hw/riscv/sifive_u.h | 2 +- meson.build | 1 - 14 files changed, 487 insertions(+), 485 deletions(-) create mode 100644 hw/gpio/sifive_gpio.c delete mode 100644 hw/riscv/sifive_gpio.c delete mode 100644 hw/riscv/trace-events delete mode 100644 hw/riscv/trace.h create mode 100644 include/hw/gpio/sifive_gpio.h delete mode 100644 include/hw/riscv/sifive_gpio.h (limited to 'include/hw/riscv/sifive_u.h') diff --git a/hw/gpio/Kconfig b/hw/gpio/Kconfig index 9227cb5598..b6fdaa2586 100644 --- a/hw/gpio/Kconfig +++ b/hw/gpio/Kconfig @@ -7,3 +7,6 @@ config PL061 config GPIO_KEY bool + +config SIFIVE_GPIO + bool diff --git a/hw/gpio/meson.build b/hw/gpio/meson.build index 6bcdfa6b1d..86cae9a0f3 100644 --- a/hw/gpio/meson.build +++ b/hw/gpio/meson.build @@ -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')) diff --git a/hw/gpio/sifive_gpio.c b/hw/gpio/sifive_gpio.c new file mode 100644 index 0000000000..78bf29e996 --- /dev/null +++ b/hw/gpio/sifive_gpio.c @@ -0,0 +1,397 @@ +/* + * SiFive System-on-Chip general purpose input/output register definition + * + * Copyright 2019 AdaCore + * + * Base on nrf51_gpio.c: + * + * Copyright 2018 Steffen Görtz + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "hw/irq.h" +#include "hw/qdev-properties.h" +#include "hw/gpio/sifive_gpio.h" +#include "migration/vmstate.h" +#include "trace.h" + +static void update_output_irq(SIFIVEGPIOState *s) +{ + uint32_t pending; + uint32_t pin; + + pending = s->high_ip & s->high_ie; + pending |= s->low_ip & s->low_ie; + pending |= s->rise_ip & s->rise_ie; + pending |= s->fall_ip & s->fall_ie; + + for (int i = 0; i < s->ngpio; i++) { + pin = 1 << i; + qemu_set_irq(s->irq[i], (pending & pin) != 0); + trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0); + } +} + +static void update_state(SIFIVEGPIOState *s) +{ + size_t i; + bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en, + rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival; + + for (i = 0; i < s->ngpio; i++) { + + prev_ival = extract32(s->value, i, 1); + in = extract32(s->in, i, 1); + in_mask = extract32(s->in_mask, i, 1); + port = extract32(s->port, i, 1); + out_xor = extract32(s->out_xor, i, 1); + pull = extract32(s->pue, i, 1); + output_en = extract32(s->output_en, i, 1); + input_en = extract32(s->input_en, i, 1); + rise_ip = extract32(s->rise_ip, i, 1); + fall_ip = extract32(s->fall_ip, i, 1); + low_ip = extract32(s->low_ip, i, 1); + high_ip = extract32(s->high_ip, i, 1); + + /* Output value (IOF not supported) */ + oval = output_en && (port ^ out_xor); + + /* Pin both driven externally and internally */ + if (output_en && in_mask) { + qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i); + } + + if (in_mask) { + /* The pin is driven by external device */ + actual_value = in; + } else if (output_en) { + /* The pin is driven by internal circuit */ + actual_value = oval; + } else { + /* Floating? Apply pull-up resistor */ + actual_value = pull; + } + + if (output_en) { + qemu_set_irq(s->output[i], actual_value); + } + + /* Input value */ + ival = input_en && actual_value; + + /* Interrupts */ + high_ip = high_ip || ival; + s->high_ip = deposit32(s->high_ip, i, 1, high_ip); + + low_ip = low_ip || !ival; + s->low_ip = deposit32(s->low_ip, i, 1, low_ip); + + rise_ip = rise_ip || (ival && !prev_ival); + s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip); + + fall_ip = fall_ip || (!ival && prev_ival); + s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip); + + /* Update value */ + s->value = deposit32(s->value, i, 1, ival); + } + update_output_irq(s); +} + +static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); + uint64_t r = 0; + + switch (offset) { + case SIFIVE_GPIO_REG_VALUE: + r = s->value; + break; + + case SIFIVE_GPIO_REG_INPUT_EN: + r = s->input_en; + break; + + case SIFIVE_GPIO_REG_OUTPUT_EN: + r = s->output_en; + break; + + case SIFIVE_GPIO_REG_PORT: + r = s->port; + break; + + case SIFIVE_GPIO_REG_PUE: + r = s->pue; + break; + + case SIFIVE_GPIO_REG_DS: + r = s->ds; + break; + + case SIFIVE_GPIO_REG_RISE_IE: + r = s->rise_ie; + break; + + case SIFIVE_GPIO_REG_RISE_IP: + r = s->rise_ip; + break; + + case SIFIVE_GPIO_REG_FALL_IE: + r = s->fall_ie; + break; + + case SIFIVE_GPIO_REG_FALL_IP: + r = s->fall_ip; + break; + + case SIFIVE_GPIO_REG_HIGH_IE: + r = s->high_ie; + break; + + case SIFIVE_GPIO_REG_HIGH_IP: + r = s->high_ip; + break; + + case SIFIVE_GPIO_REG_LOW_IE: + r = s->low_ie; + break; + + case SIFIVE_GPIO_REG_LOW_IP: + r = s->low_ip; + break; + + case SIFIVE_GPIO_REG_IOF_EN: + r = s->iof_en; + break; + + case SIFIVE_GPIO_REG_IOF_SEL: + r = s->iof_sel; + break; + + case SIFIVE_GPIO_REG_OUT_XOR: + r = s->out_xor; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bad read offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + } + + trace_sifive_gpio_read(offset, r); + + return r; +} + +static void sifive_gpio_write(void *opaque, hwaddr offset, + uint64_t value, unsigned int size) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); + + trace_sifive_gpio_write(offset, value); + + switch (offset) { + + case SIFIVE_GPIO_REG_INPUT_EN: + s->input_en = value; + break; + + case SIFIVE_GPIO_REG_OUTPUT_EN: + s->output_en = value; + break; + + case SIFIVE_GPIO_REG_PORT: + s->port = value; + break; + + case SIFIVE_GPIO_REG_PUE: + s->pue = value; + break; + + case SIFIVE_GPIO_REG_DS: + s->ds = value; + break; + + case SIFIVE_GPIO_REG_RISE_IE: + s->rise_ie = value; + break; + + case SIFIVE_GPIO_REG_RISE_IP: + /* Write 1 to clear */ + s->rise_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_FALL_IE: + s->fall_ie = value; + break; + + case SIFIVE_GPIO_REG_FALL_IP: + /* Write 1 to clear */ + s->fall_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_HIGH_IE: + s->high_ie = value; + break; + + case SIFIVE_GPIO_REG_HIGH_IP: + /* Write 1 to clear */ + s->high_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_LOW_IE: + s->low_ie = value; + break; + + case SIFIVE_GPIO_REG_LOW_IP: + /* Write 1 to clear */ + s->low_ip &= ~value; + break; + + case SIFIVE_GPIO_REG_IOF_EN: + s->iof_en = value; + break; + + case SIFIVE_GPIO_REG_IOF_SEL: + s->iof_sel = value; + break; + + case SIFIVE_GPIO_REG_OUT_XOR: + s->out_xor = value; + break; + + default: + qemu_log_mask(LOG_GUEST_ERROR, + "%s: bad write offset 0x%" HWADDR_PRIx "\n", + __func__, offset); + } + + update_state(s); +} + +static const MemoryRegionOps gpio_ops = { + .read = sifive_gpio_read, + .write = sifive_gpio_write, + .endianness = DEVICE_LITTLE_ENDIAN, + .impl.min_access_size = 4, + .impl.max_access_size = 4, +}; + +static void sifive_gpio_set(void *opaque, int line, int value) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); + + trace_sifive_gpio_set(line, value); + + assert(line >= 0 && line < SIFIVE_GPIO_PINS); + + s->in_mask = deposit32(s->in_mask, line, 1, value >= 0); + if (value >= 0) { + s->in = deposit32(s->in, line, 1, value != 0); + } + + update_state(s); +} + +static void sifive_gpio_reset(DeviceState *dev) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(dev); + + s->value = 0; + s->input_en = 0; + s->output_en = 0; + s->port = 0; + s->pue = 0; + s->ds = 0; + s->rise_ie = 0; + s->rise_ip = 0; + s->fall_ie = 0; + s->fall_ip = 0; + s->high_ie = 0; + s->high_ip = 0; + s->low_ie = 0; + s->low_ip = 0; + s->iof_en = 0; + s->iof_sel = 0; + s->out_xor = 0; + s->in = 0; + s->in_mask = 0; +} + +static const VMStateDescription vmstate_sifive_gpio = { + .name = TYPE_SIFIVE_GPIO, + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(value, SIFIVEGPIOState), + VMSTATE_UINT32(input_en, SIFIVEGPIOState), + VMSTATE_UINT32(output_en, SIFIVEGPIOState), + VMSTATE_UINT32(port, SIFIVEGPIOState), + VMSTATE_UINT32(pue, SIFIVEGPIOState), + VMSTATE_UINT32(rise_ie, SIFIVEGPIOState), + VMSTATE_UINT32(rise_ip, SIFIVEGPIOState), + VMSTATE_UINT32(fall_ie, SIFIVEGPIOState), + VMSTATE_UINT32(fall_ip, SIFIVEGPIOState), + VMSTATE_UINT32(high_ie, SIFIVEGPIOState), + VMSTATE_UINT32(high_ip, SIFIVEGPIOState), + VMSTATE_UINT32(low_ie, SIFIVEGPIOState), + VMSTATE_UINT32(low_ip, SIFIVEGPIOState), + VMSTATE_UINT32(iof_en, SIFIVEGPIOState), + VMSTATE_UINT32(iof_sel, SIFIVEGPIOState), + VMSTATE_UINT32(out_xor, SIFIVEGPIOState), + VMSTATE_UINT32(in, SIFIVEGPIOState), + VMSTATE_UINT32(in_mask, SIFIVEGPIOState), + VMSTATE_END_OF_LIST() + } +}; + +static Property sifive_gpio_properties[] = { + DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS), + DEFINE_PROP_END_OF_LIST(), +}; + +static void sifive_gpio_realize(DeviceState *dev, Error **errp) +{ + SIFIVEGPIOState *s = SIFIVE_GPIO(dev); + + memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s, + TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE); + + sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); + + for (int i = 0; i < s->ngpio; i++) { + sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); + } + + qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio); + qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio); +} + +static void sifive_gpio_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + device_class_set_props(dc, sifive_gpio_properties); + dc->vmsd = &vmstate_sifive_gpio; + dc->realize = sifive_gpio_realize; + dc->reset = sifive_gpio_reset; + dc->desc = "SiFive GPIO"; +} + +static const TypeInfo sifive_gpio_info = { + .name = TYPE_SIFIVE_GPIO, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_size = sizeof(SIFIVEGPIOState), + .class_init = sifive_gpio_class_init +}; + +static void sifive_gpio_register_types(void) +{ + type_register_static(&sifive_gpio_info); +} + +type_init(sifive_gpio_register_types) diff --git a/hw/gpio/trace-events b/hw/gpio/trace-events index c1271fdfb2..6e3f048745 100644 --- a/hw/gpio/trace-events +++ b/hw/gpio/trace-events @@ -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 diff --git a/hw/riscv/Kconfig b/hw/riscv/Kconfig index 76eaf77a80..5a8335bfec 100644 --- a/hw/riscv/Kconfig +++ b/hw/riscv/Kconfig @@ -15,6 +15,7 @@ config SIFIVE_E bool select HART select SIFIVE + select SIFIVE_GPIO select SIFIVE_E_PRCI select UNIMP @@ -23,6 +24,7 @@ config SIFIVE_U select CADENCE select HART select SIFIVE + select SIFIVE_GPIO select SIFIVE_PDMA select SIFIVE_U_OTP select SIFIVE_U_PRCI diff --git a/hw/riscv/meson.build b/hw/riscv/meson.build index 74a73b2a44..90003793d4 100644 --- a/hw/riscv/meson.build +++ b/hw/riscv/meson.build @@ -5,7 +5,6 @@ riscv_ss.add(when: 'CONFIG_HART', if_true: 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')) diff --git a/hw/riscv/sifive_gpio.c b/hw/riscv/sifive_gpio.c deleted file mode 100644 index aac6b44cac..0000000000 --- a/hw/riscv/sifive_gpio.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * SiFive System-on-Chip general purpose input/output register definition - * - * Copyright 2019 AdaCore - * - * Base on nrf51_gpio.c: - * - * Copyright 2018 Steffen Görtz - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "hw/irq.h" -#include "hw/qdev-properties.h" -#include "hw/riscv/sifive_gpio.h" -#include "migration/vmstate.h" -#include "trace.h" - -static void update_output_irq(SIFIVEGPIOState *s) -{ - uint32_t pending; - uint32_t pin; - - pending = s->high_ip & s->high_ie; - pending |= s->low_ip & s->low_ie; - pending |= s->rise_ip & s->rise_ie; - pending |= s->fall_ip & s->fall_ie; - - for (int i = 0; i < s->ngpio; i++) { - pin = 1 << i; - qemu_set_irq(s->irq[i], (pending & pin) != 0); - trace_sifive_gpio_update_output_irq(i, (pending & pin) != 0); - } -} - -static void update_state(SIFIVEGPIOState *s) -{ - size_t i; - bool prev_ival, in, in_mask, port, out_xor, pull, output_en, input_en, - rise_ip, fall_ip, low_ip, high_ip, oval, actual_value, ival; - - for (i = 0; i < s->ngpio; i++) { - - prev_ival = extract32(s->value, i, 1); - in = extract32(s->in, i, 1); - in_mask = extract32(s->in_mask, i, 1); - port = extract32(s->port, i, 1); - out_xor = extract32(s->out_xor, i, 1); - pull = extract32(s->pue, i, 1); - output_en = extract32(s->output_en, i, 1); - input_en = extract32(s->input_en, i, 1); - rise_ip = extract32(s->rise_ip, i, 1); - fall_ip = extract32(s->fall_ip, i, 1); - low_ip = extract32(s->low_ip, i, 1); - high_ip = extract32(s->high_ip, i, 1); - - /* Output value (IOF not supported) */ - oval = output_en && (port ^ out_xor); - - /* Pin both driven externally and internally */ - if (output_en && in_mask) { - qemu_log_mask(LOG_GUEST_ERROR, "GPIO pin %zu short circuited\n", i); - } - - if (in_mask) { - /* The pin is driven by external device */ - actual_value = in; - } else if (output_en) { - /* The pin is driven by internal circuit */ - actual_value = oval; - } else { - /* Floating? Apply pull-up resistor */ - actual_value = pull; - } - - if (output_en) { - qemu_set_irq(s->output[i], actual_value); - } - - /* Input value */ - ival = input_en && actual_value; - - /* Interrupts */ - high_ip = high_ip || ival; - s->high_ip = deposit32(s->high_ip, i, 1, high_ip); - - low_ip = low_ip || !ival; - s->low_ip = deposit32(s->low_ip, i, 1, low_ip); - - rise_ip = rise_ip || (ival && !prev_ival); - s->rise_ip = deposit32(s->rise_ip, i, 1, rise_ip); - - fall_ip = fall_ip || (!ival && prev_ival); - s->fall_ip = deposit32(s->fall_ip, i, 1, fall_ip); - - /* Update value */ - s->value = deposit32(s->value, i, 1, ival); - } - update_output_irq(s); -} - -static uint64_t sifive_gpio_read(void *opaque, hwaddr offset, unsigned int size) -{ - SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); - uint64_t r = 0; - - switch (offset) { - case SIFIVE_GPIO_REG_VALUE: - r = s->value; - break; - - case SIFIVE_GPIO_REG_INPUT_EN: - r = s->input_en; - break; - - case SIFIVE_GPIO_REG_OUTPUT_EN: - r = s->output_en; - break; - - case SIFIVE_GPIO_REG_PORT: - r = s->port; - break; - - case SIFIVE_GPIO_REG_PUE: - r = s->pue; - break; - - case SIFIVE_GPIO_REG_DS: - r = s->ds; - break; - - case SIFIVE_GPIO_REG_RISE_IE: - r = s->rise_ie; - break; - - case SIFIVE_GPIO_REG_RISE_IP: - r = s->rise_ip; - break; - - case SIFIVE_GPIO_REG_FALL_IE: - r = s->fall_ie; - break; - - case SIFIVE_GPIO_REG_FALL_IP: - r = s->fall_ip; - break; - - case SIFIVE_GPIO_REG_HIGH_IE: - r = s->high_ie; - break; - - case SIFIVE_GPIO_REG_HIGH_IP: - r = s->high_ip; - break; - - case SIFIVE_GPIO_REG_LOW_IE: - r = s->low_ie; - break; - - case SIFIVE_GPIO_REG_LOW_IP: - r = s->low_ip; - break; - - case SIFIVE_GPIO_REG_IOF_EN: - r = s->iof_en; - break; - - case SIFIVE_GPIO_REG_IOF_SEL: - r = s->iof_sel; - break; - - case SIFIVE_GPIO_REG_OUT_XOR: - r = s->out_xor; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: bad read offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - } - - trace_sifive_gpio_read(offset, r); - - return r; -} - -static void sifive_gpio_write(void *opaque, hwaddr offset, - uint64_t value, unsigned int size) -{ - SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); - - trace_sifive_gpio_write(offset, value); - - switch (offset) { - - case SIFIVE_GPIO_REG_INPUT_EN: - s->input_en = value; - break; - - case SIFIVE_GPIO_REG_OUTPUT_EN: - s->output_en = value; - break; - - case SIFIVE_GPIO_REG_PORT: - s->port = value; - break; - - case SIFIVE_GPIO_REG_PUE: - s->pue = value; - break; - - case SIFIVE_GPIO_REG_DS: - s->ds = value; - break; - - case SIFIVE_GPIO_REG_RISE_IE: - s->rise_ie = value; - break; - - case SIFIVE_GPIO_REG_RISE_IP: - /* Write 1 to clear */ - s->rise_ip &= ~value; - break; - - case SIFIVE_GPIO_REG_FALL_IE: - s->fall_ie = value; - break; - - case SIFIVE_GPIO_REG_FALL_IP: - /* Write 1 to clear */ - s->fall_ip &= ~value; - break; - - case SIFIVE_GPIO_REG_HIGH_IE: - s->high_ie = value; - break; - - case SIFIVE_GPIO_REG_HIGH_IP: - /* Write 1 to clear */ - s->high_ip &= ~value; - break; - - case SIFIVE_GPIO_REG_LOW_IE: - s->low_ie = value; - break; - - case SIFIVE_GPIO_REG_LOW_IP: - /* Write 1 to clear */ - s->low_ip &= ~value; - break; - - case SIFIVE_GPIO_REG_IOF_EN: - s->iof_en = value; - break; - - case SIFIVE_GPIO_REG_IOF_SEL: - s->iof_sel = value; - break; - - case SIFIVE_GPIO_REG_OUT_XOR: - s->out_xor = value; - break; - - default: - qemu_log_mask(LOG_GUEST_ERROR, - "%s: bad write offset 0x%" HWADDR_PRIx "\n", - __func__, offset); - } - - update_state(s); -} - -static const MemoryRegionOps gpio_ops = { - .read = sifive_gpio_read, - .write = sifive_gpio_write, - .endianness = DEVICE_LITTLE_ENDIAN, - .impl.min_access_size = 4, - .impl.max_access_size = 4, -}; - -static void sifive_gpio_set(void *opaque, int line, int value) -{ - SIFIVEGPIOState *s = SIFIVE_GPIO(opaque); - - trace_sifive_gpio_set(line, value); - - assert(line >= 0 && line < SIFIVE_GPIO_PINS); - - s->in_mask = deposit32(s->in_mask, line, 1, value >= 0); - if (value >= 0) { - s->in = deposit32(s->in, line, 1, value != 0); - } - - update_state(s); -} - -static void sifive_gpio_reset(DeviceState *dev) -{ - SIFIVEGPIOState *s = SIFIVE_GPIO(dev); - - s->value = 0; - s->input_en = 0; - s->output_en = 0; - s->port = 0; - s->pue = 0; - s->ds = 0; - s->rise_ie = 0; - s->rise_ip = 0; - s->fall_ie = 0; - s->fall_ip = 0; - s->high_ie = 0; - s->high_ip = 0; - s->low_ie = 0; - s->low_ip = 0; - s->iof_en = 0; - s->iof_sel = 0; - s->out_xor = 0; - s->in = 0; - s->in_mask = 0; -} - -static const VMStateDescription vmstate_sifive_gpio = { - .name = TYPE_SIFIVE_GPIO, - .version_id = 1, - .minimum_version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT32(value, SIFIVEGPIOState), - VMSTATE_UINT32(input_en, SIFIVEGPIOState), - VMSTATE_UINT32(output_en, SIFIVEGPIOState), - VMSTATE_UINT32(port, SIFIVEGPIOState), - VMSTATE_UINT32(pue, SIFIVEGPIOState), - VMSTATE_UINT32(rise_ie, SIFIVEGPIOState), - VMSTATE_UINT32(rise_ip, SIFIVEGPIOState), - VMSTATE_UINT32(fall_ie, SIFIVEGPIOState), - VMSTATE_UINT32(fall_ip, SIFIVEGPIOState), - VMSTATE_UINT32(high_ie, SIFIVEGPIOState), - VMSTATE_UINT32(high_ip, SIFIVEGPIOState), - VMSTATE_UINT32(low_ie, SIFIVEGPIOState), - VMSTATE_UINT32(low_ip, SIFIVEGPIOState), - VMSTATE_UINT32(iof_en, SIFIVEGPIOState), - VMSTATE_UINT32(iof_sel, SIFIVEGPIOState), - VMSTATE_UINT32(out_xor, SIFIVEGPIOState), - VMSTATE_UINT32(in, SIFIVEGPIOState), - VMSTATE_UINT32(in_mask, SIFIVEGPIOState), - VMSTATE_END_OF_LIST() - } -}; - -static Property sifive_gpio_properties[] = { - DEFINE_PROP_UINT32("ngpio", SIFIVEGPIOState, ngpio, SIFIVE_GPIO_PINS), - DEFINE_PROP_END_OF_LIST(), -}; - -static void sifive_gpio_realize(DeviceState *dev, Error **errp) -{ - SIFIVEGPIOState *s = SIFIVE_GPIO(dev); - - memory_region_init_io(&s->mmio, OBJECT(dev), &gpio_ops, s, - TYPE_SIFIVE_GPIO, SIFIVE_GPIO_SIZE); - - sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mmio); - - for (int i = 0; i < s->ngpio; i++) { - sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq[i]); - } - - qdev_init_gpio_in(DEVICE(s), sifive_gpio_set, s->ngpio); - qdev_init_gpio_out(DEVICE(s), s->output, s->ngpio); -} - -static void sifive_gpio_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - device_class_set_props(dc, sifive_gpio_properties); - dc->vmsd = &vmstate_sifive_gpio; - dc->realize = sifive_gpio_realize; - dc->reset = sifive_gpio_reset; - dc->desc = "SiFive GPIO"; -} - -static const TypeInfo sifive_gpio_info = { - .name = TYPE_SIFIVE_GPIO, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SIFIVEGPIOState), - .class_init = sifive_gpio_class_init -}; - -static void sifive_gpio_register_types(void) -{ - type_register_static(&sifive_gpio_info); -} - -type_init(sifive_gpio_register_types) diff --git a/hw/riscv/trace-events b/hw/riscv/trace-events deleted file mode 100644 index 6d59233e23..0000000000 --- a/hw/riscv/trace-events +++ /dev/null @@ -1,7 +0,0 @@ -# See docs/devel/tracing.txt for syntax documentation. - -# hw/gpio/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 diff --git a/hw/riscv/trace.h b/hw/riscv/trace.h deleted file mode 100644 index 8c0e3ca1f3..0000000000 --- a/hw/riscv/trace.h +++ /dev/null @@ -1 +0,0 @@ -#include "trace/trace-hw_riscv.h" diff --git a/include/hw/gpio/sifive_gpio.h b/include/hw/gpio/sifive_gpio.h new file mode 100644 index 0000000000..cf12fcfd62 --- /dev/null +++ b/include/hw/gpio/sifive_gpio.h @@ -0,0 +1,76 @@ +/* + * SiFive System-on-Chip general purpose input/output register definition + * + * Copyright 2019 AdaCore + * + * Base on nrf51_gpio.c: + * + * Copyright 2018 Steffen Görtz + * + * This code is licensed under the GPL version 2 or later. See + * the COPYING file in the top-level directory. + */ + +#ifndef SIFIVE_GPIO_H +#define SIFIVE_GPIO_H + +#include "hw/sysbus.h" + +#define TYPE_SIFIVE_GPIO "sifive_soc.gpio" +#define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO) + +#define SIFIVE_GPIO_PINS 32 + +#define SIFIVE_GPIO_SIZE 0x100 + +#define SIFIVE_GPIO_REG_VALUE 0x000 +#define SIFIVE_GPIO_REG_INPUT_EN 0x004 +#define SIFIVE_GPIO_REG_OUTPUT_EN 0x008 +#define SIFIVE_GPIO_REG_PORT 0x00C +#define SIFIVE_GPIO_REG_PUE 0x010 +#define SIFIVE_GPIO_REG_DS 0x014 +#define SIFIVE_GPIO_REG_RISE_IE 0x018 +#define SIFIVE_GPIO_REG_RISE_IP 0x01C +#define SIFIVE_GPIO_REG_FALL_IE 0x020 +#define SIFIVE_GPIO_REG_FALL_IP 0x024 +#define SIFIVE_GPIO_REG_HIGH_IE 0x028 +#define SIFIVE_GPIO_REG_HIGH_IP 0x02C +#define SIFIVE_GPIO_REG_LOW_IE 0x030 +#define SIFIVE_GPIO_REG_LOW_IP 0x034 +#define SIFIVE_GPIO_REG_IOF_EN 0x038 +#define SIFIVE_GPIO_REG_IOF_SEL 0x03C +#define SIFIVE_GPIO_REG_OUT_XOR 0x040 + +typedef struct SIFIVEGPIOState { + SysBusDevice parent_obj; + + MemoryRegion mmio; + + qemu_irq irq[SIFIVE_GPIO_PINS]; + qemu_irq output[SIFIVE_GPIO_PINS]; + + uint32_t value; /* Actual value of the pin */ + uint32_t input_en; + uint32_t output_en; + uint32_t port; /* Pin value requested by the user */ + uint32_t pue; + uint32_t ds; + uint32_t rise_ie; + uint32_t rise_ip; + uint32_t fall_ie; + uint32_t fall_ip; + uint32_t high_ie; + uint32_t high_ip; + uint32_t low_ie; + uint32_t low_ip; + uint32_t iof_en; + uint32_t iof_sel; + uint32_t out_xor; + uint32_t in; + uint32_t in_mask; + + /* config */ + uint32_t ngpio; +} SIFIVEGPIOState; + +#endif /* SIFIVE_GPIO_H */ diff --git a/include/hw/riscv/sifive_e.h b/include/hw/riscv/sifive_e.h index 637414130b..b1400843c2 100644 --- a/include/hw/riscv/sifive_e.h +++ b/include/hw/riscv/sifive_e.h @@ -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) \ diff --git a/include/hw/riscv/sifive_gpio.h b/include/hw/riscv/sifive_gpio.h deleted file mode 100644 index cf12fcfd62..0000000000 --- a/include/hw/riscv/sifive_gpio.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SiFive System-on-Chip general purpose input/output register definition - * - * Copyright 2019 AdaCore - * - * Base on nrf51_gpio.c: - * - * Copyright 2018 Steffen Görtz - * - * This code is licensed under the GPL version 2 or later. See - * the COPYING file in the top-level directory. - */ - -#ifndef SIFIVE_GPIO_H -#define SIFIVE_GPIO_H - -#include "hw/sysbus.h" - -#define TYPE_SIFIVE_GPIO "sifive_soc.gpio" -#define SIFIVE_GPIO(obj) OBJECT_CHECK(SIFIVEGPIOState, (obj), TYPE_SIFIVE_GPIO) - -#define SIFIVE_GPIO_PINS 32 - -#define SIFIVE_GPIO_SIZE 0x100 - -#define SIFIVE_GPIO_REG_VALUE 0x000 -#define SIFIVE_GPIO_REG_INPUT_EN 0x004 -#define SIFIVE_GPIO_REG_OUTPUT_EN 0x008 -#define SIFIVE_GPIO_REG_PORT 0x00C -#define SIFIVE_GPIO_REG_PUE 0x010 -#define SIFIVE_GPIO_REG_DS 0x014 -#define SIFIVE_GPIO_REG_RISE_IE 0x018 -#define SIFIVE_GPIO_REG_RISE_IP 0x01C -#define SIFIVE_GPIO_REG_FALL_IE 0x020 -#define SIFIVE_GPIO_REG_FALL_IP 0x024 -#define SIFIVE_GPIO_REG_HIGH_IE 0x028 -#define SIFIVE_GPIO_REG_HIGH_IP 0x02C -#define SIFIVE_GPIO_REG_LOW_IE 0x030 -#define SIFIVE_GPIO_REG_LOW_IP 0x034 -#define SIFIVE_GPIO_REG_IOF_EN 0x038 -#define SIFIVE_GPIO_REG_IOF_SEL 0x03C -#define SIFIVE_GPIO_REG_OUT_XOR 0x040 - -typedef struct SIFIVEGPIOState { - SysBusDevice parent_obj; - - MemoryRegion mmio; - - qemu_irq irq[SIFIVE_GPIO_PINS]; - qemu_irq output[SIFIVE_GPIO_PINS]; - - uint32_t value; /* Actual value of the pin */ - uint32_t input_en; - uint32_t output_en; - uint32_t port; /* Pin value requested by the user */ - uint32_t pue; - uint32_t ds; - uint32_t rise_ie; - uint32_t rise_ip; - uint32_t fall_ie; - uint32_t fall_ip; - uint32_t high_ie; - uint32_t high_ip; - uint32_t low_ie; - uint32_t low_ip; - uint32_t iof_en; - uint32_t iof_sel; - uint32_t out_xor; - uint32_t in; - uint32_t in_mask; - - /* config */ - uint32_t ngpio; -} SIFIVEGPIOState; - -#endif /* SIFIVE_GPIO_H */ diff --git a/include/hw/riscv/sifive_u.h b/include/hw/riscv/sifive_u.h index 936a3bd0b1..fe5c580845 100644 --- a/include/hw/riscv/sifive_u.h +++ b/include/hw/riscv/sifive_u.h @@ -23,7 +23,7 @@ #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/gpio/sifive_gpio.h" #include "hw/misc/sifive_u_otp.h" #include "hw/misc/sifive_u_prci.h" diff --git a/meson.build b/meson.build index 5421eca66a..bc869c676a 100644 --- a/meson.build +++ b/meson.build @@ -773,7 +773,6 @@ if have_system 'hw/watchdog', 'hw/xen', 'hw/gpio', - 'hw/riscv', 'migration', 'net', 'ui', -- cgit 1.4.1