mirror of
https://github.com/izzy2lost/xemu.git
synced 2026-07-06 00:20:22 -07:00
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210112-1' into staging
target-arm queue: * arm: Support emulation of ARMv8.4-TTST extension * arm: Update cpu.h ID register field definitions * arm: Fix breakage of XScale instruction emulation * hw/net/lan9118: Fix RX Status FIFO PEEK value * npcm7xx: Add ADC and PWM emulation * ui/cocoa: Make "open docs" help menu entry work again when binary is run from the build tree * ui/cocoa: Fix openFile: deprecation on Big Sur * docs: Add qemu-storage-daemon(1) manpage to meson.build # gpg: Signature made Tue 12 Jan 2021 21:22:15 GMT # gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE # gpg: issuer "peter.maydell@linaro.org" # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@gmail.com>" [ultimate] # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [ultimate] # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20210112-1: ui/cocoa: Fix openFile: deprecation on Big Sur hw/*: Use type casting for SysBusDevice in NPCM7XX hw/misc: Add QTest for NPCM7XX PWM Module hw/misc: Add a PWM module for NPCM7XX hw/adc: Add an ADC module for NPCM7XX hw/timer: Refactor NPCM7XX Timer to use CLK clock hw/misc: Add clock converter in NPCM7XX CLK module hw/net/lan9118: Add symbolic constants for register offsets hw/net/lan9118: Fix RX Status FIFO PEEK value target/arm: Don't decode insns in the XScale/iWMMXt space as cp insns docs: Add qemu-storage-daemon(1) manpage to meson.build ui/cocoa: Update path to docs in build tree target/arm: add aarch32 ID register fields to cpu.h target/arm: add aarch64 ID register fields to cpu.h target/arm: add descriptions of CLIDR_EL1, CCSIDR_EL1, CTR_EL0 to cpu.h target/arm: make ARMCPU.ctr 64-bit target/arm: make ARMCPU.clidr 64-bit target/arm: fix typo in cpu.h ID_AA64PFR1 field name target/arm: enable Small Translation tables in max CPU target/arm: ARMv8.4-TTST extension Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
@@ -62,6 +62,7 @@ if build_docs
|
||||
'qemu-img.1': (have_tools ? 'man1' : ''),
|
||||
'qemu-nbd.8': (have_tools ? 'man8' : ''),
|
||||
'qemu-pr-helper.8': (have_tools ? 'man8' : ''),
|
||||
'qemu-storage-daemon.1': (have_tools ? 'man1' : ''),
|
||||
'qemu-trace-stap.1': (config_host.has_key('CONFIG_TRACE_SYSTEMTAP') ? 'man1' : ''),
|
||||
'virtfs-proxy-helper.1': (have_virtfs_proxy_helper ? 'man1' : ''),
|
||||
'virtiofsd.1': (have_virtiofsd ? 'man1' : ''),
|
||||
|
||||
@@ -41,6 +41,8 @@ Supported devices
|
||||
* Random Number Generator (RNG)
|
||||
* USB host (USBH)
|
||||
* GPIO controller
|
||||
* Analog to Digital Converter (ADC)
|
||||
* Pulse Width Modulation (PWM)
|
||||
|
||||
Missing devices
|
||||
---------------
|
||||
@@ -58,10 +60,8 @@ Missing devices
|
||||
* USB device (USBD)
|
||||
* SMBus controller (SMBF)
|
||||
* Peripheral SPI controller (PSPI)
|
||||
* Analog to Digital Converter (ADC)
|
||||
* SD/MMC host
|
||||
* PECI interface
|
||||
* Pulse Width Modulation (PWM)
|
||||
* Tachometer
|
||||
* PCI and PCIe root complex and bridges
|
||||
* VDM and MCTP support
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
|
||||
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* Nuvoton NPCM7xx ADC Module
|
||||
*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "hw/adc/npcm7xx_adc.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/registerfields.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/log.h"
|
||||
#include "qemu/module.h"
|
||||
#include "qemu/timer.h"
|
||||
#include "qemu/units.h"
|
||||
#include "trace.h"
|
||||
|
||||
REG32(NPCM7XX_ADC_CON, 0x0)
|
||||
REG32(NPCM7XX_ADC_DATA, 0x4)
|
||||
|
||||
/* Register field definitions. */
|
||||
#define NPCM7XX_ADC_CON_MUX(rv) extract32(rv, 24, 4)
|
||||
#define NPCM7XX_ADC_CON_INT_EN BIT(21)
|
||||
#define NPCM7XX_ADC_CON_REFSEL BIT(19)
|
||||
#define NPCM7XX_ADC_CON_INT BIT(18)
|
||||
#define NPCM7XX_ADC_CON_EN BIT(17)
|
||||
#define NPCM7XX_ADC_CON_RST BIT(16)
|
||||
#define NPCM7XX_ADC_CON_CONV BIT(14)
|
||||
#define NPCM7XX_ADC_CON_DIV(rv) extract32(rv, 1, 8)
|
||||
|
||||
#define NPCM7XX_ADC_MAX_RESULT 1023
|
||||
#define NPCM7XX_ADC_DEFAULT_IREF 2000000
|
||||
#define NPCM7XX_ADC_CONV_CYCLES 20
|
||||
#define NPCM7XX_ADC_RESET_CYCLES 10
|
||||
#define NPCM7XX_ADC_R0_INPUT 500000
|
||||
#define NPCM7XX_ADC_R1_INPUT 1500000
|
||||
|
||||
static void npcm7xx_adc_reset(NPCM7xxADCState *s)
|
||||
{
|
||||
timer_del(&s->conv_timer);
|
||||
s->con = 0x000c0001;
|
||||
s->data = 0x00000000;
|
||||
}
|
||||
|
||||
static uint32_t npcm7xx_adc_convert(uint32_t input, uint32_t ref)
|
||||
{
|
||||
uint32_t result;
|
||||
|
||||
result = input * (NPCM7XX_ADC_MAX_RESULT + 1) / ref;
|
||||
if (result > NPCM7XX_ADC_MAX_RESULT) {
|
||||
result = NPCM7XX_ADC_MAX_RESULT;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t npcm7xx_adc_prescaler(NPCM7xxADCState *s)
|
||||
{
|
||||
return 2 * (NPCM7XX_ADC_CON_DIV(s->con) + 1);
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_start_timer(Clock *clk, QEMUTimer *timer,
|
||||
uint32_t cycles, uint32_t prescaler)
|
||||
{
|
||||
int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
||||
int64_t ticks = cycles;
|
||||
int64_t ns;
|
||||
|
||||
ticks *= prescaler;
|
||||
ns = clock_ticks_to_ns(clk, ticks);
|
||||
ns += now;
|
||||
timer_mod(timer, ns);
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_start_convert(NPCM7xxADCState *s)
|
||||
{
|
||||
uint32_t prescaler = npcm7xx_adc_prescaler(s);
|
||||
|
||||
npcm7xx_adc_start_timer(s->clock, &s->conv_timer, NPCM7XX_ADC_CONV_CYCLES,
|
||||
prescaler);
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_convert_done(void *opaque)
|
||||
{
|
||||
NPCM7xxADCState *s = opaque;
|
||||
uint32_t input = NPCM7XX_ADC_CON_MUX(s->con);
|
||||
uint32_t ref = (s->con & NPCM7XX_ADC_CON_REFSEL)
|
||||
? s->iref : s->vref;
|
||||
|
||||
if (input >= NPCM7XX_ADC_NUM_INPUTS) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: invalid input: %u\n",
|
||||
__func__, input);
|
||||
return;
|
||||
}
|
||||
s->data = npcm7xx_adc_convert(s->adci[input], ref);
|
||||
if (s->con & NPCM7XX_ADC_CON_INT_EN) {
|
||||
s->con |= NPCM7XX_ADC_CON_INT;
|
||||
qemu_irq_raise(s->irq);
|
||||
}
|
||||
s->con &= ~NPCM7XX_ADC_CON_CONV;
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_calibrate(NPCM7xxADCState *adc)
|
||||
{
|
||||
adc->calibration_r_values[0] = npcm7xx_adc_convert(NPCM7XX_ADC_R0_INPUT,
|
||||
adc->iref);
|
||||
adc->calibration_r_values[1] = npcm7xx_adc_convert(NPCM7XX_ADC_R1_INPUT,
|
||||
adc->iref);
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_write_con(NPCM7xxADCState *s, uint32_t new_con)
|
||||
{
|
||||
uint32_t old_con = s->con;
|
||||
|
||||
/* Write ADC_INT to 1 to clear it */
|
||||
if (new_con & NPCM7XX_ADC_CON_INT) {
|
||||
new_con &= ~NPCM7XX_ADC_CON_INT;
|
||||
qemu_irq_lower(s->irq);
|
||||
} else if (old_con & NPCM7XX_ADC_CON_INT) {
|
||||
new_con |= NPCM7XX_ADC_CON_INT;
|
||||
}
|
||||
|
||||
s->con = new_con;
|
||||
|
||||
if (s->con & NPCM7XX_ADC_CON_RST) {
|
||||
npcm7xx_adc_reset(s);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((s->con & NPCM7XX_ADC_CON_EN)) {
|
||||
if (s->con & NPCM7XX_ADC_CON_CONV) {
|
||||
if (!(old_con & NPCM7XX_ADC_CON_CONV)) {
|
||||
npcm7xx_adc_start_convert(s);
|
||||
}
|
||||
} else {
|
||||
timer_del(&s->conv_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t npcm7xx_adc_read(void *opaque, hwaddr offset, unsigned size)
|
||||
{
|
||||
uint64_t value = 0;
|
||||
NPCM7xxADCState *s = opaque;
|
||||
|
||||
switch (offset) {
|
||||
case A_NPCM7XX_ADC_CON:
|
||||
value = s->con;
|
||||
break;
|
||||
|
||||
case A_NPCM7XX_ADC_DATA:
|
||||
value = s->data;
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid offset 0x%04" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_npcm7xx_adc_read(DEVICE(s)->canonical_path, offset, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_write(void *opaque, hwaddr offset, uint64_t v,
|
||||
unsigned size)
|
||||
{
|
||||
NPCM7xxADCState *s = opaque;
|
||||
|
||||
trace_npcm7xx_adc_write(DEVICE(s)->canonical_path, offset, v);
|
||||
switch (offset) {
|
||||
case A_NPCM7XX_ADC_CON:
|
||||
npcm7xx_adc_write_con(s, v);
|
||||
break;
|
||||
|
||||
case A_NPCM7XX_ADC_DATA:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: register @ 0x%04" HWADDR_PRIx " is read-only\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
|
||||
default:
|
||||
qemu_log_mask(LOG_GUEST_ERROR,
|
||||
"%s: invalid offset 0x%04" HWADDR_PRIx "\n",
|
||||
__func__, offset);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static const struct MemoryRegionOps npcm7xx_adc_ops = {
|
||||
.read = npcm7xx_adc_read,
|
||||
.write = npcm7xx_adc_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 4,
|
||||
.max_access_size = 4,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static void npcm7xx_adc_enter_reset(Object *obj, ResetType type)
|
||||
{
|
||||
NPCM7xxADCState *s = NPCM7XX_ADC(obj);
|
||||
|
||||
npcm7xx_adc_reset(s);
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_hold_reset(Object *obj)
|
||||
{
|
||||
NPCM7xxADCState *s = NPCM7XX_ADC(obj);
|
||||
|
||||
qemu_irq_lower(s->irq);
|
||||
}
|
||||
|
||||
static void npcm7xx_adc_init(Object *obj)
|
||||
{
|
||||
NPCM7xxADCState *s = NPCM7XX_ADC(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
int i;
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
timer_init_ns(&s->conv_timer, QEMU_CLOCK_VIRTUAL,
|
||||
npcm7xx_adc_convert_done, s);
|
||||
memory_region_init_io(&s->iomem, obj, &npcm7xx_adc_ops, s,
|
||||
TYPE_NPCM7XX_ADC, 4 * KiB);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
s->clock = qdev_init_clock_in(DEVICE(s), "clock", NULL, NULL);
|
||||
|
||||
for (i = 0; i < NPCM7XX_ADC_NUM_INPUTS; ++i) {
|
||||
object_property_add_uint32_ptr(obj, "adci[*]",
|
||||
&s->adci[i], OBJ_PROP_FLAG_WRITE);
|
||||
}
|
||||
object_property_add_uint32_ptr(obj, "vref",
|
||||
&s->vref, OBJ_PROP_FLAG_WRITE);
|
||||
npcm7xx_adc_calibrate(s);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_adc = {
|
||||
.name = "npcm7xx-adc",
|
||||
.version_id = 0,
|
||||
.minimum_version_id = 0,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_TIMER(conv_timer, NPCM7xxADCState),
|
||||
VMSTATE_UINT32(con, NPCM7xxADCState),
|
||||
VMSTATE_UINT32(data, NPCM7xxADCState),
|
||||
VMSTATE_CLOCK(clock, NPCM7xxADCState),
|
||||
VMSTATE_UINT32_ARRAY(adci, NPCM7xxADCState, NPCM7XX_ADC_NUM_INPUTS),
|
||||
VMSTATE_UINT32(vref, NPCM7xxADCState),
|
||||
VMSTATE_UINT32(iref, NPCM7xxADCState),
|
||||
VMSTATE_UINT16_ARRAY(calibration_r_values, NPCM7xxADCState,
|
||||
NPCM7XX_ADC_NUM_CALIB),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
},
|
||||
};
|
||||
|
||||
static Property npcm7xx_timer_properties[] = {
|
||||
DEFINE_PROP_UINT32("iref", NPCM7xxADCState, iref, NPCM7XX_ADC_DEFAULT_IREF),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void npcm7xx_adc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
ResettableClass *rc = RESETTABLE_CLASS(klass);
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "NPCM7xx ADC Module";
|
||||
dc->vmsd = &vmstate_npcm7xx_adc;
|
||||
rc->phases.enter = npcm7xx_adc_enter_reset;
|
||||
rc->phases.hold = npcm7xx_adc_hold_reset;
|
||||
|
||||
device_class_set_props(dc, npcm7xx_timer_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo npcm7xx_adc_info = {
|
||||
.name = TYPE_NPCM7XX_ADC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(NPCM7xxADCState),
|
||||
.class_init = npcm7xx_adc_class_init,
|
||||
.instance_init = npcm7xx_adc_init,
|
||||
};
|
||||
|
||||
static void npcm7xx_adc_register_types(void)
|
||||
{
|
||||
type_register_static(&npcm7xx_adc_info);
|
||||
}
|
||||
|
||||
type_init(npcm7xx_adc_register_types);
|
||||
@@ -0,0 +1,5 @@
|
||||
# See docs/devel/tracing.txt for syntax documentation.
|
||||
|
||||
# npcm7xx_adc.c
|
||||
npcm7xx_adc_read(const char *id, uint64_t offset, uint32_t value) " %s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
|
||||
npcm7xx_adc_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value 0x%04" PRIx32
|
||||
@@ -0,0 +1 @@
|
||||
#include "trace/trace-hw_adc.h"
|
||||
+52
-3
@@ -22,6 +22,7 @@
|
||||
#include "hw/char/serial.h"
|
||||
#include "hw/loader.h"
|
||||
#include "hw/misc/unimp.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/units.h"
|
||||
@@ -50,6 +51,9 @@
|
||||
#define NPCM7XX_EHCI_BA (0xf0806000)
|
||||
#define NPCM7XX_OHCI_BA (0xf0807000)
|
||||
|
||||
/* ADC Module */
|
||||
#define NPCM7XX_ADC_BA (0xf000c000)
|
||||
|
||||
/* Internal AHB SRAM */
|
||||
#define NPCM7XX_RAM3_BA (0xc0008000)
|
||||
#define NPCM7XX_RAM3_SZ (4 * KiB)
|
||||
@@ -60,6 +64,7 @@
|
||||
#define NPCM7XX_ROM_BA (0xffff0000)
|
||||
#define NPCM7XX_ROM_SZ (64 * KiB)
|
||||
|
||||
|
||||
/* Clock configuration values to be fixed up when bypassing bootloader */
|
||||
|
||||
/* Run PLL1 at 1600 MHz */
|
||||
@@ -72,6 +77,7 @@
|
||||
* interrupts.
|
||||
*/
|
||||
enum NPCM7xxInterrupt {
|
||||
NPCM7XX_ADC_IRQ = 0,
|
||||
NPCM7XX_UART0_IRQ = 2,
|
||||
NPCM7XX_UART1_IRQ,
|
||||
NPCM7XX_UART2_IRQ,
|
||||
@@ -96,6 +102,8 @@ enum NPCM7xxInterrupt {
|
||||
NPCM7XX_WDG2_IRQ, /* Timer Module 2 Watchdog */
|
||||
NPCM7XX_EHCI_IRQ = 61,
|
||||
NPCM7XX_OHCI_IRQ = 62,
|
||||
NPCM7XX_PWM0_IRQ = 93, /* PWM module 0 */
|
||||
NPCM7XX_PWM1_IRQ, /* PWM module 1 */
|
||||
NPCM7XX_GPIO0_IRQ = 116,
|
||||
NPCM7XX_GPIO1_IRQ,
|
||||
NPCM7XX_GPIO2_IRQ,
|
||||
@@ -138,6 +146,12 @@ static const hwaddr npcm7xx_fiu3_flash_addr[] = {
|
||||
0xb8000000, /* CS3 */
|
||||
};
|
||||
|
||||
/* Register base address for each PWM Module */
|
||||
static const hwaddr npcm7xx_pwm_addr[] = {
|
||||
0xf0103000,
|
||||
0xf0104000,
|
||||
};
|
||||
|
||||
static const struct {
|
||||
hwaddr regs_addr;
|
||||
uint32_t unconnected_pins;
|
||||
@@ -295,6 +309,14 @@ static void npcm7xx_init_fuses(NPCM7xxState *s)
|
||||
sizeof(value));
|
||||
}
|
||||
|
||||
static void npcm7xx_write_adc_calibration(NPCM7xxState *s)
|
||||
{
|
||||
/* Both ADC and the fuse array must have realized. */
|
||||
QEMU_BUILD_BUG_ON(sizeof(s->adc.calibration_r_values) != 4);
|
||||
npcm7xx_otp_array_write(&s->fuse_array, s->adc.calibration_r_values,
|
||||
NPCM7XX_FUSE_ADC_CALIB, sizeof(s->adc.calibration_r_values));
|
||||
}
|
||||
|
||||
static qemu_irq npcm7xx_irq(NPCM7xxState *s, int n)
|
||||
{
|
||||
return qdev_get_gpio_in(DEVICE(&s->a9mpcore), n);
|
||||
@@ -321,6 +343,7 @@ static void npcm7xx_init(Object *obj)
|
||||
TYPE_NPCM7XX_FUSE_ARRAY);
|
||||
object_initialize_child(obj, "mc", &s->mc, TYPE_NPCM7XX_MC);
|
||||
object_initialize_child(obj, "rng", &s->rng, TYPE_NPCM7XX_RNG);
|
||||
object_initialize_child(obj, "adc", &s->adc, TYPE_NPCM7XX_ADC);
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
|
||||
object_initialize_child(obj, "tim[*]", &s->tim[i], TYPE_NPCM7XX_TIMER);
|
||||
@@ -338,6 +361,10 @@ static void npcm7xx_init(Object *obj)
|
||||
object_initialize_child(obj, npcm7xx_fiu[i].name, &s->fiu[i],
|
||||
TYPE_NPCM7XX_FIU);
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
|
||||
object_initialize_child(obj, "pwm[*]", &s->pwm[i], TYPE_NPCM7XX_PWM);
|
||||
}
|
||||
}
|
||||
|
||||
static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
@@ -413,6 +440,15 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->mc), &error_abort);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->mc), 0, NPCM7XX_MC_BA);
|
||||
|
||||
/* ADC Modules. Cannot fail. */
|
||||
qdev_connect_clock_in(DEVICE(&s->adc), "clock", qdev_get_clock_out(
|
||||
DEVICE(&s->clk), "adc-clock"));
|
||||
sysbus_realize(SYS_BUS_DEVICE(&s->adc), &error_abort);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, NPCM7XX_ADC_BA);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
|
||||
npcm7xx_irq(s, NPCM7XX_ADC_IRQ));
|
||||
npcm7xx_write_adc_calibration(s);
|
||||
|
||||
/* Timer Modules (TIM). Cannot fail. */
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_tim_addr) != ARRAY_SIZE(s->tim));
|
||||
for (i = 0; i < ARRAY_SIZE(s->tim); i++) {
|
||||
@@ -420,6 +456,10 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
int first_irq;
|
||||
int j;
|
||||
|
||||
/* Connect the timer clock. */
|
||||
qdev_connect_clock_in(DEVICE(&s->tim[i]), "clock", qdev_get_clock_out(
|
||||
DEVICE(&s->clk), "timer-clock"));
|
||||
|
||||
sysbus_realize(sbd, &error_abort);
|
||||
sysbus_mmio_map(sbd, 0, npcm7xx_tim_addr[i]);
|
||||
|
||||
@@ -485,6 +525,18 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->ohci), 0,
|
||||
npcm7xx_irq(s, NPCM7XX_OHCI_IRQ));
|
||||
|
||||
/* PWM Modules. Cannot fail. */
|
||||
QEMU_BUILD_BUG_ON(ARRAY_SIZE(npcm7xx_pwm_addr) != ARRAY_SIZE(s->pwm));
|
||||
for (i = 0; i < ARRAY_SIZE(s->pwm); i++) {
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(&s->pwm[i]);
|
||||
|
||||
qdev_connect_clock_in(DEVICE(&s->pwm[i]), "clock", qdev_get_clock_out(
|
||||
DEVICE(&s->clk), "apb3-clock"));
|
||||
sysbus_realize(sbd, &error_abort);
|
||||
sysbus_mmio_map(sbd, 0, npcm7xx_pwm_addr[i]);
|
||||
sysbus_connect_irq(sbd, i, npcm7xx_irq(s, NPCM7XX_PWM0_IRQ + i));
|
||||
}
|
||||
|
||||
/*
|
||||
* Flash Interface Unit (FIU). Can fail if incorrect number of chip selects
|
||||
* specified, but this is a programming error.
|
||||
@@ -523,7 +575,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
create_unimplemented_device("npcm7xx.vdmx", 0xe0800000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.pcierc", 0xe1000000, 64 * KiB);
|
||||
create_unimplemented_device("npcm7xx.kcs", 0xf0007000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.adc", 0xf000c000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.gfxi", 0xf000e000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.gpio[0]", 0xf0010000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.gpio[1]", 0xf0011000, 4 * KiB);
|
||||
@@ -553,8 +604,6 @@ static void npcm7xx_realize(DeviceState *dev, Error **errp)
|
||||
create_unimplemented_device("npcm7xx.peci", 0xf0100000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.siox[1]", 0xf0101000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.siox[2]", 0xf0102000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.pwm[0]", 0xf0103000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.pwm[1]", 0xf0104000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[0]", 0xf0180000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[1]", 0xf0181000, 4 * KiB);
|
||||
create_unimplemented_device("npcm7xx.mft[2]", 0xf0182000, 4 * KiB);
|
||||
|
||||
@@ -82,7 +82,7 @@ static NPCM7xxState *npcm7xx_create_soc(MachineState *machine,
|
||||
uint32_t hw_straps)
|
||||
{
|
||||
NPCM7xxMachineClass *nmc = NPCM7XX_MACHINE_GET_CLASS(machine);
|
||||
MachineClass *mc = &nmc->parent;
|
||||
MachineClass *mc = MACHINE_CLASS(nmc);
|
||||
Object *obj;
|
||||
|
||||
if (strcmp(machine->cpu_type, mc->default_cpu_type) != 0) {
|
||||
|
||||
+1
-1
@@ -62,7 +62,7 @@ static void npcm7xx_mc_realize(DeviceState *dev, Error **errp)
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &npcm7xx_mc_ops, s, "regs",
|
||||
NPCM7XX_MC_REGS_SIZE);
|
||||
sysbus_init_mmio(&s->parent, &s->mmio);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->mmio);
|
||||
}
|
||||
|
||||
static void npcm7xx_mc_class_init(ObjectClass *klass, void *data)
|
||||
|
||||
@@ -64,6 +64,7 @@ softmmu_ss.add(when: 'CONFIG_MAINSTONE', if_true: files('mst_fpga.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files(
|
||||
'npcm7xx_clk.c',
|
||||
'npcm7xx_gcr.c',
|
||||
'npcm7xx_pwm.c',
|
||||
'npcm7xx_rng.c',
|
||||
))
|
||||
softmmu_ss.add(when: 'CONFIG_OMAP', if_true: files(
|
||||
|
||||
+795
-12
File diff suppressed because it is too large
Load Diff
@@ -220,7 +220,7 @@ static void npcm7xx_gcr_init(Object *obj)
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &npcm7xx_gcr_ops, s,
|
||||
TYPE_NPCM7XX_GCR, 4 * KiB);
|
||||
sysbus_init_mmio(&s->parent, &s->iomem);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_gcr = {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -143,7 +143,7 @@ static void npcm7xx_rng_init(Object *obj)
|
||||
|
||||
memory_region_init_io(&s->iomem, obj, &npcm7xx_rng_ops, s, "regs",
|
||||
NPCM7XX_RNG_REGS_SIZE);
|
||||
sysbus_init_mmio(&s->parent, &s->iomem);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_rng = {
|
||||
|
||||
@@ -120,6 +120,12 @@ npcm7xx_gcr_write(uint64_t offset, uint32_t value) "offset: 0x%04" PRIx64 " valu
|
||||
npcm7xx_rng_read(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
|
||||
npcm7xx_rng_write(uint64_t offset, uint64_t value, unsigned size) "offset: 0x%04" PRIx64 " value: 0x%02" PRIx64 " size: %u"
|
||||
|
||||
# npcm7xx_pwm.c
|
||||
npcm7xx_pwm_read(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
|
||||
npcm7xx_pwm_write(const char *id, uint64_t offset, uint32_t value) "%s offset: 0x%04" PRIx64 " value: 0x%08" PRIx32
|
||||
npcm7xx_pwm_update_freq(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Freq: old_freq: %u, new_freq: %u"
|
||||
npcm7xx_pwm_update_duty(const char *id, uint8_t index, uint32_t old_value, uint32_t new_value) "%s pwm[%u] Update Duty: old_duty: %u, new_duty: %u"
|
||||
|
||||
# stm32f4xx_syscfg.c
|
||||
stm32f4xx_syscfg_set_irq(int gpio, int line, int level) "Interupt: GPIO: %d, Line: %d; Level: %d"
|
||||
stm32f4xx_pulse_exti(int irq) "Pulse EXTI: %d"
|
||||
|
||||
+19
-7
@@ -40,6 +40,17 @@ do { hw_error("lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
|
||||
do { fprintf(stderr, "lan9118: error: " fmt , ## __VA_ARGS__);} while (0)
|
||||
#endif
|
||||
|
||||
/* The tx and rx fifo ports are a range of aliased 32-bit registers */
|
||||
#define RX_DATA_FIFO_PORT_FIRST 0x00
|
||||
#define RX_DATA_FIFO_PORT_LAST 0x1f
|
||||
#define TX_DATA_FIFO_PORT_FIRST 0x20
|
||||
#define TX_DATA_FIFO_PORT_LAST 0x3f
|
||||
|
||||
#define RX_STATUS_FIFO_PORT 0x40
|
||||
#define RX_STATUS_FIFO_PEEK 0x44
|
||||
#define TX_STATUS_FIFO_PORT 0x48
|
||||
#define TX_STATUS_FIFO_PEEK 0x4c
|
||||
|
||||
#define CSR_ID_REV 0x50
|
||||
#define CSR_IRQ_CFG 0x54
|
||||
#define CSR_INT_STS 0x58
|
||||
@@ -1020,7 +1031,8 @@ static void lan9118_writel(void *opaque, hwaddr offset,
|
||||
offset &= 0xff;
|
||||
|
||||
//DPRINTF("Write reg 0x%02x = 0x%08x\n", (int)offset, val);
|
||||
if (offset >= 0x20 && offset < 0x40) {
|
||||
if (offset >= TX_DATA_FIFO_PORT_FIRST &&
|
||||
offset <= TX_DATA_FIFO_PORT_LAST) {
|
||||
/* TX FIFO */
|
||||
tx_fifo_push(s, val);
|
||||
return;
|
||||
@@ -1198,18 +1210,18 @@ static uint64_t lan9118_readl(void *opaque, hwaddr offset,
|
||||
lan9118_state *s = (lan9118_state *)opaque;
|
||||
|
||||
//DPRINTF("Read reg 0x%02x\n", (int)offset);
|
||||
if (offset < 0x20) {
|
||||
if (offset <= RX_DATA_FIFO_PORT_LAST) {
|
||||
/* RX FIFO */
|
||||
return rx_fifo_pop(s);
|
||||
}
|
||||
switch (offset) {
|
||||
case 0x40:
|
||||
case RX_STATUS_FIFO_PORT:
|
||||
return rx_status_fifo_pop(s);
|
||||
case 0x44:
|
||||
return s->rx_status_fifo[s->tx_status_fifo_head];
|
||||
case 0x48:
|
||||
case RX_STATUS_FIFO_PEEK:
|
||||
return s->rx_status_fifo[s->rx_status_fifo_head];
|
||||
case TX_STATUS_FIFO_PORT:
|
||||
return tx_status_fifo_pop(s);
|
||||
case 0x4c:
|
||||
case TX_STATUS_FIFO_PEEK:
|
||||
return s->tx_status_fifo[s->tx_status_fifo_head];
|
||||
case CSR_ID_REV:
|
||||
return 0x01180001;
|
||||
|
||||
@@ -371,7 +371,7 @@ static void npcm7xx_otp_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NPCM7xxOTPClass *oc = NPCM7XX_OTP_GET_CLASS(dev);
|
||||
NPCM7xxOTPState *s = NPCM7XX_OTP(dev);
|
||||
SysBusDevice *sbd = &s->parent;
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
|
||||
memset(s->array, 0, sizeof(s->array));
|
||||
|
||||
|
||||
@@ -498,7 +498,7 @@ static void npcm7xx_fiu_hold_reset(Object *obj)
|
||||
static void npcm7xx_fiu_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
NPCM7xxFIUState *s = NPCM7XX_FIU(dev);
|
||||
SysBusDevice *sbd = &s->parent;
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
int i;
|
||||
|
||||
if (s->cs_count <= 0) {
|
||||
|
||||
+18
-21
@@ -17,8 +17,8 @@
|
||||
#include "qemu/osdep.h"
|
||||
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-clock.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "hw/misc/npcm7xx_clk.h"
|
||||
#include "hw/timer/npcm7xx_timer.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "qemu/bitops.h"
|
||||
@@ -128,23 +128,18 @@ static uint32_t npcm7xx_tcsr_prescaler(uint32_t tcsr)
|
||||
/* Convert a timer cycle count to a time interval in nanoseconds. */
|
||||
static int64_t npcm7xx_timer_count_to_ns(NPCM7xxTimer *t, uint32_t count)
|
||||
{
|
||||
int64_t ns = count;
|
||||
int64_t ticks = count;
|
||||
|
||||
ns *= NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ;
|
||||
ns *= npcm7xx_tcsr_prescaler(t->tcsr);
|
||||
ticks *= npcm7xx_tcsr_prescaler(t->tcsr);
|
||||
|
||||
return ns;
|
||||
return clock_ticks_to_ns(t->ctrl->clock, ticks);
|
||||
}
|
||||
|
||||
/* Convert a time interval in nanoseconds to a timer cycle count. */
|
||||
static uint32_t npcm7xx_timer_ns_to_count(NPCM7xxTimer *t, int64_t ns)
|
||||
{
|
||||
int64_t count;
|
||||
|
||||
count = ns / (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ);
|
||||
count /= npcm7xx_tcsr_prescaler(t->tcsr);
|
||||
|
||||
return count;
|
||||
return ns / clock_ticks_to_ns(t->ctrl->clock,
|
||||
npcm7xx_tcsr_prescaler(t->tcsr));
|
||||
}
|
||||
|
||||
static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
|
||||
@@ -166,8 +161,8 @@ static uint32_t npcm7xx_watchdog_timer_prescaler(const NPCM7xxWatchdogTimer *t)
|
||||
static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
|
||||
int64_t cycles)
|
||||
{
|
||||
uint32_t prescaler = npcm7xx_watchdog_timer_prescaler(t);
|
||||
int64_t ns = (NANOSECONDS_PER_SECOND / NPCM7XX_TIMER_REF_HZ) * cycles;
|
||||
int64_t ticks = cycles * npcm7xx_watchdog_timer_prescaler(t);
|
||||
int64_t ns = clock_ticks_to_ns(t->ctrl->clock, ticks);
|
||||
|
||||
/*
|
||||
* The reset function always clears the current timer. The caller of the
|
||||
@@ -176,7 +171,6 @@ static void npcm7xx_watchdog_timer_reset_cycles(NPCM7xxWatchdogTimer *t,
|
||||
*/
|
||||
npcm7xx_timer_clear(&t->base_timer);
|
||||
|
||||
ns *= prescaler;
|
||||
t->base_timer.remaining_ns = ns;
|
||||
}
|
||||
|
||||
@@ -606,10 +600,11 @@ static void npcm7xx_timer_hold_reset(Object *obj)
|
||||
qemu_irq_lower(s->watchdog_timer.irq);
|
||||
}
|
||||
|
||||
static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
|
||||
static void npcm7xx_timer_init(Object *obj)
|
||||
{
|
||||
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(dev);
|
||||
SysBusDevice *sbd = &s->parent;
|
||||
NPCM7xxTimerCtrlState *s = NPCM7XX_TIMER(obj);
|
||||
DeviceState *dev = DEVICE(obj);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
|
||||
int i;
|
||||
NPCM7xxWatchdogTimer *w;
|
||||
|
||||
@@ -627,11 +622,12 @@ static void npcm7xx_timer_realize(DeviceState *dev, Error **errp)
|
||||
npcm7xx_watchdog_timer_expired, w);
|
||||
sysbus_init_irq(sbd, &w->irq);
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &npcm7xx_timer_ops, s,
|
||||
memory_region_init_io(&s->iomem, obj, &npcm7xx_timer_ops, s,
|
||||
TYPE_NPCM7XX_TIMER, 4 * KiB);
|
||||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
qdev_init_gpio_out_named(dev, &w->reset_signal,
|
||||
NPCM7XX_WATCHDOG_RESET_GPIO_OUT, 1);
|
||||
s->clock = qdev_init_clock_in(dev, "clock", NULL, NULL);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_base_timer = {
|
||||
@@ -675,10 +671,11 @@ static const VMStateDescription vmstate_npcm7xx_watchdog_timer = {
|
||||
|
||||
static const VMStateDescription vmstate_npcm7xx_timer_ctrl = {
|
||||
.name = "npcm7xx-timer-ctrl",
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.version_id = 2,
|
||||
.minimum_version_id = 2,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32(tisr, NPCM7xxTimerCtrlState),
|
||||
VMSTATE_CLOCK(clock, NPCM7xxTimerCtrlState),
|
||||
VMSTATE_STRUCT_ARRAY(timer, NPCM7xxTimerCtrlState,
|
||||
NPCM7XX_TIMERS_PER_CTRL, 0, vmstate_npcm7xx_timer,
|
||||
NPCM7xxTimer),
|
||||
@@ -697,7 +694,6 @@ static void npcm7xx_timer_class_init(ObjectClass *klass, void *data)
|
||||
QEMU_BUILD_BUG_ON(NPCM7XX_TIMER_REGS_END > NPCM7XX_TIMER_NR_REGS);
|
||||
|
||||
dc->desc = "NPCM7xx Timer Controller";
|
||||
dc->realize = npcm7xx_timer_realize;
|
||||
dc->vmsd = &vmstate_npcm7xx_timer_ctrl;
|
||||
rc->phases.enter = npcm7xx_timer_enter_reset;
|
||||
rc->phases.hold = npcm7xx_timer_hold_reset;
|
||||
@@ -708,6 +704,7 @@ static const TypeInfo npcm7xx_timer_info = {
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(NPCM7xxTimerCtrlState),
|
||||
.class_init = npcm7xx_timer_class_init,
|
||||
.instance_init = npcm7xx_timer_init,
|
||||
};
|
||||
|
||||
static void npcm7xx_timer_register_type(void)
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Nuvoton NPCM7xx ADC Module
|
||||
*
|
||||
* Copyright 2020 Google LLC
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef NPCM7XX_ADC_H
|
||||
#define NPCM7XX_ADC_H
|
||||
|
||||
#include "hw/clock.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/sysbus.h"
|
||||
#include "qemu/timer.h"
|
||||
|
||||
#define NPCM7XX_ADC_NUM_INPUTS 8
|
||||
/**
|
||||
* This value should not be changed unless write_adc_calibration function in
|
||||
* hw/arm/npcm7xx.c is also changed.
|
||||
*/
|
||||
#define NPCM7XX_ADC_NUM_CALIB 2
|
||||
|
||||
/**
|
||||
* struct NPCM7xxADCState - Analog to Digital Converter Module device state.
|
||||
* @parent: System bus device.
|
||||
* @iomem: Memory region through which registers are accessed.
|
||||
* @conv_timer: The timer counts down remaining cycles for the conversion.
|
||||
* @irq: GIC interrupt line to fire on expiration (if enabled).
|
||||
* @con: The Control Register.
|
||||
* @data: The Data Buffer.
|
||||
* @clock: The ADC Clock.
|
||||
* @adci: The input voltage in units of uV. 1uv = 1e-6V.
|
||||
* @vref: The external reference voltage.
|
||||
* @iref: The internal reference voltage, initialized at launch time.
|
||||
* @rv: The calibrated output values of 0.5V and 1.5V for the ADC.
|
||||
*/
|
||||
typedef struct {
|
||||
SysBusDevice parent;
|
||||
|
||||
MemoryRegion iomem;
|
||||
|
||||
QEMUTimer conv_timer;
|
||||
|
||||
qemu_irq irq;
|
||||
uint32_t con;
|
||||
uint32_t data;
|
||||
Clock *clock;
|
||||
|
||||
/* Voltages are in unit of uV. 1V = 1000000uV. */
|
||||
uint32_t adci[NPCM7XX_ADC_NUM_INPUTS];
|
||||
uint32_t vref;
|
||||
uint32_t iref;
|
||||
|
||||
uint16_t calibration_r_values[NPCM7XX_ADC_NUM_CALIB];
|
||||
} NPCM7xxADCState;
|
||||
|
||||
#define TYPE_NPCM7XX_ADC "npcm7xx-adc"
|
||||
#define NPCM7XX_ADC(obj) \
|
||||
OBJECT_CHECK(NPCM7xxADCState, (obj), TYPE_NPCM7XX_ADC)
|
||||
|
||||
#endif /* NPCM7XX_ADC_H */
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user