qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [4919] Omap DPLL & APLL locking logic.


From: Andrzej Zaborowski
Subject: [Qemu-devel] [4919] Omap DPLL & APLL locking logic.
Date: Mon, 21 Jul 2008 19:52:54 +0000

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 {






reply via email to

[Prev in Thread] Current Thread [Next in Thread]