Omap DPLL & APLL locking logic.
Reset I2C fifo on new transfers. git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4919 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
74b9decc47
commit
51fec3cc7e
119
hw/omap2.c
119
hw/omap2.c
@ -2727,6 +2727,8 @@ struct omap_prcm_s {
|
||||
|
||||
uint32_t ev;
|
||||
uint32_t evtime[2];
|
||||
|
||||
int dpll_lock, apll_lock[2];
|
||||
};
|
||||
|
||||
static void omap_prcm_int_update(struct omap_prcm_s *s, int dom)
|
||||
@ -2739,6 +2741,7 @@ static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr)
|
||||
{
|
||||
struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
|
||||
int offset = addr - s->base;
|
||||
uint32_t ret;
|
||||
|
||||
switch (offset) {
|
||||
case 0x000: /* PRCM_REVISION */
|
||||
@ -2922,14 +2925,17 @@ static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr)
|
||||
case 0x500: /* CM_CLKEN_PLL */
|
||||
return s->clken[9];
|
||||
case 0x520: /* CM_IDLEST_CKGEN */
|
||||
/* Core uses 32-kHz clock */
|
||||
ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8);
|
||||
if (!(s->clksel[6] & 3))
|
||||
return 0x00000377;
|
||||
/* DPLL not in lock mode, core uses ref_clk */
|
||||
if ((s->clken[9] & 3) != 3)
|
||||
return 0x00000375;
|
||||
/* Core uses DPLL */
|
||||
return 0x00000376;
|
||||
/* Core uses 32-kHz clock */
|
||||
ret |= 3 << 0;
|
||||
else if (!s->dpll_lock)
|
||||
/* DPLL not locked, core uses ref_clk */
|
||||
ret |= 1 << 0;
|
||||
else
|
||||
/* Core uses DPLL */
|
||||
ret |= 2 << 0;
|
||||
return ret;
|
||||
case 0x530: /* CM_AUTOIDLE_PLL */
|
||||
return s->clkidle[5];
|
||||
case 0x540: /* CM_CLKSEL1_PLL */
|
||||
@ -2976,6 +2982,69 @@ static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void omap_prcm_apll_update(struct omap_prcm_s *s)
|
||||
{
|
||||
int mode[2];
|
||||
|
||||
mode[0] = (s->clken[9] >> 6) & 3;
|
||||
s->apll_lock[0] = (mode[0] == 3);
|
||||
mode[1] = (s->clken[9] >> 2) & 3;
|
||||
s->apll_lock[1] = (mode[1] == 3);
|
||||
/* TODO: update clocks */
|
||||
|
||||
if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[2] == 2)
|
||||
fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n",
|
||||
__FUNCTION__);
|
||||
}
|
||||
|
||||
static void omap_prcm_dpll_update(struct omap_prcm_s *s)
|
||||
{
|
||||
omap_clk dpll = omap_findclk(s->mpu, "dpll");
|
||||
omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll");
|
||||
omap_clk core = omap_findclk(s->mpu, "core_clk");
|
||||
int mode = (s->clken[9] >> 0) & 3;
|
||||
int mult, div;
|
||||
|
||||
mult = (s->clksel[5] >> 12) & 0x3ff;
|
||||
div = (s->clksel[5] >> 8) & 0xf;
|
||||
if (mult == 0 || mult == 1)
|
||||
mode = 1; /* Bypass */
|
||||
|
||||
s->dpll_lock = 0;
|
||||
switch (mode) {
|
||||
case 0:
|
||||
fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__);
|
||||
break;
|
||||
case 1: /* Low-power bypass mode (Default) */
|
||||
case 2: /* Fast-relock bypass mode */
|
||||
omap_clk_setrate(dpll, 1, 1);
|
||||
omap_clk_setrate(dpll_x2, 1, 1);
|
||||
break;
|
||||
case 3: /* Lock mode */
|
||||
s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */
|
||||
|
||||
omap_clk_setrate(dpll, div + 1, mult);
|
||||
omap_clk_setrate(dpll_x2, div + 1, mult * 2);
|
||||
break;
|
||||
}
|
||||
|
||||
switch ((s->clksel[6] >> 0) & 3) {
|
||||
case 0:
|
||||
omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz"));
|
||||
break;
|
||||
case 1:
|
||||
omap_clk_reparent(core, dpll);
|
||||
break;
|
||||
case 2:
|
||||
/* Default */
|
||||
omap_clk_reparent(core, dpll_x2);
|
||||
break;
|
||||
case 3:
|
||||
fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void omap_prcm_write(void *opaque, target_phys_addr_t addr,
|
||||
uint32_t value)
|
||||
{
|
||||
@ -3235,20 +3304,44 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr,
|
||||
break;
|
||||
|
||||
case 0x500: /* CM_CLKEN_PLL */
|
||||
s->clken[9] = value & 0xcf;
|
||||
/* TODO update clocks */
|
||||
if (value & 0xffffff30)
|
||||
fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for "
|
||||
"future compatiblity\n", __FUNCTION__);
|
||||
if ((s->clken[9] ^ value) & 0xcc) {
|
||||
s->clken[9] &= ~0xcc;
|
||||
s->clken[9] |= value & 0xcc;
|
||||
omap_prcm_apll_update(s);
|
||||
}
|
||||
if ((s->clken[9] ^ value) & 3) {
|
||||
s->clken[9] &= ~3;
|
||||
s->clken[9] |= value & 3;
|
||||
omap_prcm_dpll_update(s);
|
||||
}
|
||||
break;
|
||||
case 0x530: /* CM_AUTOIDLE_PLL */
|
||||
s->clkidle[5] = value & 0x000000cf;
|
||||
/* TODO update clocks */
|
||||
break;
|
||||
case 0x540: /* CM_CLKSEL1_PLL */
|
||||
if (value & 0xfc4000d7)
|
||||
fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for "
|
||||
"future compatiblity\n", __FUNCTION__);
|
||||
if ((s->clksel[5] ^ value) & 0x003fff00) {
|
||||
s->clksel[5] = value & 0x03bfff28;
|
||||
omap_prcm_dpll_update(s);
|
||||
}
|
||||
/* TODO update the other clocks */
|
||||
|
||||
s->clksel[5] = value & 0x03bfff28;
|
||||
/* TODO update clocks */
|
||||
break;
|
||||
case 0x544: /* CM_CLKSEL2_PLL */
|
||||
s->clksel[6] = value & 3;
|
||||
/* TODO update clocks */
|
||||
if (value & ~3)
|
||||
fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for "
|
||||
"future compatiblity\n", __FUNCTION__);
|
||||
if (s->clksel[6] != (value & 3)) {
|
||||
s->clksel[6] = value & 3;
|
||||
omap_prcm_dpll_update(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x800: /* CM_FCLKEN_DSP */
|
||||
@ -3373,6 +3466,8 @@ static void omap_prcm_reset(struct omap_prcm_s *s)
|
||||
s->power[3] = 0x14;
|
||||
s->rstctrl[0] = 1;
|
||||
s->rst[3] = 1;
|
||||
omap_prcm_apll_update(s);
|
||||
omap_prcm_dpll_update(s);
|
||||
}
|
||||
|
||||
static void omap_prcm_coldreset(struct omap_prcm_s *s)
|
||||
|
@ -510,18 +510,25 @@ static struct clk clk32k = {
|
||||
.parent = &xtal_osc32k,
|
||||
};
|
||||
|
||||
static struct clk ref_clk = {
|
||||
.name = "ref_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */
|
||||
/*.parent = sys.xtalin */
|
||||
};
|
||||
|
||||
static struct clk apll_96m = {
|
||||
.name = "apll_96m",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 96000000,
|
||||
/*.parent = sys.xtalin */
|
||||
/*.parent = ref_clk */
|
||||
};
|
||||
|
||||
static struct clk apll_54m = {
|
||||
.name = "apll_54m",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
.rate = 54000000,
|
||||
/*.parent = sys.xtalin */
|
||||
/*.parent = ref_clk */
|
||||
};
|
||||
|
||||
static struct clk sys_clk = {
|
||||
@ -541,13 +548,13 @@ static struct clk sleep_clk = {
|
||||
static struct clk dpll_ck = {
|
||||
.name = "dpll",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
/*.parent = sys.xtalin */
|
||||
.parent = &ref_clk,
|
||||
};
|
||||
|
||||
static struct clk dpll_x2_ck = {
|
||||
.name = "dpll_x2",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
|
||||
/*.parent = sys.xtalin */
|
||||
.parent = &ref_clk,
|
||||
};
|
||||
|
||||
static struct clk wdt1_sys_clk = {
|
||||
@ -600,7 +607,7 @@ static struct clk sys_clkout2 = {
|
||||
static struct clk core_clk = {
|
||||
.name = "core_clk",
|
||||
.flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
|
||||
.parent = &dpll_ck,
|
||||
.parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */
|
||||
};
|
||||
|
||||
static struct clk l3_clk = {
|
||||
@ -1009,6 +1016,7 @@ static struct clk *onchip_clks[] = {
|
||||
|
||||
/* OMAP 2 */
|
||||
|
||||
&ref_clk,
|
||||
&apll_96m,
|
||||
&apll_54m,
|
||||
&sys_clk,
|
||||
|
@ -395,6 +395,7 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
|
||||
(~value >> 9) & 1); /* TRX */
|
||||
s->stat |= nack << 1; /* NACK */
|
||||
s->control &= ~(1 << 0); /* STT */
|
||||
s->fifo = 0;
|
||||
if (nack)
|
||||
s->control &= ~(1 << 1); /* STP */
|
||||
else {
|
||||
|
Loading…
Reference in New Issue
Block a user