Commit 51fec3cc7eb7a9c8e1be2f2bb971db303d17ea61
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
Showing
3 changed files
with
121 additions
and
17 deletions
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 { | ... | ... |