Commit 51fec3cc7eb7a9c8e1be2f2bb971db303d17ea61

Authored by balrog
1 parent 74b9decc

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
hw/omap2.c
... ... @@ -2727,6 +2727,8 @@ struct omap_prcm_s {
2727 2727  
2728 2728 uint32_t ev;
2729 2729 uint32_t evtime[2];
  2730 +
  2731 + int dpll_lock, apll_lock[2];
2730 2732 };
2731 2733  
2732 2734 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)
2739 2741 {
2740 2742 struct omap_prcm_s *s = (struct omap_prcm_s *) opaque;
2741 2743 int offset = addr - s->base;
  2744 + uint32_t ret;
2742 2745  
2743 2746 switch (offset) {
2744 2747 case 0x000: /* PRCM_REVISION */
... ... @@ -2922,14 +2925,17 @@ static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr)
2922 2925 case 0x500: /* CM_CLKEN_PLL */
2923 2926 return s->clken[9];
2924 2927 case 0x520: /* CM_IDLEST_CKGEN */
2925   - /* Core uses 32-kHz clock */
  2928 + ret = 0x0000070 | (s->apll_lock[0] << 9) | (s->apll_lock[1] << 8);
2926 2929 if (!(s->clksel[6] & 3))
2927   - return 0x00000377;
2928   - /* DPLL not in lock mode, core uses ref_clk */
2929   - if ((s->clken[9] & 3) != 3)
2930   - return 0x00000375;
2931   - /* Core uses DPLL */
2932   - return 0x00000376;
  2930 + /* Core uses 32-kHz clock */
  2931 + ret |= 3 << 0;
  2932 + else if (!s->dpll_lock)
  2933 + /* DPLL not locked, core uses ref_clk */
  2934 + ret |= 1 << 0;
  2935 + else
  2936 + /* Core uses DPLL */
  2937 + ret |= 2 << 0;
  2938 + return ret;
2933 2939 case 0x530: /* CM_AUTOIDLE_PLL */
2934 2940 return s->clkidle[5];
2935 2941 case 0x540: /* CM_CLKSEL1_PLL */
... ... @@ -2976,6 +2982,69 @@ static uint32_t omap_prcm_read(void *opaque, target_phys_addr_t addr)
2976 2982 return 0;
2977 2983 }
2978 2984  
  2985 +static void omap_prcm_apll_update(struct omap_prcm_s *s)
  2986 +{
  2987 + int mode[2];
  2988 +
  2989 + mode[0] = (s->clken[9] >> 6) & 3;
  2990 + s->apll_lock[0] = (mode[0] == 3);
  2991 + mode[1] = (s->clken[9] >> 2) & 3;
  2992 + s->apll_lock[1] = (mode[1] == 3);
  2993 + /* TODO: update clocks */
  2994 +
  2995 + if (mode[0] == 1 || mode[0] == 2 || mode[1] == 1 || mode[2] == 2)
  2996 + fprintf(stderr, "%s: bad EN_54M_PLL or bad EN_96M_PLL\n",
  2997 + __FUNCTION__);
  2998 +}
  2999 +
  3000 +static void omap_prcm_dpll_update(struct omap_prcm_s *s)
  3001 +{
  3002 + omap_clk dpll = omap_findclk(s->mpu, "dpll");
  3003 + omap_clk dpll_x2 = omap_findclk(s->mpu, "dpll");
  3004 + omap_clk core = omap_findclk(s->mpu, "core_clk");
  3005 + int mode = (s->clken[9] >> 0) & 3;
  3006 + int mult, div;
  3007 +
  3008 + mult = (s->clksel[5] >> 12) & 0x3ff;
  3009 + div = (s->clksel[5] >> 8) & 0xf;
  3010 + if (mult == 0 || mult == 1)
  3011 + mode = 1; /* Bypass */
  3012 +
  3013 + s->dpll_lock = 0;
  3014 + switch (mode) {
  3015 + case 0:
  3016 + fprintf(stderr, "%s: bad EN_DPLL\n", __FUNCTION__);
  3017 + break;
  3018 + case 1: /* Low-power bypass mode (Default) */
  3019 + case 2: /* Fast-relock bypass mode */
  3020 + omap_clk_setrate(dpll, 1, 1);
  3021 + omap_clk_setrate(dpll_x2, 1, 1);
  3022 + break;
  3023 + case 3: /* Lock mode */
  3024 + s->dpll_lock = 1; /* After 20 FINT cycles (ref_clk / (div + 1)). */
  3025 +
  3026 + omap_clk_setrate(dpll, div + 1, mult);
  3027 + omap_clk_setrate(dpll_x2, div + 1, mult * 2);
  3028 + break;
  3029 + }
  3030 +
  3031 + switch ((s->clksel[6] >> 0) & 3) {
  3032 + case 0:
  3033 + omap_clk_reparent(core, omap_findclk(s->mpu, "clk32-kHz"));
  3034 + break;
  3035 + case 1:
  3036 + omap_clk_reparent(core, dpll);
  3037 + break;
  3038 + case 2:
  3039 + /* Default */
  3040 + omap_clk_reparent(core, dpll_x2);
  3041 + break;
  3042 + case 3:
  3043 + fprintf(stderr, "%s: bad CORE_CLK_SRC\n", __FUNCTION__);
  3044 + break;
  3045 + }
  3046 +}
  3047 +
2979 3048 static void omap_prcm_write(void *opaque, target_phys_addr_t addr,
2980 3049 uint32_t value)
2981 3050 {
... ... @@ -3235,20 +3304,44 @@ static void omap_prcm_write(void *opaque, target_phys_addr_t addr,
3235 3304 break;
3236 3305  
3237 3306 case 0x500: /* CM_CLKEN_PLL */
3238   - s->clken[9] = value & 0xcf;
3239   - /* TODO update clocks */
  3307 + if (value & 0xffffff30)
  3308 + fprintf(stderr, "%s: write 0s in CM_CLKEN_PLL for "
  3309 + "future compatiblity\n", __FUNCTION__);
  3310 + if ((s->clken[9] ^ value) & 0xcc) {
  3311 + s->clken[9] &= ~0xcc;
  3312 + s->clken[9] |= value & 0xcc;
  3313 + omap_prcm_apll_update(s);
  3314 + }
  3315 + if ((s->clken[9] ^ value) & 3) {
  3316 + s->clken[9] &= ~3;
  3317 + s->clken[9] |= value & 3;
  3318 + omap_prcm_dpll_update(s);
  3319 + }
3240 3320 break;
3241 3321 case 0x530: /* CM_AUTOIDLE_PLL */
3242 3322 s->clkidle[5] = value & 0x000000cf;
3243 3323 /* TODO update clocks */
3244 3324 break;
3245 3325 case 0x540: /* CM_CLKSEL1_PLL */
  3326 + if (value & 0xfc4000d7)
  3327 + fprintf(stderr, "%s: write 0s in CM_CLKSEL1_PLL for "
  3328 + "future compatiblity\n", __FUNCTION__);
  3329 + if ((s->clksel[5] ^ value) & 0x003fff00) {
  3330 + s->clksel[5] = value & 0x03bfff28;
  3331 + omap_prcm_dpll_update(s);
  3332 + }
  3333 + /* TODO update the other clocks */
  3334 +
3246 3335 s->clksel[5] = value & 0x03bfff28;
3247   - /* TODO update clocks */
3248 3336 break;
3249 3337 case 0x544: /* CM_CLKSEL2_PLL */
3250   - s->clksel[6] = value & 3;
3251   - /* TODO update clocks */
  3338 + if (value & ~3)
  3339 + fprintf(stderr, "%s: write 0s in CM_CLKSEL2_PLL[31:2] for "
  3340 + "future compatiblity\n", __FUNCTION__);
  3341 + if (s->clksel[6] != (value & 3)) {
  3342 + s->clksel[6] = value & 3;
  3343 + omap_prcm_dpll_update(s);
  3344 + }
3252 3345 break;
3253 3346  
3254 3347 case 0x800: /* CM_FCLKEN_DSP */
... ... @@ -3373,6 +3466,8 @@ static void omap_prcm_reset(struct omap_prcm_s *s)
3373 3466 s->power[3] = 0x14;
3374 3467 s->rstctrl[0] = 1;
3375 3468 s->rst[3] = 1;
  3469 + omap_prcm_apll_update(s);
  3470 + omap_prcm_dpll_update(s);
3376 3471 }
3377 3472  
3378 3473 static void omap_prcm_coldreset(struct omap_prcm_s *s)
... ...
hw/omap_clk.c
... ... @@ -510,18 +510,25 @@ static struct clk clk32k = {
510 510 .parent = &xtal_osc32k,
511 511 };
512 512  
  513 +static struct clk ref_clk = {
  514 + .name = "ref_clk",
  515 + .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
  516 + .rate = 12000000, /* 12 MHz or 13 MHz or 19.2 MHz */
  517 + /*.parent = sys.xtalin */
  518 +};
  519 +
513 520 static struct clk apll_96m = {
514 521 .name = "apll_96m",
515 522 .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
516 523 .rate = 96000000,
517   - /*.parent = sys.xtalin */
  524 + /*.parent = ref_clk */
518 525 };
519 526  
520 527 static struct clk apll_54m = {
521 528 .name = "apll_54m",
522 529 .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
523 530 .rate = 54000000,
524   - /*.parent = sys.xtalin */
  531 + /*.parent = ref_clk */
525 532 };
526 533  
527 534 static struct clk sys_clk = {
... ... @@ -541,13 +548,13 @@ static struct clk sleep_clk = {
541 548 static struct clk dpll_ck = {
542 549 .name = "dpll",
543 550 .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
544   - /*.parent = sys.xtalin */
  551 + .parent = &ref_clk,
545 552 };
546 553  
547 554 static struct clk dpll_x2_ck = {
548 555 .name = "dpll_x2",
549 556 .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X | ALWAYS_ENABLED,
550   - /*.parent = sys.xtalin */
  557 + .parent = &ref_clk,
551 558 };
552 559  
553 560 static struct clk wdt1_sys_clk = {
... ... @@ -600,7 +607,7 @@ static struct clk sys_clkout2 = {
600 607 static struct clk core_clk = {
601 608 .name = "core_clk",
602 609 .flags = CLOCK_IN_OMAP242X | CLOCK_IN_OMAP243X,
603   - .parent = &dpll_ck,
  610 + .parent = &dpll_x2_ck, /* Switchable between dpll_ck and clk32k */
604 611 };
605 612  
606 613 static struct clk l3_clk = {
... ... @@ -1009,6 +1016,7 @@ static struct clk *onchip_clks[] = {
1009 1016  
1010 1017 /* OMAP 2 */
1011 1018  
  1019 + &ref_clk,
1012 1020 &apll_96m,
1013 1021 &apll_54m,
1014 1022 &sys_clk,
... ...
hw/omap_i2c.c
... ... @@ -395,6 +395,7 @@ static void omap_i2c_write(void *opaque, target_phys_addr_t addr,
395 395 (~value >> 9) & 1); /* TRX */
396 396 s->stat |= nack << 1; /* NACK */
397 397 s->control &= ~(1 << 0); /* STT */
  398 + s->fifo = 0;
398 399 if (nack)
399 400 s->control &= ~(1 << 1); /* STP */
400 401 else {
... ...