mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-04 08:13:54 -06:00
hw: aspeed_scu: Add AST2600 support
The SCU controller on the AST2600 SoC has extra registers. Increase the number of regs of the model and introduce a new field in the class to customize the MemoryRegion operations depending on the SoC model. Signed-off-by: Joel Stanley <joel@jms.id.au> Signed-off-by: Cédric Le Goater <clg@kaod.org> Message-id: 20190925143248.10000-4-clg@kaod.org [clg: - improved commit log - changed vmstate version - reworked model integration into new object class - included AST2600_HPLL_PARAM value ] Signed-off-by: Cédric Le Goater <clg@kaod.org> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
2bea128c3d
commit
e09cf36321
2 changed files with 191 additions and 8 deletions
|
@ -88,6 +88,35 @@
|
||||||
#define BMC_REV TO_REG(0x19C)
|
#define BMC_REV TO_REG(0x19C)
|
||||||
#define BMC_DEV_ID TO_REG(0x1A4)
|
#define BMC_DEV_ID TO_REG(0x1A4)
|
||||||
|
|
||||||
|
#define AST2600_PROT_KEY TO_REG(0x00)
|
||||||
|
#define AST2600_SILICON_REV TO_REG(0x04)
|
||||||
|
#define AST2600_SILICON_REV2 TO_REG(0x14)
|
||||||
|
#define AST2600_SYS_RST_CTRL TO_REG(0x40)
|
||||||
|
#define AST2600_SYS_RST_CTRL_CLR TO_REG(0x44)
|
||||||
|
#define AST2600_SYS_RST_CTRL2 TO_REG(0x50)
|
||||||
|
#define AST2600_SYS_RST_CTRL2_CLR TO_REG(0x54)
|
||||||
|
#define AST2600_CLK_STOP_CTRL TO_REG(0x80)
|
||||||
|
#define AST2600_CLK_STOP_CTRL_CLR TO_REG(0x84)
|
||||||
|
#define AST2600_CLK_STOP_CTRL2 TO_REG(0x90)
|
||||||
|
#define AST2600_CLK_STOP_CTR2L_CLR TO_REG(0x94)
|
||||||
|
#define AST2600_HPLL_PARAM TO_REG(0x200)
|
||||||
|
#define AST2600_HPLL_EXT TO_REG(0x204)
|
||||||
|
#define AST2600_MPLL_EXT TO_REG(0x224)
|
||||||
|
#define AST2600_EPLL_EXT TO_REG(0x244)
|
||||||
|
#define AST2600_CLK_SEL TO_REG(0x300)
|
||||||
|
#define AST2600_CLK_SEL2 TO_REG(0x304)
|
||||||
|
#define AST2600_CLK_SEL3 TO_REG(0x310)
|
||||||
|
#define AST2600_HW_STRAP1 TO_REG(0x500)
|
||||||
|
#define AST2600_HW_STRAP1_CLR TO_REG(0x504)
|
||||||
|
#define AST2600_HW_STRAP1_PROT TO_REG(0x508)
|
||||||
|
#define AST2600_HW_STRAP2 TO_REG(0x510)
|
||||||
|
#define AST2600_HW_STRAP2_CLR TO_REG(0x514)
|
||||||
|
#define AST2600_HW_STRAP2_PROT TO_REG(0x518)
|
||||||
|
#define AST2600_RNG_CTRL TO_REG(0x524)
|
||||||
|
#define AST2600_RNG_DATA TO_REG(0x540)
|
||||||
|
|
||||||
|
#define AST2600_CLK TO_REG(0x40)
|
||||||
|
|
||||||
#define SCU_IO_REGION_SIZE 0x1000
|
#define SCU_IO_REGION_SIZE 0x1000
|
||||||
|
|
||||||
static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
|
static const uint32_t ast2400_a0_resets[ASPEED_SCU_NR_REGS] = {
|
||||||
|
@ -178,7 +207,7 @@ static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
|
||||||
AspeedSCUState *s = ASPEED_SCU(opaque);
|
AspeedSCUState *s = ASPEED_SCU(opaque);
|
||||||
int reg = TO_REG(offset);
|
int reg = TO_REG(offset);
|
||||||
|
|
||||||
if (reg >= ARRAY_SIZE(s->regs)) {
|
if (reg >= ASPEED_SCU_NR_REGS) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
|
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
|
||||||
__func__, offset);
|
__func__, offset);
|
||||||
|
@ -208,7 +237,7 @@ static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data,
|
||||||
AspeedSCUState *s = ASPEED_SCU(opaque);
|
AspeedSCUState *s = ASPEED_SCU(opaque);
|
||||||
int reg = TO_REG(offset);
|
int reg = TO_REG(offset);
|
||||||
|
|
||||||
if (reg >= ARRAY_SIZE(s->regs)) {
|
if (reg >= ASPEED_SCU_NR_REGS) {
|
||||||
qemu_log_mask(LOG_GUEST_ERROR,
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
|
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
|
||||||
__func__, offset);
|
__func__, offset);
|
||||||
|
@ -346,7 +375,7 @@ static void aspeed_scu_reset(DeviceState *dev)
|
||||||
AspeedSCUState *s = ASPEED_SCU(dev);
|
AspeedSCUState *s = ASPEED_SCU(dev);
|
||||||
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
|
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
|
||||||
|
|
||||||
memcpy(s->regs, asc->resets, sizeof(s->regs));
|
memcpy(s->regs, asc->resets, asc->nr_regs * 4);
|
||||||
s->regs[SILICON_REV] = s->silicon_rev;
|
s->regs[SILICON_REV] = s->silicon_rev;
|
||||||
s->regs[HW_STRAP1] = s->hw_strap1;
|
s->regs[HW_STRAP1] = s->hw_strap1;
|
||||||
s->regs[HW_STRAP2] = s->hw_strap2;
|
s->regs[HW_STRAP2] = s->hw_strap2;
|
||||||
|
@ -358,6 +387,7 @@ static uint32_t aspeed_silicon_revs[] = {
|
||||||
AST2400_A1_SILICON_REV,
|
AST2400_A1_SILICON_REV,
|
||||||
AST2500_A0_SILICON_REV,
|
AST2500_A0_SILICON_REV,
|
||||||
AST2500_A1_SILICON_REV,
|
AST2500_A1_SILICON_REV,
|
||||||
|
AST2600_A0_SILICON_REV,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_supported_silicon_rev(uint32_t silicon_rev)
|
bool is_supported_silicon_rev(uint32_t silicon_rev)
|
||||||
|
@ -377,6 +407,7 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
|
||||||
{
|
{
|
||||||
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
|
||||||
AspeedSCUState *s = ASPEED_SCU(dev);
|
AspeedSCUState *s = ASPEED_SCU(dev);
|
||||||
|
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
|
||||||
|
|
||||||
if (!is_supported_silicon_rev(s->silicon_rev)) {
|
if (!is_supported_silicon_rev(s->silicon_rev)) {
|
||||||
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
|
error_setg(errp, "Unknown silicon revision: 0x%" PRIx32,
|
||||||
|
@ -384,7 +415,7 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
memory_region_init_io(&s->iomem, OBJECT(s), &aspeed_scu_ops, s,
|
memory_region_init_io(&s->iomem, OBJECT(s), asc->ops, s,
|
||||||
TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE);
|
TYPE_ASPEED_SCU, SCU_IO_REGION_SIZE);
|
||||||
|
|
||||||
sysbus_init_mmio(sbd, &s->iomem);
|
sysbus_init_mmio(sbd, &s->iomem);
|
||||||
|
@ -392,10 +423,10 @@ static void aspeed_scu_realize(DeviceState *dev, Error **errp)
|
||||||
|
|
||||||
static const VMStateDescription vmstate_aspeed_scu = {
|
static const VMStateDescription vmstate_aspeed_scu = {
|
||||||
.name = "aspeed.scu",
|
.name = "aspeed.scu",
|
||||||
.version_id = 1,
|
.version_id = 2,
|
||||||
.minimum_version_id = 1,
|
.minimum_version_id = 2,
|
||||||
.fields = (VMStateField[]) {
|
.fields = (VMStateField[]) {
|
||||||
VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_SCU_NR_REGS),
|
VMSTATE_UINT32_ARRAY(regs, AspeedSCUState, ASPEED_AST2600_SCU_NR_REGS),
|
||||||
VMSTATE_END_OF_LIST()
|
VMSTATE_END_OF_LIST()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -436,6 +467,8 @@ static void aspeed_2400_scu_class_init(ObjectClass *klass, void *data)
|
||||||
asc->resets = ast2400_a0_resets;
|
asc->resets = ast2400_a0_resets;
|
||||||
asc->calc_hpll = aspeed_2400_scu_calc_hpll;
|
asc->calc_hpll = aspeed_2400_scu_calc_hpll;
|
||||||
asc->apb_divider = 2;
|
asc->apb_divider = 2;
|
||||||
|
asc->nr_regs = ASPEED_SCU_NR_REGS;
|
||||||
|
asc->ops = &aspeed_scu_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo aspeed_2400_scu_info = {
|
static const TypeInfo aspeed_2400_scu_info = {
|
||||||
|
@ -454,6 +487,8 @@ static void aspeed_2500_scu_class_init(ObjectClass *klass, void *data)
|
||||||
asc->resets = ast2500_a1_resets;
|
asc->resets = ast2500_a1_resets;
|
||||||
asc->calc_hpll = aspeed_2500_scu_calc_hpll;
|
asc->calc_hpll = aspeed_2500_scu_calc_hpll;
|
||||||
asc->apb_divider = 4;
|
asc->apb_divider = 4;
|
||||||
|
asc->nr_regs = ASPEED_SCU_NR_REGS;
|
||||||
|
asc->ops = &aspeed_scu_ops;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const TypeInfo aspeed_2500_scu_info = {
|
static const TypeInfo aspeed_2500_scu_info = {
|
||||||
|
@ -463,11 +498,154 @@ static const TypeInfo aspeed_2500_scu_info = {
|
||||||
.class_init = aspeed_2500_scu_class_init,
|
.class_init = aspeed_2500_scu_class_init,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static uint64_t aspeed_ast2600_scu_read(void *opaque, hwaddr offset,
|
||||||
|
unsigned size)
|
||||||
|
{
|
||||||
|
AspeedSCUState *s = ASPEED_SCU(opaque);
|
||||||
|
int reg = TO_REG(offset);
|
||||||
|
|
||||||
|
if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Out-of-bounds read at offset 0x%" HWADDR_PRIx "\n",
|
||||||
|
__func__, offset);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case AST2600_HPLL_EXT:
|
||||||
|
case AST2600_EPLL_EXT:
|
||||||
|
case AST2600_MPLL_EXT:
|
||||||
|
/* PLLs are always "locked" */
|
||||||
|
return s->regs[reg] | BIT(31);
|
||||||
|
case AST2600_RNG_DATA:
|
||||||
|
/*
|
||||||
|
* On hardware, RNG_DATA works regardless of the state of the
|
||||||
|
* enable bit in RNG_CTRL
|
||||||
|
*
|
||||||
|
* TODO: Check this is true for ast2600
|
||||||
|
*/
|
||||||
|
s->regs[AST2600_RNG_DATA] = aspeed_scu_get_random();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s->regs[reg];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_ast2600_scu_write(void *opaque, hwaddr offset, uint64_t data,
|
||||||
|
unsigned size)
|
||||||
|
{
|
||||||
|
AspeedSCUState *s = ASPEED_SCU(opaque);
|
||||||
|
int reg = TO_REG(offset);
|
||||||
|
|
||||||
|
if (reg >= ASPEED_AST2600_SCU_NR_REGS) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Out-of-bounds write at offset 0x%" HWADDR_PRIx "\n",
|
||||||
|
__func__, offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reg > PROT_KEY && !s->regs[PROT_KEY]) {
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR, "%s: SCU is locked!\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
trace_aspeed_scu_write(offset, size, data);
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
case AST2600_PROT_KEY:
|
||||||
|
s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
|
||||||
|
return;
|
||||||
|
case AST2600_HW_STRAP1:
|
||||||
|
case AST2600_HW_STRAP2:
|
||||||
|
if (s->regs[reg + 2]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* fall through */
|
||||||
|
case AST2600_SYS_RST_CTRL:
|
||||||
|
case AST2600_SYS_RST_CTRL2:
|
||||||
|
/* W1S (Write 1 to set) registers */
|
||||||
|
s->regs[reg] |= data;
|
||||||
|
return;
|
||||||
|
case AST2600_SYS_RST_CTRL_CLR:
|
||||||
|
case AST2600_SYS_RST_CTRL2_CLR:
|
||||||
|
case AST2600_HW_STRAP1_CLR:
|
||||||
|
case AST2600_HW_STRAP2_CLR:
|
||||||
|
/* W1C (Write 1 to clear) registers */
|
||||||
|
s->regs[reg] &= ~data;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case AST2600_RNG_DATA:
|
||||||
|
case AST2600_SILICON_REV:
|
||||||
|
case AST2600_SILICON_REV2:
|
||||||
|
/* Add read only registers here */
|
||||||
|
qemu_log_mask(LOG_GUEST_ERROR,
|
||||||
|
"%s: Write to read-only offset 0x%" HWADDR_PRIx "\n",
|
||||||
|
__func__, offset);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
s->regs[reg] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MemoryRegionOps aspeed_ast2600_scu_ops = {
|
||||||
|
.read = aspeed_ast2600_scu_read,
|
||||||
|
.write = aspeed_ast2600_scu_write,
|
||||||
|
.endianness = DEVICE_LITTLE_ENDIAN,
|
||||||
|
.valid.min_access_size = 4,
|
||||||
|
.valid.max_access_size = 4,
|
||||||
|
.valid.unaligned = false,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32_t ast2600_a0_resets[ASPEED_AST2600_SCU_NR_REGS] = {
|
||||||
|
[AST2600_SILICON_REV] = AST2600_SILICON_REV,
|
||||||
|
[AST2600_SILICON_REV2] = AST2600_SILICON_REV,
|
||||||
|
[AST2600_SYS_RST_CTRL] = 0xF7CFFEDC | 0x100,
|
||||||
|
[AST2600_SYS_RST_CTRL2] = 0xFFFFFFFC,
|
||||||
|
[AST2600_CLK_STOP_CTRL] = 0xEFF43E8B,
|
||||||
|
[AST2600_CLK_STOP_CTRL2] = 0xFFF0FFF0,
|
||||||
|
[AST2600_HPLL_PARAM] = 0x1000405F,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void aspeed_ast2600_scu_reset(DeviceState *dev)
|
||||||
|
{
|
||||||
|
AspeedSCUState *s = ASPEED_SCU(dev);
|
||||||
|
AspeedSCUClass *asc = ASPEED_SCU_GET_CLASS(dev);
|
||||||
|
|
||||||
|
memcpy(s->regs, asc->resets, asc->nr_regs * 4);
|
||||||
|
|
||||||
|
s->regs[AST2600_SILICON_REV] = s->silicon_rev;
|
||||||
|
s->regs[AST2600_SILICON_REV2] = s->silicon_rev;
|
||||||
|
s->regs[AST2600_HW_STRAP1] = s->hw_strap1;
|
||||||
|
s->regs[AST2600_HW_STRAP2] = s->hw_strap2;
|
||||||
|
s->regs[PROT_KEY] = s->hw_prot_key;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void aspeed_2600_scu_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
AspeedSCUClass *asc = ASPEED_SCU_CLASS(klass);
|
||||||
|
|
||||||
|
dc->desc = "ASPEED 2600 System Control Unit";
|
||||||
|
dc->reset = aspeed_ast2600_scu_reset;
|
||||||
|
asc->resets = ast2600_a0_resets;
|
||||||
|
asc->calc_hpll = aspeed_2500_scu_calc_hpll; /* No change since AST2500 */
|
||||||
|
asc->apb_divider = 4;
|
||||||
|
asc->nr_regs = ASPEED_AST2600_SCU_NR_REGS;
|
||||||
|
asc->ops = &aspeed_ast2600_scu_ops;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo aspeed_2600_scu_info = {
|
||||||
|
.name = TYPE_ASPEED_2600_SCU,
|
||||||
|
.parent = TYPE_ASPEED_SCU,
|
||||||
|
.instance_size = sizeof(AspeedSCUState),
|
||||||
|
.class_init = aspeed_2600_scu_class_init,
|
||||||
|
};
|
||||||
|
|
||||||
static void aspeed_scu_register_types(void)
|
static void aspeed_scu_register_types(void)
|
||||||
{
|
{
|
||||||
type_register_static(&aspeed_scu_info);
|
type_register_static(&aspeed_scu_info);
|
||||||
type_register_static(&aspeed_2400_scu_info);
|
type_register_static(&aspeed_2400_scu_info);
|
||||||
type_register_static(&aspeed_2500_scu_info);
|
type_register_static(&aspeed_2500_scu_info);
|
||||||
|
type_register_static(&aspeed_2600_scu_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(aspeed_scu_register_types);
|
type_init(aspeed_scu_register_types);
|
||||||
|
|
|
@ -17,8 +17,10 @@
|
||||||
#define ASPEED_SCU(obj) OBJECT_CHECK(AspeedSCUState, (obj), TYPE_ASPEED_SCU)
|
#define ASPEED_SCU(obj) OBJECT_CHECK(AspeedSCUState, (obj), TYPE_ASPEED_SCU)
|
||||||
#define TYPE_ASPEED_2400_SCU TYPE_ASPEED_SCU "-ast2400"
|
#define TYPE_ASPEED_2400_SCU TYPE_ASPEED_SCU "-ast2400"
|
||||||
#define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500"
|
#define TYPE_ASPEED_2500_SCU TYPE_ASPEED_SCU "-ast2500"
|
||||||
|
#define TYPE_ASPEED_2600_SCU TYPE_ASPEED_SCU "-ast2600"
|
||||||
|
|
||||||
#define ASPEED_SCU_NR_REGS (0x1A8 >> 2)
|
#define ASPEED_SCU_NR_REGS (0x1A8 >> 2)
|
||||||
|
#define ASPEED_AST2600_SCU_NR_REGS (0xE20 >> 2)
|
||||||
|
|
||||||
typedef struct AspeedSCUState {
|
typedef struct AspeedSCUState {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
|
@ -27,7 +29,7 @@ typedef struct AspeedSCUState {
|
||||||
/*< public >*/
|
/*< public >*/
|
||||||
MemoryRegion iomem;
|
MemoryRegion iomem;
|
||||||
|
|
||||||
uint32_t regs[ASPEED_SCU_NR_REGS];
|
uint32_t regs[ASPEED_AST2600_SCU_NR_REGS];
|
||||||
uint32_t silicon_rev;
|
uint32_t silicon_rev;
|
||||||
uint32_t hw_strap1;
|
uint32_t hw_strap1;
|
||||||
uint32_t hw_strap2;
|
uint32_t hw_strap2;
|
||||||
|
@ -38,6 +40,7 @@ typedef struct AspeedSCUState {
|
||||||
#define AST2400_A1_SILICON_REV 0x02010303U
|
#define AST2400_A1_SILICON_REV 0x02010303U
|
||||||
#define AST2500_A0_SILICON_REV 0x04000303U
|
#define AST2500_A0_SILICON_REV 0x04000303U
|
||||||
#define AST2500_A1_SILICON_REV 0x04010303U
|
#define AST2500_A1_SILICON_REV 0x04010303U
|
||||||
|
#define AST2600_A0_SILICON_REV 0x05000303U
|
||||||
|
|
||||||
#define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04)
|
#define ASPEED_IS_AST2500(si_rev) ((((si_rev) >> 24) & 0xff) == 0x04)
|
||||||
|
|
||||||
|
@ -54,6 +57,8 @@ typedef struct AspeedSCUClass {
|
||||||
const uint32_t *resets;
|
const uint32_t *resets;
|
||||||
uint32_t (*calc_hpll)(AspeedSCUState *s, uint32_t hpll_reg);
|
uint32_t (*calc_hpll)(AspeedSCUState *s, uint32_t hpll_reg);
|
||||||
uint32_t apb_divider;
|
uint32_t apb_divider;
|
||||||
|
uint32_t nr_regs;
|
||||||
|
const MemoryRegionOps *ops;
|
||||||
} AspeedSCUClass;
|
} AspeedSCUClass;
|
||||||
|
|
||||||
#define ASPEED_SCU_PROT_KEY 0x1688A8A8
|
#define ASPEED_SCU_PROT_KEY 0x1688A8A8
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue