linux/arch/arm/mach-omap2/clock.c
<<
>>
Prefs
   1/*
   2 *  linux/arch/arm/mach-omap2/clock.c
   3 *
   4 *  Copyright (C) 2005 Texas Instruments Inc.
   5 *  Richard Woodruff <r-woodruff2@ti.com>
   6 *  Created for OMAP2.
   7 *
   8 *  Cleaned up and modified to use omap shared clock framework by
   9 *  Tony Lindgren <tony@atomide.com>
  10 *
  11 *  Based on omap1 clock.c, Copyright (C) 2004 - 2005 Nokia corporation
  12 *  Written by Tuukka Tikkanen <tuukka.tikkanen@elektrobit.com>
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License version 2 as
  16 * published by the Free Software Foundation.
  17 */
  18#include <linux/module.h>
  19#include <linux/kernel.h>
  20#include <linux/device.h>
  21#include <linux/list.h>
  22#include <linux/errno.h>
  23#include <linux/delay.h>
  24#include <linux/clk.h>
  25
  26#include <asm/io.h>
  27
  28#include <asm/arch/clock.h>
  29#include <asm/arch/sram.h>
  30#include <asm/div64.h>
  31
  32#include "prcm-regs.h"
  33#include "memory.h"
  34#include "clock.h"
  35
  36#undef DEBUG
  37
  38//#define DOWN_VARIABLE_DPLL 1                  /* Experimental */
  39
  40static struct prcm_config *curr_prcm_set;
  41static u32 curr_perf_level = PRCM_FULL_SPEED;
  42static struct clk *vclk;
  43static struct clk *sclk;
  44
  45/*-------------------------------------------------------------------------
  46 * Omap2 specific clock functions
  47 *-------------------------------------------------------------------------*/
  48
  49/* Recalculate SYST_CLK */
  50static void omap2_sys_clk_recalc(struct clk * clk)
  51{
  52        u32 div = PRCM_CLKSRC_CTRL;
  53        div &= (1 << 7) | (1 << 6);     /* Test if ext clk divided by 1 or 2 */
  54        div >>= clk->rate_offset;
  55        clk->rate = (clk->parent->rate / div);
  56        propagate_rate(clk);
  57}
  58
  59static u32 omap2_get_dpll_rate(struct clk * tclk)
  60{
  61        long long dpll_clk;
  62        int dpll_mult, dpll_div, amult;
  63
  64        dpll_mult = (CM_CLKSEL1_PLL >> 12) & 0x03ff;    /* 10 bits */
  65        dpll_div = (CM_CLKSEL1_PLL >> 8) & 0x0f;        /* 4 bits */
  66        dpll_clk = (long long)tclk->parent->rate * dpll_mult;
  67        do_div(dpll_clk, dpll_div + 1);
  68        amult = CM_CLKSEL2_PLL & 0x3;
  69        dpll_clk *= amult;
  70
  71        return dpll_clk;
  72}
  73
  74static void omap2_followparent_recalc(struct clk *clk)
  75{
  76        followparent_recalc(clk);
  77}
  78
  79static void omap2_propagate_rate(struct clk * clk)
  80{
  81        if (!(clk->flags & RATE_FIXED))
  82                clk->rate = clk->parent->rate;
  83
  84        propagate_rate(clk);
  85}
  86
  87static void omap2_set_osc_ck(int enable)
  88{
  89        if (enable)
  90                PRCM_CLKSRC_CTRL &= ~(0x3 << 3);
  91        else
  92                PRCM_CLKSRC_CTRL |= 0x3 << 3;
  93}
  94
  95/* Enable an APLL if off */
  96static void omap2_clk_fixed_enable(struct clk *clk)
  97{
  98        u32 cval, i=0;
  99
 100        if (clk->enable_bit == 0xff)                    /* Parent will do it */
 101                return;
 102
 103        cval = CM_CLKEN_PLL;
 104
 105        if ((cval & (0x3 << clk->enable_bit)) == (0x3 << clk->enable_bit))
 106                return;
 107
 108        cval &= ~(0x3 << clk->enable_bit);
 109        cval |= (0x3 << clk->enable_bit);
 110        CM_CLKEN_PLL = cval;
 111
 112        if (clk == &apll96_ck)
 113                cval = (1 << 8);
 114        else if (clk == &apll54_ck)
 115                cval = (1 << 6);
 116
 117        while (!(CM_IDLEST_CKGEN & cval)) {             /* Wait for lock */
 118                ++i;
 119                udelay(1);
 120                if (i == 100000) {
 121                        printk(KERN_ERR "Clock %s didn't lock\n", clk->name);
 122                        break;
 123                }
 124        }
 125}
 126
 127static void omap2_clk_wait_ready(struct clk *clk)
 128{
 129        unsigned long reg, other_reg, st_reg;
 130        u32 bit;
 131        int i;
 132
 133        reg = (unsigned long) clk->enable_reg;
 134        if (reg == (unsigned long) &CM_FCLKEN1_CORE ||
 135            reg == (unsigned long) &CM_FCLKEN2_CORE)
 136                other_reg = (reg & ~0xf0) | 0x10;
 137        else if (reg == (unsigned long) &CM_ICLKEN1_CORE ||
 138                 reg == (unsigned long) &CM_ICLKEN2_CORE)
 139                other_reg = (reg & ~0xf0) | 0x00;
 140        else
 141                return;
 142
 143        /* No check for DSS or cam clocks */
 144        if ((reg & 0x0f) == 0) {
 145                if (clk->enable_bit <= 1 || clk->enable_bit == 31)
 146                        return;
 147        }
 148
 149        /* Check if both functional and interface clocks
 150         * are running. */
 151        bit = 1 << clk->enable_bit;
 152        if (!(__raw_readl(other_reg) & bit))
 153                return;
 154        st_reg = (other_reg & ~0xf0) | 0x20;
 155        i = 0;
 156        while (!(__raw_readl(st_reg) & bit)) {
 157                i++;
 158                if (i == 100000) {
 159                        printk(KERN_ERR "Timeout enabling clock %s\n", clk->name);
 160                        break;
 161                }
 162        }
 163        if (i)
 164                pr_debug("Clock %s stable after %d loops\n", clk->name, i);
 165}
 166
 167/* Enables clock without considering parent dependencies or use count
 168 * REVISIT: Maybe change this to use clk->enable like on omap1?
 169 */
 170static int _omap2_clk_enable(struct clk * clk)
 171{
 172        u32 regval32;
 173
 174        if (clk->flags & ALWAYS_ENABLED)
 175                return 0;
 176
 177        if (unlikely(clk == &osc_ck)) {
 178                omap2_set_osc_ck(1);
 179                return 0;
 180        }
 181
 182        if (unlikely(clk->enable_reg == 0)) {
 183                printk(KERN_ERR "clock.c: Enable for %s without enable code\n",
 184                       clk->name);
 185                return 0;
 186        }
 187
 188        if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) {
 189                omap2_clk_fixed_enable(clk);
 190                return 0;
 191        }
 192
 193        regval32 = __raw_readl(clk->enable_reg);
 194        regval32 |= (1 << clk->enable_bit);
 195        __raw_writel(regval32, clk->enable_reg);
 196        wmb();
 197
 198        omap2_clk_wait_ready(clk);
 199
 200        return 0;
 201}
 202
 203/* Stop APLL */
 204static void omap2_clk_fixed_disable(struct clk *clk)
 205{
 206        u32 cval;
 207
 208        if(clk->enable_bit == 0xff)             /* let parent off do it */
 209                return;
 210
 211        cval = CM_CLKEN_PLL;
 212        cval &= ~(0x3 << clk->enable_bit);
 213        CM_CLKEN_PLL = cval;
 214}
 215
 216/* Disables clock without considering parent dependencies or use count */
 217static void _omap2_clk_disable(struct clk *clk)
 218{
 219        u32 regval32;
 220
 221        if (unlikely(clk == &osc_ck)) {
 222                omap2_set_osc_ck(0);
 223                return;
 224        }
 225
 226        if (clk->enable_reg == 0)
 227                return;
 228
 229        if (clk->enable_reg == (void __iomem *)&CM_CLKEN_PLL) {
 230                omap2_clk_fixed_disable(clk);
 231                return;
 232        }
 233
 234        regval32 = __raw_readl(clk->enable_reg);
 235        regval32 &= ~(1 << clk->enable_bit);
 236        __raw_writel(regval32, clk->enable_reg);
 237        wmb();
 238}
 239
 240static int omap2_clk_enable(struct clk *clk)
 241{
 242        int ret = 0;
 243
 244        if (clk->usecount++ == 0) {
 245                if (likely((u32)clk->parent))
 246                        ret = omap2_clk_enable(clk->parent);
 247
 248                if (unlikely(ret != 0)) {
 249                        clk->usecount--;
 250                        return ret;
 251                }
 252
 253                ret = _omap2_clk_enable(clk);
 254
 255                if (unlikely(ret != 0) && clk->parent) {
 256                        omap2_clk_disable(clk->parent);
 257                        clk->usecount--;
 258                }
 259        }
 260
 261        return ret;
 262}
 263
 264static void omap2_clk_disable(struct clk *clk)
 265{
 266        if (clk->usecount > 0 && !(--clk->usecount)) {
 267                _omap2_clk_disable(clk);
 268                if (likely((u32)clk->parent))
 269                        omap2_clk_disable(clk->parent);
 270        }
 271}
 272
 273/*
 274 * Uses the current prcm set to tell if a rate is valid.
 275 * You can go slower, but not faster within a given rate set.
 276 */
 277static u32 omap2_dpll_round_rate(unsigned long target_rate)
 278{
 279        u32 high, low;
 280
 281        if ((CM_CLKSEL2_PLL & 0x3) == 1) {      /* DPLL clockout */
 282                high = curr_prcm_set->dpll_speed * 2;
 283                low = curr_prcm_set->dpll_speed;
 284        } else {                                /* DPLL clockout x 2 */
 285                high = curr_prcm_set->dpll_speed;
 286                low = curr_prcm_set->dpll_speed / 2;
 287        }
 288
 289#ifdef DOWN_VARIABLE_DPLL
 290        if (target_rate > high)
 291                return high;
 292        else
 293                return target_rate;
 294#else
 295        if (target_rate > low)
 296                return high;
 297        else
 298                return low;
 299#endif
 300
 301}
 302
 303/*
 304 * Used for clocks that are part of CLKSEL_xyz governed clocks.
 305 * REVISIT: Maybe change to use clk->enable() functions like on omap1?
 306 */
 307static void omap2_clksel_recalc(struct clk * clk)
 308{
 309        u32 fixed = 0, div = 0;
 310
 311        if (clk == &dpll_ck) {
 312                clk->rate = omap2_get_dpll_rate(clk);
 313                fixed = 1;
 314                div = 0;
 315        }
 316
 317        if (clk == &iva1_mpu_int_ifck) {
 318                div = 2;
 319                fixed = 1;
 320        }
 321
 322        if ((clk == &dss1_fck) && ((CM_CLKSEL1_CORE & (0x1f << 8)) == 0)) {
 323                clk->rate = sys_ck.rate;
 324                return;
 325        }
 326
 327        if (!fixed) {
 328                div = omap2_clksel_get_divisor(clk);
 329                if (div == 0)
 330                        return;
 331        }
 332
 333        if (div != 0) {
 334                if (unlikely(clk->rate == clk->parent->rate / div))
 335                        return;
 336                clk->rate = clk->parent->rate / div;
 337        }
 338
 339        if (unlikely(clk->flags & RATE_PROPAGATES))
 340                propagate_rate(clk);
 341}
 342
 343/*
 344 * Finds best divider value in an array based on the source and target
 345 * rates. The divider array must be sorted with smallest divider first.
 346 */
 347static inline u32 omap2_divider_from_table(u32 size, u32 *div_array,
 348                                           u32 src_rate, u32 tgt_rate)
 349{
 350        int i, test_rate;
 351
 352        if (div_array == NULL)
 353                return ~1;
 354
 355        for (i=0; i < size; i++) {
 356                test_rate = src_rate / *div_array;
 357                if (test_rate <= tgt_rate)
 358                        return *div_array;
 359                ++div_array;
 360        }
 361
 362        return ~0;      /* No acceptable divider */
 363}
 364
 365/*
 366 * Find divisor for the given clock and target rate.
 367 *
 368 * Note that this will not work for clocks which are part of CONFIG_PARTICIPANT,
 369 * they are only settable as part of virtual_prcm set.
 370 */
 371static u32 omap2_clksel_round_rate(struct clk *tclk, u32 target_rate,
 372        u32 *new_div)
 373{
 374        u32 gfx_div[] = {2, 3, 4};
 375        u32 sysclkout_div[] = {1, 2, 4, 8, 16};
 376        u32 dss1_div[] = {1, 2, 3, 4, 5, 6, 8, 9, 12, 16};
 377        u32 vylnq_div[] = {1, 2, 3, 4, 6, 8, 9, 12, 16, 18};
 378        u32 best_div = ~0, asize = 0;
 379        u32 *div_array = NULL;
 380
 381        switch (tclk->flags & SRC_RATE_SEL_MASK) {
 382        case CM_GFX_SEL1:
 383                asize = 3;
 384                div_array = gfx_div;
 385                break;
 386        case CM_PLL_SEL1:
 387                return omap2_dpll_round_rate(target_rate);
 388        case CM_SYSCLKOUT_SEL1:
 389                asize = 5;
 390                div_array = sysclkout_div;
 391                break;
 392        case CM_CORE_SEL1:
 393                if(tclk == &dss1_fck){
 394                        if(tclk->parent == &core_ck){
 395                                asize = 10;
 396                                div_array = dss1_div;
 397                        } else {
 398                                *new_div = 0; /* fixed clk */
 399                                return(tclk->parent->rate);
 400                        }
 401                } else if((tclk == &vlynq_fck) && cpu_is_omap2420()){
 402                        if(tclk->parent == &core_ck){
 403                                asize = 10;
 404                                div_array = vylnq_div;
 405                        } else {
 406                                *new_div = 0; /* fixed clk */
 407                                return(tclk->parent->rate);
 408                        }
 409                }
 410                break;
 411        }
 412
 413        best_div = omap2_divider_from_table(asize, div_array,
 414         tclk->parent->rate, target_rate);
 415        if (best_div == ~0){
 416                *new_div = 1;
 417                return best_div; /* signal error */
 418        }
 419
 420        *new_div = best_div;
 421        return (tclk->parent->rate / best_div);
 422}
 423
 424/* Given a clock and a rate apply a clock specific rounding function */
 425static long omap2_clk_round_rate(struct clk *clk, unsigned long rate)
 426{
 427        u32 new_div = 0;
 428        int valid_rate;
 429
 430        if (clk->flags & RATE_FIXED)
 431                return clk->rate;
 432
 433        if (clk->flags & RATE_CKCTL) {
 434                valid_rate = omap2_clksel_round_rate(clk, rate, &new_div);
 435                return valid_rate;
 436        }
 437
 438        if (clk->round_rate != 0)
 439                return clk->round_rate(clk, rate);
 440
 441        return clk->rate;
 442}
 443
 444/*
 445 * Check the DLL lock state, and return tue if running in unlock mode.
 446 * This is needed to compensate for the shifted DLL value in unlock mode.
 447 */
 448static u32 omap2_dll_force_needed(void)
 449{
 450        u32 dll_state = SDRC_DLLA_CTRL;         /* dlla and dllb are a set */
 451
 452        if ((dll_state & (1 << 2)) == (1 << 2))
 453                return 1;
 454        else
 455                return 0;
 456}
 457
 458static u32 omap2_reprogram_sdrc(u32 level, u32 force)
 459{
 460        u32 slow_dll_ctrl, fast_dll_ctrl, m_type;
 461        u32 prev = curr_perf_level, flags;
 462
 463        if ((curr_perf_level == level) && !force)
 464                return prev;
 465
 466        m_type = omap2_memory_get_type();
 467        slow_dll_ctrl = omap2_memory_get_slow_dll_ctrl();
 468        fast_dll_ctrl = omap2_memory_get_fast_dll_ctrl();
 469
 470        if (level == PRCM_HALF_SPEED) {
 471                local_irq_save(flags);
 472                PRCM_VOLTSETUP = 0xffff;
 473                omap2_sram_reprogram_sdrc(PRCM_HALF_SPEED,
 474                                          slow_dll_ctrl, m_type);
 475                curr_perf_level = PRCM_HALF_SPEED;
 476                local_irq_restore(flags);
 477        }
 478        if (level == PRCM_FULL_SPEED) {
 479                local_irq_save(flags);
 480                PRCM_VOLTSETUP = 0xffff;
 481                omap2_sram_reprogram_sdrc(PRCM_FULL_SPEED,
 482                                          fast_dll_ctrl, m_type);
 483                curr_perf_level = PRCM_FULL_SPEED;
 484                local_irq_restore(flags);
 485        }
 486
 487        return prev;
 488}
 489
 490static int omap2_reprogram_dpll(struct clk * clk, unsigned long rate)
 491{
 492        u32 flags, cur_rate, low, mult, div, valid_rate, done_rate;
 493        u32 bypass = 0;
 494        struct prcm_config tmpset;
 495        int ret = -EINVAL;
 496
 497        local_irq_save(flags);
 498        cur_rate = omap2_get_dpll_rate(&dpll_ck);
 499        mult = CM_CLKSEL2_PLL & 0x3;
 500
 501        if ((rate == (cur_rate / 2)) && (mult == 2)) {
 502                omap2_reprogram_sdrc(PRCM_HALF_SPEED, 1);
 503        } else if ((rate == (cur_rate * 2)) && (mult == 1)) {
 504                omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);
 505        } else if (rate != cur_rate) {
 506                valid_rate = omap2_dpll_round_rate(rate);
 507                if (valid_rate != rate)
 508                        goto dpll_exit;
 509
 510                if ((CM_CLKSEL2_PLL & 0x3) == 1)
 511                        low = curr_prcm_set->dpll_speed;
 512                else
 513                        low = curr_prcm_set->dpll_speed / 2;
 514
 515                tmpset.cm_clksel1_pll = CM_CLKSEL1_PLL;
 516                tmpset.cm_clksel1_pll &= ~(0x3FFF << 8);
 517                div = ((curr_prcm_set->xtal_speed / 1000000) - 1);
 518                tmpset.cm_clksel2_pll = CM_CLKSEL2_PLL;
 519                tmpset.cm_clksel2_pll &= ~0x3;
 520                if (rate > low) {
 521                        tmpset.cm_clksel2_pll |= 0x2;
 522                        mult = ((rate / 2) / 1000000);
 523                        done_rate = PRCM_FULL_SPEED;
 524                } else {
 525                        tmpset.cm_clksel2_pll |= 0x1;
 526                        mult = (rate / 1000000);
 527                        done_rate = PRCM_HALF_SPEED;
 528                }
 529                tmpset.cm_clksel1_pll |= ((div << 8) | (mult << 12));
 530
 531                /* Worst case */
 532                tmpset.base_sdrc_rfr = V24XX_SDRC_RFR_CTRL_BYPASS;
 533
 534                if (rate == curr_prcm_set->xtal_speed)  /* If asking for 1-1 */
 535                        bypass = 1;
 536
 537                omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1); /* For init_mem */
 538
 539                /* Force dll lock mode */
 540                omap2_set_prcm(tmpset.cm_clksel1_pll, tmpset.base_sdrc_rfr,
 541                               bypass);
 542
 543                /* Errata: ret dll entry state */
 544                omap2_init_memory_params(omap2_dll_force_needed());
 545                omap2_reprogram_sdrc(done_rate, 0);
 546        }
 547        omap2_clksel_recalc(&dpll_ck);
 548        ret = 0;
 549
 550dpll_exit:
 551        local_irq_restore(flags);
 552        return(ret);
 553}
 554
 555/* Just return the MPU speed */
 556static void omap2_mpu_recalc(struct clk * clk)
 557{
 558        clk->rate = curr_prcm_set->mpu_speed;
 559}
 560
 561/*
 562 * Look for a rate equal or less than the target rate given a configuration set.
 563 *
 564 * What's not entirely clear is "which" field represents the key field.
 565 * Some might argue L3-DDR, others ARM, others IVA. This code is simple and
 566 * just uses the ARM rates.
 567 */
 568static long omap2_round_to_table_rate(struct clk * clk, unsigned long rate)
 569{
 570        struct prcm_config * ptr;
 571        long highest_rate;
 572
 573        if (clk != &virt_prcm_set)
 574                return -EINVAL;
 575
 576        highest_rate = -EINVAL;
 577
 578        for (ptr = rate_table; ptr->mpu_speed; ptr++) {
 579                if (ptr->xtal_speed != sys_ck.rate)
 580                        continue;
 581
 582                highest_rate = ptr->mpu_speed;
 583
 584                /* Can check only after xtal frequency check */
 585                if (ptr->mpu_speed <= rate)
 586                        break;
 587        }
 588        return highest_rate;
 589}
 590
 591/*
 592 * omap2_convert_field_to_div() - turn field value into integer divider
 593 */
 594static u32 omap2_clksel_to_divisor(u32 div_sel, u32 field_val)
 595{
 596        u32 i;
 597        u32 clkout_array[] = {1, 2, 4, 8, 16};
 598
 599        if ((div_sel & SRC_RATE_SEL_MASK) == CM_SYSCLKOUT_SEL1) {
 600                for (i = 0; i < 5; i++) {
 601                        if (field_val == i)
 602                                return clkout_array[i];
 603                }
 604                return ~0;
 605        } else
 606                return field_val;
 607}
 608
 609/*
 610 * Returns the CLKSEL divider register value
 611 * REVISIT: This should be cleaned up to work nicely with void __iomem *
 612 */
 613static u32 omap2_get_clksel(u32 *div_sel, u32 *field_mask,
 614                            struct clk *clk)
 615{
 616        int ret = ~0;
 617        u32 reg_val, div_off;
 618        u32 div_addr = 0;
 619        u32 mask = ~0;
 620
 621        div_off = clk->rate_offset;
 622
 623        switch ((*div_sel & SRC_RATE_SEL_MASK)) {
 624        case CM_MPU_SEL1:
 625                div_addr = (u32)&CM_CLKSEL_MPU;
 626                mask = 0x1f;
 627                break;
 628        case CM_DSP_SEL1:
 629                div_addr = (u32)&CM_CLKSEL_DSP;
 630                if (cpu_is_omap2420()) {
 631                        if ((div_off == 0) || (div_off == 8))
 632                                mask = 0x1f;
 633                        else if (div_off == 5)
 634                                mask = 0x3;
 635                } else if (cpu_is_omap2430()) {
 636                        if (div_off == 0)
 637                                mask = 0x1f;
 638                        else if (div_off == 5)
 639                                mask = 0x3;
 640                }
 641                break;
 642        case CM_GFX_SEL1:
 643                div_addr = (u32)&CM_CLKSEL_GFX;
 644                if (div_off == 0)
 645                        mask = 0x7;
 646                break;
 647        case CM_MODEM_SEL1:
 648                div_addr = (u32)&CM_CLKSEL_MDM;
 649                if (div_off == 0)
 650                        mask = 0xf;
 651                break;
 652        case CM_SYSCLKOUT_SEL1:
 653                div_addr = (u32)&PRCM_CLKOUT_CTRL;
 654                if ((div_off == 3) || (div_off = 11))
 655                        mask= 0x3;
 656                break;
 657        case CM_CORE_SEL1:
 658                div_addr = (u32)&CM_CLKSEL1_CORE;
 659                switch (div_off) {
 660                case 0:                                 /* l3 */
 661                case 8:                                 /* dss1 */
 662                case 15:                                /* vylnc-2420 */
 663                case 20:                                /* ssi */
 664                        mask = 0x1f; break;
 665                case 5:                                 /* l4 */
 666                        mask = 0x3; break;
 667                case 13:                                /* dss2 */
 668                        mask = 0x1; break;
 669                case 25:                                /* usb */
 670                        mask = 0x7; break;
 671                }
 672        }
 673
 674        *field_mask = mask;
 675
 676        if (unlikely(mask == ~0))
 677                div_addr = 0;
 678
 679        *div_sel = div_addr;
 680
 681        if (unlikely(div_addr == 0))
 682                return ret;
 683
 684        /* Isolate field */
 685        reg_val = __raw_readl((void __iomem *)div_addr) & (mask << div_off);
 686
 687        /* Normalize back to divider value */
 688        reg_val >>= div_off;
 689
 690        return reg_val;
 691}
 692
 693/*
 694 * Return divider to be applied to parent clock.
 695 * Return 0 on error.
 696 */
 697static u32 omap2_clksel_get_divisor(struct clk *clk)
 698{
 699        int ret = 0;
 700        u32 div, div_sel, div_off, field_mask, field_val;
 701
 702        /* isolate control register */
 703        div_sel = (SRC_RATE_SEL_MASK & clk->flags);
 704
 705        div_off = clk->rate_offset;
 706        field_val = omap2_get_clksel(&div_sel, &field_mask, clk);
 707        if (div_sel == 0)
 708                return ret;
 709
 710        div_sel = (SRC_RATE_SEL_MASK & clk->flags);
 711        div = omap2_clksel_to_divisor(div_sel, field_val);
 712
 713        return div;
 714}
 715
 716/* Set the clock rate for a clock source */
 717static int omap2_clk_set_rate(struct clk *clk, unsigned long rate)
 718
 719{
 720        int ret = -EINVAL;
 721        void __iomem * reg;
 722        u32 div_sel, div_off, field_mask, field_val, reg_val, validrate;
 723        u32 new_div = 0;
 724
 725        if (!(clk->flags & CONFIG_PARTICIPANT) && (clk->flags & RATE_CKCTL)) {
 726                if (clk == &dpll_ck)
 727                        return omap2_reprogram_dpll(clk, rate);
 728
 729                /* Isolate control register */
 730                div_sel = (SRC_RATE_SEL_MASK & clk->flags);
 731                div_off = clk->rate_offset;
 732
 733                validrate = omap2_clksel_round_rate(clk, rate, &new_div);
 734                if (validrate != rate)
 735                        return(ret);
 736
 737                field_val = omap2_get_clksel(&div_sel, &field_mask, clk);
 738                if (div_sel == 0)
 739                        return ret;
 740
 741                if (clk->flags & CM_SYSCLKOUT_SEL1) {
 742                        switch (new_div) {
 743                        case 16:
 744                                field_val = 4;
 745                                break;
 746                        case 8:
 747                                field_val = 3;
 748                                break;
 749                        case 4:
 750                                field_val = 2;
 751                                break;
 752                        case 2:
 753                                field_val = 1;
 754                                break;
 755                        case 1:
 756                                field_val = 0;
 757                                break;
 758                        }
 759                } else
 760                        field_val = new_div;
 761
 762                reg = (void __iomem *)div_sel;
 763
 764                reg_val = __raw_readl(reg);
 765                reg_val &= ~(field_mask << div_off);
 766                reg_val |= (field_val << div_off);
 767                __raw_writel(reg_val, reg);
 768                wmb();
 769                clk->rate = clk->parent->rate / field_val;
 770
 771                if (clk->flags & DELAYED_APP) {
 772                        __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
 773                        wmb();
 774                }
 775                ret = 0;
 776        } else if (clk->set_rate != 0)
 777                ret = clk->set_rate(clk, rate);
 778
 779        if (unlikely(ret == 0 && (clk->flags & RATE_PROPAGATES)))
 780                propagate_rate(clk);
 781
 782        return ret;
 783}
 784
 785/* Converts encoded control register address into a full address */
 786static u32 omap2_get_src_field(u32 *type_to_addr, u32 reg_offset,
 787                               struct clk *src_clk, u32 *field_mask)
 788{
 789        u32 val = ~0, src_reg_addr = 0, mask = 0;
 790
 791        /* Find target control register.*/
 792        switch ((*type_to_addr & SRC_RATE_SEL_MASK)) {
 793        case CM_CORE_SEL1:
 794                src_reg_addr = (u32)&CM_CLKSEL1_CORE;
 795                if (reg_offset == 13) {                 /* DSS2_fclk */
 796                        mask = 0x1;
 797                        if (src_clk == &sys_ck)
 798                                val = 0;
 799                        if (src_clk == &func_48m_ck)
 800                                val = 1;
 801                } else if (reg_offset == 8) {           /* DSS1_fclk */
 802                        mask = 0x1f;
 803                        if (src_clk == &sys_ck)
 804                                val = 0;
 805                        else if (src_clk == &core_ck)   /* divided clock */
 806                                val = 0x10;             /* rate needs fixing */
 807                } else if ((reg_offset == 15) && cpu_is_omap2420()){ /*vlnyq*/
 808                        mask = 0x1F;
 809                        if(src_clk == &func_96m_ck)
 810                                val = 0;
 811                        else if (src_clk == &core_ck)
 812                                val = 0x10;
 813                }
 814                break;
 815        case CM_CORE_SEL2:
 816                src_reg_addr = (u32)&CM_CLKSEL2_CORE;
 817                mask = 0x3;
 818                if (src_clk == &func_32k_ck)
 819                        val = 0x0;
 820                if (src_clk == &sys_ck)
 821                        val = 0x1;
 822                if (src_clk == &alt_ck)
 823                        val = 0x2;
 824                break;
 825        case CM_WKUP_SEL1:
 826                src_reg_addr = (u32)&CM_CLKSEL_WKUP;
 827                mask = 0x3;
 828                if (src_clk == &func_32k_ck)
 829                        val = 0x0;
 830                if (src_clk == &sys_ck)
 831                        val = 0x1;
 832                if (src_clk == &alt_ck)
 833                        val = 0x2;
 834                break;
 835        case CM_PLL_SEL1:
 836                src_reg_addr = (u32)&CM_CLKSEL1_PLL;
 837                mask = 0x1;
 838                if (reg_offset == 0x3) {
 839                        if (src_clk == &apll96_ck)
 840                                val = 0;
 841                        if (src_clk == &alt_ck)
 842                                val = 1;
 843                }
 844                else if (reg_offset == 0x5) {
 845                        if (src_clk == &apll54_ck)
 846                                val = 0;
 847                        if (src_clk == &alt_ck)
 848                                val = 1;
 849                }
 850                break;
 851        case CM_PLL_SEL2:
 852                src_reg_addr = (u32)&CM_CLKSEL2_PLL;
 853                mask = 0x3;
 854                if (src_clk == &func_32k_ck)
 855                        val = 0x0;
 856                if (src_clk == &dpll_ck)
 857                        val = 0x2;
 858                break;
 859        case CM_SYSCLKOUT_SEL1:
 860                src_reg_addr = (u32)&PRCM_CLKOUT_CTRL;
 861                mask = 0x3;
 862                if (src_clk == &dpll_ck)
 863                        val = 0;
 864                if (src_clk == &sys_ck)
 865                        val = 1;
 866                if (src_clk == &func_96m_ck)
 867                        val = 2;
 868                if (src_clk == &func_54m_ck)
 869                        val = 3;
 870                break;
 871        }
 872
 873        if (val == ~0)                  /* Catch errors in offset */
 874                *type_to_addr = 0;
 875        else
 876                *type_to_addr = src_reg_addr;
 877        *field_mask = mask;
 878
 879        return val;
 880}
 881
 882static int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
 883{
 884        void __iomem * reg;
 885        u32 src_sel, src_off, field_val, field_mask, reg_val, rate;
 886        int ret = -EINVAL;
 887
 888        if (unlikely(clk->flags & CONFIG_PARTICIPANT))
 889                return ret;
 890
 891        if (clk->flags & SRC_SEL_MASK) {        /* On-chip SEL collection */
 892                src_sel = (SRC_RATE_SEL_MASK & clk->flags);
 893                src_off = clk->src_offset;
 894
 895                if (src_sel == 0)
 896                        goto set_parent_error;
 897
 898                field_val = omap2_get_src_field(&src_sel, src_off, new_parent,
 899                                                &field_mask);
 900
 901                reg = (void __iomem *)src_sel;
 902
 903                if (clk->usecount > 0)
 904                        _omap2_clk_disable(clk);
 905
 906                /* Set new source value (previous dividers if any in effect) */
 907                reg_val = __raw_readl(reg) & ~(field_mask << src_off);
 908                reg_val |= (field_val << src_off);
 909                __raw_writel(reg_val, reg);
 910                wmb();
 911
 912                if (clk->flags & DELAYED_APP) {
 913                        __raw_writel(0x1, (void __iomem *)&PRCM_CLKCFG_CTRL);
 914                        wmb();
 915                }
 916                if (clk->usecount > 0)
 917                        _omap2_clk_enable(clk);
 918
 919                clk->parent = new_parent;
 920
 921                /* SRC_RATE_SEL_MASK clocks follow their parents rates.*/
 922                if ((new_parent == &core_ck) && (clk == &dss1_fck))
 923                        clk->rate = new_parent->rate / 0x10;
 924                else
 925                        clk->rate = new_parent->rate;
 926
 927                if (unlikely(clk->flags & RATE_PROPAGATES))
 928                        propagate_rate(clk);
 929
 930                return 0;
 931        } else {
 932                clk->parent = new_parent;
 933                rate = new_parent->rate;
 934                omap2_clk_set_rate(clk, rate);
 935                ret = 0;
 936        }
 937
 938 set_parent_error:
 939        return ret;
 940}
 941
 942/* Sets basic clocks based on the specified rate */
 943static int omap2_select_table_rate(struct clk * clk, unsigned long rate)
 944{
 945        u32 flags, cur_rate, done_rate, bypass = 0;
 946        u8 cpu_mask = 0;
 947        struct prcm_config *prcm;
 948        unsigned long found_speed = 0;
 949
 950        if (clk != &virt_prcm_set)
 951                return -EINVAL;
 952
 953        /* FIXME: Change cpu_is_omap2420() to cpu_is_omap242x() */
 954        if (cpu_is_omap2420())
 955                cpu_mask = RATE_IN_242X;
 956        else if (cpu_is_omap2430())
 957                cpu_mask = RATE_IN_243X;
 958
 959        for (prcm = rate_table; prcm->mpu_speed; prcm++) {
 960                if (!(prcm->flags & cpu_mask))
 961                        continue;
 962
 963                if (prcm->xtal_speed != sys_ck.rate)
 964                        continue;
 965
 966                if (prcm->mpu_speed <= rate) {
 967                        found_speed = prcm->mpu_speed;
 968                        break;
 969                }
 970        }
 971
 972        if (!found_speed) {
 973                printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
 974         rate / 1000000);
 975                return -EINVAL;
 976        }
 977
 978        curr_prcm_set = prcm;
 979        cur_rate = omap2_get_dpll_rate(&dpll_ck);
 980
 981        if (prcm->dpll_speed == cur_rate / 2) {
 982                omap2_reprogram_sdrc(PRCM_HALF_SPEED, 1);
 983        } else if (prcm->dpll_speed == cur_rate * 2) {
 984                omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);
 985        } else if (prcm->dpll_speed != cur_rate) {
 986                local_irq_save(flags);
 987
 988                if (prcm->dpll_speed == prcm->xtal_speed)
 989                        bypass = 1;
 990
 991                if ((prcm->cm_clksel2_pll & 0x3) == 2)
 992                        done_rate = PRCM_FULL_SPEED;
 993                else
 994                        done_rate = PRCM_HALF_SPEED;
 995
 996                /* MPU divider */
 997                CM_CLKSEL_MPU = prcm->cm_clksel_mpu;
 998
 999                /* dsp + iva1 div(2420), iva2.1(2430) */
1000                CM_CLKSEL_DSP = prcm->cm_clksel_dsp;
1001
1002                CM_CLKSEL_GFX = prcm->cm_clksel_gfx;
1003
1004                /* Major subsystem dividers */
1005                CM_CLKSEL1_CORE = prcm->cm_clksel1_core;
1006                if (cpu_is_omap2430())
1007                        CM_CLKSEL_MDM = prcm->cm_clksel_mdm;
1008
1009                /* x2 to enter init_mem */
1010                omap2_reprogram_sdrc(PRCM_FULL_SPEED, 1);
1011
1012                omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
1013                               bypass);
1014
1015                omap2_init_memory_params(omap2_dll_force_needed());
1016                omap2_reprogram_sdrc(done_rate, 0);
1017
1018                local_irq_restore(flags);
1019        }
1020        omap2_clksel_recalc(&dpll_ck);
1021
1022        return 0;
1023}
1024
1025/*-------------------------------------------------------------------------
1026 * Omap2 clock reset and init functions
1027 *-------------------------------------------------------------------------*/
1028
1029#ifdef CONFIG_OMAP_RESET_CLOCKS
1030static void __init omap2_clk_disable_unused(struct clk *clk)
1031{
1032        u32 regval32;
1033
1034        regval32 = __raw_readl(clk->enable_reg);
1035        if ((regval32 & (1 << clk->enable_bit)) == 0)
1036                return;
1037
1038        printk(KERN_INFO "Disabling unused clock \"%s\"\n", clk->name);
1039        _omap2_clk_disable(clk);
1040}
1041#else
1042#define omap2_clk_disable_unused        NULL
1043#endif
1044
1045static struct clk_functions omap2_clk_functions = {
1046        .clk_enable             = omap2_clk_enable,
1047        .clk_disable            = omap2_clk_disable,
1048        .clk_round_rate         = omap2_clk_round_rate,
1049        .clk_set_rate           = omap2_clk_set_rate,
1050        .clk_set_parent         = omap2_clk_set_parent,
1051        .clk_disable_unused     = omap2_clk_disable_unused,
1052};
1053
1054static void __init omap2_get_crystal_rate(struct clk *osc, struct clk *sys)
1055{
1056        u32 div, aplls, sclk = 13000000;
1057
1058        aplls = CM_CLKSEL1_PLL;
1059        aplls &= ((1 << 23) | (1 << 24) | (1 << 25));
1060        aplls >>= 23;                   /* Isolate field, 0,2,3 */
1061
1062        if (aplls == 0)
1063                sclk = 19200000;
1064        else if (aplls == 2)
1065                sclk = 13000000;
1066        else if (aplls == 3)
1067                sclk = 12000000;
1068
1069        div = PRCM_CLKSRC_CTRL;
1070        div &= ((1 << 7) | (1 << 6));
1071        div >>= sys->rate_offset;
1072
1073        osc->rate = sclk * div;
1074        sys->rate = sclk;
1075}
1076
1077/*
1078 * Set clocks for bypass mode for reboot to work.
1079 */
1080void omap2_clk_prepare_for_reboot(void)
1081{
1082        u32 rate;
1083
1084        if (vclk == NULL || sclk == NULL)
1085                return;
1086
1087        rate = clk_get_rate(sclk);
1088        clk_set_rate(vclk, rate);
1089}
1090
1091/*
1092 * Switch the MPU rate if specified on cmdline.
1093 * We cannot do this early until cmdline is parsed.
1094 */
1095static int __init omap2_clk_arch_init(void)
1096{
1097        if (!mpurate)
1098                return -EINVAL;
1099
1100        if (omap2_select_table_rate(&virt_prcm_set, mpurate))
1101                printk(KERN_ERR "Could not find matching MPU rate\n");
1102
1103        propagate_rate(&osc_ck);                /* update main root fast */
1104        propagate_rate(&func_32k_ck);           /* update main root slow */
1105
1106        printk(KERN_INFO "Switched to new clocking rate (Crystal/DPLL/MPU): "
1107               "%ld.%01ld/%ld/%ld MHz\n",
1108               (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
1109               (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
1110
1111        return 0;
1112}
1113arch_initcall(omap2_clk_arch_init);
1114
1115int __init omap2_clk_init(void)
1116{
1117        struct prcm_config *prcm;
1118        struct clk ** clkp;
1119        u32 clkrate;
1120
1121        clk_init(&omap2_clk_functions);
1122        omap2_get_crystal_rate(&osc_ck, &sys_ck);
1123
1124        for (clkp = onchip_clks; clkp < onchip_clks + ARRAY_SIZE(onchip_clks);
1125             clkp++) {
1126
1127                if ((*clkp)->flags & CLOCK_IN_OMAP242X && cpu_is_omap2420()) {
1128                        clk_register(*clkp);
1129                        continue;
1130                }
1131
1132                if ((*clkp)->flags & CLOCK_IN_OMAP243X && cpu_is_omap2430()) {
1133                        clk_register(*clkp);
1134                        continue;
1135                }
1136        }
1137
1138        /* Check the MPU rate set by bootloader */
1139        clkrate = omap2_get_dpll_rate(&dpll_ck);
1140        for (prcm = rate_table; prcm->mpu_speed; prcm++) {
1141                if (prcm->xtal_speed != sys_ck.rate)
1142                        continue;
1143                if (prcm->dpll_speed <= clkrate)
1144                         break;
1145        }
1146        curr_prcm_set = prcm;
1147
1148        propagate_rate(&osc_ck);                /* update main root fast */
1149        propagate_rate(&func_32k_ck);           /* update main root slow */
1150
1151        printk(KERN_INFO "Clocking rate (Crystal/DPLL/MPU): "
1152               "%ld.%01ld/%ld/%ld MHz\n",
1153               (sys_ck.rate / 1000000), (sys_ck.rate / 100000) % 10,
1154               (dpll_ck.rate / 1000000), (mpu_ck.rate / 1000000)) ;
1155
1156        /*
1157         * Only enable those clocks we will need, let the drivers
1158         * enable other clocks as necessary
1159         */
1160        clk_enable(&sync_32k_ick);
1161        clk_enable(&omapctrl_ick);
1162
1163        /* Force the APLLs active during bootup to avoid disabling and
1164         * enabling them unnecessarily. */
1165        clk_enable(&apll96_ck);
1166        clk_enable(&apll54_ck);
1167
1168        if (cpu_is_omap2430())
1169                clk_enable(&sdrc_ick);
1170
1171        /* Avoid sleeping sleeping during omap2_clk_prepare_for_reboot() */
1172        vclk = clk_get(NULL, "virt_prcm_set");
1173        sclk = clk_get(NULL, "sys_ck");
1174
1175        return 0;
1176}
1177
1178static int __init omap2_disable_aplls(void)
1179{
1180        clk_disable(&apll96_ck);
1181        clk_disable(&apll54_ck);
1182
1183        return 0;
1184}
1185late_initcall(omap2_disable_aplls);
1186
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.