Re: [PATCH] hw/misc/imx6_ccm: add the i.MX6SLL variant

Peter Maydell <[email protected]>
Newsgroups org.nongnu.qemu-arm,org.nongnu.qemu-devel
Message-ID <CAFEAcA8H0f6FjkQJJM=qp0CoXJCX1Ow81ac6v8V7xO-jpQzfEw@mail.gmail.com>
On Mon, 3 Aug 2026 at 20:36, Pablo Mazzini <[email protected]> wrote:
>
> The i.MX6SLL shares the i.MX6Q clock tree, but reports its own chip id
> in the ANATOP DIGPROG register and implements the PMU and XTALOSC24M
> registers that the i.MX6Q does not.
>
> Add TYPE_IMX6SLL_CCM as a subtype of TYPE_IMX6_CCM.  QOM runs the
> parent's instance_init first, so the subtype only has to override
> DIGPROG and widen the decoded ANALOG window to cover the extra
> registers; the i.MX6Q window is unchanged.

There's no user of this new type. We prefer patches adding new
devices to come in a patchset that includes support for whatever
their user is.

>
> DIGPROG is a hardwired chip identifier rather than a reset value, so
> move its default out of imx6_ccm_reset() and into imx6_ccm_init().
>
> The analog register array grows to cover the new registers.
>
> Signed-off-by: Pablo Mazzini <[email protected]>
> ---
>  hw/misc/imx6_ccm.c         | 39 ++++++++++++++++++++++++++++++++++++--
>  include/hw/misc/imx6_ccm.h | 12 +++++++++++-
>  2 files changed, 48 insertions(+), 3 deletions(-)
>
> diff --git a/hw/misc/imx6_ccm.c b/hw/misc/imx6_ccm.c
> index 45fdd0d5a8..6f48de5954 100644
> --- a/hw/misc/imx6_ccm.c
> +++ b/hw/misc/imx6_ccm.c
> @@ -223,6 +223,14 @@ static const char *imx6_analog_reg_name(uint32_t reg)
>          return "PMU_MISC1_TOG";
>      case USB_ANALOG_DIGPROG:
>          return "USB_ANALOG_DIGPROG";
> +    case PMU_LOW_PWR_CTRL:
> +        return "PMU_LOW_PWR_CTRL";
> +    case XTALOSC24M_OSC_CONFIG0:
> +        return "XTALOSC24M_OSC_CONFIG0";
> +    case XTALOSC24M_OSC_CONFIG1:
> +        return "XTALOSC24M_OSC_CONFIG1";
> +    case XTALOSC24M_OSC_CONFIG2:
> +        return "XTALOSC24M_OSC_CONFIG2";
>      default:
>          snprintf(unknown, sizeof(unknown), "%u ?", reg);
>          return unknown;
> @@ -237,7 +245,7 @@ static const VMStateDescription vmstate_imx6_ccm = {
>      .minimum_version_id = 1,
>      .fields = (const VMStateField[]) {
>          VMSTATE_UINT32_ARRAY(ccm, IMX6CCMState, CCM_MAX),
> -        VMSTATE_UINT32_ARRAY(analog, IMX6CCMState, CCM_ANALOG_MAX),
> +        VMSTATE_UINT32_ARRAY(analog, IMX6CCMState, CCM_ANALOG_REGS),
>          VMSTATE_END_OF_LIST()
>      },
>  };

Adding new elements to a vmstate is a migration bump, and at
minimum needs the version ID numbers to be incremented.

In this case I would favour having the new register state
in a vmstate subsection so that we only migrate it for the new
device type, and the existing device's migration info doesn't change.

> @@ -474,7 +482,6 @@ static void imx6_ccm_reset(DeviceState *dev)
>      s->analog[USB_ANALOG_USB2_VBUS_DETECT] = 0x00000004;
>      s->analog[USB_ANALOG_USB2_CHRG_DETECT] = 0x00000000;
>      s->analog[USB_ANALOG_USB2_MISC] = 0x00000002;
> -    s->analog[USB_ANALOG_DIGPROG] = 0x00630000;
>
>      /* all PLLs need to be locked */
>      s->analog[CCM_ANALOG_PLL_ARM]   |= CCM_ANALOG_PLL_LOCK;
> @@ -763,6 +770,12 @@ static void imx6_ccm_init(Object *obj)
>      memory_region_add_subregion(&s->container, 0x4000, &s->ioanalog);
>
>      sysbus_init_mmio(sd, &s->container);
> +
> +    /*
> +     * DIGPROG is a hardwired chip identifier: it is not affected by reset.
> +     * Default to i.MX6Q; variants sharing this CCM override it below.
> +     */
> +    s->analog[USB_ANALOG_DIGPROG] = 0x00630000;
>  }
>
>  static void imx6_ccm_class_init(ObjectClass *klass, const void *data)
> @@ -777,6 +790,21 @@ static void imx6_ccm_class_init(ObjectClass *klass, const void *data)
>      ccm->get_clock_frequency = imx6_ccm_get_clock_frequency;
>  }
>
> +static void imx6sll_ccm_init(Object *obj)
> +{
> +    IMX6CCMState *s = IMX6_CCM(obj);
> +
> +    /*
> +     * Runs after imx6_ccm_init(), which installs the i.MX6Q default.  The
> +     * clock tree is the same; only the chip identifier differs:
> +     * MXC_CPU_IMX6SLL (0x67), revision 1.0.
> +     */
> +    s->analog[USB_ANALOG_DIGPROG] = 0x00670000;
> +
> +    /* Unlike the i.MX6Q, this one implements the PMU/XTALOSC24M registers. */
> +    memory_region_set_size(&s->ioanalog, CCM_ANALOG_REGS * sizeof(uint32_t));

memory_region_set_size() is really for MRs that dynamically change size,
not for fixing up a size that we could have got right in the first place.

I recommend that you add a class struct to the TYPE_IMX6_CCM, and give
that struct suitable fields that define how the subclasses differ (DIGPROG
reset value, whether XTALOSC24M registers are present, etc). In the class_init
function for each subclass you set those fields in the class struct. Then in
instance_init you can look at the class struct to see how big you should
make the MemoryRegion, and in reset you can look to see what reset value to
use, and so on.

hw/misc/npcm_gcr.c is an example of this approach.

thanks
-- PMM
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.