aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>2008-07-21 19:52:54 +0000
committerbalrog <balrog@c046a42c-6fe2-441c-8c8c-71466251a162>2008-07-21 19:52:54 +0000
commit51fec3cc7eb7a9c8e1be2f2bb971db303d17ea61 (patch)
tree292aa91fc9ced21ff6377e80d0942e29ba81e527
parent74b9decc473177f16cb84b3504ad8169f13ec147 (diff)
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
-rw-r--r--hw/omap2.c119
-rw-r--r--hw/omap_clk.c18
-rw-r--r--hw/omap_i2c.c1
3 files changed, 121 insertions, 17 deletions
diff --git a/hw/omap2.c b/hw/omap2.c
index ce5955fecc..8c9ac6a81e 100644
--- a/hw/omap2.c
+++ b/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)
diff --git a/hw/omap_clk.c b/hw/omap_clk.c
index da03e156e6..13d7411838 100644
--- a/hw/omap_clk.c
+++ b/hw/omap_clk.c
@@ -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,
diff --git a/hw/omap_i2c.c b/hw/omap_i2c.c
index f3ccbf0549..127e69ca0a 100644
--- a/hw/omap_i2c.c
+++ b/hw/omap_i2c.c
@@ -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 {