From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1KL1RJ-00013h-AZ for qemu-devel@nongnu.org; Mon, 21 Jul 2008 15:52:57 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1KL1RI-00013D-Du for qemu-devel@nongnu.org; Mon, 21 Jul 2008 15:52:56 -0400 Received: from [199.232.76.173] (port=33969 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1KL1RI-000134-7Z for qemu-devel@nongnu.org; Mon, 21 Jul 2008 15:52:56 -0400 Received: from savannah.gnu.org ([199.232.41.3]:60330 helo=sv.gnu.org) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1KL1RH-0001gZ-Uc for qemu-devel@nongnu.org; Mon, 21 Jul 2008 15:52:56 -0400 Received: from cvs.savannah.gnu.org ([199.232.41.69]) by sv.gnu.org with esmtp (Exim 4.63) (envelope-from ) id 1KL1RH-000218-0w for qemu-devel@nongnu.org; Mon, 21 Jul 2008 19:52:55 +0000 Received: from balrog by cvs.savannah.gnu.org with local (Exim 4.63) (envelope-from ) id 1KL1RG-000213-LH for qemu-devel@nongnu.org; Mon, 21 Jul 2008 19:52:54 +0000 MIME-Version: 1.0 Errors-To: balrog Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From: Andrzej Zaborowski Message-Id: Date: Mon, 21 Jul 2008 19:52:54 +0000 Subject: [Qemu-devel] [4919] Omap DPLL & APLL locking logic. Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Revision: 4919 http://svn.sv.gnu.org/viewvc/?view=rev&root=qemu&revision=4919 Author: balrog Date: 2008-07-21 19:52:54 +0000 (Mon, 21 Jul 2008) Log Message: ----------- Omap DPLL & APLL locking logic. Reset I2C fifo on new transfers. Modified Paths: -------------- trunk/hw/omap2.c trunk/hw/omap_clk.c trunk/hw/omap_i2c.c Modified: trunk/hw/omap2.c =================================================================== --- trunk/hw/omap2.c 2008-07-21 18:43:32 UTC (rev 4918) +++ trunk/hw/omap2.c 2008-07-21 19:52:54 UTC (rev 4919) @@ -2727,6 +2727,8 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ 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) Modified: trunk/hw/omap_clk.c =================================================================== --- trunk/hw/omap_clk.c 2008-07-21 18:43:32 UTC (rev 4918) +++ trunk/hw/omap_clk.c 2008-07-21 19:52:54 UTC (rev 4919) @@ -510,18 +510,25 @@ .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 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 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 @@ /* OMAP 2 */ + &ref_clk, &apll_96m, &apll_54m, &sys_clk, Modified: trunk/hw/omap_i2c.c =================================================================== --- trunk/hw/omap_i2c.c 2008-07-21 18:43:32 UTC (rev 4918) +++ trunk/hw/omap_i2c.c 2008-07-21 19:52:54 UTC (rev 4919) @@ -395,6 +395,7 @@ (~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 {