qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
From: Luc Michel <luc@lmichel.fr>
To: "Philippe Mathieu-Daudé" <f4bug@amsat.org>
Cc: Peter Maydell <peter.maydell@linaro.org>,
	qemu-arm@nongnu.org, qemu-devel@nongnu.org,
	Andrew Baumann <Andrew.Baumann@microsoft.com>
Subject: Re: [PATCH 09/14] hw/misc/bcm2835_cprman: add a clock mux skeleton implementation
Date: Sun, 4 Oct 2020 21:34:21 +0200	[thread overview]
Message-ID: <20201004193421.2a2znqtgwaoslvm3@sekoia-pc.home.lmichel.fr> (raw)
In-Reply-To: <2a18bb94-1e6c-d853-3e6e-f6874b617a2b@amsat.org>

On 16:42 Fri 02 Oct     , Philippe Mathieu-Daudé wrote:
> On 9/25/20 12:17 PM, Luc Michel wrote:
> > The clock multiplexers are the last clock stage in the cprman. Each mux
> > outputs one clock signal that goes out of the cprman to the SoC
> > peripherals.
> >
> > Each mux has at most 10 sources. The sources 0 to 3 are common to all
> > muxes. They are:
> >    0. ground (no clock signal)
> >    1. the main oscillator (xosc)
> >    2. "test debug 0" clock
> >    3. "test debug 1" clock
> >
> > Test debug 0 and 1 are actual clock muxes that can be used as sources to
> > other muxes (for debug purpose).
> >
> > Sources 4 to 9 are mux specific and can be unpopulated (grounded). Those
> > sources are fed by the PLL channels outputs.
> >
> > One corner case exists for DSI0E and DSI0P muxes. They have their source
> > number 4 connected to an intermediate multiplexer that can select
> > between PLLA-DSI0 and PLLD-DSI0 channel. This multiplexer is called
> > DSI0HSCK and is not a clock mux as such. It is really a simple mux from
> > the hardware point of view (see https://elinux.org/The_Undocumented_Pi).
> > This mux is not implemented in this commit.
> >
> > Note that there is some muxes for which sources are unknown (because of
> > a lack of documentation). For those cases all the sources are connected
> > to ground in this implementation.
> >
> > Each clock mux output is exported by the cprman at the qdev level,
> > adding the suffix '-out' to the mux name to form the output clock name.
> > (E.g. the 'uart' mux sees its output exported as 'uart-out' at the
> > cprman level.)
> >
> > Signed-off-by: Luc Michel <luc@lmichel.fr>
> > ---
> >  include/hw/misc/bcm2835_cprman.h           |  84 ++++
> >  include/hw/misc/bcm2835_cprman_internals.h | 421 +++++++++++++++++++++
> >  hw/misc/bcm2835_cprman.c                   | 151 ++++++++
> >  3 files changed, 656 insertions(+)
> >
> > diff --git a/include/hw/misc/bcm2835_cprman.h b/include/hw/misc/bcm2835_cprman.h
> > index aaf15fb20c..c2a89e8e90 100644
> > --- a/include/hw/misc/bcm2835_cprman.h
> > +++ b/include/hw/misc/bcm2835_cprman.h
> > @@ -52,12 +52,73 @@ typedef enum CprmanPLLChannel {
> >      CPRMAN_PLLH_CHANNEL_PIX,
> >
> >      CPRMAN_PLLB_CHANNEL_ARM,
> >
> >      CPRMAN_NUM_PLL_CHANNEL,
> > +
> > +    /* Special values used when connecting clock sources to clocks */
> > +    CPRMAN_CLOCK_SRC_NORMAL = -1,
> > +    CPRMAN_CLOCK_SRC_FORCE_GROUND = -2,
> > +    CPRMAN_CLOCK_SRC_DSI0HSCK = -3,
>
> Why not use CPRMAN_NORMAL_CHANNEL,
> CPRMAN_FORCED_GROUND_CHANNEL and CPRMAN_DSI0HSCK_CHANNEL?
Well, those are special values used when connecting the clock sources to
the muxes in connect_mux_sources(). They are not channels hence the
name. To keep the code simple, I reused the CprmanPLLChannel type for
mux sources (it is used in bcm2835_cprman_internals.h to describe what
source connects to what mux input).

Ideally this type should be named something like ClockMuxSources (and
CprmanPLLChannel should be a sub-set of this type). But doing so
complicates the code quite a bit so I chose to simply have those three
constants here instead.

>
> >  } CprmanPLLChannel;
> >
> > +typedef enum CprmanClockMux {
> > +    CPRMAN_CLOCK_GNRIC,
> > +    CPRMAN_CLOCK_VPU,
> > +    CPRMAN_CLOCK_SYS,
> > +    CPRMAN_CLOCK_PERIA,
> > +    CPRMAN_CLOCK_PERII,
> > +    CPRMAN_CLOCK_H264,
> > +    CPRMAN_CLOCK_ISP,
> > +    CPRMAN_CLOCK_V3D,
> > +    CPRMAN_CLOCK_CAM0,
> > +    CPRMAN_CLOCK_CAM1,
> > +    CPRMAN_CLOCK_CCP2,
> > +    CPRMAN_CLOCK_DSI0E,
> > +    CPRMAN_CLOCK_DSI0P,
> > +    CPRMAN_CLOCK_DPI,
> > +    CPRMAN_CLOCK_GP0,
> > +    CPRMAN_CLOCK_GP1,
> > +    CPRMAN_CLOCK_GP2,
> > +    CPRMAN_CLOCK_HSM,
> > +    CPRMAN_CLOCK_OTP,
> > +    CPRMAN_CLOCK_PCM,
> > +    CPRMAN_CLOCK_PWM,
> > +    CPRMAN_CLOCK_SLIM,
> > +    CPRMAN_CLOCK_SMI,
> > +    CPRMAN_CLOCK_TEC,
> > +    CPRMAN_CLOCK_TD0,
> > +    CPRMAN_CLOCK_TD1,
> > +    CPRMAN_CLOCK_TSENS,
> > +    CPRMAN_CLOCK_TIMER,
> > +    CPRMAN_CLOCK_UART,
> > +    CPRMAN_CLOCK_VEC,
> > +    CPRMAN_CLOCK_PULSE,
> > +    CPRMAN_CLOCK_SDC,
> > +    CPRMAN_CLOCK_ARM,
> > +    CPRMAN_CLOCK_AVEO,
> > +    CPRMAN_CLOCK_EMMC,
> > +    CPRMAN_CLOCK_EMMC2,
> > +
> > +    CPRMAN_NUM_CLOCK_MUX
> > +} CprmanClockMux;
> > +
> > +typedef enum CprmanClockMuxSource {
> > +    CPRMAN_CLOCK_SRC_GND = 0,
> > +    CPRMAN_CLOCK_SRC_XOSC,
> > +    CPRMAN_CLOCK_SRC_TD0,
> > +    CPRMAN_CLOCK_SRC_TD1,
> > +    CPRMAN_CLOCK_SRC_PLLA,
> > +    CPRMAN_CLOCK_SRC_PLLC,
> > +    CPRMAN_CLOCK_SRC_PLLD,
> > +    CPRMAN_CLOCK_SRC_PLLH,
> > +    CPRMAN_CLOCK_SRC_PLLC_CORE1,
> > +    CPRMAN_CLOCK_SRC_PLLC_CORE2,
> > +
> > +    CPRMAN_NUM_CLOCK_MUX_SRC
> > +} CprmanClockMuxSource;
> > +
> >  typedef struct CprmanPLLState {
> >      /*< private >*/
> >      DeviceState parent_obj;
> >
> >      /*< public >*/
> > @@ -89,22 +150,45 @@ typedef struct CprmanPLLChannelState {
> >
> >      Clock *pll_in;
> >      Clock *out;
> >  } CprmanPLLChannelState;
> >
> > +typedef struct CprmanClockMuxState {
> > +    /*< private >*/
> > +    DeviceState parent_obj;
> > +
> > +    /*< public >*/
> > +    CprmanClockMux id;
> > +
> > +    uint32_t *reg_cm;
> > +    int int_bits;
> > +    int frac_bits;
> > +
> > +    Clock *srcs[CPRMAN_NUM_CLOCK_MUX_SRC];
> > +    Clock *out;
> > +
> > +    /*
> > +     * Used by clock srcs update callback to retrieve both the clock and the
> > +     * source number.
> > +     */
> > +    struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
> > +} CprmanClockMuxState;
> > +
> >  struct BCM2835CprmanState {
> >      /*< private >*/
> >      SysBusDevice parent_obj;
> >
> >      /*< public >*/
> >      MemoryRegion iomem;
> >
> >      CprmanPLLState plls[CPRMAN_NUM_PLL];
> >      CprmanPLLChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
> > +    CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
> >
> >      uint32_t regs[CPRMAN_NUM_REGS];
> >      uint32_t xosc_freq;
> >
> >      Clock *xosc;
> > +    Clock *gnd;
>
> This one seems to belong to MachineState in "hw/boards.h".
>
> >  };
> >
> >  #endif
> > diff --git a/include/hw/misc/bcm2835_cprman_internals.h b/include/hw/misc/bcm2835_cprman_internals.h
> > index 8a5b9aae67..a2b5a1aa50 100644
> > --- a/include/hw/misc/bcm2835_cprman_internals.h
> > +++ b/include/hw/misc/bcm2835_cprman_internals.h
> > @@ -12,15 +12,18 @@
> >  #include "hw/registerfields.h"
> >  #include "hw/misc/bcm2835_cprman.h"
> >
> >  #define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
> >  #define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
> > +#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
> >
> >  DECLARE_INSTANCE_CHECKER(CprmanPLLState, CPRMAN_PLL,
> >                           TYPE_CPRMAN_PLL)
> >  DECLARE_INSTANCE_CHECKER(CprmanPLLChannelState, CPRMAN_PLL_CHANNEL,
> >                           TYPE_CPRMAN_PLL_CHANNEL)
> > +DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
> > +                         TYPE_CPRMAN_CLOCK_MUX)
> >
> >  /* Register map */
> >
> >  /* PLLs */
> >  REG32(CM_PLLA, 0x104)
> > @@ -126,10 +129,94 @@ REG32(A2W_PLLH_RCAL, 0x1460)
> >  REG32(A2W_PLLH_PIX, 0x1560)
> >  REG32(A2W_PLLH_STS, 0x1660)
> >
> >  REG32(A2W_PLLB_ARM, 0x13e0)
> >
> > +/* Clock muxes */
> > +REG32(CM_GNRICCTL, 0x000)
> > +    FIELD(CM_CLOCKx_CTL, SRC, 0, 4)
> > +    FIELD(CM_CLOCKx_CTL, ENABLE, 4, 1)
> > +    FIELD(CM_CLOCKx_CTL, KILL, 5, 1)
> > +    FIELD(CM_CLOCKx_CTL, GATE, 6, 1)
> > +    FIELD(CM_CLOCKx_CTL, BUSY, 7, 1)
> > +    FIELD(CM_CLOCKx_CTL, BUSYD, 8, 1)
> > +    FIELD(CM_CLOCKx_CTL, MASH, 9, 2)
> > +    FIELD(CM_CLOCKx_CTL, FLIP, 11, 1)
> > +REG32(CM_GNRICDIV, 0x004)
> > +    FIELD(CM_CLOCKx_DIV, FRAC, 0, 12)
> > +REG32(CM_VPUCTL, 0x008)
> > +REG32(CM_VPUDIV, 0x00c)
> > +REG32(CM_SYSCTL, 0x010)
> > +REG32(CM_SYSDIV, 0x014)
> > +REG32(CM_PERIACTL, 0x018)
> > +REG32(CM_PERIADIV, 0x01c)
> > +REG32(CM_PERIICTL, 0x020)
> > +REG32(CM_PERIIDIV, 0x024)
> > +REG32(CM_H264CTL, 0x028)
> > +REG32(CM_H264DIV, 0x02c)
> > +REG32(CM_ISPCTL, 0x030)
> > +REG32(CM_ISPDIV, 0x034)
> > +REG32(CM_V3DCTL, 0x038)
> > +REG32(CM_V3DDIV, 0x03c)
> > +REG32(CM_CAM0CTL, 0x040)
> > +REG32(CM_CAM0DIV, 0x044)
> > +REG32(CM_CAM1CTL, 0x048)
> > +REG32(CM_CAM1DIV, 0x04c)
> > +REG32(CM_CCP2CTL, 0x050)
> > +REG32(CM_CCP2DIV, 0x054)
> > +REG32(CM_DSI0ECTL, 0x058)
> > +REG32(CM_DSI0EDIV, 0x05c)
> > +REG32(CM_DSI0PCTL, 0x060)
> > +REG32(CM_DSI0PDIV, 0x064)
> > +REG32(CM_DPICTL, 0x068)
> > +REG32(CM_DPIDIV, 0x06c)
> > +REG32(CM_GP0CTL, 0x070)
> > +REG32(CM_GP0DIV, 0x074)
> > +REG32(CM_GP1CTL, 0x078)
> > +REG32(CM_GP1DIV, 0x07c)
> > +REG32(CM_GP2CTL, 0x080)
> > +REG32(CM_GP2DIV, 0x084)
> > +REG32(CM_HSMCTL, 0x088)
> > +REG32(CM_HSMDIV, 0x08c)
> > +REG32(CM_OTPCTL, 0x090)
> > +REG32(CM_OTPDIV, 0x094)
> > +REG32(CM_PCMCTL, 0x098)
> > +REG32(CM_PCMDIV, 0x09c)
> > +REG32(CM_PWMCTL, 0x0a0)
> > +REG32(CM_PWMDIV, 0x0a4)
> > +REG32(CM_SLIMCTL, 0x0a8)
> > +REG32(CM_SLIMDIV, 0x0ac)
> > +REG32(CM_SMICTL, 0x0b0)
> > +REG32(CM_SMIDIV, 0x0b4)
> > +REG32(CM_TCNTCTL, 0x0c0)
> > +REG32(CM_TCNTCNT, 0x0c4)
> > +REG32(CM_TECCTL, 0x0c8)
> > +REG32(CM_TECDIV, 0x0cc)
> > +REG32(CM_TD0CTL, 0x0d0)
> > +REG32(CM_TD0DIV, 0x0d4)
> > +REG32(CM_TD1CTL, 0x0d8)
> > +REG32(CM_TD1DIV, 0x0dc)
> > +REG32(CM_TSENSCTL, 0x0e0)
> > +REG32(CM_TSENSDIV, 0x0e4)
> > +REG32(CM_TIMERCTL, 0x0e8)
> > +REG32(CM_TIMERDIV, 0x0ec)
> > +REG32(CM_UARTCTL, 0x0f0)
> > +REG32(CM_UARTDIV, 0x0f4)
> > +REG32(CM_VECCTL, 0x0f8)
> > +REG32(CM_VECDIV, 0x0fc)
> > +REG32(CM_PULSECTL, 0x190)
> > +REG32(CM_PULSEDIV, 0x194)
> > +REG32(CM_SDCCTL, 0x1a8)
> > +REG32(CM_SDCDIV, 0x1ac)
> > +REG32(CM_ARMCTL, 0x1b0)
> > +REG32(CM_AVEOCTL, 0x1b8)
> > +REG32(CM_AVEODIV, 0x1bc)
> > +REG32(CM_EMMCCTL, 0x1c0)
> > +REG32(CM_EMMCDIV, 0x1c4)
> > +REG32(CM_EMMC2CTL, 0x1d0)
> > +REG32(CM_EMMC2DIV, 0x1d4)
> > +
> >  /* misc registers */
> >  REG32(CM_LOCK, 0x114)
> >      FIELD(CM_LOCK, FLOCKH, 12, 1)
> >      FIELD(CM_LOCK, FLOCKD, 11, 1)
> >      FIELD(CM_LOCK, FLOCKC, 10, 1)
> > @@ -317,6 +404,340 @@ static inline void set_pll_channel_init_info(BCM2835CprmanState *s,
> >      channel->load_mask = PLL_CHANNEL_INIT_INFO[id].cm_load_mask;
> >      channel->reg_a2w_ctrl = &s->regs[PLL_CHANNEL_INIT_INFO[id].a2w_ctrl_offset];
> >      channel->fixed_divider = PLL_CHANNEL_INIT_INFO[id].fixed_divider;
> >  }
> >
> > +/* Clock mux init info */
> > +typedef struct ClockMuxInitInfo {
> > +    const char *name;
> > +    size_t cm_offset;
> > +    int int_bits;
> > +    int frac_bits;
> > +
> > +    CprmanPLLChannel src_mapping[CPRMAN_NUM_CLOCK_MUX_SRC];
> > +} ClockMuxInitInfo;
> > +
> > +/*
> > + * Each clock mux can have up to 10 sources. Sources 0 to 3 are always the
> > + * same (ground, xosc, td0, td1). Sources 4 to 9 are mux specific, and are not
> > + * always populated. The following macros catch all those cases.
> > + */
> > +
> > +/* Unknown mapping. Connect everything to ground */
> > +#define SRC_MAPPING_INFO_unknown                          \
> > +    .src_mapping = {                                      \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* gnd */          \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* xosc */         \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 0 */ \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* test debug 1 */ \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll a */        \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c */        \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll d */        \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll h */        \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core1 */ \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, /* pll c, core2 */ \
> > +    }
> > +
> > +/* Only the oscillator and the two test debug clocks */
> > +#define SRC_MAPPING_INFO_xosc          \
> > +    .src_mapping = {                   \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +    }
> > +
> > +/* All the PLL "core" channels */
> > +#define SRC_MAPPING_INFO_core      \
> > +    .src_mapping = {               \
> > +        CPRMAN_CLOCK_SRC_NORMAL,   \
> > +        CPRMAN_CLOCK_SRC_NORMAL,   \
> > +        CPRMAN_CLOCK_SRC_NORMAL,   \
> > +        CPRMAN_CLOCK_SRC_NORMAL,   \
> > +        CPRMAN_PLLA_CHANNEL_CORE,  \
> > +        CPRMAN_PLLC_CHANNEL_CORE0, \
> > +        CPRMAN_PLLD_CHANNEL_CORE,  \
> > +        CPRMAN_PLLH_CHANNEL_AUX,   \
> > +        CPRMAN_PLLC_CHANNEL_CORE1, \
> > +        CPRMAN_PLLC_CHANNEL_CORE2, \
> > +    }
> > +
> > +/* All the PLL "per" channels */
> > +#define SRC_MAPPING_INFO_periph        \
> > +    .src_mapping = {                   \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_PLLA_CHANNEL_PER,       \
> > +        CPRMAN_PLLC_CHANNEL_PER,       \
> > +        CPRMAN_PLLD_CHANNEL_PER,       \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +    }
> > +
> > +/*
> > + * The DSI0 channels. This one got an intermediate mux between the PLL channels
> > + * and the clock input.
> > + */
> > +#define SRC_MAPPING_INFO_dsi0          \
> > +    .src_mapping = {                   \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_DSI0HSCK,     \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +    }
> > +
> > +/* The DSI1 channel */
> > +#define SRC_MAPPING_INFO_dsi1          \
> > +    .src_mapping = {                   \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_CLOCK_SRC_NORMAL,       \
> > +        CPRMAN_PLLD_CHANNEL_DSI1,      \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +        CPRMAN_CLOCK_SRC_FORCE_GROUND, \
> > +    }
> > +
> > +#define FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_) \
> > +    SRC_MAPPING_INFO_ ## kind_
> > +
> > +#define FILL_CLOCK_MUX_INIT_INFO(clock_, kind_) \
> > +    .cm_offset = R_CM_ ## clock_ ## CTL,        \
> > +    FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO(kind_)
> > +
> > +static ClockMuxInitInfo CLOCK_MUX_INIT_INFO[] = {
> > +    [CPRMAN_CLOCK_GNRIC] = {
> > +        .name = "gnric",
> > +        FILL_CLOCK_MUX_INIT_INFO(GNRIC, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_VPU] = {
> > +        .name = "vpu",
> > +        .int_bits = 12,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(VPU, core),
> > +    },
> > +    [CPRMAN_CLOCK_SYS] = {
> > +        .name = "sys",
> > +        FILL_CLOCK_MUX_INIT_INFO(SYS, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_PERIA] = {
> > +        .name = "peria",
> > +        FILL_CLOCK_MUX_INIT_INFO(PERIA, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_PERII] = {
> > +        .name = "perii",
> > +        FILL_CLOCK_MUX_INIT_INFO(PERII, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_H264] = {
> > +        .name = "h264",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(H264, core),
> > +    },
> > +    [CPRMAN_CLOCK_ISP] = {
> > +        .name = "isp",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(ISP, core),
> > +    },
> > +    [CPRMAN_CLOCK_V3D] = {
> > +        .name = "v3d",
> > +        FILL_CLOCK_MUX_INIT_INFO(V3D, core),
> > +    },
> > +    [CPRMAN_CLOCK_CAM0] = {
> > +        .name = "cam0",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(CAM0, periph),
> > +    },
> > +    [CPRMAN_CLOCK_CAM1] = {
> > +        .name = "cam1",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(CAM1, periph),
> > +    },
> > +    [CPRMAN_CLOCK_CCP2] = {
> > +        .name = "ccp2",
> > +        FILL_CLOCK_MUX_INIT_INFO(CCP2, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_DSI0E] = {
> > +        .name = "dsi0e",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(DSI0E, dsi0),
> > +    },
> > +    [CPRMAN_CLOCK_DSI0P] = {
> > +        .name = "dsi0p",
> > +        .int_bits = 0,
> > +        .frac_bits = 0,
> > +        FILL_CLOCK_MUX_INIT_INFO(DSI0P, dsi0),
> > +    },
> > +    [CPRMAN_CLOCK_DPI] = {
> > +        .name = "dpi",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(DPI, periph),
> > +    },
> > +    [CPRMAN_CLOCK_GP0] = {
> > +        .name = "gp0",
> > +        .int_bits = 12,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(GP0, periph),
> > +    },
> > +    [CPRMAN_CLOCK_GP1] = {
> > +        .name = "gp1",
> > +        .int_bits = 12,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(GP1, periph),
> > +    },
> > +    [CPRMAN_CLOCK_GP2] = {
> > +        .name = "gp2",
> > +        .int_bits = 12,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(GP2, periph),
> > +    },
> > +    [CPRMAN_CLOCK_HSM] = {
> > +        .name = "hsm",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(HSM, periph),
> > +    },
> > +    [CPRMAN_CLOCK_OTP] = {
> > +        .name = "otp",
> > +        .int_bits = 4,
> > +        .frac_bits = 0,
> > +        FILL_CLOCK_MUX_INIT_INFO(OTP, xosc),
> > +    },
> > +    [CPRMAN_CLOCK_PCM] = {
> > +        .name = "pcm",
> > +        .int_bits = 12,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(PCM, periph),
> > +    },
> > +    [CPRMAN_CLOCK_PWM] = {
> > +        .name = "pwm",
> > +        .int_bits = 12,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(PWM, periph),
> > +    },
> > +    [CPRMAN_CLOCK_SLIM] = {
> > +        .name = "slim",
> > +        .int_bits = 12,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(SLIM, periph),
> > +    },
> > +    [CPRMAN_CLOCK_SMI] = {
> > +        .name = "smi",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(SMI, periph),
> > +    },
> > +    [CPRMAN_CLOCK_TEC] = {
> > +        .name = "tec",
> > +        .int_bits = 6,
> > +        .frac_bits = 0,
> > +        FILL_CLOCK_MUX_INIT_INFO(TEC, xosc),
> > +    },
> > +    [CPRMAN_CLOCK_TD0] = {
> > +        .name = "td0",
> > +        FILL_CLOCK_MUX_INIT_INFO(TD0, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_TD1] = {
> > +        .name = "td1",
> > +        FILL_CLOCK_MUX_INIT_INFO(TD1, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_TSENS] = {
> > +        .name = "tsens",
> > +        .int_bits = 5,
> > +        .frac_bits = 0,
> > +        FILL_CLOCK_MUX_INIT_INFO(TSENS, xosc),
> > +    },
> > +    [CPRMAN_CLOCK_TIMER] = {
> > +        .name = "timer",
> > +        .int_bits = 6,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(TIMER, xosc),
> > +    },
> > +    [CPRMAN_CLOCK_UART] = {
> > +        .name = "uart",
> > +        .int_bits = 10,
> > +        .frac_bits = 12,
> > +        FILL_CLOCK_MUX_INIT_INFO(UART, periph),
> > +    },
> > +    [CPRMAN_CLOCK_VEC] = {
> > +        .name = "vec",
> > +        .int_bits = 4,
> > +        .frac_bits = 0,
> > +        FILL_CLOCK_MUX_INIT_INFO(VEC, periph),
> > +    },
> > +    [CPRMAN_CLOCK_PULSE] = {
> > +        .name = "pulse",
> > +        FILL_CLOCK_MUX_INIT_INFO(PULSE, xosc),
> > +    },
> > +    [CPRMAN_CLOCK_SDC] = {
> > +        .name = "sdram",
> > +        .int_bits = 6,
> > +        .frac_bits = 0,
> > +        FILL_CLOCK_MUX_INIT_INFO(SDC, core),
> > +    },
> > +    [CPRMAN_CLOCK_ARM] = {
> > +        .name = "arm",
> > +        FILL_CLOCK_MUX_INIT_INFO(ARM, unknown),
> > +    },
> > +    [CPRMAN_CLOCK_AVEO] = {
> > +        .name = "aveo",
> > +        .int_bits = 4,
> > +        .frac_bits = 0,
> > +        FILL_CLOCK_MUX_INIT_INFO(AVEO, periph),
> > +    },
> > +    [CPRMAN_CLOCK_EMMC] = {
> > +        .name = "emmc",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(EMMC, periph),
> > +    },
> > +    [CPRMAN_CLOCK_EMMC2] = {
> > +        .name = "emmc2",
> > +        .int_bits = 4,
> > +        .frac_bits = 8,
> > +        FILL_CLOCK_MUX_INIT_INFO(EMMC2, unknown),
> > +    },
> > +};
> > +
> > +#undef FILL_CLOCK_MUX_INIT_INFO
> > +#undef FILL_CLOCK_MUX_SRC_MAPPING_INIT_INFO
> > +#undef SRC_MAPPING_INFO_dsi1
> > +#undef SRC_MAPPING_INFO_dsi0
> > +#undef SRC_MAPPING_INFO_periph
> > +#undef SRC_MAPPING_INFO_core
> > +#undef SRC_MAPPING_INFO_xosc
> > +#undef SRC_MAPPING_INFO_unknown
> > +
> > +static inline void set_clock_mux_init_info(BCM2835CprmanState *s,
> > +                                           CprmanClockMuxState *mux,
> > +                                           CprmanClockMux id)
> > +{
> > +    mux->id = id;
> > +    mux->reg_cm = &s->regs[CLOCK_MUX_INIT_INFO[id].cm_offset];
> > +    mux->int_bits = CLOCK_MUX_INIT_INFO[id].int_bits;
> > +    mux->frac_bits = CLOCK_MUX_INIT_INFO[id].frac_bits;
> > +}
> > +
> >  #endif
> > diff --git a/hw/misc/bcm2835_cprman.c b/hw/misc/bcm2835_cprman.c
> > index e644aeb2b5..8df2db0fd9 100644
> > --- a/hw/misc/bcm2835_cprman.c
> > +++ b/hw/misc/bcm2835_cprman.c
> > @@ -36,10 +36,13 @@
> >   *          |                                          [mux]
> >   *          \-->[PLL]--->[PLL channel]                 [mux]
> >   *
> >   * The page at https://elinux.org/The_Undocumented_Pi gives the actual clock
> >   * tree configuration.
> > + *
> > + * The CPRMAN exposes clock outputs with the name of the clock mux suffixed
> > + * with "-out" (e.g. "uart-out", "h264-out", ...).
> >   */
> >
> >  #include "qemu/osdep.h"
> >  #include "qemu/log.h"
> >  #include "migration/vmstate.h"
> > @@ -224,10 +227,69 @@ static const TypeInfo cprman_pll_channel_info = {
> >      .class_init = pll_channel_class_init,
> >      .instance_init = pll_channel_init,
> >  };
> >
> >
> > +/* clock mux */
> > +
> > +static void clock_mux_update(CprmanClockMuxState *mux)
> > +{
> > +    clock_update(mux->out, 0);
> > +}
> > +
> > +static void clock_mux_src_update(void *opaque)
> > +{
> > +    CprmanClockMuxState **backref = opaque;
> > +    CprmanClockMuxState *s = *backref;
> > +
> > +    clock_mux_update(s);
> > +}
> > +
> > +static void clock_mux_init(Object *obj)
> > +{
> > +    CprmanClockMuxState *s = CPRMAN_CLOCK_MUX(obj);
> > +    size_t i;
> > +
> > +    for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
> > +        char *name = g_strdup_printf("srcs[%zu]", i);
> > +        s->backref[i] = s;
> > +        s->srcs[i] = qdev_init_clock_in(DEVICE(s), name,
> > +                                        clock_mux_src_update,
> > +                                        &s->backref[i]);
> > +        g_free(name);
> > +    }
> > +
> > +    s->out = qdev_init_clock_out(DEVICE(s), "out");
> > +}
> > +
> > +static const VMStateDescription clock_mux_vmstate = {
> > +    .name = TYPE_CPRMAN_CLOCK_MUX,
> > +    .version_id = 1,
> > +    .minimum_version_id = 1,
> > +    .fields = (VMStateField[]) {
> > +        VMSTATE_ARRAY_CLOCK(srcs, CprmanClockMuxState,
> > +                            CPRMAN_NUM_CLOCK_MUX_SRC),
> > +        VMSTATE_END_OF_LIST()
> > +    }
> > +};
> > +
> > +static void clock_mux_class_init(ObjectClass *klass, void *data)
> > +{
> > +    DeviceClass *dc = DEVICE_CLASS(klass);
> > +
> > +    dc->vmsd = &clock_mux_vmstate;
> > +}
> > +
> > +static const TypeInfo cprman_clock_mux_info = {
> > +    .name = TYPE_CPRMAN_CLOCK_MUX,
> > +    .parent = TYPE_DEVICE,
> > +    .instance_size = sizeof(CprmanClockMuxState),
> > +    .class_init = clock_mux_class_init,
> > +    .instance_init = clock_mux_init,
> > +};
> > +
> > +
> >  /* CPRMAN "top level" model */
> >
> >  static uint32_t get_cm_lock(const BCM2835CprmanState *s)
> >  {
> >      static const int CM_LOCK_MAPPING[] = {
> > @@ -291,10 +353,23 @@ static inline void update_channel_from_a2w(BCM2835CprmanState *s, size_t idx)
> >              return;
> >          }
> >      }
> >  }
> >
> > +static inline void update_mux_from_cm(BCM2835CprmanState *s, size_t idx)
> > +{
> > +    size_t i;
> > +
> > +    for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
> > +        if ((CLOCK_MUX_INIT_INFO[i].cm_offset == idx)
> > +           || (CLOCK_MUX_INIT_INFO[i].cm_offset == idx + 4)) {
>
> Indent by one ;)
>
> > +            clock_mux_update(&s->clock_muxes[i]);
> > +            return;
> > +        }
> > +    }
> > +}
> > +
> >  #define CASE_PLL_A2W_REGS(pll_) \
> >      case R_A2W_ ## pll_ ## _CTRL: \
> >      case R_A2W_ ## pll_ ## _ANA0: \
> >      case R_A2W_ ## pll_ ## _ANA1: \
> >      case R_A2W_ ## pll_ ## _ANA2: \
> > @@ -363,10 +438,19 @@ static void cprman_write(void *opaque, hwaddr offset,
> >      case R_A2W_PLLH_RCAL:
> >      case R_A2W_PLLH_PIX:
> >      case R_A2W_PLLB_ARM:
> >          update_channel_from_a2w(s, idx);
> >          break;
> > +
> > +    case R_CM_GNRICCTL ... R_CM_SMIDIV:
> > +    case R_CM_TCNTCNT ... R_CM_VECDIV:
> > +    case R_CM_PULSECTL ... R_CM_PULSEDIV:
> > +    case R_CM_SDCCTL ... R_CM_ARMCTL:
> > +    case R_CM_AVEOCTL ... R_CM_EMMCDIV:
> > +    case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
> > +        update_mux_from_cm(s, idx);
> > +        break;
> >      }
> >  }
> >
> >  #undef CASE_PLL_A2W_REGS
> >
> > @@ -394,10 +478,14 @@ static void cprman_reset(DeviceState *dev)
> >
> >      for (i = 0; i < CPRMAN_NUM_PLL_CHANNEL; i++) {
> >          device_cold_reset(DEVICE(&s->channels[i]));
> >      }
> >
> > +    for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
> > +        device_cold_reset(DEVICE(&s->clock_muxes[i]));
> > +    }
> > +
> >      clock_update_hz(s->xosc, s->xosc_freq);
> >  }
> >
> >  static Clock *init_internal_clock(BCM2835CprmanState *s,
> >                                    const char *name)
> > @@ -431,17 +519,69 @@ static void cprman_init(Object *obj)
> >                                  &s->channels[i],
> >                                  TYPE_CPRMAN_PLL_CHANNEL);
> >          set_pll_channel_init_info(s, &s->channels[i], i);
> >      }
> >
> > +    for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
> > +        char *alias;
> > +
> > +        object_initialize_child(obj, CLOCK_MUX_INIT_INFO[i].name,
> > +                                &s->clock_muxes[i],
> > +                                TYPE_CPRMAN_CLOCK_MUX);
> > +        set_clock_mux_init_info(s, &s->clock_muxes[i], i);
> > +
> > +        /* Expose muxes output as CPRMAN outputs */
> > +        alias = g_strdup_printf("%s-out", CLOCK_MUX_INIT_INFO[i].name);
> > +        qdev_alias_clock(DEVICE(&s->clock_muxes[i]), "out", DEVICE(obj), alias);
> > +        g_free(alias);
> > +
>
> NL.
>
> > +    }
> > +
> >      s->xosc = init_internal_clock(s, "xosc");
> > +    s->gnd = init_internal_clock(s, "gnd");
> > +
> > +    clock_set(s->gnd, 0);
> >
> >      memory_region_init_io(&s->iomem, obj, &cprman_ops,
> >                            s, "bcm2835-cprman", 0x2000);
> >      sysbus_init_mmio(SYS_BUS_DEVICE(obj), &s->iomem);
> >  }
> >
> > +static void connect_mux_sources(BCM2835CprmanState *s,
> > +                                CprmanClockMuxState *mux,
> > +                                const CprmanPLLChannel *clk_mapping)
> > +{
> > +    size_t i;
> > +    Clock *td0 = s->clock_muxes[CPRMAN_CLOCK_TD0].out;
> > +    Clock *td1 = s->clock_muxes[CPRMAN_CLOCK_TD1].out;
> > +
> > +    /* For sources from 0 to 3. Source 4 to 9 are mux specific */
> > +    Clock * const CLK_SRC_MAPPING[] = {
> > +        [CPRMAN_CLOCK_SRC_GND] = s->gnd,
> > +        [CPRMAN_CLOCK_SRC_XOSC] = s->xosc,
> > +        [CPRMAN_CLOCK_SRC_TD0] = td0,
> > +        [CPRMAN_CLOCK_SRC_TD1] = td1,
> > +    };
> > +
> > +    for (i = 0; i < CPRMAN_NUM_CLOCK_MUX_SRC; i++) {
> > +        CprmanPLLChannel mapping = clk_mapping[i];
> > +        Clock *src;
> > +
> > +        if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
> > +            src = s->gnd;
> > +        } else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
> > +            src = s->gnd; /* TODO */
> > +        } else if (i < CPRMAN_CLOCK_SRC_PLLA) {
> > +            src = CLK_SRC_MAPPING[i];
> > +        } else {
> > +            src = s->channels[mapping].out;
> > +        }
> > +
> > +        clock_set_source(mux->srcs[i], src);
> > +    }
> > +}
> > +
> >  static void cprman_realize(DeviceState *dev, Error **errp)
> >  {
> >      BCM2835CprmanState *s = CPRMAN(dev);
> >      size_t i;
> >
> > @@ -464,10 +604,20 @@ static void cprman_realize(DeviceState *dev, Error **errp)
> >
> >          if (!qdev_realize(DEVICE(channel), NULL, errp)) {
> >              return;
> >          }
> >      }
> > +
> > +    for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
> > +        CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
> > +
> > +        connect_mux_sources(s, clock_mux, CLOCK_MUX_INIT_INFO[i].src_mapping);
> > +
> > +        if (!qdev_realize(DEVICE(clock_mux), NULL, errp)) {
> > +            return;
> > +        }
> > +    }
> >  }
> >
> >  static const VMStateDescription cprman_vmstate = {
> >      .name = TYPE_BCM2835_CPRMAN,
> >      .version_id = 1,
> > @@ -504,8 +654,9 @@ static const TypeInfo cprman_info = {
> >  static void cprman_register_types(void)
> >  {
> >      type_register_static(&cprman_info);
> >      type_register_static(&cprman_pll_info);
> >      type_register_static(&cprman_pll_channel_info);
> > +    type_register_static(&cprman_clock_mux_info);
> >  }
> >
> >  type_init(cprman_register_types);
> >
>
> Few comments, nice work!
>
> Regards,
>
> Phil.

--


  parent reply	other threads:[~2020-10-04 19:34 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-09-25 10:17 [PATCH 00/14] raspi: add the bcm2835 cprman clock manager Luc Michel
2020-09-25 10:17 ` [PATCH 01/14] hw/core/clock: provide the VMSTATE_ARRAY_CLOCK macro Luc Michel
2020-09-26 20:36   ` Philippe Mathieu-Daudé
2020-09-28  8:38   ` Damien Hedde
2020-09-25 10:17 ` [PATCH 02/14] hw/core/clock: trace clock values in Hz instead of ns Luc Michel
2020-09-26 20:36   ` Philippe Mathieu-Daudé
2020-09-28  8:42     ` Damien Hedde
2020-09-25 10:17 ` [PATCH 03/14] hw/arm/raspi: fix cprman base address Luc Michel
2020-09-26 21:04   ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 04/14] hw/arm/raspi: add a skeleton implementation of the cprman Luc Michel
2020-09-26 21:05   ` Philippe Mathieu-Daudé
2020-09-28  8:45     ` Luc Michel
2020-10-02 14:37       ` Philippe Mathieu-Daudé
2020-10-03 11:54         ` Luc Michel
2020-10-03 18:14           ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 05/14] hw/misc/bcm2835_cprman: add a PLL skeleton implementation Luc Michel
2020-09-26 21:17   ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 06/14] hw/misc/bcm2835_cprman: implement PLLs behaviour Luc Michel
2020-09-26 21:26   ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 07/14] hw/misc/bcm2835_cprman: add a PLL channel skeleton implementation Luc Michel
2020-09-26 21:32   ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 08/14] hw/misc/bcm2835_cprman: implement PLL channels behaviour Luc Michel
2020-09-26 21:36   ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 09/14] hw/misc/bcm2835_cprman: add a clock mux skeleton implementation Luc Michel
2020-10-02 14:42   ` Philippe Mathieu-Daudé
2020-10-02 15:34     ` Philippe Mathieu-Daudé
2020-10-04 19:34     ` Luc Michel [this message]
2020-10-04 20:17       ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 10/14] hw/misc/bcm2835_cprman: implement clock mux behaviour Luc Michel
2020-09-26 21:40   ` Philippe Mathieu-Daudé
2020-10-02 14:51     ` Philippe Mathieu-Daudé
2020-10-04 18:37       ` Luc Michel
2020-10-05 19:50         ` Luc Michel
2020-09-25 10:17 ` [PATCH 11/14] hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer Luc Michel
2020-10-02 14:55   ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [PATCH 12/14] hw/misc/bcm2835_cprman: add sane reset values to the registers Luc Michel
2020-09-25 10:17 ` [RFC PATCH 13/14] hw/char/pl011: add a clock input Luc Michel
2020-09-25 10:36   ` Philippe Mathieu-Daudé
2020-09-25 10:17 ` [RFC PATCH 14/14] hw/arm/bcm2835_peripherals: connect the UART clock Luc Michel
2020-09-25 11:56 ` [PATCH 00/14] raspi: add the bcm2835 cprman clock manager no-reply
2020-09-25 12:55 ` Philippe Mathieu-Daudé

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20201004193421.2a2znqtgwaoslvm3@sekoia-pc.home.lmichel.fr \
    --to=luc@lmichel.fr \
    --cc=Andrew.Baumann@microsoft.com \
    --cc=f4bug@amsat.org \
    --cc=peter.maydell@linaro.org \
    --cc=qemu-arm@nongnu.org \
    --cc=qemu-devel@nongnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).