diff options
Diffstat (limited to 'hw/misc')
| -rw-r--r-- | hw/misc/Kconfig | 5 | ||||
| -rw-r--r-- | hw/misc/allwinner-r40-ccu.c | 209 | ||||
| -rw-r--r-- | hw/misc/allwinner-r40-dramc.c | 513 | ||||
| -rw-r--r-- | hw/misc/allwinner-sramc.c | 184 | ||||
| -rw-r--r-- | hw/misc/aspeed_hace.c | 2 | ||||
| -rw-r--r-- | hw/misc/axp209.c | 238 | ||||
| -rw-r--r-- | hw/misc/axp2xx.c | 283 | ||||
| -rw-r--r-- | hw/misc/bcm2835_property.c | 132 | ||||
| -rw-r--r-- | hw/misc/imx_rngc.c | 6 | ||||
| -rw-r--r-- | hw/misc/macio/mac_dbdma.c | 2 | ||||
| -rw-r--r-- | hw/misc/macio/meson.build | 2 | ||||
| -rw-r--r-- | hw/misc/meson.build | 149 | ||||
| -rw-r--r-- | hw/misc/trace-events | 26 |
13 files changed, 1376 insertions, 375 deletions
diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig index 2ef5781ef8..e4c2149175 100644 --- a/hw/misc/Kconfig +++ b/hw/misc/Kconfig @@ -170,13 +170,16 @@ config VIRT_CTRL config LASI bool +config ALLWINNER_SRAMC + bool + config ALLWINNER_A10_CCM bool config ALLWINNER_A10_DRAMC bool -config AXP209_PMU +config AXP2XX_PMU bool depends on I2C diff --git a/hw/misc/allwinner-r40-ccu.c b/hw/misc/allwinner-r40-ccu.c new file mode 100644 index 0000000000..d82fee12db --- /dev/null +++ b/hw/misc/allwinner-r40-ccu.c @@ -0,0 +1,209 @@ +/* + * Allwinner R40 Clock Control Unit emulation + * + * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.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 of the License, or + * (at your option) any later version. + * + * 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/units.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "hw/misc/allwinner-r40-ccu.h" + +/* CCU register offsets */ +enum { + REG_PLL_CPUX_CTRL = 0x0000, + REG_PLL_AUDIO_CTRL = 0x0008, + REG_PLL_VIDEO0_CTRL = 0x0010, + REG_PLL_VE_CTRL = 0x0018, + REG_PLL_DDR0_CTRL = 0x0020, + REG_PLL_PERIPH0_CTRL = 0x0028, + REG_PLL_PERIPH1_CTRL = 0x002c, + REG_PLL_VIDEO1_CTRL = 0x0030, + REG_PLL_SATA_CTRL = 0x0034, + REG_PLL_GPU_CTRL = 0x0038, + REG_PLL_MIPI_CTRL = 0x0040, + REG_PLL_DE_CTRL = 0x0048, + REG_PLL_DDR1_CTRL = 0x004c, + REG_AHB1_APB1_CFG = 0x0054, + REG_APB2_CFG = 0x0058, + REG_MMC0_CLK = 0x0088, + REG_MMC1_CLK = 0x008c, + REG_MMC2_CLK = 0x0090, + REG_MMC3_CLK = 0x0094, + REG_USBPHY_CFG = 0x00cc, + REG_PLL_DDR_AUX = 0x00f0, + REG_DRAM_CFG = 0x00f4, + REG_PLL_DDR1_CFG = 0x00f8, + REG_DRAM_CLK_GATING = 0x0100, + REG_GMAC_CLK = 0x0164, + REG_SYS_32K_CLK = 0x0310, + REG_PLL_LOCK_CTRL = 0x0320, +}; + +#define REG_INDEX(offset) (offset / sizeof(uint32_t)) + +/* CCU register flags */ +enum { + REG_PLL_ENABLE = (1 << 31), + REG_PLL_LOCK = (1 << 28), +}; + +static uint64_t allwinner_r40_ccu_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwR40ClockCtlState *s = AW_R40_CCU(opaque); + const uint32_t idx = REG_INDEX(offset); + + switch (offset) { + case 0x324 ... AW_R40_CCU_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + return s->regs[idx]; +} + +static void allwinner_r40_ccu_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwR40ClockCtlState *s = AW_R40_CCU(opaque); + + switch (offset) { + case REG_DRAM_CFG: /* DRAM Configuration(for DDR0) */ + /* bit16: SDRCLK_UPD (SDRCLK configuration 0 update) */ + val &= ~(1 << 16); + break; + case REG_PLL_DDR1_CTRL: /* DDR1 Control register */ + /* bit30: SDRPLL_UPD */ + val &= ~(1 << 30); + if (val & REG_PLL_ENABLE) { + val |= REG_PLL_LOCK; + } + break; + case REG_PLL_CPUX_CTRL: + case REG_PLL_AUDIO_CTRL: + case REG_PLL_VE_CTRL: + case REG_PLL_VIDEO0_CTRL: + case REG_PLL_DDR0_CTRL: + case REG_PLL_PERIPH0_CTRL: + case REG_PLL_PERIPH1_CTRL: + case REG_PLL_VIDEO1_CTRL: + case REG_PLL_SATA_CTRL: + case REG_PLL_GPU_CTRL: + case REG_PLL_MIPI_CTRL: + case REG_PLL_DE_CTRL: + if (val & REG_PLL_ENABLE) { + val |= REG_PLL_LOCK; + } + break; + case 0x324 ... AW_R40_CCU_IOSIZE: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + default: + qemu_log_mask(LOG_UNIMP, "%s: unimplemented write offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + } + + s->regs[REG_INDEX(offset)] = (uint32_t) val; +} + +static const MemoryRegionOps allwinner_r40_ccu_ops = { + .read = allwinner_r40_ccu_read, + .write = allwinner_r40_ccu_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static void allwinner_r40_ccu_reset(DeviceState *dev) +{ + AwR40ClockCtlState *s = AW_R40_CCU(dev); + + memset(s->regs, 0, sizeof(s->regs)); + + /* Set default values for registers */ + s->regs[REG_INDEX(REG_PLL_CPUX_CTRL)] = 0x00001000; + s->regs[REG_INDEX(REG_PLL_AUDIO_CTRL)] = 0x00035514; + s->regs[REG_INDEX(REG_PLL_VIDEO0_CTRL)] = 0x03006207; + s->regs[REG_INDEX(REG_PLL_VE_CTRL)] = 0x03006207; + s->regs[REG_INDEX(REG_PLL_DDR0_CTRL)] = 0x00001000, + s->regs[REG_INDEX(REG_PLL_PERIPH0_CTRL)] = 0x00041811; + s->regs[REG_INDEX(REG_PLL_PERIPH1_CTRL)] = 0x00041811; + s->regs[REG_INDEX(REG_PLL_VIDEO1_CTRL)] = 0x03006207; + s->regs[REG_INDEX(REG_PLL_SATA_CTRL)] = 0x00001811; + s->regs[REG_INDEX(REG_PLL_GPU_CTRL)] = 0x03006207; + s->regs[REG_INDEX(REG_PLL_MIPI_CTRL)] = 0x00000515; + s->regs[REG_INDEX(REG_PLL_DE_CTRL)] = 0x03006207; + s->regs[REG_INDEX(REG_PLL_DDR1_CTRL)] = 0x00001800; + s->regs[REG_INDEX(REG_AHB1_APB1_CFG)] = 0x00001010; + s->regs[REG_INDEX(REG_APB2_CFG)] = 0x01000000; + s->regs[REG_INDEX(REG_PLL_DDR_AUX)] = 0x00000001; + s->regs[REG_INDEX(REG_PLL_DDR1_CFG)] = 0x0ccca000; + s->regs[REG_INDEX(REG_SYS_32K_CLK)] = 0x0000000f; +} + +static void allwinner_r40_ccu_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + AwR40ClockCtlState *s = AW_R40_CCU(obj); + + /* Memory mapping */ + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_r40_ccu_ops, s, + TYPE_AW_R40_CCU, AW_R40_CCU_IOSIZE); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const VMStateDescription allwinner_r40_ccu_vmstate = { + .name = "allwinner-r40-ccu", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(regs, AwR40ClockCtlState, AW_R40_CCU_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_r40_ccu_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = allwinner_r40_ccu_reset; + dc->vmsd = &allwinner_r40_ccu_vmstate; +} + +static const TypeInfo allwinner_r40_ccu_info = { + .name = TYPE_AW_R40_CCU, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = allwinner_r40_ccu_init, + .instance_size = sizeof(AwR40ClockCtlState), + .class_init = allwinner_r40_ccu_class_init, +}; + +static void allwinner_r40_ccu_register(void) +{ + type_register_static(&allwinner_r40_ccu_info); +} + +type_init(allwinner_r40_ccu_register) diff --git a/hw/misc/allwinner-r40-dramc.c b/hw/misc/allwinner-r40-dramc.c new file mode 100644 index 0000000000..ea6124744f --- /dev/null +++ b/hw/misc/allwinner-r40-dramc.c @@ -0,0 +1,513 @@ +/* + * Allwinner R40 SDRAM Controller emulation + * + * CCopyright (C) 2023 qianfan Zhao <qianfanguijin@163.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 of the License, or + * (at your option) any later version. + * + * 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/units.h" +#include "qemu/error-report.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "exec/address-spaces.h" +#include "hw/qdev-properties.h" +#include "qapi/error.h" +#include "qemu/bitops.h" +#include "hw/misc/allwinner-r40-dramc.h" +#include "trace.h" + +#define REG_INDEX(offset) (offset / sizeof(uint32_t)) + +/* DRAMCOM register offsets */ +enum { + REG_DRAMCOM_CR = 0x0000, /* Control Register */ +}; + +/* DRAMCOMM register flags */ +enum { + REG_DRAMCOM_CR_DUAL_RANK = (1 << 0), +}; + +/* DRAMCTL register offsets */ +enum { + REG_DRAMCTL_PIR = 0x0000, /* PHY Initialization Register */ + REG_DRAMCTL_PGSR = 0x0010, /* PHY General Status Register */ + REG_DRAMCTL_STATR = 0x0018, /* Status Register */ + REG_DRAMCTL_PGCR = 0x0100, /* PHY general configuration registers */ +}; + +/* DRAMCTL register flags */ +enum { + REG_DRAMCTL_PGSR_INITDONE = (1 << 0), + REG_DRAMCTL_PGSR_READ_TIMEOUT = (1 << 13), + REG_DRAMCTL_PGCR_ENABLE_READ_TIMEOUT = (1 << 25), +}; + +enum { + REG_DRAMCTL_STATR_ACTIVE = (1 << 0), +}; + +#define DRAM_MAX_ROW_BITS 16 +#define DRAM_MAX_COL_BITS 13 /* 8192 */ +#define DRAM_MAX_BANK 3 + +static uint64_t dram_autodetect_cells[DRAM_MAX_ROW_BITS] + [DRAM_MAX_BANK] + [DRAM_MAX_COL_BITS]; +struct VirtualDDRChip { + uint32_t ram_size; + uint8_t bank_bits; + uint8_t row_bits; + uint8_t col_bits; +}; + +/* + * Only power of 2 RAM sizes from 256MiB up to 2048MiB are supported, + * 2GiB memory is not supported due to dual rank feature. + */ +static const struct VirtualDDRChip dummy_ddr_chips[] = { + { + .ram_size = 256, + .bank_bits = 3, + .row_bits = 12, + .col_bits = 13, + }, { + .ram_size = 512, + .bank_bits = 3, + .row_bits = 13, + .col_bits = 13, + }, { + .ram_size = 1024, + .bank_bits = 3, + .row_bits = 14, + .col_bits = 13, + }, { + 0 + } +}; + +static const struct VirtualDDRChip *get_match_ddr(uint32_t ram_size) +{ + const struct VirtualDDRChip *ddr; + + for (ddr = &dummy_ddr_chips[0]; ddr->ram_size; ddr++) { + if (ddr->ram_size == ram_size) { + return ddr; + } + } + + return NULL; +} + +static uint64_t *address_to_autodetect_cells(AwR40DramCtlState *s, + const struct VirtualDDRChip *ddr, + uint32_t offset) +{ + int row_index = 0, bank_index = 0, col_index = 0; + uint32_t row_addr, bank_addr, col_addr; + + row_addr = extract32(offset, s->set_col_bits + s->set_bank_bits, + s->set_row_bits); + bank_addr = extract32(offset, s->set_col_bits, s->set_bank_bits); + col_addr = extract32(offset, 0, s->set_col_bits); + + for (int i = 0; i < ddr->row_bits; i++) { + if (row_addr & BIT(i)) { + row_index = i; + } + } + + for (int i = 0; i < ddr->bank_bits; i++) { + if (bank_addr & BIT(i)) { + bank_index = i; + } + } + + for (int i = 0; i < ddr->col_bits; i++) { + if (col_addr & BIT(i)) { + col_index = i; + } + } + + trace_allwinner_r40_dramc_offset_to_cell(offset, row_index, bank_index, + col_index); + return &dram_autodetect_cells[row_index][bank_index][col_index]; +} + +static void allwinner_r40_dramc_map_rows(AwR40DramCtlState *s, uint8_t row_bits, + uint8_t bank_bits, uint8_t col_bits) +{ + const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size); + bool enable_detect_cells; + + trace_allwinner_r40_dramc_map_rows(row_bits, bank_bits, col_bits); + + if (!ddr) { + return; + } + + s->set_row_bits = row_bits; + s->set_bank_bits = bank_bits; + s->set_col_bits = col_bits; + + enable_detect_cells = ddr->bank_bits != bank_bits + || ddr->row_bits != row_bits + || ddr->col_bits != col_bits; + + if (enable_detect_cells) { + trace_allwinner_r40_dramc_detect_cells_enable(); + } else { + trace_allwinner_r40_dramc_detect_cells_disable(); + } + + memory_region_set_enabled(&s->detect_cells, enable_detect_cells); +} + +static uint64_t allwinner_r40_dramcom_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + if (idx >= AW_R40_DRAMCOM_REGS_NUM) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + trace_allwinner_r40_dramcom_read(offset, s->dramcom[idx], size); + return s->dramcom[idx]; +} + +static void allwinner_r40_dramcom_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + trace_allwinner_r40_dramcom_write(offset, val, size); + + if (idx >= AW_R40_DRAMCOM_REGS_NUM) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return; + } + + switch (offset) { + case REG_DRAMCOM_CR: /* Control Register */ + if (!(val & REG_DRAMCOM_CR_DUAL_RANK)) { + allwinner_r40_dramc_map_rows(s, ((val >> 4) & 0xf) + 1, + ((val >> 2) & 0x1) + 2, + (((val >> 8) & 0xf) + 3)); + } + break; + }; + + s->dramcom[idx] = (uint32_t) val; +} + +static uint64_t allwinner_r40_dramctl_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + if (idx >= AW_R40_DRAMCTL_REGS_NUM) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + trace_allwinner_r40_dramctl_read(offset, s->dramctl[idx], size); + return s->dramctl[idx]; +} + +static void allwinner_r40_dramctl_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + trace_allwinner_r40_dramctl_write(offset, val, size); + + if (idx >= AW_R40_DRAMCTL_REGS_NUM) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return; + } + + switch (offset) { + case REG_DRAMCTL_PIR: /* PHY Initialization Register */ + s->dramctl[REG_INDEX(REG_DRAMCTL_PGSR)] |= REG_DRAMCTL_PGSR_INITDONE; + s->dramctl[REG_INDEX(REG_DRAMCTL_STATR)] |= REG_DRAMCTL_STATR_ACTIVE; + break; + } + + s->dramctl[idx] = (uint32_t) val; +} + +static uint64_t allwinner_r40_dramphy_read(void *opaque, hwaddr offset, + unsigned size) +{ + const AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + if (idx >= AW_R40_DRAMPHY_REGS_NUM) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + trace_allwinner_r40_dramphy_read(offset, s->dramphy[idx], size); + return s->dramphy[idx]; +} + +static void allwinner_r40_dramphy_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const uint32_t idx = REG_INDEX(offset); + + trace_allwinner_r40_dramphy_write(offset, val, size); + + if (idx >= AW_R40_DRAMPHY_REGS_NUM) { + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return; + } + + s->dramphy[idx] = (uint32_t) val; +} + +static const MemoryRegionOps allwinner_r40_dramcom_ops = { + .read = allwinner_r40_dramcom_read, + .write = allwinner_r40_dramcom_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static const MemoryRegionOps allwinner_r40_dramctl_ops = { + .read = allwinner_r40_dramctl_read, + .write = allwinner_r40_dramctl_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static const MemoryRegionOps allwinner_r40_dramphy_ops = { + .read = allwinner_r40_dramphy_read, + .write = allwinner_r40_dramphy_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static uint64_t allwinner_r40_detect_read(void *opaque, hwaddr offset, + unsigned size) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size); + uint64_t data = 0; + + if (ddr) { + data = *address_to_autodetect_cells(s, ddr, (uint32_t)offset); + } + + trace_allwinner_r40_dramc_detect_cell_read(offset, data); + return data; +} + +static void allwinner_r40_detect_write(void *opaque, hwaddr offset, + uint64_t data, unsigned size) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + const struct VirtualDDRChip *ddr = get_match_ddr(s->ram_size); + + if (ddr) { + uint64_t *cell = address_to_autodetect_cells(s, ddr, (uint32_t)offset); + trace_allwinner_r40_dramc_detect_cell_write(offset, data); + *cell = data; + } +} + +static const MemoryRegionOps allwinner_r40_detect_ops = { + .read = allwinner_r40_detect_read, + .write = allwinner_r40_detect_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +/* + * mctl_r40_detect_rank_count in u-boot will write the high 1G of DDR + * to detect wether the board support dual_rank or not. Create a virtual memory + * if the board's ram_size less or equal than 1G, and set read time out flag of + * REG_DRAMCTL_PGSR when the user touch this high dram. + */ +static uint64_t allwinner_r40_dualrank_detect_read(void *opaque, hwaddr offset, + unsigned size) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(opaque); + uint32_t reg; + + reg = s->dramctl[REG_INDEX(REG_DRAMCTL_PGCR)]; + if (reg & REG_DRAMCTL_PGCR_ENABLE_READ_TIMEOUT) { /* Enable read time out */ + /* + * this driver only support one rank, mark READ_TIMEOUT when try + * read the second rank. + */ + s->dramctl[REG_INDEX(REG_DRAMCTL_PGSR)] + |= REG_DRAMCTL_PGSR_READ_TIMEOUT; + } + + return 0; +} + +static const MemoryRegionOps allwinner_r40_dualrank_detect_ops = { + .read = allwinner_r40_dualrank_detect_read, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static void allwinner_r40_dramc_reset(DeviceState *dev) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(dev); + + /* Set default values for registers */ + memset(&s->dramcom, 0, sizeof(s->dramcom)); + memset(&s->dramctl, 0, sizeof(s->dramctl)); + memset(&s->dramphy, 0, sizeof(s->dramphy)); +} + +static void allwinner_r40_dramc_realize(DeviceState *dev, Error **errp) +{ + AwR40DramCtlState *s = AW_R40_DRAMC(dev); + + if (!get_match_ddr(s->ram_size)) { + error_report("%s: ram-size %u MiB is not supported", + __func__, s->ram_size); + exit(1); + } + + /* detect_cells */ + sysbus_mmio_map_overlap(SYS_BUS_DEVICE(s), 3, s->ram_addr, 10); + memory_region_set_enabled(&s->detect_cells, false); + + /* + * We only support DRAM size up to 1G now, so prepare a high memory page + * after 1G for dualrank detect. index = 4 + */ + memory_region_init_io(&s->dram_high, OBJECT(s), + &allwinner_r40_dualrank_detect_ops, s, + "DRAMHIGH", KiB); + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->dram_high); + sysbus_mmio_map(SYS_BUS_DEVICE(s), 4, s->ram_addr + GiB); +} + +static void allwinner_r40_dramc_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + AwR40DramCtlState *s = AW_R40_DRAMC(obj); + + /* DRAMCOM registers, index 0 */ + memory_region_init_io(&s->dramcom_iomem, OBJECT(s), + &allwinner_r40_dramcom_ops, s, + "DRAMCOM", 4 * KiB); + sysbus_init_mmio(sbd, &s->dramcom_iomem); + + /* DRAMCTL registers, index 1 */ + memory_region_init_io(&s->dramctl_iomem, OBJECT(s), + &allwinner_r40_dramctl_ops, s, + "DRAMCTL", 4 * KiB); + sysbus_init_mmio(sbd, &s->dramctl_iomem); + + /* DRAMPHY registers. index 2 */ + memory_region_init_io(&s->dramphy_iomem, OBJECT(s), + &allwinner_r40_dramphy_ops, s, + "DRAMPHY", 4 * KiB); + sysbus_init_mmio(sbd, &s->dramphy_iomem); + + /* R40 support max 2G memory but we only support up to 1G now. index 3 */ + memory_region_init_io(&s->detect_cells, OBJECT(s), + &allwinner_r40_detect_ops, s, + "DRAMCELLS", 1 * GiB); + sysbus_init_mmio(sbd, &s->detect_cells); +} + +static Property allwinner_r40_dramc_properties[] = { + DEFINE_PROP_UINT64("ram-addr", AwR40DramCtlState, ram_addr, 0x0), + DEFINE_PROP_UINT32("ram-size", AwR40DramCtlState, ram_size, 256), /* MiB */ + DEFINE_PROP_END_OF_LIST() +}; + +static const VMStateDescription allwinner_r40_dramc_vmstate = { + .name = "allwinner-r40-dramc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32_ARRAY(dramcom, AwR40DramCtlState, + AW_R40_DRAMCOM_REGS_NUM), + VMSTATE_UINT32_ARRAY(dramctl, AwR40DramCtlState, + AW_R40_DRAMCTL_REGS_NUM), + VMSTATE_UINT32_ARRAY(dramphy, AwR40DramCtlState, + AW_R40_DRAMPHY_REGS_NUM), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_r40_dramc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = allwinner_r40_dramc_reset; + dc->vmsd = &allwinner_r40_dramc_vmstate; + dc->realize = allwinner_r40_dramc_realize; + device_class_set_props(dc, allwinner_r40_dramc_properties); +} + +static const TypeInfo allwinner_r40_dramc_info = { + .name = TYPE_AW_R40_DRAMC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = allwinner_r40_dramc_init, + .instance_size = sizeof(AwR40DramCtlState), + .class_init = allwinner_r40_dramc_class_init, +}; + +static void allwinner_r40_dramc_register(void) +{ + type_register_static(&allwinner_r40_dramc_info); +} + +type_init(allwinner_r40_dramc_register) diff --git a/hw/misc/allwinner-sramc.c b/hw/misc/allwinner-sramc.c new file mode 100644 index 0000000000..a8b731f8f2 --- /dev/null +++ b/hw/misc/allwinner-sramc.c @@ -0,0 +1,184 @@ +/* + * Allwinner R40 SRAM controller emulation + * + * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.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 of the License, or + * (at your option) any later version. + * + * 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/units.h" +#include "hw/sysbus.h" +#include "migration/vmstate.h" +#include "qemu/log.h" +#include "qemu/module.h" +#include "qapi/error.h" +#include "hw/qdev-properties.h" +#include "hw/qdev-properties-system.h" +#include "hw/misc/allwinner-sramc.h" +#include "trace.h" + +/* + * register offsets + * https://linux-sunxi.org/SRAM_Controller_Register_Guide + */ +enum { + REG_SRAM_CTL1_CFG = 0x04, /* SRAM Control register 1 */ + REG_SRAM_VER = 0x24, /* SRAM Version register */ + REG_SRAM_R40_SOFT_ENTRY_REG0 = 0xbc, +}; + +/* REG_SRAMC_VERSION bit defines */ +#define SRAM_VER_READ_ENABLE (1 << 15) +#define SRAM_VER_VERSION_SHIFT 16 +#define SRAM_VERSION_SUN8I_R40 0x1701 + +static uint64_t allwinner_sramc_read(void *opaque, hwaddr offset, + unsigned size) +{ + AwSRAMCState *s = AW_SRAMC(opaque); + AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s); + uint64_t val = 0; + + switch (offset) { + case REG_SRAM_CTL1_CFG: + val = s->sram_ctl1; + break; + case REG_SRAM_VER: + /* bit15: lock bit, set this bit before reading this register */ + if (s->sram_ver & SRAM_VER_READ_ENABLE) { + val = SRAM_VER_READ_ENABLE | + (sc->sram_version_code << SRAM_VER_VERSION_SHIFT); + } + break; + case REG_SRAM_R40_SOFT_ENTRY_REG0: + val = s->sram_soft_entry_reg0; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + return 0; + } + + trace_allwinner_sramc_read(offset, val); + + return val; +} + +static void allwinner_sramc_write(void *opaque, hwaddr offset, + uint64_t val, unsigned size) +{ + AwSRAMCState *s = AW_SRAMC(opaque); + + trace_allwinner_sramc_write(offset, val); + + switch (offset) { + case REG_SRAM_CTL1_CFG: + s->sram_ctl1 = val; + break; + case REG_SRAM_VER: + /* Only the READ_ENABLE bit is writeable */ + s->sram_ver = val & SRAM_VER_READ_ENABLE; + break; + case REG_SRAM_R40_SOFT_ENTRY_REG0: + s->sram_soft_entry_reg0 = val; + break; + default: + qemu_log_mask(LOG_GUEST_ERROR, "%s: out-of-bounds offset 0x%04x\n", + __func__, (uint32_t)offset); + break; + } +} + +static const MemoryRegionOps allwinner_sramc_ops = { + .read = allwinner_sramc_read, + .write = allwinner_sramc_write, + .endianness = DEVICE_NATIVE_ENDIAN, + .valid = { + .min_access_size = 4, + .max_access_size = 4, + }, + .impl.min_access_size = 4, +}; + +static const VMStateDescription allwinner_sramc_vmstate = { + .name = "allwinner-sramc", + .version_id = 1, + .minimum_version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT32(sram_ver, AwSRAMCState), + VMSTATE_UINT32(sram_soft_entry_reg0, AwSRAMCState), + VMSTATE_END_OF_LIST() + } +}; + +static void allwinner_sramc_reset(DeviceState *dev) +{ + AwSRAMCState *s = AW_SRAMC(dev); + AwSRAMCClass *sc = AW_SRAMC_GET_CLASS(s); + + switch (sc->sram_version_code) { + case SRAM_VERSION_SUN8I_R40: + s->sram_ctl1 = 0x1300; + break; + } +} + +static void allwinner_sramc_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + + dc->reset = allwinner_sramc_reset; + dc->vmsd = &allwinner_sramc_vmstate; +} + +static void allwinner_sramc_init(Object *obj) +{ + SysBusDevice *sbd = SYS_BUS_DEVICE(obj); + AwSRAMCState *s = AW_SRAMC(obj); + + /* Memory mapping */ + memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sramc_ops, s, + TYPE_AW_SRAMC, 1 * KiB); + sysbus_init_mmio(sbd, &s->iomem); +} + +static const TypeInfo allwinner_sramc_info = { + .name = TYPE_AW_SRAMC, + .parent = TYPE_SYS_BUS_DEVICE, + .instance_init = allwinner_sramc_init, + .instance_size = sizeof(AwSRAMCState), + .class_init = allwinner_sramc_class_init, +}; + +static void allwinner_r40_sramc_class_init(ObjectClass *klass, void *data) +{ + AwSRAMCClass *sc = AW_SRAMC_CLASS(klass); + + sc->sram_version_code = SRAM_VERSION_SUN8I_R40; +} + +static const TypeInfo allwinner_r40_sramc_info = { + .name = TYPE_AW_SRAMC_SUN8I_R40, + .parent = TYPE_AW_SRAMC, + .class_init = allwinner_r40_sramc_class_init, +}; + +static void allwinner_sramc_register(void) +{ + type_register_static(&allwinner_sramc_info); + type_register_static(&allwinner_r40_sramc_info); +} + +type_init(allwinner_sramc_register) diff --git a/hw/misc/aspeed_hace.c b/hw/misc/aspeed_hace.c index 12a761f1f5..b07506ec04 100644 --- a/hw/misc/aspeed_hace.c +++ b/hw/misc/aspeed_hace.c @@ -189,7 +189,7 @@ static void do_hash_operation(AspeedHACEState *s, int algo, bool sg_mode, bool acc_mode) { struct iovec iov[ASPEED_HACE_MAX_SG]; - g_autofree uint8_t *digest_buf; + g_autofree uint8_t *digest_buf = NULL; size_t digest_len = 0; int niov = 0; int i; diff --git a/hw/misc/axp209.c b/hw/misc/axp209.c deleted file mode 100644 index 2908ed99a6..0000000000 --- a/hw/misc/axp209.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * AXP-209 PMU Emulation - * - * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.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. - * - * SPDX-License-Identifier: MIT - */ - -#include "qemu/osdep.h" -#include "qemu/log.h" -#include "trace.h" -#include "hw/i2c/i2c.h" -#include "migration/vmstate.h" - -#define TYPE_AXP209_PMU "axp209_pmu" - -#define AXP209(obj) \ - OBJECT_CHECK(AXP209I2CState, (obj), TYPE_AXP209_PMU) - -/* registers */ -enum { - REG_POWER_STATUS = 0x0u, - REG_OPERATING_MODE, - REG_OTG_VBUS_STATUS, - REG_CHIP_VERSION, - REG_DATA_CACHE_0, - REG_DATA_CACHE_1, - REG_DATA_CACHE_2, - REG_DATA_CACHE_3, - REG_DATA_CACHE_4, - REG_DATA_CACHE_5, - REG_DATA_CACHE_6, - REG_DATA_CACHE_7, - REG_DATA_CACHE_8, - REG_DATA_CACHE_9, - REG_DATA_CACHE_A, - REG_DATA_CACHE_B, - REG_POWER_OUTPUT_CTRL = 0x12u, - REG_DC_DC2_OUT_V_CTRL = 0x23u, - REG_DC_DC2_DVS_CTRL = 0x25u, - REG_DC_DC3_OUT_V_CTRL = 0x27u, - REG_LDO2_4_OUT_V_CTRL, - REG_LDO3_OUT_V_CTRL, - REG_VBUS_CH_MGMT = 0x30u, - REG_SHUTDOWN_V_CTRL, - REG_SHUTDOWN_CTRL, - REG_CHARGE_CTRL_1, - REG_CHARGE_CTRL_2, - REG_SPARE_CHARGE_CTRL, - REG_PEK_KEY_CTRL, - REG_DC_DC_FREQ_SET, - REG_CHR_TEMP_TH_SET, - REG_CHR_HIGH_TEMP_TH_CTRL, - REG_IPSOUT_WARN_L1, - REG_IPSOUT_WARN_L2, - REG_DISCHR_TEMP_TH_SET, - REG_DISCHR_HIGH_TEMP_TH_CTRL, - REG_IRQ_BANK_1_CTRL = 0x40u, - REG_IRQ_BANK_2_CTRL, - REG_IRQ_BANK_3_CTRL, - REG_IRQ_BANK_4_CTRL, - REG_IRQ_BANK_5_CTRL, - REG_IRQ_BANK_1_STAT = 0x48u, - REG_IRQ_BANK_2_STAT, - REG_IRQ_BANK_3_STAT, - REG_IRQ_BANK_4_STAT, - REG_IRQ_BANK_5_STAT, - REG_ADC_ACIN_V_H = 0x56u, - REG_ADC_ACIN_V_L, - REG_ADC_ACIN_CURR_H, - REG_ADC_ACIN_CURR_L, - REG_ADC_VBUS_V_H, - REG_ADC_VBUS_V_L, - REG_ADC_VBUS_CURR_H, - REG_ADC_VBUS_CURR_L, - REG_ADC_INT_TEMP_H, - REG_ADC_INT_TEMP_L, - REG_ADC_TEMP_SENS_V_H = 0x62u, - REG_ADC_TEMP_SENS_V_L, - REG_ADC_BAT_V_H = 0x78u, - REG_ADC_BAT_V_L, - REG_ADC_BAT_DISCHR_CURR_H, - REG_ADC_BAT_DISCHR_CURR_L, - REG_ADC_BAT_CHR_CURR_H, - REG_ADC_BAT_CHR_CURR_L, - REG_ADC_IPSOUT_V_H, - REG_ADC_IPSOUT_V_L, - REG_DC_DC_MOD_SEL = 0x80u, - REG_ADC_EN_1, - REG_ADC_EN_2, - REG_ADC_SR_CTRL, - REG_ADC_IN_RANGE, - REG_GPIO1_ADC_IRQ_RISING_TH, - REG_GPIO1_ADC_IRQ_FALLING_TH, - REG_TIMER_CTRL = 0x8au, - REG_VBUS_CTRL_MON_SRP, - REG_OVER_TEMP_SHUTDOWN = 0x8fu, - REG_GPIO0_FEAT_SET, - REG_GPIO_OUT_HIGH_SET, - REG_GPIO1_FEAT_SET, - REG_GPIO2_FEAT_SET, - REG_GPIO_SIG_STATE_SET_MON, - REG_GPIO3_SET, - REG_COULOMB_CNTR_CTRL = 0xb8u, - REG_POWER_MEAS_RES, - NR_REGS -}; - -#define AXP209_CHIP_VERSION_ID (0x01) -#define AXP209_DC_DC2_OUT_V_CTRL_RESET (0x16) -#define AXP209_IRQ_BANK_1_CTRL_RESET (0xd8) - -/* A simple I2C slave which returns values of ID or CNT register. */ -typedef struct AXP209I2CState { - /*< private >*/ - I2CSlave i2c; - /*< public >*/ - uint8_t regs[NR_REGS]; /* peripheral registers */ - uint8_t ptr; /* current register index */ - uint8_t count; /* counter used for tx/rx */ -} AXP209I2CState; - -/* Reset all counters and load ID register */ -static void axp209_reset_enter(Object *obj, ResetType type) -{ - AXP209I2CState *s = AXP209(obj); - - memset(s->regs, 0, NR_REGS); - s->ptr = 0; - s->count = 0; - s->regs[REG_CHIP_VERSION] = AXP209_CHIP_VERSION_ID; - s->regs[REG_DC_DC2_OUT_V_CTRL] = AXP209_DC_DC2_OUT_V_CTRL_RESET; - s->regs[REG_IRQ_BANK_1_CTRL] = AXP209_IRQ_BANK_1_CTRL_RESET; -} - -/* Handle events from master. */ -static int axp209_event(I2CSlave *i2c, enum i2c_event event) -{ - AXP209I2CState *s = AXP209(i2c); - - s->count = 0; - - return 0; -} - -/* Called when master requests read */ -static uint8_t axp209_rx(I2CSlave *i2c) -{ - AXP209I2CState *s = AXP209(i2c); - uint8_t ret = 0xff; - - if (s->ptr < NR_REGS) { - ret = s->regs[s->ptr++]; - } - - trace_axp209_rx(s->ptr - 1, ret); - - return ret; -} - -/* - * Called when master sends write. - * Update ptr with byte 0, then perform write with second byte. - */ -static int axp209_tx(I2CSlave *i2c, uint8_t data) -{ - AXP209I2CState *s = AXP209(i2c); - - if (s->count == 0) { - /* Store register address */ - s->ptr = data; - s->count++; - trace_axp209_select(data); - } else { - trace_axp209_tx(s->ptr, data); - if (s->ptr == REG_DC_DC2_OUT_V_CTRL) { - s->regs[s->ptr++] = data; - } - } - - return 0; -} - -static const VMStateDescription vmstate_axp209 = { - .name = TYPE_AXP209_PMU, - .version_id = 1, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY(regs, AXP209I2CState, NR_REGS), - VMSTATE_UINT8(count, AXP209I2CState), - VMSTATE_UINT8(ptr, AXP209I2CState), - VMSTATE_END_OF_LIST() - } -}; - -static void axp209_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); - ResettableClass *rc = RESETTABLE_CLASS(oc); - - rc->phases.enter = axp209_reset_enter; - dc->vmsd = &vmstate_axp209; - isc->event = axp209_event; - isc->recv = axp209_rx; - isc->send = axp209_tx; -} - -static const TypeInfo axp209_info = { - .name = TYPE_AXP209_PMU, - .parent = TYPE_I2C_SLAVE, - .instance_size = sizeof(AXP209I2CState), - .class_init = axp209_class_init -}; - -static void axp209_register_devices(void) -{ - type_register_static(&axp209_info); -} - -type_init(axp209_register_devices); diff --git a/hw/misc/axp2xx.c b/hw/misc/axp2xx.c new file mode 100644 index 0000000000..41538c1cd7 --- /dev/null +++ b/hw/misc/axp2xx.c @@ -0,0 +1,283 @@ +/* + * AXP-2XX PMU Emulation, supported lists: + * AXP209 + * AXP221 + * + * Copyright (C) 2022 Strahinja Jankovic <strahinja.p.jankovic@gmail.com> + * Copyright (C) 2023 qianfan Zhao <qianfanguijin@163.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. + * + * SPDX-License-Identifier: MIT + */ + +#include "qemu/osdep.h" +#include "qemu/log.h" +#include "qom/object.h" +#include "trace.h" +#include "hw/i2c/i2c.h" +#include "migration/vmstate.h" + +#define TYPE_AXP2XX "axp2xx_pmu" +#define TYPE_AXP209_PMU "axp209_pmu" +#define TYPE_AXP221_PMU "axp221_pmu" + +OBJECT_DECLARE_TYPE(AXP2xxI2CState, AXP2xxClass, AXP2XX) + +#define NR_REGS (0xff) + +/* A simple I2C slave which returns values of ID or CNT register. */ +typedef struct AXP2xxI2CState { + /*< private >*/ + I2CSlave i2c; + /*< public >*/ + uint8_t regs[NR_REGS]; /* peripheral registers */ + uint8_t ptr; /* current register index */ + uint8_t count; /* counter used for tx/rx */ +} AXP2xxI2CState; + +typedef struct AXP2xxClass { + /*< private >*/ + I2CSlaveClass parent_class; + /*< public >*/ + void (*reset_enter)(AXP2xxI2CState *s, ResetType type); +} AXP2xxClass; + +#define AXP209_CHIP_VERSION_ID (0x01) +#define AXP209_DC_DC2_OUT_V_CTRL_RESET (0x16) + +/* Reset all counters and load ID register */ +static void axp209_reset_enter(AXP2xxI2CState *s, ResetType type) +{ + memset(s->regs, 0, NR_REGS); + s->ptr = 0; + s->count = 0; + + s->regs[0x03] = AXP209_CHIP_VERSION_ID; + s->regs[0x23] = AXP209_DC_DC2_OUT_V_CTRL_RESET; + + s->regs[0x30] = 0x60; + s->regs[0x32] = 0x46; + s->regs[0x34] = 0x41; + s->regs[0x35] = 0x22; + s->regs[0x36] = 0x5d; + s->regs[0x37] = 0x08; + s->regs[0x38] = 0xa5; + s->regs[0x39] = 0x1f; + s->regs[0x3a] = 0x68; + s->regs[0x3b] = 0x5f; + s->regs[0x3c] = 0xfc; + s->regs[0x3d] = 0x16; + s->regs[0x40] = 0xd8; + s->regs[0x42] = 0xff; + s->regs[0x43] = 0x3b; + s->regs[0x80] = 0xe0; + s->regs[0x82] = 0x83; + s->regs[0x83] = 0x80; + s->regs[0x84] = 0x32; + s->regs[0x86] = 0xff; + s->regs[0x90] = 0x07; + s->regs[0x91] = 0xa0; + s->regs[0x92] = 0x07; + s->regs[0x93] = 0x07; +} + +#define AXP221_PWR_STATUS_ACIN_PRESENT BIT(7) +#define AXP221_PWR_STATUS_ACIN_AVAIL BIT(6) +#define AXP221_PWR_STATUS_VBUS_PRESENT BIT(5) +#define AXP221_PWR_STATUS_VBUS_USED BIT(4) +#define AXP221_PWR_STATUS_BAT_CHARGING BIT(2) +#define AXP221_PWR_STATUS_ACIN_VBUS_POWERED BIT(1) + +/* Reset all counters and load ID register */ +static void axp221_reset_enter(AXP2xxI2CState *s, ResetType type) +{ + memset(s->regs, 0, NR_REGS); + s->ptr = 0; + s->count = 0; + + /* input power status register */ + s->regs[0x00] = AXP221_PWR_STATUS_ACIN_PRESENT + | AXP221_PWR_STATUS_ACIN_AVAIL + | AXP221_PWR_STATUS_ACIN_VBUS_POWERED; + + s->regs[0x01] = 0x00; /* no battery is connected */ + + /* + * CHIPID register, no documented on datasheet, but it is checked in + * u-boot spl. I had read it from AXP221s and got 0x06 value. + * So leave 06h here. + */ + s->regs[0x03] = 0x06; + + s->regs[0x10] = 0xbf; + s->regs[0x13] = 0x01; + s->regs[0x30] = 0x60; + s->regs[0x31] = 0x03; + s->regs[0x32] = 0x43; + s->regs[0x33] = 0xc6; + s->regs[0x34] = 0x45; + s->regs[0x35] = 0x0e; + s->regs[0x36] = 0x5d; + s->regs[0x37] = 0x08; + s->regs[0x38] = 0xa5; + s->regs[0x39] = 0x1f; + s->regs[0x3c] = 0xfc; + s->regs[0x3d] = 0x16; + s->regs[0x80] = 0x80; + s->regs[0x82] = 0xe0; + s->regs[0x84] = 0x32; + s->regs[0x8f] = 0x01; + + s->regs[0x90] = 0x07; + s->regs[0x91] = 0x1f; + s->regs[0x92] = 0x07; + s->regs[0x93] = 0x1f; + + s->regs[0x40] = 0xd8; + s->regs[0x41] = 0xff; + s->regs[0x42] = 0x03; + s->regs[0x43] = 0x03; + + s->regs[0xb8] = 0xc0; + s->regs[0xb9] = 0x64; + s->regs[0xe6] = 0xa0; +} + +static void axp2xx_reset_enter(Object *obj, ResetType type) +{ + AXP2xxI2CState *s = AXP2XX(obj); + AXP2xxClass *sc = AXP2XX_GET_CLASS(s); + + sc->reset_enter(s, type); +} + +/* Handle events from master. */ +static int axp2xx_event(I2CSlave *i2c, enum i2c_event event) +{ + AXP2xxI2CState *s = AXP2XX(i2c); + + s->count = 0; + + return 0; +} + +/* Called when master requests read */ +static uint8_t axp2xx_rx(I2CSlave *i2c) +{ + AXP2xxI2CState *s = AXP2XX(i2c); + uint8_t ret = 0xff; + + if (s->ptr < NR_REGS) { + ret = s->regs[s->ptr++]; + } + + trace_axp2xx_rx(s->ptr - 1, ret); + + return ret; +} + +/* + * Called when master sends write. + * Update ptr with byte 0, then perform write with second byte. + */ +static int axp2xx_tx(I2CSlave *i2c, uint8_t data) +{ + AXP2xxI2CState *s = AXP2XX(i2c); + + if (s->count == 0) { + /* Store register address */ + s->ptr = data; + s->count++; + trace_axp2xx_select(data); + } else { + trace_axp2xx_tx(s->ptr, data); + s->regs[s->ptr++] = data; + } + + return 0; +} + +static const VMStateDescription vmstate_axp2xx = { + .name = TYPE_AXP2XX, + .version_id = 1, + .fields = (VMStateField[]) { + VMSTATE_UINT8_ARRAY(regs, AXP2xxI2CState, NR_REGS), + VMSTATE_UINT8(ptr, AXP2xxI2CState), + VMSTATE_UINT8(count, AXP2xxI2CState), + VMSTATE_END_OF_LIST() + } +}; + +static void axp2xx_class_init(ObjectClass *oc, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(oc); + I2CSlaveClass *isc = I2C_SLAVE_CLASS(oc); + ResettableClass *rc = RESETTABLE_CLASS(oc); + + rc->phases.enter = axp2xx_reset_enter; + dc->vmsd = &vmstate_axp2xx; + isc->event = axp2xx_event; + isc->recv = axp2xx_rx; + isc->send = axp2xx_tx; +} + +static const TypeInfo axp2xx_info = { + .name = TYPE_AXP2XX, + .parent = TYPE_I2C_SLAVE, + .instance_size = sizeof(AXP2xxI2CState), + .class_size = sizeof(AXP2xxClass), + .class_init = axp2xx_class_init, + .abstract = true, +}; + +static void axp209_class_init(ObjectClass *oc, void *data) +{ + AXP2xxClass *sc = AXP2XX_CLASS(oc); + + sc->reset_enter = axp209_reset_enter; +} + +static const TypeInfo axp209_info = { + .name = TYPE_AXP209_PMU, + .parent = TYPE_AXP2XX, + .class_init = axp209_class_init +}; + +static void axp221_class_init(ObjectClass *oc, void *data) +{ + AXP2xxClass *sc = AXP2XX_CLASS(oc); + + sc->reset_enter = axp221_reset_enter; +} + +static const TypeInfo axp221_info = { + .name = TYPE_AXP221_PMU, + .parent = TYPE_AXP2XX, + .class_init = axp221_class_init, +}; + +static void axp2xx_register_devices(void) +{ + type_register_static(&axp2xx_info); + type_register_static(&axp209_info); + type_register_static(&axp221_info); +} + +type_init(axp2xx_register_devices); diff --git a/hw/misc/bcm2835_property.c b/hw/misc/bcm2835_property.c index 890ae7bae5..4ed9faa54a 100644 --- a/hw/misc/bcm2835_property.c +++ b/hw/misc/bcm2835_property.c @@ -12,10 +12,12 @@ #include "migration/vmstate.h" #include "hw/irq.h" #include "hw/misc/bcm2835_mbox_defs.h" +#include "hw/misc/raspberrypi-fw-defs.h" #include "sysemu/dma.h" #include "qemu/log.h" #include "qemu/module.h" #include "trace.h" +#include "hw/arm/raspi_platform.h" /* https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface */ @@ -51,48 +53,48 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) /* @(value + 8) : Request/response indicator */ resplen = 0; switch (tag) { - case 0x00000000: /* End tag */ + case RPI_FWREQ_PROPERTY_END: break; - case 0x00000001: /* Get firmware revision */ + case RPI_FWREQ_GET_FIRMWARE_REVISION: stl_le_phys(&s->dma_as, value + 12, 346337); resplen = 4; break; - case 0x00010001: /* Get board model */ + case RPI_FWREQ_GET_BOARD_MODEL: qemu_log_mask(LOG_UNIMP, "bcm2835_property: 0x%08x get board model NYI\n", tag); resplen = 4; break; - case 0x00010002: /* Get board revision */ + case RPI_FWREQ_GET_BOARD_REVISION: stl_le_phys(&s->dma_as, value + 12, s->board_rev); resplen = 4; break; - case 0x00010003: /* Get board MAC address */ + case RPI_FWREQ_GET_BOARD_MAC_ADDRESS: resplen = sizeof(s->macaddr.a); dma_memory_write(&s->dma_as, value + 12, s->macaddr.a, resplen, MEMTXATTRS_UNSPECIFIED); break; - case 0x00010004: /* Get board serial */ + case RPI_FWREQ_GET_BOARD_SERIAL: qemu_log_mask(LOG_UNIMP, "bcm2835_property: 0x%08x get board serial NYI\n", tag); resplen = 8; break; - case 0x00010005: /* Get ARM memory */ + case RPI_FWREQ_GET_ARM_MEMORY: /* base */ stl_le_phys(&s->dma_as, value + 12, 0); /* size */ stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_base); resplen = 8; break; - case 0x00010006: /* Get VC memory */ + case RPI_FWREQ_GET_VC_MEMORY: /* base */ stl_le_phys(&s->dma_as, value + 12, s->fbdev->vcram_base); /* size */ stl_le_phys(&s->dma_as, value + 16, s->fbdev->vcram_size); resplen = 8; break; - case 0x00028001: /* Set power state */ + case RPI_FWREQ_SET_POWER_STATE: /* Assume that whatever device they asked for exists, * and we'll just claim we set it to the desired state */ @@ -103,38 +105,42 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) /* Clocks */ - case 0x00030001: /* Get clock state */ + case RPI_FWREQ_GET_CLOCK_STATE: stl_le_phys(&s->dma_as, value + 16, 0x1); resplen = 8; break; - case 0x00038001: /* Set clock state */ + case RPI_FWREQ_SET_CLOCK_STATE: qemu_log_mask(LOG_UNIMP, "bcm2835_property: 0x%08x set clock state NYI\n", tag); resplen = 8; break; - case 0x00030002: /* Get clock rate */ - case 0x00030004: /* Get max clock rate */ - case 0x00030007: /* Get min clock rate */ + case RPI_FWREQ_GET_CLOCK_RATE: + case RPI_FWREQ_GET_MAX_CLOCK_RATE: + case RPI_FWREQ_GET_MIN_CLOCK_RATE: switch (ldl_le_phys(&s->dma_as, value + 12)) { - case 1: /* EMMC */ - stl_le_phys(&s->dma_as, value + 16, 50000000); + case RPI_FIRMWARE_EMMC_CLK_ID: + stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_EMMC_CLK_RATE); break; - case 2: /* UART */ - stl_le_phys(&s->dma_as, value + 16, 3000000); + case RPI_FIRMWARE_UART_CLK_ID: + stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_UART_CLK_RATE); + break; + case RPI_FIRMWARE_CORE_CLK_ID: + stl_le_phys(&s->dma_as, value + 16, RPI_FIRMWARE_CORE_CLK_RATE); break; default: - stl_le_phys(&s->dma_as, value + 16, 700000000); + stl_le_phys(&s->dma_as, value + 16, + RPI_FIRMWARE_DEFAULT_CLK_RATE); break; } resplen = 8; break; - case 0x00038002: /* Set clock rate */ - case 0x00038004: /* Set max clock rate */ - case 0x00038007: /* Set min clock rate */ + case RPI_FWREQ_SET_CLOCK_RATE: + case RPI_FWREQ_SET_MAX_CLOCK_RATE: + case RPI_FWREQ_SET_MIN_CLOCK_RATE: qemu_log_mask(LOG_UNIMP, "bcm2835_property: 0x%08x set clock rate NYI\n", tag); @@ -143,121 +149,121 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) /* Temperature */ - case 0x00030006: /* Get temperature */ + case RPI_FWREQ_GET_TEMPERATURE: stl_le_phys(&s->dma_as, value + 16, 25000); resplen = 8; break; - case 0x0003000A: /* Get max temperature */ + case RPI_FWREQ_GET_MAX_TEMPERATURE: stl_le_phys(&s->dma_as, value + 16, 99000); resplen = 8; break; /* Frame buffer */ - case 0x00040001: /* Allocate buffer */ + case RPI_FWREQ_FRAMEBUFFER_ALLOCATE: stl_le_phys(&s->dma_as, value + 12, fbconfig.base); stl_le_phys(&s->dma_as, value + 16, bcm2835_fb_get_size(&fbconfig)); resplen = 8; break; - case 0x00048001: /* Release buffer */ + case RPI_FWREQ_FRAMEBUFFER_RELEASE: resplen = 0; break; - case 0x00040002: /* Blank screen */ + case RPI_FWREQ_FRAMEBUFFER_BLANK: resplen = 4; break; - case 0x00044003: /* Test physical display width/height */ - case 0x00044004: /* Test virtual display width/height */ + case RPI_FWREQ_FRAMEBUFFER_TEST_PHYSICAL_WIDTH_HEIGHT: + case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_WIDTH_HEIGHT: resplen = 8; break; - case 0x00048003: /* Set physical display width/height */ + case RPI_FWREQ_FRAMEBUFFER_SET_PHYSICAL_WIDTH_HEIGHT: fbconfig.xres = ldl_le_phys(&s->dma_as, value + 12); fbconfig.yres = ldl_le_phys(&s->dma_as, value + 16); bcm2835_fb_validate_config(&fbconfig); fbconfig_updated = true; /* fall through */ - case 0x00040003: /* Get physical display width/height */ + case RPI_FWREQ_FRAMEBUFFER_GET_PHYSICAL_WIDTH_HEIGHT: stl_le_phys(&s->dma_as, value + 12, fbconfig.xres); stl_le_phys(&s->dma_as, value + 16, fbconfig.yres); resplen = 8; break; - case 0x00048004: /* Set virtual display width/height */ + case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_WIDTH_HEIGHT: fbconfig.xres_virtual = ldl_le_phys(&s->dma_as, value + 12); fbconfig.yres_virtual = ldl_le_phys(&s->dma_as, value + 16); bcm2835_fb_validate_config(&fbconfig); fbconfig_updated = true; /* fall through */ - case 0x00040004: /* Get virtual display width/height */ + case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_WIDTH_HEIGHT: stl_le_phys(&s->dma_as, value + 12, fbconfig.xres_virtual); stl_le_phys(&s->dma_as, value + 16, fbconfig.yres_virtual); resplen = 8; break; - case 0x00044005: /* Test depth */ + case RPI_FWREQ_FRAMEBUFFER_TEST_DEPTH: resplen = 4; break; - case 0x00048005: /* Set depth */ + case RPI_FWREQ_FRAMEBUFFER_SET_DEPTH: fbconfig.bpp = ldl_le_phys(&s->dma_as, value + 12); bcm2835_fb_validate_config(&fbconfig); fbconfig_updated = true; /* fall through */ - case 0x00040005: /* Get depth */ + case RPI_FWREQ_FRAMEBUFFER_GET_DEPTH: stl_le_phys(&s->dma_as, value + 12, fbconfig.bpp); resplen = 4; break; - case 0x00044006: /* Test pixel order */ + case RPI_FWREQ_FRAMEBUFFER_TEST_PIXEL_ORDER: resplen = 4; break; - case 0x00048006: /* Set pixel order */ + case RPI_FWREQ_FRAMEBUFFER_SET_PIXEL_ORDER: fbconfig.pixo = ldl_le_phys(&s->dma_as, value + 12); bcm2835_fb_validate_config(&fbconfig); fbconfig_updated = true; /* fall through */ - case 0x00040006: /* Get pixel order */ + case RPI_FWREQ_FRAMEBUFFER_GET_PIXEL_ORDER: stl_le_phys(&s->dma_as, value + 12, fbconfig.pixo); resplen = 4; break; - case 0x00044007: /* Test pixel alpha */ + case RPI_FWREQ_FRAMEBUFFER_TEST_ALPHA_MODE: resplen = 4; break; - case 0x00048007: /* Set alpha */ + case RPI_FWREQ_FRAMEBUFFER_SET_ALPHA_MODE: fbconfig.alpha = ldl_le_phys(&s->dma_as, value + 12); bcm2835_fb_validate_config(&fbconfig); fbconfig_updated = true; /* fall through */ - case 0x00040007: /* Get alpha */ + case RPI_FWREQ_FRAMEBUFFER_GET_ALPHA_MODE: stl_le_phys(&s->dma_as, value + 12, fbconfig.alpha); resplen = 4; break; - case 0x00040008: /* Get pitch */ + case RPI_FWREQ_FRAMEBUFFER_GET_PITCH: stl_le_phys(&s->dma_as, value + 12, bcm2835_fb_get_pitch(&fbconfig)); resplen = 4; break; - case 0x00044009: /* Test virtual offset */ + case RPI_FWREQ_FRAMEBUFFER_TEST_VIRTUAL_OFFSET: resplen = 8; break; - case 0x00048009: /* Set virtual offset */ + case RPI_FWREQ_FRAMEBUFFER_SET_VIRTUAL_OFFSET: fbconfig.xoffset = ldl_le_phys(&s->dma_as, value + 12); fbconfig.yoffset = ldl_le_phys(&s->dma_as, value + 16); bcm2835_fb_validate_config(&fbconfig); fbconfig_updated = true; /* fall through */ - case 0x00040009: /* Get virtual offset */ + case RPI_FWREQ_FRAMEBUFFER_GET_VIRTUAL_OFFSET: stl_le_phys(&s->dma_as, value + 12, fbconfig.xoffset); stl_le_phys(&s->dma_as, value + 16, fbconfig.yoffset); resplen = 8; break; - case 0x0004000a: /* Get/Test/Set overscan */ - case 0x0004400a: - case 0x0004800a: + case RPI_FWREQ_FRAMEBUFFER_GET_OVERSCAN: + case RPI_FWREQ_FRAMEBUFFER_TEST_OVERSCAN: + case RPI_FWREQ_FRAMEBUFFER_SET_OVERSCAN: stl_le_phys(&s->dma_as, value + 12, 0); stl_le_phys(&s->dma_as, value + 16, 0); stl_le_phys(&s->dma_as, value + 20, 0); stl_le_phys(&s->dma_as, value + 24, 0); resplen = 16; break; - case 0x0004800b: /* Set palette */ + case RPI_FWREQ_FRAMEBUFFER_SET_PALETTE: offset = ldl_le_phys(&s->dma_as, value + 12); length = ldl_le_phys(&s->dma_as, value + 16); n = 0; @@ -270,19 +276,29 @@ static void bcm2835_property_mbox_push(BCM2835PropertyState *s, uint32_t value) stl_le_phys(&s->dma_as, value + 12, 0); resplen = 4; break; - case 0x00040013: /* Get number of displays */ + case RPI_FWREQ_FRAMEBUFFER_GET_NUM_DISPLAYS: stl_le_phys(&s->dma_as, value + 12, 1); resplen = 4; break; - case 0x00060001: /* Get DMA channels */ + case RPI_FWREQ_GET_DMA_CHANNELS: /* channels 2-5 */ stl_le_phys(&s->dma_as, value + 12, 0x003C); resplen = 4; break; - case 0x00050001: /* Get command line */ - resplen = 0; + case RPI_FWREQ_GET_COMMAND_LINE: + /* + * We follow the firmware behaviour: no NUL terminator is + * written to the buffer, and if the buffer is too short + * we report the required length in the response header + * and copy nothing to the buffer. + */ + resplen = strlen(s->command_line); + if (bufsize >= resplen) + address_space_write(&s->dma_as, value + 12, + MEMTXATTRS_UNSPECIFIED, s->command_line, + resplen); break; default: @@ -382,6 +398,13 @@ static void bcm2835_property_init(Object *obj) memory_region_init_io(&s->iomem, OBJECT(s), &bcm2835_property_ops, s, TYPE_BCM2835_PROPERTY, 0x10); + + /* + * bcm2835_property_ops call into bcm2835_mbox, which in-turn reads from + * iomem. As such, mark iomem as re-entracy safe. + */ + s->iomem.disable_reentrancy_guard = true; + sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem); sysbus_init_irq(SYS_BUS_DEVICE(s), &s->mbox_irq); } @@ -413,6 +436,7 @@ static void bcm2835_property_realize(DeviceState *dev, Error **errp) static Property bcm2835_property_props[] = { DEFINE_PROP_UINT32("board-rev", BCM2835PropertyState, board_rev, 0), + DEFINE_PROP_STRING("command-line", BCM2835PropertyState, command_line), DEFINE_PROP_END_OF_LIST() }; diff --git a/hw/misc/imx_rngc.c b/hw/misc/imx_rngc.c index 632c03779c..082c6980ad 100644 --- a/hw/misc/imx_rngc.c +++ b/hw/misc/imx_rngc.c @@ -228,8 +228,10 @@ static void imx_rngc_realize(DeviceState *dev, Error **errp) sysbus_init_mmio(sbd, &s->iomem); sysbus_init_irq(sbd, &s->irq); - s->self_test_bh = qemu_bh_new(imx_rngc_self_test, s); - s->seed_bh = qemu_bh_new(imx_rngc_seed, s); + s->self_test_bh = qemu_bh_new_guarded(imx_rngc_self_test, s, + &dev->mem_reentrancy_guard); + s->seed_bh = qemu_bh_new_guarded(imx_rngc_seed, s, + &dev->mem_reentrancy_guard); } static void imx_rngc_reset(DeviceState *dev) diff --git a/hw/misc/macio/mac_dbdma.c b/hw/misc/macio/mac_dbdma.c index 43bb1f56ba..80a789f32b 100644 --- a/hw/misc/macio/mac_dbdma.c +++ b/hw/misc/macio/mac_dbdma.c @@ -914,7 +914,7 @@ static void mac_dbdma_realize(DeviceState *dev, Error **errp) { DBDMAState *s = MAC_DBDMA(dev); - s->bh = qemu_bh_new(DBDMA_run_bh, s); + s->bh = qemu_bh_new_guarded(DBDMA_run_bh, s, &dev->mem_reentrancy_guard); } static void mac_dbdma_class_init(ObjectClass *oc, void *data) diff --git a/hw/misc/macio/meson.build b/hw/misc/macio/meson.build index 17282da20a..8984b818b0 100644 --- a/hw/misc/macio/meson.build +++ b/hw/misc/macio/meson.build @@ -5,4 +5,4 @@ macio_ss.add(when: 'CONFIG_MACIO_GPIO', if_true: files('gpio.c')) macio_ss.add(when: 'CONFIG_MAC_DBDMA', if_true: files('mac_dbdma.c')) macio_ss.add(when: 'CONFIG_MAC_PMU', if_true: files('pmu.c')) -softmmu_ss.add_all(when: 'CONFIG_MACIO', if_true: macio_ss) +system_ss.add_all(when: 'CONFIG_MACIO', if_true: macio_ss) diff --git a/hw/misc/meson.build b/hw/misc/meson.build index a40245ad44..05877f61cc 100644 --- a/hw/misc/meson.build +++ b/hw/misc/meson.build @@ -1,55 +1,58 @@ -softmmu_ss.add(when: 'CONFIG_APPLESMC', if_true: files('applesmc.c')) -softmmu_ss.add(when: 'CONFIG_EDU', if_true: files('edu.c')) -softmmu_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmcoreinfo.c')) -softmmu_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c')) -softmmu_ss.add(when: 'CONFIG_ISA_TESTDEV', if_true: files('pc-testdev.c')) -softmmu_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c')) -softmmu_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c')) -softmmu_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) -softmmu_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) -softmmu_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) -softmmu_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c')) +system_ss.add(when: 'CONFIG_APPLESMC', if_true: files('applesmc.c')) +system_ss.add(when: 'CONFIG_EDU', if_true: files('edu.c')) +system_ss.add(when: 'CONFIG_FW_CFG_DMA', if_true: files('vmcoreinfo.c')) +system_ss.add(when: 'CONFIG_ISA_DEBUG', if_true: files('debugexit.c')) +system_ss.add(when: 'CONFIG_ISA_TESTDEV', if_true: files('pc-testdev.c')) +system_ss.add(when: 'CONFIG_PCA9552', if_true: files('pca9552.c')) +system_ss.add(when: 'CONFIG_PCI_TESTDEV', if_true: files('pci-testdev.c')) +system_ss.add(when: 'CONFIG_UNIMP', if_true: files('unimp.c')) +system_ss.add(when: 'CONFIG_EMPTY_SLOT', if_true: files('empty_slot.c')) +system_ss.add(when: 'CONFIG_LED', if_true: files('led.c')) +system_ss.add(when: 'CONFIG_PVPANIC_COMMON', if_true: files('pvpanic.c')) # ARM devices -softmmu_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) -softmmu_ss.add(when: 'CONFIG_INTEGRATOR_DEBUG', if_true: files('arm_integrator_debug.c')) -softmmu_ss.add(when: 'CONFIG_A9SCU', if_true: files('a9scu.c')) -softmmu_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c')) +system_ss.add(when: 'CONFIG_PL310', if_true: files('arm_l2x0.c')) +system_ss.add(when: 'CONFIG_INTEGRATOR_DEBUG', if_true: files('arm_integrator_debug.c')) +system_ss.add(when: 'CONFIG_A9SCU', if_true: files('a9scu.c')) +system_ss.add(when: 'CONFIG_ARM11SCU', if_true: files('arm11scu.c')) -softmmu_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_ras.c')) +system_ss.add(when: 'CONFIG_ARM_V7M', if_true: files('armv7m_ras.c')) # Mac devices -softmmu_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) +system_ss.add(when: 'CONFIG_MOS6522', if_true: files('mos6522.c')) # virt devices -softmmu_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c')) +system_ss.add(when: 'CONFIG_VIRT_CTRL', if_true: files('virt_ctrl.c')) # RISC-V devices -softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true: files('mchp_pfsoc_dmc.c')) -softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb.c')) -softmmu_ss.add(when: 'CONFIG_MCHP_PFSOC_SYSREG', if_true: files('mchp_pfsoc_sysreg.c')) -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')) +system_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true: files('mchp_pfsoc_dmc.c')) +system_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true: files('mchp_pfsoc_ioscb.c')) +system_ss.add(when: 'CONFIG_MCHP_PFSOC_SYSREG', if_true: files('mchp_pfsoc_sysreg.c')) +system_ss.add(when: 'CONFIG_SIFIVE_TEST', if_true: files('sifive_test.c')) +system_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true: files('sifive_e_prci.c')) +system_ss.add(when: 'CONFIG_SIFIVE_U_OTP', if_true: files('sifive_u_otp.c')) +system_ss.add(when: 'CONFIG_SIFIVE_U_PRCI', if_true: files('sifive_u_prci.c')) subdir('macio') -softmmu_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c')) +system_ss.add(when: 'CONFIG_IVSHMEM_DEVICE', if_true: files('ivshmem.c')) -softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_CCM', if_true: files('allwinner-a10-ccm.c')) -softmmu_ss.add(when: 'CONFIG_ALLWINNER_A10_DRAMC', if_true: files('allwinner-a10-dramc.c')) -softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-ccu.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_SRAMC', if_true: files('allwinner-sramc.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_A10_CCM', if_true: files('allwinner-a10-ccm.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_A10_DRAMC', if_true: files('allwinner-a10-dramc.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-ccu.c')) specific_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-cpucfg.c')) -softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c')) -softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-sysctrl.c')) -softmmu_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c')) -softmmu_ss.add(when: 'CONFIG_AXP209_PMU', if_true: files('axp209.c')) -softmmu_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c')) -softmmu_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c')) -softmmu_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c')) -softmmu_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c')) -softmmu_ss.add(when: 'CONFIG_IMX', if_true: files( +system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-dramc.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-h3-sysctrl.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_H3', if_true: files('allwinner-sid.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-ccu.c')) +system_ss.add(when: 'CONFIG_ALLWINNER_R40', if_true: files('allwinner-r40-dramc.c')) +system_ss.add(when: 'CONFIG_AXP2XX_PMU', if_true: files('axp2xx.c')) +system_ss.add(when: 'CONFIG_REALVIEW', if_true: files('arm_sysctl.c')) +system_ss.add(when: 'CONFIG_NSERIES', if_true: files('cbus.c')) +system_ss.add(when: 'CONFIG_ECCMEMCTL', if_true: files('eccmemctl.c')) +system_ss.add(when: 'CONFIG_EXYNOS4', if_true: files('exynos4210_pmu.c', 'exynos4210_clk.c', 'exynos4210_rng.c')) +system_ss.add(when: 'CONFIG_IMX', if_true: files( 'imx25_ccm.c', 'imx31_ccm.c', 'imx6_ccm.c', @@ -61,22 +64,22 @@ softmmu_ss.add(when: 'CONFIG_IMX', if_true: files( 'imx_ccm.c', 'imx_rngc.c', )) -softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c')) -softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files( +system_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c')) +system_ss.add(when: 'CONFIG_NPCM7XX', if_true: files( 'npcm7xx_clk.c', 'npcm7xx_gcr.c', 'npcm7xx_mft.c', 'npcm7xx_pwm.c', 'npcm7xx_rng.c', )) -softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files( +system_ss.add(when: 'CONFIG_OMAP', if_true: files( 'omap_clk.c', 'omap_gpmc.c', 'omap_l4.c', 'omap_sdrc.c', 'omap_tap.c', )) -softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( +system_ss.add(when: 'CONFIG_RASPI', if_true: files( 'bcm2835_mbox.c', 'bcm2835_mphi.c', 'bcm2835_property.c', @@ -85,35 +88,35 @@ softmmu_ss.add(when: 'CONFIG_RASPI', if_true: files( 'bcm2835_cprman.c', 'bcm2835_powermgt.c', )) -softmmu_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) -softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c')) -softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) -softmmu_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) +system_ss.add(when: 'CONFIG_SLAVIO', if_true: files('slavio_misc.c')) +system_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq_slcr.c')) +system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-crf.c')) +system_ss.add(when: 'CONFIG_XLNX_ZYNQMP_ARM', if_true: files('xlnx-zynqmp-apu-ctrl.c')) specific_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files('xlnx-versal-crl.c')) -softmmu_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files( +system_ss.add(when: 'CONFIG_XLNX_VERSAL', if_true: files( 'xlnx-versal-xramc.c', 'xlnx-versal-pmc-iou-slcr.c', )) -softmmu_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c')) -softmmu_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c')) -softmmu_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c')) -softmmu_ss.add(when: 'CONFIG_MPS2_FPGAIO', if_true: files('mps2-fpgaio.c')) -softmmu_ss.add(when: 'CONFIG_MPS2_SCC', if_true: files('mps2-scc.c')) - -softmmu_ss.add(when: 'CONFIG_TZ_MPC', if_true: files('tz-mpc.c')) -softmmu_ss.add(when: 'CONFIG_TZ_MSC', if_true: files('tz-msc.c')) -softmmu_ss.add(when: 'CONFIG_TZ_PPC', if_true: files('tz-ppc.c')) -softmmu_ss.add(when: 'CONFIG_IOTKIT_SECCTL', if_true: files('iotkit-secctl.c')) -softmmu_ss.add(when: 'CONFIG_IOTKIT_SYSCTL', if_true: files('iotkit-sysctl.c')) -softmmu_ss.add(when: 'CONFIG_IOTKIT_SYSINFO', if_true: files('iotkit-sysinfo.c')) -softmmu_ss.add(when: 'CONFIG_ARMSSE_CPU_PWRCTRL', if_true: files('armsse-cpu-pwrctrl.c')) -softmmu_ss.add(when: 'CONFIG_ARMSSE_CPUID', if_true: files('armsse-cpuid.c')) -softmmu_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files('armsse-mhu.c')) - -softmmu_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c')) -softmmu_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c')) -softmmu_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c')) -softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( +system_ss.add(when: 'CONFIG_STM32F2XX_SYSCFG', if_true: files('stm32f2xx_syscfg.c')) +system_ss.add(when: 'CONFIG_STM32F4XX_SYSCFG', if_true: files('stm32f4xx_syscfg.c')) +system_ss.add(when: 'CONFIG_STM32F4XX_EXTI', if_true: files('stm32f4xx_exti.c')) +system_ss.add(when: 'CONFIG_MPS2_FPGAIO', if_true: files('mps2-fpgaio.c')) +system_ss.add(when: 'CONFIG_MPS2_SCC', if_true: files('mps2-scc.c')) + +system_ss.add(when: 'CONFIG_TZ_MPC', if_true: files('tz-mpc.c')) +system_ss.add(when: 'CONFIG_TZ_MSC', if_true: files('tz-msc.c')) +system_ss.add(when: 'CONFIG_TZ_PPC', if_true: files('tz-ppc.c')) +system_ss.add(when: 'CONFIG_IOTKIT_SECCTL', if_true: files('iotkit-secctl.c')) +system_ss.add(when: 'CONFIG_IOTKIT_SYSCTL', if_true: files('iotkit-sysctl.c')) +system_ss.add(when: 'CONFIG_IOTKIT_SYSINFO', if_true: files('iotkit-sysinfo.c')) +system_ss.add(when: 'CONFIG_ARMSSE_CPU_PWRCTRL', if_true: files('armsse-cpu-pwrctrl.c')) +system_ss.add(when: 'CONFIG_ARMSSE_CPUID', if_true: files('armsse-cpuid.c')) +system_ss.add(when: 'CONFIG_ARMSSE_MHU', if_true: files('armsse-mhu.c')) + +system_ss.add(when: 'CONFIG_PVPANIC_ISA', if_true: files('pvpanic-isa.c')) +system_ss.add(when: 'CONFIG_PVPANIC_PCI', if_true: files('pvpanic-pci.c')) +system_ss.add(when: 'CONFIG_AUX', if_true: files('auxbus.c')) +system_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_hace.c', 'aspeed_i3c.c', 'aspeed_lpc.c', @@ -123,12 +126,12 @@ softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files( 'aspeed_xdma.c', 'aspeed_peci.c')) -softmmu_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c')) -softmmu_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c')) +system_ss.add(when: 'CONFIG_MSF2', if_true: files('msf2-sysreg.c')) +system_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_rng.c')) -softmmu_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c')) +system_ss.add(when: 'CONFIG_GRLIB', if_true: files('grlib_ahb_apb_pnp.c')) -softmmu_ss.add(when: 'CONFIG_I2C', if_true: files('i2c-echo.c')) +system_ss.add(when: 'CONFIG_I2C', if_true: files('i2c-echo.c')) specific_ss.add(when: 'CONFIG_AVR_POWER', if_true: files('avr_power.c')) @@ -137,7 +140,7 @@ specific_ss.add(when: 'CONFIG_MAC_VIA', if_true: files('mac_via.c')) specific_ss.add(when: 'CONFIG_MIPS_CPS', if_true: files('mips_cmgcr.c', 'mips_cpc.c')) specific_ss.add(when: 'CONFIG_MIPS_ITU', if_true: files('mips_itu.c')) -softmmu_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) +system_ss.add(when: 'CONFIG_SBSA_REF', if_true: files('sbsa_ec.c')) # HPPA devices -softmmu_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) +system_ss.add(when: 'CONFIG_LASI', if_true: files('lasi.c')) diff --git a/hw/misc/trace-events b/hw/misc/trace-events index c47876a902..4d1a0e17af 100644 --- a/hw/misc/trace-events +++ b/hw/misc/trace-events @@ -15,18 +15,36 @@ allwinner_h3_dramctl_write(uint64_t offset, uint64_t data, unsigned size) "Write allwinner_h3_dramphy_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 allwinner_h3_dramphy_write(uint64_t offset, uint64_t data, unsigned size) "write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +# allwinner-r40-dramc.c +allwinner_r40_dramc_detect_cells_disable(void) "Disable detect cells" +allwinner_r40_dramc_detect_cells_enable(void) "Enable detect cells" +allwinner_r40_dramc_map_rows(uint8_t row_bits, uint8_t bank_bits, uint8_t col_bits) "DRAM layout: row_bits %d, bank_bits %d, col_bits %d" +allwinner_r40_dramc_offset_to_cell(uint64_t offset, int row, int bank, int col) "offset 0x%" PRIx64 " row %d bank %d col %d" +allwinner_r40_dramc_detect_cell_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 "" +allwinner_r40_dramc_detect_cell_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 "" +allwinner_r40_dramcom_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +allwinner_r40_dramcom_write(uint64_t offset, uint64_t data, unsigned size) "Write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +allwinner_r40_dramctl_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +allwinner_r40_dramctl_write(uint64_t offset, uint64_t data, unsigned size) "Write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +allwinner_r40_dramphy_read(uint64_t offset, uint64_t data, unsigned size) "Read: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +allwinner_r40_dramphy_write(uint64_t offset, uint64_t data, unsigned size) "write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 + # allwinner-sid.c allwinner_sid_read(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 allwinner_sid_write(uint64_t offset, uint64_t data, unsigned size) "offset 0x%" PRIx64 " data 0x%" PRIx64 " size %" PRIu32 +# allwinner-sramc.c +allwinner_sramc_read(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 +allwinner_sramc_write(uint64_t offset, uint64_t data) "offset 0x%" PRIx64 " data 0x%" PRIx64 + # avr_power.c avr_power_read(uint8_t value) "power_reduc read value:%u" avr_power_write(uint8_t value) "power_reduc write value:%u" -# axp209.c -axp209_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 " : 0x%" PRIx8 -axp209_select(uint8_t reg) "Accessing reg 0x%" PRIx8 -axp209_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8 +# axp2xx +axp2xx_rx(uint8_t reg, uint8_t data) "Read reg 0x%" PRIx8 " : 0x%" PRIx8 +axp2xx_select(uint8_t reg) "Accessing reg 0x%" PRIx8 +axp2xx_tx(uint8_t reg, uint8_t data) "Write reg 0x%" PRIx8 " : 0x%" PRIx8 # eccmemctl.c ecc_mem_writel_mer(uint32_t val) "Write memory enable 0x%08x" |