mirror of https://github.com/xemu-project/xemu.git
Aspeed patches :
* I2C QOMify (Cedric) * SMC model cleanup and QOMify (Cedric) * ADC model (Peter and Andrew) * GPIO fixes (Peter) -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEEoPZlSPBIlev+awtgUaNDx8/77KEFAmFlOvYACgkQUaNDx8/7 7KGimQ/+LG8B04Aveo74ezIX0GCNQIi6ZVRAzPBOsHZ1FSW3rXfOxr1k/uUWDWiC t05r9e63f4IPVtoP14H8zFnQngddG2Q3AByOilJLRYYct3N6G+ewUqBmR1LN+iBZ 1F/koyNvBNfCBQHCmPHsJF6UGgs48NbXPWoQX2Dsudkkxk3KS+RTUrtIk4fD9tB9 a5lDxSjJ756pkQkvS7tCLjyGB4rOicfEE0gDh4Uyr3+t9VRXPVCSG7NX1jvytZ2t 1udj7MmnNEjY0CtUFjtfjog5f3gcXU40lGmbvNxEB8dPykJnnPqbdSWtStRryN5L FVvOeP4rKb0jF0TmNsBWTtSZvNuNBzQkwL/tYgzJ+bKNVoYQUDHzhWsC99GqH9Vi +z3s5TlEqiTN1krw8+0vF/4GeTse0lsYuGIvD3jqdrERCtpPvmSynMWXtIGi/QOr ILVXaSbJ4A6ZkAXQjKNVOGqqEeQqr96synSeyiNQs9su9X/Sl5P71r9mFRhVV9T7 4EgvzGQCMIH+aL/nMnb2IhQNd/3sq51wc+TOnmb+by22s85LWvaSuBQVI2kvDn4v Bckl11qP6AZFu2xvq+mGnPI3cXRm57N5S499mwF+wygLpWOQI2CjoUunC+0GWQ7O ISMvukTskpwOkDNbfTB+e0cT80w5REdIcLL5oLmxcA+s35zthb8= =ydTX -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/clg/tags/pull-aspeed-20211012' into staging Aspeed patches : * I2C QOMify (Cedric) * SMC model cleanup and QOMify (Cedric) * ADC model (Peter and Andrew) * GPIO fixes (Peter) # gpg: Signature made Tue 12 Oct 2021 12:36:22 AM PDT # gpg: using RSA key A0F66548F04895EBFE6B0B6051A343C7CFFBECA1 # gpg: Good signature from "Cédric Le Goater <clg@kaod.org>" [marginal] # gpg: WARNING: This key is not certified with sufficiently trusted signatures! # gpg: It is not certain that the signature belongs to the owner. # Primary key fingerprint: A0F6 6548 F048 95EB FE6B 0B60 51A3 43C7 CFFB ECA1 * remotes/clg/tags/pull-aspeed-20211012: aspeed/smc: Dump address offset in trace events aspeed/wdt: Add trace events hw/arm: Integrate ADC model into Aspeed SoC hw/adc: Add basic Aspeed ADC model hw: aspeed_gpio: Fix GPIO array indexing hw: aspeed_gpio: Fix pin I/O type declarations aspeed/i2c: QOMify AspeedI2CBus aspeed/smc: Remove unused attribute 'irqline' aspeed/smc: Introduce a new addr_width() class handler aspeed/smc: Add default reset values aspeed/smc: QOMify AspeedSMCFlash aspeed/smc: Rename AspeedSMCFlash 'id' to 'cs' aspeed/smc: Remove the 'size' attribute from AspeedSMCFlash aspeed/smc: Remove the 'flash' attribute from AspeedSMCFlash aspeed/smc: Drop AspeedSMCController structure aspeed/smc: Stop using the model name for the memory regions aspeed/smc: Introduce aspeed_smc_error() helper aspeed/smc: Add watchdog Control/Status Registers Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
commit
81d8537cb2
|
@ -0,0 +1,427 @@
|
|||
/*
|
||||
* Aspeed ADC
|
||||
*
|
||||
* Copyright 2017-2021 IBM Corp.
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/log.h"
|
||||
#include "hw/irq.h"
|
||||
#include "hw/qdev-properties.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "hw/adc/aspeed_adc.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define ASPEED_ADC_MEMORY_REGION_SIZE 0x1000
|
||||
#define ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE 0x100
|
||||
#define ASPEED_ADC_ENGINE_CH_EN_MASK 0xffff0000
|
||||
#define ASPEED_ADC_ENGINE_CH_EN(x) ((BIT(x)) << 16)
|
||||
#define ASPEED_ADC_ENGINE_INIT BIT(8)
|
||||
#define ASPEED_ADC_ENGINE_AUTO_COMP BIT(5)
|
||||
#define ASPEED_ADC_ENGINE_COMP BIT(4)
|
||||
#define ASPEED_ADC_ENGINE_MODE_MASK 0x0000000e
|
||||
#define ASPEED_ADC_ENGINE_MODE_OFF (0b000 << 1)
|
||||
#define ASPEED_ADC_ENGINE_MODE_STANDBY (0b001 << 1)
|
||||
#define ASPEED_ADC_ENGINE_MODE_NORMAL (0b111 << 1)
|
||||
#define ASPEED_ADC_ENGINE_EN BIT(0)
|
||||
#define ASPEED_ADC_HYST_EN BIT(31)
|
||||
|
||||
#define ASPEED_ADC_L_MASK ((1 << 10) - 1)
|
||||
#define ASPEED_ADC_L(x) ((x) & ASPEED_ADC_L_MASK)
|
||||
#define ASPEED_ADC_H(x) (((x) >> 16) & ASPEED_ADC_L_MASK)
|
||||
#define ASPEED_ADC_LH_MASK (ASPEED_ADC_L_MASK << 16 | ASPEED_ADC_L_MASK)
|
||||
#define LOWER_CHANNEL_MASK ((1 << 10) - 1)
|
||||
#define LOWER_CHANNEL_DATA(x) ((x) & LOWER_CHANNEL_MASK)
|
||||
#define UPPER_CHANNEL_DATA(x) (((x) >> 16) & LOWER_CHANNEL_MASK)
|
||||
|
||||
#define TO_REG(addr) (addr >> 2)
|
||||
|
||||
#define ENGINE_CONTROL TO_REG(0x00)
|
||||
#define INTERRUPT_CONTROL TO_REG(0x04)
|
||||
#define VGA_DETECT_CONTROL TO_REG(0x08)
|
||||
#define CLOCK_CONTROL TO_REG(0x0C)
|
||||
#define DATA_CHANNEL_1_AND_0 TO_REG(0x10)
|
||||
#define DATA_CHANNEL_7_AND_6 TO_REG(0x1C)
|
||||
#define DATA_CHANNEL_9_AND_8 TO_REG(0x20)
|
||||
#define DATA_CHANNEL_15_AND_14 TO_REG(0x2C)
|
||||
#define BOUNDS_CHANNEL_0 TO_REG(0x30)
|
||||
#define BOUNDS_CHANNEL_7 TO_REG(0x4C)
|
||||
#define BOUNDS_CHANNEL_8 TO_REG(0x50)
|
||||
#define BOUNDS_CHANNEL_15 TO_REG(0x6C)
|
||||
#define HYSTERESIS_CHANNEL_0 TO_REG(0x70)
|
||||
#define HYSTERESIS_CHANNEL_7 TO_REG(0x8C)
|
||||
#define HYSTERESIS_CHANNEL_8 TO_REG(0x90)
|
||||
#define HYSTERESIS_CHANNEL_15 TO_REG(0xAC)
|
||||
#define INTERRUPT_SOURCE TO_REG(0xC0)
|
||||
#define COMPENSATING_AND_TRIMMING TO_REG(0xC4)
|
||||
|
||||
static inline uint32_t update_channels(uint32_t current)
|
||||
{
|
||||
return ((((current >> 16) & ASPEED_ADC_L_MASK) + 7) << 16) |
|
||||
((current + 5) & ASPEED_ADC_L_MASK);
|
||||
}
|
||||
|
||||
static bool breaks_threshold(AspeedADCEngineState *s, int reg)
|
||||
{
|
||||
assert(reg >= DATA_CHANNEL_1_AND_0 &&
|
||||
reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
|
||||
|
||||
int a_bounds_reg = BOUNDS_CHANNEL_0 + (reg - DATA_CHANNEL_1_AND_0) * 2;
|
||||
int b_bounds_reg = a_bounds_reg + 1;
|
||||
uint32_t a_and_b = s->regs[reg];
|
||||
uint32_t a_bounds = s->regs[a_bounds_reg];
|
||||
uint32_t b_bounds = s->regs[b_bounds_reg];
|
||||
uint32_t a = ASPEED_ADC_L(a_and_b);
|
||||
uint32_t b = ASPEED_ADC_H(a_and_b);
|
||||
uint32_t a_lower = ASPEED_ADC_L(a_bounds);
|
||||
uint32_t a_upper = ASPEED_ADC_H(a_bounds);
|
||||
uint32_t b_lower = ASPEED_ADC_L(b_bounds);
|
||||
uint32_t b_upper = ASPEED_ADC_H(b_bounds);
|
||||
|
||||
return (a < a_lower || a > a_upper) ||
|
||||
(b < b_lower || b > b_upper);
|
||||
}
|
||||
|
||||
static uint32_t read_channel_sample(AspeedADCEngineState *s, int reg)
|
||||
{
|
||||
assert(reg >= DATA_CHANNEL_1_AND_0 &&
|
||||
reg < DATA_CHANNEL_1_AND_0 + s->nr_channels / 2);
|
||||
|
||||
/* Poor man's sampling */
|
||||
uint32_t value = s->regs[reg];
|
||||
s->regs[reg] = update_channels(s->regs[reg]);
|
||||
|
||||
if (breaks_threshold(s, reg)) {
|
||||
s->regs[INTERRUPT_CONTROL] |= BIT(reg - DATA_CHANNEL_1_AND_0);
|
||||
qemu_irq_raise(s->irq);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint64_t aspeed_adc_engine_read(void *opaque, hwaddr addr,
|
||||
unsigned int size)
|
||||
{
|
||||
AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
|
||||
int reg = TO_REG(addr);
|
||||
uint32_t value = 0;
|
||||
|
||||
switch (reg) {
|
||||
case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
|
||||
if (s->nr_channels <= 8) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
|
||||
"bounds register %u invalid, only 0...7 valid\n",
|
||||
__func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
|
||||
if (s->nr_channels <= 8) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
|
||||
"hysteresis register %u invalid, only 0...7 valid\n",
|
||||
__func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
|
||||
case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
|
||||
case ENGINE_CONTROL:
|
||||
case INTERRUPT_CONTROL:
|
||||
case VGA_DETECT_CONTROL:
|
||||
case CLOCK_CONTROL:
|
||||
case INTERRUPT_SOURCE:
|
||||
case COMPENSATING_AND_TRIMMING:
|
||||
value = s->regs[reg];
|
||||
break;
|
||||
case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
|
||||
if (s->nr_channels <= 8) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
|
||||
"data register %u invalid, only 0...3 valid\n",
|
||||
__func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
|
||||
value = read_channel_sample(s, reg);
|
||||
/* Allow 16-bit reads of the data registers */
|
||||
if (addr & 0x2) {
|
||||
assert(size == 2);
|
||||
value >>= 16;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: 0x%" HWADDR_PRIx "\n",
|
||||
__func__, s->engine_id, addr);
|
||||
break;
|
||||
}
|
||||
|
||||
trace_aspeed_adc_engine_read(s->engine_id, addr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static void aspeed_adc_engine_write(void *opaque, hwaddr addr, uint64_t value,
|
||||
unsigned int size)
|
||||
{
|
||||
AspeedADCEngineState *s = ASPEED_ADC_ENGINE(opaque);
|
||||
int reg = TO_REG(addr);
|
||||
uint32_t init = 0;
|
||||
|
||||
trace_aspeed_adc_engine_write(s->engine_id, addr, value);
|
||||
|
||||
switch (reg) {
|
||||
case ENGINE_CONTROL:
|
||||
init = !!(value & ASPEED_ADC_ENGINE_EN);
|
||||
init *= ASPEED_ADC_ENGINE_INIT;
|
||||
|
||||
value &= ~ASPEED_ADC_ENGINE_INIT;
|
||||
value |= init;
|
||||
|
||||
value &= ~ASPEED_ADC_ENGINE_AUTO_COMP;
|
||||
break;
|
||||
case INTERRUPT_CONTROL:
|
||||
case VGA_DETECT_CONTROL:
|
||||
case CLOCK_CONTROL:
|
||||
break;
|
||||
case DATA_CHANNEL_9_AND_8 ... DATA_CHANNEL_15_AND_14:
|
||||
if (s->nr_channels <= 8) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
|
||||
"data register %u invalid, only 0...3 valid\n",
|
||||
__func__, s->engine_id, reg - DATA_CHANNEL_1_AND_0);
|
||||
return;
|
||||
}
|
||||
/* fallthrough */
|
||||
case BOUNDS_CHANNEL_8 ... BOUNDS_CHANNEL_15:
|
||||
if (s->nr_channels <= 8) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
|
||||
"bounds register %u invalid, only 0...7 valid\n",
|
||||
__func__, s->engine_id, reg - BOUNDS_CHANNEL_0);
|
||||
return;
|
||||
}
|
||||
/* fallthrough */
|
||||
case DATA_CHANNEL_1_AND_0 ... DATA_CHANNEL_7_AND_6:
|
||||
case BOUNDS_CHANNEL_0 ... BOUNDS_CHANNEL_7:
|
||||
value &= ASPEED_ADC_LH_MASK;
|
||||
break;
|
||||
case HYSTERESIS_CHANNEL_8 ... HYSTERESIS_CHANNEL_15:
|
||||
if (s->nr_channels <= 8) {
|
||||
qemu_log_mask(LOG_GUEST_ERROR, "%s: engine[%u]: "
|
||||
"hysteresis register %u invalid, only 0...7 valid\n",
|
||||
__func__, s->engine_id, reg - HYSTERESIS_CHANNEL_0);
|
||||
return;
|
||||
}
|
||||
/* fallthrough */
|
||||
case HYSTERESIS_CHANNEL_0 ... HYSTERESIS_CHANNEL_7:
|
||||
value &= (ASPEED_ADC_HYST_EN | ASPEED_ADC_LH_MASK);
|
||||
break;
|
||||
case INTERRUPT_SOURCE:
|
||||
value &= 0xffff;
|
||||
break;
|
||||
case COMPENSATING_AND_TRIMMING:
|
||||
value &= 0xf;
|
||||
break;
|
||||
default:
|
||||
qemu_log_mask(LOG_UNIMP, "%s: engine[%u]: "
|
||||
"0x%" HWADDR_PRIx " 0x%" PRIx64 "\n",
|
||||
__func__, s->engine_id, addr, value);
|
||||
break;
|
||||
}
|
||||
|
||||
s->regs[reg] = value;
|
||||
}
|
||||
|
||||
static const MemoryRegionOps aspeed_adc_engine_ops = {
|
||||
.read = aspeed_adc_engine_read,
|
||||
.write = aspeed_adc_engine_write,
|
||||
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||
.valid = {
|
||||
.min_access_size = 2,
|
||||
.max_access_size = 4,
|
||||
.unaligned = false,
|
||||
},
|
||||
};
|
||||
|
||||
static const uint32_t aspeed_adc_resets[ASPEED_ADC_NR_REGS] = {
|
||||
[ENGINE_CONTROL] = 0x00000000,
|
||||
[INTERRUPT_CONTROL] = 0x00000000,
|
||||
[VGA_DETECT_CONTROL] = 0x0000000f,
|
||||
[CLOCK_CONTROL] = 0x0000000f,
|
||||
};
|
||||
|
||||
static void aspeed_adc_engine_reset(DeviceState *dev)
|
||||
{
|
||||
AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
|
||||
|
||||
memcpy(s->regs, aspeed_adc_resets, sizeof(aspeed_adc_resets));
|
||||
}
|
||||
|
||||
static void aspeed_adc_engine_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
AspeedADCEngineState *s = ASPEED_ADC_ENGINE(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
g_autofree char *name = g_strdup_printf(TYPE_ASPEED_ADC_ENGINE ".%d",
|
||||
s->engine_id);
|
||||
|
||||
assert(s->engine_id < 2);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
memory_region_init_io(&s->mmio, OBJECT(s), &aspeed_adc_engine_ops, s, name,
|
||||
ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_aspeed_adc_engine = {
|
||||
.name = TYPE_ASPEED_ADC,
|
||||
.version_id = 1,
|
||||
.minimum_version_id = 1,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_UINT32_ARRAY(regs, AspeedADCEngineState, ASPEED_ADC_NR_REGS),
|
||||
VMSTATE_END_OF_LIST(),
|
||||
}
|
||||
};
|
||||
|
||||
static Property aspeed_adc_engine_properties[] = {
|
||||
DEFINE_PROP_UINT32("engine-id", AspeedADCEngineState, engine_id, 0),
|
||||
DEFINE_PROP_UINT32("nr-channels", AspeedADCEngineState, nr_channels, 0),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void aspeed_adc_engine_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->realize = aspeed_adc_engine_realize;
|
||||
dc->reset = aspeed_adc_engine_reset;
|
||||
device_class_set_props(dc, aspeed_adc_engine_properties);
|
||||
dc->desc = "Aspeed Analog-to-Digital Engine";
|
||||
dc->vmsd = &vmstate_aspeed_adc_engine;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_adc_engine_info = {
|
||||
.name = TYPE_ASPEED_ADC_ENGINE,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AspeedADCEngineState),
|
||||
.class_init = aspeed_adc_engine_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_adc_instance_init(Object *obj)
|
||||
{
|
||||
AspeedADCState *s = ASPEED_ADC(obj);
|
||||
AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(obj);
|
||||
uint32_t nr_channels = ASPEED_ADC_NR_CHANNELS / aac->nr_engines;
|
||||
|
||||
for (int i = 0; i < aac->nr_engines; i++) {
|
||||
AspeedADCEngineState *engine = &s->engines[i];
|
||||
object_initialize_child(obj, "engine[*]", engine,
|
||||
TYPE_ASPEED_ADC_ENGINE);
|
||||
qdev_prop_set_uint32(DEVICE(engine), "engine-id", i);
|
||||
qdev_prop_set_uint32(DEVICE(engine), "nr-channels", nr_channels);
|
||||
}
|
||||
}
|
||||
|
||||
static void aspeed_adc_set_irq(void *opaque, int n, int level)
|
||||
{
|
||||
AspeedADCState *s = opaque;
|
||||
AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(s);
|
||||
uint32_t pending = 0;
|
||||
|
||||
/* TODO: update Global IRQ status register on AST2600 (Need specs) */
|
||||
for (int i = 0; i < aac->nr_engines; i++) {
|
||||
uint32_t irq_status = s->engines[i].regs[INTERRUPT_CONTROL] & 0xFF;
|
||||
pending |= irq_status << (i * 8);
|
||||
}
|
||||
|
||||
qemu_set_irq(s->irq, !!pending);
|
||||
}
|
||||
|
||||
static void aspeed_adc_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
AspeedADCState *s = ASPEED_ADC(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
AspeedADCClass *aac = ASPEED_ADC_GET_CLASS(dev);
|
||||
|
||||
qdev_init_gpio_in_named_with_opaque(DEVICE(sbd), aspeed_adc_set_irq,
|
||||
s, NULL, aac->nr_engines);
|
||||
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
memory_region_init(&s->mmio, OBJECT(s), TYPE_ASPEED_ADC,
|
||||
ASPEED_ADC_MEMORY_REGION_SIZE);
|
||||
|
||||
sysbus_init_mmio(sbd, &s->mmio);
|
||||
|
||||
for (int i = 0; i < aac->nr_engines; i++) {
|
||||
Object *eng = OBJECT(&s->engines[i]);
|
||||
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(eng), errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(eng), 0,
|
||||
qdev_get_gpio_in(DEVICE(sbd), i));
|
||||
memory_region_add_subregion(&s->mmio,
|
||||
i * ASPEED_ADC_ENGINE_MEMORY_REGION_SIZE,
|
||||
&s->engines[i].mmio);
|
||||
}
|
||||
}
|
||||
|
||||
static void aspeed_adc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
|
||||
|
||||
dc->realize = aspeed_adc_realize;
|
||||
dc->desc = "Aspeed Analog-to-Digital Converter";
|
||||
aac->nr_engines = 1;
|
||||
}
|
||||
|
||||
static void aspeed_2600_adc_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
AspeedADCClass *aac = ASPEED_ADC_CLASS(klass);
|
||||
|
||||
dc->desc = "ASPEED 2600 ADC Controller";
|
||||
aac->nr_engines = 2;
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_adc_info = {
|
||||
.name = TYPE_ASPEED_ADC,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_init = aspeed_adc_instance_init,
|
||||
.instance_size = sizeof(AspeedADCState),
|
||||
.class_init = aspeed_adc_class_init,
|
||||
.class_size = sizeof(AspeedADCClass),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static const TypeInfo aspeed_2400_adc_info = {
|
||||
.name = TYPE_ASPEED_2400_ADC,
|
||||
.parent = TYPE_ASPEED_ADC,
|
||||
};
|
||||
|
||||
static const TypeInfo aspeed_2500_adc_info = {
|
||||
.name = TYPE_ASPEED_2500_ADC,
|
||||
.parent = TYPE_ASPEED_ADC,
|
||||
};
|
||||
|
||||
static const TypeInfo aspeed_2600_adc_info = {
|
||||
.name = TYPE_ASPEED_2600_ADC,
|
||||
.parent = TYPE_ASPEED_ADC,
|
||||
.class_init = aspeed_2600_adc_class_init,
|
||||
};
|
||||
|
||||
static void aspeed_adc_register_types(void)
|
||||
{
|
||||
type_register_static(&aspeed_adc_engine_info);
|
||||
type_register_static(&aspeed_adc_info);
|
||||
type_register_static(&aspeed_2400_adc_info);
|
||||
type_register_static(&aspeed_2500_adc_info);
|
||||
type_register_static(&aspeed_2600_adc_info);
|
||||
}
|
||||
|
||||
type_init(aspeed_adc_register_types);
|
|
@ -1,4 +1,5 @@
|
|||
softmmu_ss.add(when: 'CONFIG_STM32F2XX_ADC', if_true: files('stm32f2xx_adc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ASPEED_SOC', if_true: files('aspeed_adc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_NPCM7XX', if_true: files('npcm7xx_adc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_ZYNQ', if_true: files('zynq-xadc.c'))
|
||||
softmmu_ss.add(when: 'CONFIG_MAX111X', if_true: files('max111x.c'))
|
||||
|
|
|
@ -3,3 +3,6 @@
|
|||
# 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
|
||||
|
||||
aspeed_adc_engine_read(uint32_t engine_id, uint64_t addr, uint64_t value) "engine[%u] 0x%" PRIx64 " 0x%" PRIx64
|
||||
aspeed_adc_engine_write(uint32_t engine_id, uint64_t addr, uint64_t value) "engine[%u] 0x%" PRIx64 " 0x%" PRIx64
|
||||
|
|
|
@ -274,18 +274,17 @@ static void aspeed_board_init_flashes(AspeedSMCState *s,
|
|||
int i ;
|
||||
|
||||
for (i = 0; i < s->num_cs; ++i) {
|
||||
AspeedSMCFlash *fl = &s->flashes[i];
|
||||
DriveInfo *dinfo = drive_get_next(IF_MTD);
|
||||
qemu_irq cs_line;
|
||||
DeviceState *dev;
|
||||
|
||||
fl->flash = qdev_new(flashtype);
|
||||
dev = qdev_new(flashtype);
|
||||
if (dinfo) {
|
||||
qdev_prop_set_drive(fl->flash, "drive",
|
||||
blk_by_legacy_dinfo(dinfo));
|
||||
qdev_prop_set_drive(dev, "drive", blk_by_legacy_dinfo(dinfo));
|
||||
}
|
||||
qdev_realize_and_unref(fl->flash, BUS(s->spi), &error_fatal);
|
||||
qdev_realize_and_unref(dev, BUS(s->spi), &error_fatal);
|
||||
|
||||
cs_line = qdev_get_gpio_in_named(fl->flash, SSI_GPIO_CS, 0);
|
||||
cs_line = qdev_get_gpio_in_named(dev, SSI_GPIO_CS, 0);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(s), i + 1, cs_line);
|
||||
}
|
||||
}
|
||||
|
@ -377,6 +376,7 @@ static void aspeed_machine_init(MachineState *machine)
|
|||
if (drive0) {
|
||||
AspeedSMCFlash *fl = &bmc->soc.fmc.flashes[0];
|
||||
MemoryRegion *boot_rom = g_new(MemoryRegion, 1);
|
||||
uint64_t size = memory_region_size(&fl->mmio);
|
||||
|
||||
/*
|
||||
* create a ROM region using the default mapping window size of
|
||||
|
@ -386,15 +386,15 @@ static void aspeed_machine_init(MachineState *machine)
|
|||
*/
|
||||
if (ASPEED_MACHINE(machine)->mmio_exec) {
|
||||
memory_region_init_alias(boot_rom, NULL, "aspeed.boot_rom",
|
||||
&fl->mmio, 0, fl->size);
|
||||
&fl->mmio, 0, size);
|
||||
memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR,
|
||||
boot_rom);
|
||||
} else {
|
||||
memory_region_init_rom(boot_rom, NULL, "aspeed.boot_rom",
|
||||
fl->size, &error_abort);
|
||||
size, &error_abort);
|
||||
memory_region_add_subregion(get_system_memory(), FIRMWARE_ADDR,
|
||||
boot_rom);
|
||||
write_boot_rom(drive0, FIRMWARE_ADDR, fl->size, &error_abort);
|
||||
write_boot_rom(drive0, FIRMWARE_ADDR, size, &error_abort);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -148,6 +148,9 @@ static void aspeed_soc_ast2600_init(Object *obj)
|
|||
snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
|
||||
object_initialize_child(obj, "timerctrl", &s->timerctrl, typename);
|
||||
|
||||
snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
|
||||
object_initialize_child(obj, "adc", &s->adc, typename);
|
||||
|
||||
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
|
||||
object_initialize_child(obj, "i2c", &s->i2c, typename);
|
||||
|
||||
|
@ -322,6 +325,14 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
|
||||
}
|
||||
|
||||
/* ADC */
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
|
||||
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
|
||||
|
||||
/* UART - attach an 8250 to the IO space as our UART */
|
||||
serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2,
|
||||
aspeed_soc_get_irq(s, s->uart_default), 38400,
|
||||
|
@ -337,11 +348,8 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
|||
for (i = 0; i < ASPEED_I2C_GET_CLASS(&s->i2c)->num_busses; i++) {
|
||||
qemu_irq irq = qdev_get_gpio_in(DEVICE(&s->a7mpcore),
|
||||
sc->irqmap[ASPEED_DEV_I2C] + i);
|
||||
/*
|
||||
* The AST2600 SoC has one IRQ per I2C bus. Skip the common
|
||||
* IRQ (AST2400 and AST2500) and connect all bussses.
|
||||
*/
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c), i + 1, irq);
|
||||
/* The AST2600 I2C controller has one IRQ per bus. */
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->i2c.busses[i]), 0, irq);
|
||||
}
|
||||
|
||||
/* FMC, The number of CS is set at the board level */
|
||||
|
@ -352,7 +360,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
|
||||
s->fmc.ctrl->flash_window_base);
|
||||
ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
|
||||
aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
|
||||
|
||||
|
@ -367,7 +375,7 @@ static void aspeed_soc_ast2600_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
|
||||
sc->memmap[ASPEED_DEV_SPI1 + i]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
|
||||
s->spi[i].ctrl->flash_window_base);
|
||||
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
|
||||
}
|
||||
|
||||
/* EHCI */
|
||||
|
|
|
@ -162,6 +162,9 @@ static void aspeed_soc_init(Object *obj)
|
|||
snprintf(typename, sizeof(typename), "aspeed.timer-%s", socname);
|
||||
object_initialize_child(obj, "timerctrl", &s->timerctrl, typename);
|
||||
|
||||
snprintf(typename, sizeof(typename), "aspeed.adc-%s", socname);
|
||||
object_initialize_child(obj, "adc", &s->adc, typename);
|
||||
|
||||
snprintf(typename, sizeof(typename), "aspeed.i2c-%s", socname);
|
||||
object_initialize_child(obj, "i2c", &s->i2c, typename);
|
||||
|
||||
|
@ -287,6 +290,14 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->timerctrl), i, irq);
|
||||
}
|
||||
|
||||
/* ADC */
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(&s->adc), errp)) {
|
||||
return;
|
||||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->adc), 0, sc->memmap[ASPEED_DEV_ADC]);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->adc), 0,
|
||||
aspeed_soc_get_irq(s, ASPEED_DEV_ADC));
|
||||
|
||||
/* UART - attach an 8250 to the IO space as our UART */
|
||||
serial_mm_init(get_system_memory(), sc->memmap[s->uart_default], 2,
|
||||
aspeed_soc_get_irq(s, s->uart_default), 38400,
|
||||
|
@ -310,7 +321,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
}
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 0, sc->memmap[ASPEED_DEV_FMC]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->fmc), 1,
|
||||
s->fmc.ctrl->flash_window_base);
|
||||
ASPEED_SMC_GET_CLASS(&s->fmc)->flash_window_base);
|
||||
sysbus_connect_irq(SYS_BUS_DEVICE(&s->fmc), 0,
|
||||
aspeed_soc_get_irq(s, ASPEED_DEV_FMC));
|
||||
|
||||
|
@ -323,7 +334,7 @@ static void aspeed_soc_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 0,
|
||||
sc->memmap[ASPEED_DEV_SPI1 + i]);
|
||||
sysbus_mmio_map(SYS_BUS_DEVICE(&s->spi[i]), 1,
|
||||
s->spi[i].ctrl->flash_window_base);
|
||||
ASPEED_SMC_GET_CLASS(&s->spi[i])->flash_window_base);
|
||||
}
|
||||
|
||||
/* EHCI */
|
||||
|
|
|
@ -16,11 +16,7 @@
|
|||
#include "hw/irq.h"
|
||||
#include "migration/vmstate.h"
|
||||
|
||||
#define GPIOS_PER_REG 32
|
||||
#define GPIOS_PER_SET GPIOS_PER_REG
|
||||
#define GPIO_PIN_GAP_SIZE 4
|
||||
#define GPIOS_PER_GROUP 8
|
||||
#define GPIO_GROUP_SHIFT 3
|
||||
|
||||
/* GPIO Source Types */
|
||||
#define ASPEED_CMD_SRC_MASK 0x01010101
|
||||
|
@ -259,7 +255,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
|
|||
|
||||
diff = old ^ new;
|
||||
if (diff) {
|
||||
for (gpio = 0; gpio < GPIOS_PER_REG; gpio++) {
|
||||
for (gpio = 0; gpio < ASPEED_GPIOS_PER_SET; gpio++) {
|
||||
uint32_t mask = 1 << gpio;
|
||||
|
||||
/* If the gpio needs to be updated... */
|
||||
|
@ -283,8 +279,7 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
|
|||
if (direction & mask) {
|
||||
/* ...trigger the line-state IRQ */
|
||||
ptrdiff_t set = aspeed_gpio_set_idx(s, regs);
|
||||
size_t offset = set * GPIOS_PER_SET + gpio;
|
||||
qemu_set_irq(s->gpios[offset], !!(new & mask));
|
||||
qemu_set_irq(s->gpios[set][gpio], !!(new & mask));
|
||||
} else {
|
||||
/* ...otherwise if we meet the line's current IRQ policy... */
|
||||
if (aspeed_evaluate_irq(regs, old & mask, gpio)) {
|
||||
|
@ -297,21 +292,6 @@ static void aspeed_gpio_update(AspeedGPIOState *s, GPIOSets *regs,
|
|||
qemu_set_irq(s->irq, !!(s->pending));
|
||||
}
|
||||
|
||||
static uint32_t aspeed_adjust_pin(AspeedGPIOState *s, uint32_t pin)
|
||||
{
|
||||
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
|
||||
/*
|
||||
* The 2500 has a 4 pin gap in group AB and the 2400 has a 4 pin
|
||||
* gap in group Y (and only four pins in AB but this is the last group so
|
||||
* it doesn't matter).
|
||||
*/
|
||||
if (agc->gap && pin >= agc->gap) {
|
||||
pin += GPIO_PIN_GAP_SIZE;
|
||||
}
|
||||
|
||||
return pin;
|
||||
}
|
||||
|
||||
static bool aspeed_gpio_get_pin_level(AspeedGPIOState *s, uint32_t set_idx,
|
||||
uint32_t pin)
|
||||
{
|
||||
|
@ -367,7 +347,7 @@ static uint32_t update_value_control_source(GPIOSets *regs, uint32_t old_value,
|
|||
uint32_t new_value = 0;
|
||||
|
||||
/* for each group in set */
|
||||
for (i = 0; i < GPIOS_PER_REG; i += GPIOS_PER_GROUP) {
|
||||
for (i = 0; i < ASPEED_GPIOS_PER_SET; i += GPIOS_PER_GROUP) {
|
||||
cmd_source = extract32(regs->cmd_source_0, i, 1)
|
||||
| (extract32(regs->cmd_source_1, i, 1) << 1);
|
||||
|
||||
|
@ -637,7 +617,7 @@ static void aspeed_gpio_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
* bidirectional | 1 | 1 | data
|
||||
* input only | 1 | 0 | 0
|
||||
* output only | 0 | 1 | 1
|
||||
* no pin / gap | 0 | 0 | 0
|
||||
* no pin | 0 | 0 | 0
|
||||
*
|
||||
* which is captured by:
|
||||
* data = ( data | ~input) & output;
|
||||
|
@ -779,7 +759,7 @@ static void aspeed_gpio_set_pin(Object *obj, Visitor *v, const char *name,
|
|||
}
|
||||
|
||||
/****************** Setup functions ******************/
|
||||
static const GPIOSetProperties ast2400_set_props[] = {
|
||||
static const GPIOSetProperties ast2400_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
|
||||
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
|
||||
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
|
||||
[2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
|
||||
|
@ -789,28 +769,28 @@ static const GPIOSetProperties ast2400_set_props[] = {
|
|||
[6] = {0x0000000f, 0x0fffff0f, {"Y", "Z", "AA", "AB"} },
|
||||
};
|
||||
|
||||
static const GPIOSetProperties ast2500_set_props[] = {
|
||||
static const GPIOSetProperties ast2500_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
|
||||
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
|
||||
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
|
||||
[2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
|
||||
[3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} },
|
||||
[4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} },
|
||||
[5] = {0xffffffff, 0x0000ffff, {"U", "V", "W", "X"} },
|
||||
[6] = {0xffffff0f, 0x0fffff0f, {"Y", "Z", "AA", "AB"} },
|
||||
[6] = {0x0fffffff, 0x0fffffff, {"Y", "Z", "AA", "AB"} },
|
||||
[7] = {0x000000ff, 0x000000ff, {"AC"} },
|
||||
};
|
||||
|
||||
static GPIOSetProperties ast2600_3_3v_set_props[] = {
|
||||
static GPIOSetProperties ast2600_3_3v_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
|
||||
[0] = {0xffffffff, 0xffffffff, {"A", "B", "C", "D"} },
|
||||
[1] = {0xffffffff, 0xffffffff, {"E", "F", "G", "H"} },
|
||||
[2] = {0xffffffff, 0xffffffff, {"I", "J", "K", "L"} },
|
||||
[3] = {0xffffffff, 0xffffffff, {"M", "N", "O", "P"} },
|
||||
[4] = {0xffffffff, 0xffffffff, {"Q", "R", "S", "T"} },
|
||||
[5] = {0xffffffff, 0x0000ffff, {"U", "V", "W", "X"} },
|
||||
[6] = {0xffff0000, 0x0fff0000, {"Y", "Z", "", ""} },
|
||||
[4] = {0xffffffff, 0x00ffffff, {"Q", "R", "S", "T"} },
|
||||
[5] = {0xffffffff, 0xffffff00, {"U", "V", "W", "X"} },
|
||||
[6] = {0x0000ffff, 0x0000ffff, {"Y", "Z"} },
|
||||
};
|
||||
|
||||
static GPIOSetProperties ast2600_1_8v_set_props[] = {
|
||||
static GPIOSetProperties ast2600_1_8v_set_props[ASPEED_GPIO_MAX_NR_SETS] = {
|
||||
[0] = {0xffffffff, 0xffffffff, {"18A", "18B", "18C", "18D"} },
|
||||
[1] = {0x0000000f, 0x0000000f, {"18E"} },
|
||||
};
|
||||
|
@ -836,14 +816,20 @@ static void aspeed_gpio_realize(DeviceState *dev, Error **errp)
|
|||
AspeedGPIOState *s = ASPEED_GPIO(dev);
|
||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
|
||||
int pin;
|
||||
|
||||
/* Interrupt parent line */
|
||||
sysbus_init_irq(sbd, &s->irq);
|
||||
|
||||
/* Individual GPIOs */
|
||||
for (pin = 0; pin < agc->nr_gpio_pins; pin++) {
|
||||
sysbus_init_irq(sbd, &s->gpios[pin]);
|
||||
for (int i = 0; i < ASPEED_GPIO_MAX_NR_SETS; i++) {
|
||||
const GPIOSetProperties *props = &agc->props[i];
|
||||
uint32_t skip = ~(props->input | props->output);
|
||||
for (int j = 0; j < ASPEED_GPIOS_PER_SET; j++) {
|
||||
if (skip >> j & 1) {
|
||||
continue;
|
||||
}
|
||||
sysbus_init_irq(sbd, &s->gpios[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_gpio_ops, s,
|
||||
|
@ -856,20 +842,22 @@ static void aspeed_gpio_init(Object *obj)
|
|||
{
|
||||
AspeedGPIOState *s = ASPEED_GPIO(obj);
|
||||
AspeedGPIOClass *agc = ASPEED_GPIO_GET_CLASS(s);
|
||||
int pin;
|
||||
|
||||
for (pin = 0; pin < agc->nr_gpio_pins; pin++) {
|
||||
char *name;
|
||||
int set_idx = pin / GPIOS_PER_SET;
|
||||
int pin_idx = aspeed_adjust_pin(s, pin) - (set_idx * GPIOS_PER_SET);
|
||||
int group_idx = pin_idx >> GPIO_GROUP_SHIFT;
|
||||
const GPIOSetProperties *props = &agc->props[set_idx];
|
||||
|
||||
name = g_strdup_printf("gpio%s%d", props->group_label[group_idx],
|
||||
pin_idx % GPIOS_PER_GROUP);
|
||||
object_property_add(obj, name, "bool", aspeed_gpio_get_pin,
|
||||
aspeed_gpio_set_pin, NULL, NULL);
|
||||
g_free(name);
|
||||
for (int i = 0; i < ASPEED_GPIO_MAX_NR_SETS; i++) {
|
||||
const GPIOSetProperties *props = &agc->props[i];
|
||||
uint32_t skip = ~(props->input | props->output);
|
||||
for (int j = 0; j < ASPEED_GPIOS_PER_SET; j++) {
|
||||
if (skip >> j & 1) {
|
||||
continue;
|
||||
}
|
||||
int group_idx = j / GPIOS_PER_GROUP;
|
||||
int pin_idx = j % GPIOS_PER_GROUP;
|
||||
const char *group = &props->group_label[group_idx][0];
|
||||
char *name = g_strdup_printf("gpio%s%d", group, pin_idx);
|
||||
object_property_add(obj, name, "bool", aspeed_gpio_get_pin,
|
||||
aspeed_gpio_set_pin, NULL, NULL);
|
||||
g_free(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -926,7 +914,6 @@ static void aspeed_gpio_ast2400_class_init(ObjectClass *klass, void *data)
|
|||
agc->props = ast2400_set_props;
|
||||
agc->nr_gpio_pins = 216;
|
||||
agc->nr_gpio_sets = 7;
|
||||
agc->gap = 196;
|
||||
agc->reg_table = aspeed_3_3v_gpios;
|
||||
}
|
||||
|
||||
|
@ -937,7 +924,6 @@ static void aspeed_gpio_2500_class_init(ObjectClass *klass, void *data)
|
|||
agc->props = ast2500_set_props;
|
||||
agc->nr_gpio_pins = 228;
|
||||
agc->nr_gpio_sets = 8;
|
||||
agc->gap = 220;
|
||||
agc->reg_table = aspeed_3_3v_gpios;
|
||||
}
|
||||
|
||||
|
|
|
@ -740,20 +740,20 @@ static const VMStateDescription aspeed_i2c_vmstate = {
|
|||
|
||||
static void aspeed_i2c_reset(DeviceState *dev)
|
||||
{
|
||||
int i;
|
||||
AspeedI2CState *s = ASPEED_I2C(dev);
|
||||
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
|
||||
|
||||
s->intr_status = 0;
|
||||
}
|
||||
|
||||
static void aspeed_i2c_instance_init(Object *obj)
|
||||
{
|
||||
AspeedI2CState *s = ASPEED_I2C(obj);
|
||||
AspeedI2CClass *aic = ASPEED_I2C_GET_CLASS(s);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < aic->num_busses; i++) {
|
||||
s->busses[i].intr_ctrl = 0;
|
||||
s->busses[i].intr_status = 0;
|
||||
s->busses[i].cmd = 0;
|
||||
s->busses[i].buf = 0;
|
||||
s->busses[i].dma_addr = 0;
|
||||
s->busses[i].dma_len = 0;
|
||||
i2c_end_transfer(s->busses[i].bus);
|
||||
object_initialize_child(obj, "bus[*]", &s->busses[i],
|
||||
TYPE_ASPEED_I2C_BUS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -791,17 +791,21 @@ static void aspeed_i2c_realize(DeviceState *dev, Error **errp)
|
|||
sysbus_init_mmio(sbd, &s->iomem);
|
||||
|
||||
for (i = 0; i < aic->num_busses; i++) {
|
||||
char name[32];
|
||||
Object *bus = OBJECT(&s->busses[i]);
|
||||
int offset = i < aic->gap ? 1 : 5;
|
||||
|
||||
sysbus_init_irq(sbd, &s->busses[i].irq);
|
||||
snprintf(name, sizeof(name), "aspeed.i2c.%d", i);
|
||||
s->busses[i].controller = s;
|
||||
s->busses[i].id = i;
|
||||
s->busses[i].bus = i2c_init_bus(dev, name);
|
||||
memory_region_init_io(&s->busses[i].mr, OBJECT(dev),
|
||||
&aspeed_i2c_bus_ops, &s->busses[i], name,
|
||||
aic->reg_size);
|
||||
if (!object_property_set_link(bus, "controller", OBJECT(s), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!object_property_set_uint(bus, "bus-id", i, errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!sysbus_realize(SYS_BUS_DEVICE(bus), errp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memory_region_add_subregion(&s->iomem, aic->reg_size * (i + offset),
|
||||
&s->busses[i].mr);
|
||||
}
|
||||
|
@ -841,12 +845,72 @@ static void aspeed_i2c_class_init(ObjectClass *klass, void *data)
|
|||
static const TypeInfo aspeed_i2c_info = {
|
||||
.name = TYPE_ASPEED_I2C,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_init = aspeed_i2c_instance_init,
|
||||
.instance_size = sizeof(AspeedI2CState),
|
||||
.class_init = aspeed_i2c_class_init,
|
||||
.class_size = sizeof(AspeedI2CClass),
|
||||
.abstract = true,
|
||||
};
|
||||
|
||||
static void aspeed_i2c_bus_reset(DeviceState *dev)
|
||||
{
|
||||
AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
|
||||
|
||||
s->intr_ctrl = 0;
|
||||
s->intr_status = 0;
|
||||
s->cmd = 0;
|
||||
s->buf = 0;
|
||||
s->dma_addr = 0;
|
||||
s->dma_len = 0;
|
||||
i2c_end_transfer(s->bus);
|
||||
}
|
||||
|
||||
static void aspeed_i2c_bus_realize(DeviceState *dev, Error **errp)
|
||||
{
|
||||
AspeedI2CBus *s = ASPEED_I2C_BUS(dev);
|
||||
AspeedI2CClass *aic;
|
||||
g_autofree char *name = g_strdup_printf(TYPE_ASPEED_I2C_BUS ".%d", s->id);
|
||||
|
||||
if (!s->controller) {
|
||||
error_setg(errp, TYPE_ASPEED_I2C_BUS ": 'controller' link not set");
|
||||
return;
|
||||
}
|
||||
|
||||
aic = ASPEED_I2C_GET_CLASS(s->controller);
|
||||
|
||||
sysbus_init_irq(SYS_BUS_DEVICE(dev), &s->irq);
|
||||
|
||||
s->bus = i2c_init_bus(dev, name);
|
||||
|
||||
memory_region_init_io(&s->mr, OBJECT(s), &aspeed_i2c_bus_ops,
|
||||
s, name, aic->reg_size);
|
||||
sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->mr);
|
||||
}
|
||||
|
||||
static Property aspeed_i2c_bus_properties[] = {
|
||||
DEFINE_PROP_UINT8("bus-id", AspeedI2CBus, id, 0),
|
||||
DEFINE_PROP_LINK("controller", AspeedI2CBus, controller, TYPE_ASPEED_I2C,
|
||||
AspeedI2CState *),
|
||||
DEFINE_PROP_END_OF_LIST(),
|
||||
};
|
||||
|
||||
static void aspeed_i2c_bus_class_init(ObjectClass *klass, void *data)
|
||||
{
|
||||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
|
||||
dc->desc = "Aspeed I2C Bus";
|
||||
dc->realize = aspeed_i2c_bus_realize;
|
||||
dc->reset = aspeed_i2c_bus_reset;
|
||||
device_class_set_props(dc, aspeed_i2c_bus_properties);
|
||||
}
|
||||
|
||||
static const TypeInfo aspeed_i2c_bus_info = {
|
||||
.name = TYPE_ASPEED_I2C_BUS,
|
||||
.parent = TYPE_SYS_BUS_DEVICE,
|
||||
.instance_size = sizeof(AspeedI2CBus),
|
||||
.class_init = aspeed_i2c_bus_class_init,
|
||||
};
|
||||
|
||||
static qemu_irq aspeed_2400_i2c_bus_get_irq(AspeedI2CBus *bus)
|
||||
{
|
||||
return bus->controller->irq;
|
||||
|
@ -951,6 +1015,7 @@ static const TypeInfo aspeed_2600_i2c_info = {
|
|||
|
||||
static void aspeed_i2c_register_types(void)
|
||||
{
|
||||
type_register_static(&aspeed_i2c_bus_info);
|
||||
type_register_static(&aspeed_i2c_info);
|
||||
type_register_static(&aspeed_2400_i2c_info);
|
||||
type_register_static(&aspeed_2500_i2c_info);
|
||||
|
|
1134
hw/ssi/aspeed_smc.c
1134
hw/ssi/aspeed_smc.c
File diff suppressed because it is too large
Load Diff
|
@ -5,3 +5,7 @@ cmsdk_apb_watchdog_read(uint64_t offset, uint64_t data, unsigned size) "CMSDK AP
|
|||
cmsdk_apb_watchdog_write(uint64_t offset, uint64_t data, unsigned size) "CMSDK APB watchdog write: offset 0x%" PRIx64 " data 0x%" PRIx64 " size %u"
|
||||
cmsdk_apb_watchdog_reset(void) "CMSDK APB watchdog: reset"
|
||||
cmsdk_apb_watchdog_lock(uint32_t lock) "CMSDK APB watchdog: lock %" PRIu32
|
||||
|
||||
# wdt-aspeed.c
|
||||
aspeed_wdt_read(uint64_t addr, uint32_t size) "@0x%" PRIx64 " size=%d"
|
||||
aspeed_wdt_write(uint64_t addr, uint32_t size, uint64_t data) "@0x%" PRIx64 " size=%d value=0x%"PRIx64
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "hw/sysbus.h"
|
||||
#include "hw/watchdog/wdt_aspeed.h"
|
||||
#include "migration/vmstate.h"
|
||||
#include "trace.h"
|
||||
|
||||
#define WDT_STATUS (0x00 / 4)
|
||||
#define WDT_RELOAD_VALUE (0x04 / 4)
|
||||
|
@ -60,6 +61,8 @@ static uint64_t aspeed_wdt_read(void *opaque, hwaddr offset, unsigned size)
|
|||
{
|
||||
AspeedWDTState *s = ASPEED_WDT(opaque);
|
||||
|
||||
trace_aspeed_wdt_read(offset, size);
|
||||
|
||||
offset >>= 2;
|
||||
|
||||
switch (offset) {
|
||||
|
@ -140,6 +143,8 @@ static void aspeed_wdt_write(void *opaque, hwaddr offset, uint64_t data,
|
|||
AspeedWDTClass *awc = ASPEED_WDT_GET_CLASS(s);
|
||||
bool enable;
|
||||
|
||||
trace_aspeed_wdt_write(offset, size, data);
|
||||
|
||||
offset >>= 2;
|
||||
|
||||
switch (offset) {
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Aspeed ADC
|
||||
*
|
||||
* Copyright 2017-2021 IBM Corp.
|
||||
*
|
||||
* Andrew Jeffery <andrew@aj.id.au>
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#ifndef HW_ADC_ASPEED_ADC_H
|
||||
#define HW_ADC_ASPEED_ADC_H
|
||||
|
||||
#include "hw/sysbus.h"
|
||||
|
||||
#define TYPE_ASPEED_ADC "aspeed.adc"
|
||||
#define TYPE_ASPEED_2400_ADC TYPE_ASPEED_ADC "-ast2400"
|
||||
#define TYPE_ASPEED_2500_ADC TYPE_ASPEED_ADC "-ast2500"
|
||||
#define TYPE_ASPEED_2600_ADC TYPE_ASPEED_ADC "-ast2600"
|
||||
OBJECT_DECLARE_TYPE(AspeedADCState, AspeedADCClass, ASPEED_ADC)
|
||||
|
||||
#define TYPE_ASPEED_ADC_ENGINE "aspeed.adc.engine"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(AspeedADCEngineState, ASPEED_ADC_ENGINE)
|
||||
|
||||
#define ASPEED_ADC_NR_CHANNELS 16
|
||||
#define ASPEED_ADC_NR_REGS (0xD0 >> 2)
|
||||
|
||||
struct AspeedADCEngineState {
|
||||
/* <private> */
|
||||
SysBusDevice parent;
|
||||
|
||||
MemoryRegion mmio;
|
||||
qemu_irq irq;
|
||||
uint32_t engine_id;
|
||||
uint32_t nr_channels;
|
||||
uint32_t regs[ASPEED_ADC_NR_REGS];
|
||||
};
|
||||
|
||||
struct AspeedADCState {
|
||||
/* <private> */
|
||||
SysBusDevice parent;
|
||||
|
||||
MemoryRegion mmio;
|
||||
qemu_irq irq;
|
||||
|
||||
AspeedADCEngineState engines[2];
|
||||
};
|
||||
|
||||
struct AspeedADCClass {
|
||||
SysBusDeviceClass parent_class;
|
||||
|
||||
uint32_t nr_engines;
|
||||
};
|
||||
|
||||
#endif /* HW_ADC_ASPEED_ADC_H */
|
|
@ -15,6 +15,7 @@
|
|||
#include "hw/cpu/a15mpcore.h"
|
||||
#include "hw/intc/aspeed_vic.h"
|
||||
#include "hw/misc/aspeed_scu.h"
|
||||
#include "hw/adc/aspeed_adc.h"
|
||||
#include "hw/misc/aspeed_sdmc.h"
|
||||
#include "hw/misc/aspeed_xdma.h"
|
||||
#include "hw/timer/aspeed_timer.h"
|
||||
|
@ -53,6 +54,7 @@ struct AspeedSoCState {
|
|||
AspeedSCUState scu;
|
||||
AspeedHACEState hace;
|
||||
AspeedXDMAState xdma;
|
||||
AspeedADCState adc;
|
||||
AspeedSMCState fmc;
|
||||
AspeedSMCState spi[ASPEED_SPIS_NUM];
|
||||
EHCISysBusState ehci[ASPEED_EHCIS_NUM];
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
OBJECT_DECLARE_TYPE(AspeedGPIOState, AspeedGPIOClass, ASPEED_GPIO)
|
||||
|
||||
#define ASPEED_GPIO_MAX_NR_SETS 8
|
||||
#define ASPEED_GPIOS_PER_SET 32
|
||||
#define ASPEED_REGS_PER_BANK 14
|
||||
#define ASPEED_GPIO_MAX_NR_REGS (ASPEED_REGS_PER_BANK * ASPEED_GPIO_MAX_NR_SETS)
|
||||
#define ASPEED_GPIO_NR_PINS 228
|
||||
#define ASPEED_GROUPS_PER_SET 4
|
||||
#define ASPEED_GPIO_NR_DEBOUNCE_REGS 3
|
||||
#define ASPEED_CHARS_PER_GROUP_LABEL 4
|
||||
|
@ -60,7 +60,6 @@ struct AspeedGPIOClass {
|
|||
const GPIOSetProperties *props;
|
||||
uint32_t nr_gpio_pins;
|
||||
uint32_t nr_gpio_sets;
|
||||
uint32_t gap;
|
||||
const AspeedGPIOReg *reg_table;
|
||||
};
|
||||
|
||||
|
@ -72,7 +71,7 @@ struct AspeedGPIOState {
|
|||
MemoryRegion iomem;
|
||||
int pending;
|
||||
qemu_irq irq;
|
||||
qemu_irq gpios[ASPEED_GPIO_NR_PINS];
|
||||
qemu_irq gpios[ASPEED_GPIO_MAX_NR_SETS][ASPEED_GPIOS_PER_SET];
|
||||
|
||||
/* Parallel GPIO Registers */
|
||||
uint32_t debounce_regs[ASPEED_GPIO_NR_DEBOUNCE_REGS];
|
||||
|
|
|
@ -36,7 +36,11 @@ OBJECT_DECLARE_TYPE(AspeedI2CState, AspeedI2CClass, ASPEED_I2C)
|
|||
|
||||
struct AspeedI2CState;
|
||||
|
||||
typedef struct AspeedI2CBus {
|
||||
#define TYPE_ASPEED_I2C_BUS "aspeed.i2c.bus"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(AspeedI2CBus, ASPEED_I2C_BUS)
|
||||
struct AspeedI2CBus {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
struct AspeedI2CState *controller;
|
||||
|
||||
MemoryRegion mr;
|
||||
|
@ -54,7 +58,7 @@ typedef struct AspeedI2CBus {
|
|||
uint32_t pool_ctrl;
|
||||
uint32_t dma_addr;
|
||||
uint32_t dma_len;
|
||||
} AspeedI2CBus;
|
||||
};
|
||||
|
||||
struct AspeedI2CState {
|
||||
SysBusDevice parent_obj;
|
||||
|
|
|
@ -29,66 +29,33 @@
|
|||
#include "hw/sysbus.h"
|
||||
#include "qom/object.h"
|
||||
|
||||
typedef struct AspeedSegments {
|
||||
hwaddr addr;
|
||||
uint32_t size;
|
||||
} AspeedSegments;
|
||||
|
||||
struct AspeedSMCState;
|
||||
typedef struct AspeedSMCController {
|
||||
const char *name;
|
||||
uint8_t r_conf;
|
||||
uint8_t r_ce_ctrl;
|
||||
uint8_t r_ctrl0;
|
||||
uint8_t r_timings;
|
||||
uint8_t nregs_timings;
|
||||
uint8_t conf_enable_w0;
|
||||
uint8_t max_peripherals;
|
||||
const AspeedSegments *segments;
|
||||
hwaddr flash_window_base;
|
||||
uint32_t flash_window_size;
|
||||
uint32_t features;
|
||||
hwaddr dma_flash_mask;
|
||||
hwaddr dma_dram_mask;
|
||||
uint32_t nregs;
|
||||
uint32_t (*segment_to_reg)(const struct AspeedSMCState *s,
|
||||
const AspeedSegments *seg);
|
||||
void (*reg_to_segment)(const struct AspeedSMCState *s, uint32_t reg,
|
||||
AspeedSegments *seg);
|
||||
void (*dma_ctrl)(struct AspeedSMCState *s, uint32_t value);
|
||||
} AspeedSMCController;
|
||||
|
||||
typedef struct AspeedSMCFlash {
|
||||
#define TYPE_ASPEED_SMC_FLASH "aspeed.smc.flash"
|
||||
OBJECT_DECLARE_SIMPLE_TYPE(AspeedSMCFlash, ASPEED_SMC_FLASH)
|
||||
struct AspeedSMCFlash {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
struct AspeedSMCState *controller;
|
||||
|
||||
uint8_t id;
|
||||
uint32_t size;
|
||||
uint8_t cs;
|
||||
|
||||
MemoryRegion mmio;
|
||||
DeviceState *flash;
|
||||
} AspeedSMCFlash;
|
||||
};
|
||||
|
||||
#define TYPE_ASPEED_SMC "aspeed.smc"
|
||||
OBJECT_DECLARE_TYPE(AspeedSMCState, AspeedSMCClass, ASPEED_SMC)
|
||||
|
||||
struct AspeedSMCClass {
|
||||
SysBusDevice parent_obj;
|
||||
const AspeedSMCController *ctrl;
|
||||
};
|
||||
|
||||
#define ASPEED_SMC_R_MAX (0x100 / 4)
|
||||
#define ASPEED_SMC_CS_MAX 5
|
||||
|
||||
struct AspeedSMCState {
|
||||
SysBusDevice parent_obj;
|
||||
|
||||
const AspeedSMCController *ctrl;
|
||||
|
||||
MemoryRegion mmio;
|
||||
MemoryRegion mmio_flash;
|
||||
MemoryRegion mmio_flash_alias;
|
||||
|
||||
qemu_irq irq;
|
||||
int irqline;
|
||||
|
||||
uint32_t num_cs;
|
||||
qemu_irq *cs_lines;
|
||||
|
@ -109,10 +76,41 @@ struct AspeedSMCState {
|
|||
MemoryRegion *dram_mr;
|
||||
AddressSpace dram_as;
|
||||
|
||||
AspeedSMCFlash *flashes;
|
||||
AspeedSMCFlash flashes[ASPEED_SMC_CS_MAX];
|
||||
|
||||
uint8_t snoop_index;
|
||||
uint8_t snoop_dummies;
|
||||
};
|
||||
|
||||
typedef struct AspeedSegments {
|
||||
hwaddr addr;
|
||||
uint32_t size;
|
||||
} AspeedSegments;
|
||||
|
||||
struct AspeedSMCClass {
|
||||
SysBusDeviceClass parent_obj;
|
||||
|
||||
uint8_t r_conf;
|
||||
uint8_t r_ce_ctrl;
|
||||
uint8_t r_ctrl0;
|
||||
uint8_t r_timings;
|
||||
uint8_t nregs_timings;
|
||||
uint8_t conf_enable_w0;
|
||||
uint8_t max_peripherals;
|
||||
const uint32_t *resets;
|
||||
const AspeedSegments *segments;
|
||||
hwaddr flash_window_base;
|
||||
uint32_t flash_window_size;
|
||||
uint32_t features;
|
||||
hwaddr dma_flash_mask;
|
||||
hwaddr dma_dram_mask;
|
||||
uint32_t nregs;
|
||||
uint32_t (*segment_to_reg)(const AspeedSMCState *s,
|
||||
const AspeedSegments *seg);
|
||||
void (*reg_to_segment)(const AspeedSMCState *s, uint32_t reg,
|
||||
AspeedSegments *seg);
|
||||
void (*dma_ctrl)(AspeedSMCState *s, uint32_t value);
|
||||
int (*addr_width)(const AspeedSMCState *s);
|
||||
};
|
||||
|
||||
#endif /* ASPEED_SMC_H */
|
||||
|
|
Loading…
Reference in New Issue