hw/misc/bcm2835_cprman: add the DSI0HSCK multiplexer
This simple mux sits between the PLL channels and the DSI0E and DSI0P clock muxes. This mux selects between PLLA-DSI0 and PLLD-DSI0 channel and outputs the selected signal to source number 4 of DSI0E/P clock muxes. It is controlled by the cm_dsi0hsck register. Reviewed-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Tested-by: Philippe Mathieu-Daudé <f4bug@amsat.org> Signed-off-by: Luc Michel <luc@lmichel.fr> Tested-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
fc9840850b
commit
502960ca04
|
@ -339,6 +339,58 @@ static const TypeInfo cprman_clock_mux_info = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* DSI0HSCK mux */
|
||||||
|
|
||||||
|
static void dsi0hsck_mux_update(CprmanDsi0HsckMuxState *s)
|
||||||
|
{
|
||||||
|
bool src_is_plld = FIELD_EX32(*s->reg_cm, CM_DSI0HSCK, SELPLLD);
|
||||||
|
Clock *src = src_is_plld ? s->plld_in : s->plla_in;
|
||||||
|
|
||||||
|
clock_update(s->out, clock_get(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsi0hsck_mux_in_update(void *opaque)
|
||||||
|
{
|
||||||
|
dsi0hsck_mux_update(CPRMAN_DSI0HSCK_MUX(opaque));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void dsi0hsck_mux_init(Object *obj)
|
||||||
|
{
|
||||||
|
CprmanDsi0HsckMuxState *s = CPRMAN_DSI0HSCK_MUX(obj);
|
||||||
|
DeviceState *dev = DEVICE(obj);
|
||||||
|
|
||||||
|
s->plla_in = qdev_init_clock_in(dev, "plla-in", dsi0hsck_mux_in_update, s);
|
||||||
|
s->plld_in = qdev_init_clock_in(dev, "plld-in", dsi0hsck_mux_in_update, s);
|
||||||
|
s->out = qdev_init_clock_out(DEVICE(s), "out");
|
||||||
|
}
|
||||||
|
|
||||||
|
static const VMStateDescription dsi0hsck_mux_vmstate = {
|
||||||
|
.name = TYPE_CPRMAN_DSI0HSCK_MUX,
|
||||||
|
.version_id = 1,
|
||||||
|
.minimum_version_id = 1,
|
||||||
|
.fields = (VMStateField[]) {
|
||||||
|
VMSTATE_CLOCK(plla_in, CprmanDsi0HsckMuxState),
|
||||||
|
VMSTATE_CLOCK(plld_in, CprmanDsi0HsckMuxState),
|
||||||
|
VMSTATE_END_OF_LIST()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static void dsi0hsck_mux_class_init(ObjectClass *klass, void *data)
|
||||||
|
{
|
||||||
|
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||||
|
|
||||||
|
dc->vmsd = &dsi0hsck_mux_vmstate;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const TypeInfo cprman_dsi0hsck_mux_info = {
|
||||||
|
.name = TYPE_CPRMAN_DSI0HSCK_MUX,
|
||||||
|
.parent = TYPE_DEVICE,
|
||||||
|
.instance_size = sizeof(CprmanDsi0HsckMuxState),
|
||||||
|
.class_init = dsi0hsck_mux_class_init,
|
||||||
|
.instance_init = dsi0hsck_mux_init,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* CPRMAN "top level" model */
|
/* CPRMAN "top level" model */
|
||||||
|
|
||||||
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
|
static uint32_t get_cm_lock(const BCM2835CprmanState *s)
|
||||||
|
@ -501,6 +553,10 @@ static void cprman_write(void *opaque, hwaddr offset,
|
||||||
case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
|
case R_CM_EMMC2CTL ... R_CM_EMMC2DIV:
|
||||||
update_mux_from_cm(s, idx);
|
update_mux_from_cm(s, idx);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case R_CM_DSI0HSCK:
|
||||||
|
dsi0hsck_mux_update(&s->dsi0hsck_mux);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -540,6 +596,8 @@ static void cprman_reset(DeviceState *dev)
|
||||||
device_cold_reset(DEVICE(&s->channels[i]));
|
device_cold_reset(DEVICE(&s->channels[i]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
device_cold_reset(DEVICE(&s->dsi0hsck_mux));
|
||||||
|
|
||||||
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
|
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
|
||||||
device_cold_reset(DEVICE(&s->clock_muxes[i]));
|
device_cold_reset(DEVICE(&s->clock_muxes[i]));
|
||||||
}
|
}
|
||||||
|
@ -565,6 +623,10 @@ static void cprman_init(Object *obj)
|
||||||
set_pll_channel_init_info(s, &s->channels[i], i);
|
set_pll_channel_init_info(s, &s->channels[i], i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object_initialize_child(obj, "dsi0hsck-mux",
|
||||||
|
&s->dsi0hsck_mux, TYPE_CPRMAN_DSI0HSCK_MUX);
|
||||||
|
s->dsi0hsck_mux.reg_cm = &s->regs[R_CM_DSI0HSCK];
|
||||||
|
|
||||||
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
|
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
|
||||||
char *alias;
|
char *alias;
|
||||||
|
|
||||||
|
@ -612,7 +674,7 @@ static void connect_mux_sources(BCM2835CprmanState *s,
|
||||||
if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
|
if (mapping == CPRMAN_CLOCK_SRC_FORCE_GROUND) {
|
||||||
src = s->gnd;
|
src = s->gnd;
|
||||||
} else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
|
} else if (mapping == CPRMAN_CLOCK_SRC_DSI0HSCK) {
|
||||||
src = s->gnd; /* TODO */
|
src = s->dsi0hsck_mux.out;
|
||||||
} else if (i < CPRMAN_CLOCK_SRC_PLLA) {
|
} else if (i < CPRMAN_CLOCK_SRC_PLLA) {
|
||||||
src = CLK_SRC_MAPPING[i];
|
src = CLK_SRC_MAPPING[i];
|
||||||
} else {
|
} else {
|
||||||
|
@ -650,6 +712,15 @@ static void cprman_realize(DeviceState *dev, Error **errp)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clock_set_source(s->dsi0hsck_mux.plla_in,
|
||||||
|
s->channels[CPRMAN_PLLA_CHANNEL_DSI0].out);
|
||||||
|
clock_set_source(s->dsi0hsck_mux.plld_in,
|
||||||
|
s->channels[CPRMAN_PLLD_CHANNEL_DSI0].out);
|
||||||
|
|
||||||
|
if (!qdev_realize(DEVICE(&s->dsi0hsck_mux), NULL, errp)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
|
for (i = 0; i < CPRMAN_NUM_CLOCK_MUX; i++) {
|
||||||
CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
|
CprmanClockMuxState *clock_mux = &s->clock_muxes[i];
|
||||||
|
|
||||||
|
@ -700,6 +771,7 @@ static void cprman_register_types(void)
|
||||||
type_register_static(&cprman_pll_info);
|
type_register_static(&cprman_pll_info);
|
||||||
type_register_static(&cprman_pll_channel_info);
|
type_register_static(&cprman_pll_channel_info);
|
||||||
type_register_static(&cprman_clock_mux_info);
|
type_register_static(&cprman_clock_mux_info);
|
||||||
|
type_register_static(&cprman_dsi0hsck_mux_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
type_init(cprman_register_types);
|
type_init(cprman_register_types);
|
||||||
|
|
|
@ -174,6 +174,20 @@ typedef struct CprmanClockMuxState {
|
||||||
struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
|
struct CprmanClockMuxState *backref[CPRMAN_NUM_CLOCK_MUX_SRC];
|
||||||
} CprmanClockMuxState;
|
} CprmanClockMuxState;
|
||||||
|
|
||||||
|
typedef struct CprmanDsi0HsckMuxState {
|
||||||
|
/*< private >*/
|
||||||
|
DeviceState parent_obj;
|
||||||
|
|
||||||
|
/*< public >*/
|
||||||
|
CprmanClockMux id;
|
||||||
|
|
||||||
|
uint32_t *reg_cm;
|
||||||
|
|
||||||
|
Clock *plla_in;
|
||||||
|
Clock *plld_in;
|
||||||
|
Clock *out;
|
||||||
|
} CprmanDsi0HsckMuxState;
|
||||||
|
|
||||||
struct BCM2835CprmanState {
|
struct BCM2835CprmanState {
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
SysBusDevice parent_obj;
|
SysBusDevice parent_obj;
|
||||||
|
@ -184,6 +198,7 @@ struct BCM2835CprmanState {
|
||||||
CprmanPllState plls[CPRMAN_NUM_PLL];
|
CprmanPllState plls[CPRMAN_NUM_PLL];
|
||||||
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
|
CprmanPllChannelState channels[CPRMAN_NUM_PLL_CHANNEL];
|
||||||
CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
|
CprmanClockMuxState clock_muxes[CPRMAN_NUM_CLOCK_MUX];
|
||||||
|
CprmanDsi0HsckMuxState dsi0hsck_mux;
|
||||||
|
|
||||||
uint32_t regs[CPRMAN_NUM_REGS];
|
uint32_t regs[CPRMAN_NUM_REGS];
|
||||||
uint32_t xosc_freq;
|
uint32_t xosc_freq;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
|
#define TYPE_CPRMAN_PLL "bcm2835-cprman-pll"
|
||||||
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
|
#define TYPE_CPRMAN_PLL_CHANNEL "bcm2835-cprman-pll-channel"
|
||||||
#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
|
#define TYPE_CPRMAN_CLOCK_MUX "bcm2835-cprman-clock-mux"
|
||||||
|
#define TYPE_CPRMAN_DSI0HSCK_MUX "bcm2835-cprman-dsi0hsck-mux"
|
||||||
|
|
||||||
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
|
DECLARE_INSTANCE_CHECKER(CprmanPllState, CPRMAN_PLL,
|
||||||
TYPE_CPRMAN_PLL)
|
TYPE_CPRMAN_PLL)
|
||||||
|
@ -22,6 +23,8 @@ DECLARE_INSTANCE_CHECKER(CprmanPllChannelState, CPRMAN_PLL_CHANNEL,
|
||||||
TYPE_CPRMAN_PLL_CHANNEL)
|
TYPE_CPRMAN_PLL_CHANNEL)
|
||||||
DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
|
DECLARE_INSTANCE_CHECKER(CprmanClockMuxState, CPRMAN_CLOCK_MUX,
|
||||||
TYPE_CPRMAN_CLOCK_MUX)
|
TYPE_CPRMAN_CLOCK_MUX)
|
||||||
|
DECLARE_INSTANCE_CHECKER(CprmanDsi0HsckMuxState, CPRMAN_DSI0HSCK_MUX,
|
||||||
|
TYPE_CPRMAN_DSI0HSCK_MUX)
|
||||||
|
|
||||||
/* Register map */
|
/* Register map */
|
||||||
|
|
||||||
|
@ -223,6 +226,9 @@ REG32(CM_LOCK, 0x114)
|
||||||
FIELD(CM_LOCK, FLOCKB, 9, 1)
|
FIELD(CM_LOCK, FLOCKB, 9, 1)
|
||||||
FIELD(CM_LOCK, FLOCKA, 8, 1)
|
FIELD(CM_LOCK, FLOCKA, 8, 1)
|
||||||
|
|
||||||
|
REG32(CM_DSI0HSCK, 0x120)
|
||||||
|
FIELD(CM_DSI0HSCK, SELPLLD, 0, 1)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This field is common to all registers. Each register write value must match
|
* This field is common to all registers. Each register write value must match
|
||||||
* the CPRMAN_PASSWORD magic value in its 8 MSB.
|
* the CPRMAN_PASSWORD magic value in its 8 MSB.
|
||||||
|
|
Loading…
Reference in a new issue