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:
balrog 2008-07-21 19:52:54 +00:00
parent 74b9decc47
commit 51fec3cc7e
3 changed files with 121 additions and 17 deletions

View file

@ -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)

View file

@ -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,

View file

@ -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 {