Re: [PATCH 04/26] hw/misc: pfsoc: Model L2 cache controller registers

Alistair <[email protected]>
Newsgroups org.nongnu.qemu-riscv,org.nongnu.qemu-devel
Message-ID <[email protected]>
On Thu, 2026-07-23 at 23:18 +0800, Bin Meng wrote:
> Implement the Config, WayEnable, and per-master WayMask registers
> described by the PolarFire SoC MSS reference manual. Make WayEnable
> monotonic and report the remaining register space as unimplemented.
> 
> Signed-off-by: Bin Meng <[email protected]>
> ---
> 
>  MAINTAINERS                       |   2 +
>  include/hw/misc/mchp_pfsoc_l2cc.h |  30 +++++
>  hw/misc/mchp_pfsoc_l2cc.c         | 180
> ++++++++++++++++++++++++++++++
>  hw/misc/Kconfig                   |   3 +
>  hw/misc/meson.build               |   1 +
>  5 files changed, 216 insertions(+)
>  create mode 100644 include/hw/misc/mchp_pfsoc_l2cc.h
>  create mode 100644 hw/misc/mchp_pfsoc_l2cc.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index a28935c898..c0bb18c47a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1770,11 +1770,13 @@ F: hw/riscv/microchip_pfsoc.c
>  F: hw/char/mchp_pfsoc_mmuart.c
>  F: hw/misc/mchp_pfsoc_dmc.c
>  F: hw/misc/mchp_pfsoc_ioscb.c
> +F: hw/misc/mchp_pfsoc_l2cc.c
>  F: hw/misc/mchp_pfsoc_sysreg.c
>  F: include/hw/riscv/microchip_pfsoc.h
>  F: include/hw/char/mchp_pfsoc_mmuart.h
>  F: include/hw/misc/mchp_pfsoc_dmc.h
>  F: include/hw/misc/mchp_pfsoc_ioscb.h
> +F: include/hw/misc/mchp_pfsoc_l2cc.h
>  F: include/hw/misc/mchp_pfsoc_sysreg.h
>  
>  Shakti C class SoC
> diff --git a/include/hw/misc/mchp_pfsoc_l2cc.h
> b/include/hw/misc/mchp_pfsoc_l2cc.h
> new file mode 100644
> index 0000000000..1b5b3888d5
> --- /dev/null
> +++ b/include/hw/misc/mchp_pfsoc_l2cc.h
> @@ -0,0 +1,30 @@
> +/*
> + * Microchip PolarFire SoC L2 cache controller
> + *
> + * Copyright (c) 2026 Process Mission
> + *
> + * Author:
> + *   Bin Meng <[email protected]>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#ifndef MCHP_PFSOC_L2CC_H
> +#define MCHP_PFSOC_L2CC_H
> +
> +#include "hw/core/register.h"
> +#include "hw/core/sysbus.h"
> +
> +#define MCHP_PFSOC_L2CC_REG_SIZE 0x1000
> +#define MCHP_PFSOC_L2CC_REG_NUM  (MCHP_PFSOC_L2CC_REG_SIZE / 8)
> +
> +typedef struct MchpPfSoCL2ccState {
> +    SysBusDevice parent;
> +    uint64_t regs[MCHP_PFSOC_L2CC_REG_NUM];
> +    RegisterInfo regs_info[MCHP_PFSOC_L2CC_REG_NUM];
> +} MchpPfSoCL2ccState;
> +
> +#define TYPE_MCHP_PFSOC_L2CC "mchp.pfsoc.l2cc"
> +OBJECT_DECLARE_SIMPLE_TYPE(MchpPfSoCL2ccState, MCHP_PFSOC_L2CC)
> +
> +#endif
> diff --git a/hw/misc/mchp_pfsoc_l2cc.c b/hw/misc/mchp_pfsoc_l2cc.c
> new file mode 100644
> index 0000000000..b320356572
> --- /dev/null
> +++ b/hw/misc/mchp_pfsoc_l2cc.c
> @@ -0,0 +1,180 @@
> +/*
> + * Microchip PolarFire SoC L2 cache controller
> + *
> + * Copyright (c) 2026 Process Mission
> + *
> + * Author:
> + *   Bin Meng <[email protected]>
> + *
> + * SPDX-License-Identifier: GPL-2.0-or-later
> + */
> +
> +#include "qemu/osdep.h"
> +#include "qemu/log.h"
> +#include "hw/core/register.h"
> +#include "hw/core/registerfields.h"
> +#include "hw/misc/mchp_pfsoc_l2cc.h"
> +
> +REG64(L2_CONFIG, 0x000)
> +    FIELD(L2_CONFIG, BANKS, 0, 8)
> +    FIELD(L2_CONFIG, WAYS, 8, 8)
> +    FIELD(L2_CONFIG, SETS, 16, 8)
> +    FIELD(L2_CONFIG, BYTES, 24, 8)
> +REG64(L2_WAY_ENABLE, 0x008)
> +    FIELD(L2_WAY_ENABLE, VALUE, 0, 8)
> +REG64(L2_WAY_MASK_DMA, 0x800)
> +REG64(L2_WAY_MASK_AXI4_PORT_0, 0x808)
> +REG64(L2_WAY_MASK_AXI4_PORT_1, 0x810)
> +REG64(L2_WAY_MASK_AXI4_PORT_2, 0x818)
> +REG64(L2_WAY_MASK_AXI4_PORT_3, 0x820)
> +REG64(L2_WAY_MASK_HART0_DCACHE, 0x828)
> +REG64(L2_WAY_MASK_HART0_ICACHE, 0x830)
> +REG64(L2_WAY_MASK_HART1_DCACHE, 0x838)
> +REG64(L2_WAY_MASK_HART1_ICACHE, 0x840)
> +REG64(L2_WAY_MASK_HART2_DCACHE, 0x848)
> +REG64(L2_WAY_MASK_HART2_ICACHE, 0x850)
> +REG64(L2_WAY_MASK_HART3_DCACHE, 0x858)
> +REG64(L2_WAY_MASK_HART3_ICACHE, 0x860)
> +REG64(L2_WAY_MASK_HART4_DCACHE, 0x868)
> +REG64(L2_WAY_MASK_HART4_ICACHE, 0x870)
> +
> +#define L2_CONFIG_RESET         0x06091004
> +
> +static uint64_t mchp_pfsoc_l2cc_way_enable_pre_write(RegisterInfo
> *reg,
> +                                                     uint64_t value)
> +{
> +    uint64_t current = *(uint64_t *)reg->data;
> +
> +    return MAX(current, value);
> +}
> +
> +#define WAY_MASK_REGISTER(_name)                \
> +    {                                           \
> +        .name = "WAY_MASK_" #_name,             \
> +        .addr = A_L2_WAY_MASK_ ## _name,        \
> +        .reset = UINT64_MAX,                    \
> +    }
> +
> +static const RegisterAccessInfo mchp_pfsoc_l2cc_regs_info[] = {
> +    {
> +        .name = "CONFIG",
> +        .addr = A_L2_CONFIG,
> +        .reset = L2_CONFIG_RESET,
> +        .ro = UINT64_MAX,
> +    }, {
> +        .name = "WAY_ENABLE",
> +        .addr = A_L2_WAY_ENABLE,
> +        .rsvd = ~R_L2_WAY_ENABLE_VALUE_MASK,
> +        .pre_write = mchp_pfsoc_l2cc_way_enable_pre_write,
> +    },
> +    WAY_MASK_REGISTER(DMA),
> +    WAY_MASK_REGISTER(AXI4_PORT_0),
> +    WAY_MASK_REGISTER(AXI4_PORT_1),
> +    WAY_MASK_REGISTER(AXI4_PORT_2),
> +    WAY_MASK_REGISTER(AXI4_PORT_3),
> +    WAY_MASK_REGISTER(HART0_DCACHE),
> +    WAY_MASK_REGISTER(HART0_ICACHE),
> +    WAY_MASK_REGISTER(HART1_DCACHE),
> +    WAY_MASK_REGISTER(HART1_ICACHE),
> +    WAY_MASK_REGISTER(HART2_DCACHE),
> +    WAY_MASK_REGISTER(HART2_ICACHE),
> +    WAY_MASK_REGISTER(HART3_DCACHE),
> +    WAY_MASK_REGISTER(HART3_ICACHE),
> +    WAY_MASK_REGISTER(HART4_DCACHE),
> +    WAY_MASK_REGISTER(HART4_ICACHE),
> +};
> +
> +static bool mchp_pfsoc_l2cc_register_implemented(hwaddr offset)
> +{
> +    size_t i;
> +
> +    for (i = 0; i < ARRAY_SIZE(mchp_pfsoc_l2cc_regs_info); i++) {
> +        if (mchp_pfsoc_l2cc_regs_info[i].addr == offset) {
> +            return true;
> +        }
> +    }
> +
> +    return false;
> +}
> +
> +static uint64_t mchp_pfsoc_l2cc_read(void *opaque, hwaddr offset,
> +                                     unsigned size)
> +{
> +    if (mchp_pfsoc_l2cc_register_implemented(offset)) {
> +        return register_read_memory(opaque, offset, size);
> +    }
> +
> +    qemu_log_mask(LOG_UNIMP, "%s: unimplemented device read "
> +                  "(size %u, offset 0x%" HWADDR_PRIx ")\n",
> +                  __func__, size, offset);
> +    return 0;
> +}
> +
> +static void mchp_pfsoc_l2cc_write(void *opaque, hwaddr offset,
> +                                  uint64_t value, unsigned size)
> +{
> +    if (mchp_pfsoc_l2cc_register_implemented(offset)) {
> +        register_write_memory(opaque, offset, value, size);
> +        return;
> +    }
> +
> +    qemu_log_mask(LOG_UNIMP, "%s: unimplemented device write "
> +                  "(size %u, value 0x%" PRIx64
> +                  ", offset 0x%" HWADDR_PRIx ")\n",
> +                  __func__, size, value, offset);
> +}
> +
> +static const MemoryRegionOps mchp_pfsoc_l2cc_ops = {
> +    .read = mchp_pfsoc_l2cc_read,
> +    .write = mchp_pfsoc_l2cc_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = { .min_access_size = 1, .max_access_size = 8 },
> +    .impl = { .min_access_size = 1, .max_access_size = 8 },
> +};
> +
> +static void mchp_pfsoc_l2cc_reset(DeviceState *dev)
> +{
> +    MchpPfSoCL2ccState *s = MCHP_PFSOC_L2CC(dev);
> +    size_t i;
> +
> +    memset(s->regs, 0, sizeof(s->regs));
> +    for (i = 0; i < ARRAY_SIZE(mchp_pfsoc_l2cc_regs_info); i++) {
> +        hwaddr addr = mchp_pfsoc_l2cc_regs_info[i].addr;
> +
> +        register_reset(&s->regs_info[addr / sizeof(uint64_t)]);
> +    }
> +}
> +
> +static void mchp_pfsoc_l2cc_init(Object *obj)
> +{
> +    MchpPfSoCL2ccState *s = MCHP_PFSOC_L2CC(obj);
> +    RegisterInfoArray *reg_array;
> +
> +    reg_array = register_init_block64(
> +        DEVICE(obj), mchp_pfsoc_l2cc_regs_info,
> +        ARRAY_SIZE(mchp_pfsoc_l2cc_regs_info), s->regs_info, s-
> >regs,
> +        &mchp_pfsoc_l2cc_ops, false, MCHP_PFSOC_L2CC_REG_SIZE);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(obj), &reg_array->mem);
> +}
> +
> +static void mchp_pfsoc_l2cc_class_init(ObjectClass *klass, const
> void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    device_class_set_legacy_reset(dc, mchp_pfsoc_l2cc_reset);

Again, non-legacy reset would be best

Otherwise:

Acked-by: Alistair Francis <[email protected]>

Alistair

> +}
> +
> +static const TypeInfo mchp_pfsoc_l2cc_info = {
> +    .name = TYPE_MCHP_PFSOC_L2CC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(MchpPfSoCL2ccState),
> +    .instance_init = mchp_pfsoc_l2cc_init,
> +    .class_init = mchp_pfsoc_l2cc_class_init,
> +};
> +
> +static void mchp_pfsoc_l2cc_register_types(void)
> +{
> +    type_register_static(&mchp_pfsoc_l2cc_info);
> +}
> +
> +type_init(mchp_pfsoc_l2cc_register_types)
> diff --git a/hw/misc/Kconfig b/hw/misc/Kconfig
> index 1543ee6653..772a2d87b3 100644
> --- a/hw/misc/Kconfig
> +++ b/hw/misc/Kconfig
> @@ -203,6 +203,9 @@ config MCHP_PFSOC_DMC
>  config MCHP_PFSOC_IOSCB
>      bool
>  
> +config MCHP_PFSOC_L2CC
> +    bool
> +
>  config MCHP_PFSOC_SYSREG
>      bool
>  
> diff --git a/hw/misc/meson.build b/hw/misc/meson.build
> index 23265f6035..5f45861d8a 100644
> --- a/hw/misc/meson.build
> +++ b/hw/misc/meson.build
> @@ -30,6 +30,7 @@ system_ss.add(when: 'CONFIG_VIRT_CTRL', if_true:
> files('virt_ctrl.c'))
>  # RISC-V devices
>  system_ss.add(when: 'CONFIG_MCHP_PFSOC_DMC', if_true:
> files('mchp_pfsoc_dmc.c'))
>  system_ss.add(when: 'CONFIG_MCHP_PFSOC_IOSCB', if_true:
> files('mchp_pfsoc_ioscb.c'))
> +system_ss.add(when: 'CONFIG_MCHP_PFSOC_L2CC', if_true:
> files('mchp_pfsoc_l2cc.c'))
>  system_ss.add(when: 'CONFIG_MCHP_PFSOC_SYSREG', if_true:
> files('mchp_pfsoc_sysreg.c'))
>  system_ss.add(when: 'CONFIG_SIFIVE_TEST', if_true:
> files('sifive_test.c'))
>  system_ss.add(when: 'CONFIG_SIFIVE_E_PRCI', if_true:
> files('sifive_e_prci.c'))
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.