uboot/arch/arm/cpu/arm1176/tnetv107x/clock.c
<<
>>
Prefs
   1/*
   2 * TNETV107X: Clock management APIs
   3 *
   4 * See file CREDITS for list of people who contributed to this
   5 * project.
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21
  22#include <common.h>
  23#include <asm-generic/errno.h>
  24#include <asm/io.h>
  25#include <asm/processor.h>
  26#include <asm/arch/clock.h>
  27
  28#define CLOCK_BASE              TNETV107X_CLOCK_CONTROL_BASE
  29#define PSC_BASE                TNETV107X_PSC_BASE
  30
  31#define BIT(x)                  (1 << (x))
  32
  33#define MAX_PREDIV              64
  34#define MAX_POSTDIV             8
  35#define MAX_MULT                512
  36#define MAX_DIV                 (MAX_PREDIV * MAX_POSTDIV)
  37
  38/* LPSC registers */
  39#define PSC_PTCMD               0x120
  40#define PSC_PTSTAT              0x128
  41#define PSC_MDSTAT(n)           (0x800 + (n) * 4)
  42#define PSC_MDCTL(n)            (0xA00 + (n) * 4)
  43
  44#define PSC_MDCTL_LRSTZ         BIT(8)
  45
  46#define psc_reg_read(reg)       __raw_readl((u32 *)(PSC_BASE + (reg)))
  47#define psc_reg_write(reg, val) __raw_writel(val, (u32 *)(PSC_BASE + (reg)))
  48
  49/* SSPLL registers */
  50struct sspll_regs {
  51        u32     modes;
  52        u32     postdiv;
  53        u32     prediv;
  54        u32     mult_factor;
  55        u32     divider_range;
  56        u32     bw_divider;
  57        u32     spr_amount;
  58        u32     spr_rate_div;
  59        u32     diag;
  60};
  61
  62/* SSPLL base addresses */
  63static struct sspll_regs *sspll_regs[] = {
  64        (struct sspll_regs *)(CLOCK_BASE + 0x040),
  65        (struct sspll_regs *)(CLOCK_BASE + 0x080),
  66        (struct sspll_regs *)(CLOCK_BASE + 0x0c0),
  67};
  68
  69#define sspll_reg(pll, reg)             (&(sspll_regs[pll]->reg))
  70#define sspll_reg_read(pll, reg)        __raw_readl(sspll_reg(pll, reg))
  71#define sspll_reg_write(pll, reg, val)  __raw_writel(val, sspll_reg(pll, reg))
  72
  73
  74/* PLL Control Registers */
  75struct pllctl_regs {
  76        u32     ctl;            /* 00 */
  77        u32     ocsel;          /* 04 */
  78        u32     secctl;         /* 08 */
  79        u32     __pad0;
  80        u32     mult;           /* 10 */
  81        u32     prediv;         /* 14 */
  82        u32     div1;           /* 18 */
  83        u32     div2;           /* 1c */
  84        u32     div3;           /* 20 */
  85        u32     oscdiv1;        /* 24 */
  86        u32     postdiv;        /* 28 */
  87        u32     bpdiv;          /* 2c */
  88        u32     wakeup;         /* 30 */
  89        u32     __pad1;
  90        u32     cmd;            /* 38 */
  91        u32     stat;           /* 3c */
  92        u32     alnctl;         /* 40 */
  93        u32     dchange;        /* 44 */
  94        u32     cken;           /* 48 */
  95        u32     ckstat;         /* 4c */
  96        u32     systat;         /* 50 */
  97        u32     ckctl;          /* 54 */
  98        u32     __pad2[2];
  99        u32     div4;           /* 60 */
 100        u32     div5;           /* 64 */
 101        u32     div6;           /* 68 */
 102        u32     div7;           /* 6c */
 103        u32     div8;           /* 70 */
 104};
 105
 106struct lpsc_map {
 107        int     pll, div;
 108};
 109
 110static struct pllctl_regs *pllctl_regs[] = {
 111        (struct pllctl_regs *)(CLOCK_BASE + 0x700),
 112        (struct pllctl_regs *)(CLOCK_BASE + 0x300),
 113        (struct pllctl_regs *)(CLOCK_BASE + 0x500),
 114};
 115
 116#define pllctl_reg(pll, reg)            (&(pllctl_regs[pll]->reg))
 117#define pllctl_reg_read(pll, reg)       __raw_readl(pllctl_reg(pll, reg))
 118#define pllctl_reg_write(pll, reg, val) __raw_writel(val, pllctl_reg(pll, reg))
 119
 120#define pllctl_reg_rmw(pll, reg, mask, val)                     \
 121        pllctl_reg_write(pll, reg,                              \
 122                (pllctl_reg_read(pll, reg) & ~(mask)) | val)
 123
 124#define pllctl_reg_setbits(pll, reg, mask)                      \
 125        pllctl_reg_rmw(pll, reg, 0, mask)
 126
 127#define pllctl_reg_clrbits(pll, reg, mask)                      \
 128        pllctl_reg_rmw(pll, reg, mask, 0)
 129
 130/* PLLCTL Bits */
 131#define PLLCTL_CLKMODE          BIT(8)
 132#define PLLCTL_PLLSELB          BIT(7)
 133#define PLLCTL_PLLENSRC         BIT(5)
 134#define PLLCTL_PLLDIS           BIT(4)
 135#define PLLCTL_PLLRST           BIT(3)
 136#define PLLCTL_PLLPWRDN         BIT(1)
 137#define PLLCTL_PLLEN            BIT(0)
 138
 139#define PLLDIV_ENABLE           BIT(15)
 140
 141static int pll_div_offset[] = {
 142#define div_offset(reg) offsetof(struct pllctl_regs, reg)
 143        div_offset(div1), div_offset(div2), div_offset(div3),
 144        div_offset(div4), div_offset(div5), div_offset(div6),
 145        div_offset(div7), div_offset(div8),
 146};
 147
 148static unsigned long pll_bypass_mask[] = { 1, 4, 2 };
 149static unsigned long pll_div_mask[] = { 0x01ff, 0x00ff, 0x00ff };
 150
 151/* Mappings from PLL+DIV to subsystem clocks */
 152#define sys_arm1176_clk         {SYS_PLL, 0}
 153#define sys_dsp_clk             {SYS_PLL, 1}
 154#define sys_ddr_clk             {SYS_PLL, 2}
 155#define sys_full_clk            {SYS_PLL, 3}
 156#define sys_lcd_clk             {SYS_PLL, 4}
 157#define sys_vlynq_ref_clk       {SYS_PLL, 5}
 158#define sys_tsc_clk             {SYS_PLL, 6}
 159#define sys_half_clk            {SYS_PLL, 7}
 160
 161#define eth_clk_5               {ETH_PLL, 0}
 162#define eth_clk_50              {ETH_PLL, 1}
 163#define eth_clk_125             {ETH_PLL, 2}
 164#define eth_clk_250             {ETH_PLL, 3}
 165#define eth_clk_25              {ETH_PLL, 4}
 166
 167#define tdm_clk                 {TDM_PLL, 0}
 168#define tdm_extra_clk           {TDM_PLL, 1}
 169#define tdm1_clk                {TDM_PLL, 2}
 170
 171/* Optimization barrier */
 172#define barrier()       \
 173        __asm__ __volatile__("mov r0, r0\n" : : : "memory");
 174
 175static const struct lpsc_map lpsc_clk_map[] = {
 176        [TNETV107X_LPSC_ARM]                    = sys_arm1176_clk,
 177        [TNETV107X_LPSC_GEM]                    = sys_dsp_clk,
 178        [TNETV107X_LPSC_DDR2_PHY]               = sys_ddr_clk,
 179        [TNETV107X_LPSC_TPCC]                   = sys_full_clk,
 180        [TNETV107X_LPSC_TPTC0]                  = sys_full_clk,
 181        [TNETV107X_LPSC_TPTC1]                  = sys_full_clk,
 182        [TNETV107X_LPSC_RAM]                    = sys_full_clk,
 183        [TNETV107X_LPSC_MBX_LITE]               = sys_arm1176_clk,
 184        [TNETV107X_LPSC_LCD]                    = sys_lcd_clk,
 185        [TNETV107X_LPSC_ETHSS]                  = eth_clk_125,
 186        [TNETV107X_LPSC_AEMIF]                  = sys_full_clk,
 187        [TNETV107X_LPSC_CHIP_CFG]               = sys_half_clk,
 188        [TNETV107X_LPSC_TSC]                    = sys_tsc_clk,
 189        [TNETV107X_LPSC_ROM]                    = sys_half_clk,
 190        [TNETV107X_LPSC_UART2]                  = sys_half_clk,
 191        [TNETV107X_LPSC_PKTSEC]                 = sys_half_clk,
 192        [TNETV107X_LPSC_SECCTL]                 = sys_half_clk,
 193        [TNETV107X_LPSC_KEYMGR]                 = sys_half_clk,
 194        [TNETV107X_LPSC_KEYPAD]                 = sys_half_clk,
 195        [TNETV107X_LPSC_GPIO]                   = sys_half_clk,
 196        [TNETV107X_LPSC_MDIO]                   = sys_half_clk,
 197        [TNETV107X_LPSC_SDIO0]                  = sys_half_clk,
 198        [TNETV107X_LPSC_UART0]                  = sys_half_clk,
 199        [TNETV107X_LPSC_UART1]                  = sys_half_clk,
 200        [TNETV107X_LPSC_TIMER0]                 = sys_half_clk,
 201        [TNETV107X_LPSC_TIMER1]                 = sys_half_clk,
 202        [TNETV107X_LPSC_WDT_ARM]                = sys_half_clk,
 203        [TNETV107X_LPSC_WDT_DSP]                = sys_half_clk,
 204        [TNETV107X_LPSC_SSP]                    = sys_half_clk,
 205        [TNETV107X_LPSC_TDM0]                   = tdm_clk,
 206        [TNETV107X_LPSC_VLYNQ]                  = sys_vlynq_ref_clk,
 207        [TNETV107X_LPSC_MCDMA]                  = sys_half_clk,
 208        [TNETV107X_LPSC_USB0]                   = sys_half_clk,
 209        [TNETV107X_LPSC_TDM1]                   = tdm1_clk,
 210        [TNETV107X_LPSC_DEBUGSS]                = sys_half_clk,
 211        [TNETV107X_LPSC_ETHSS_RGMII]            = eth_clk_250,
 212        [TNETV107X_LPSC_SYSTEM]                 = sys_half_clk,
 213        [TNETV107X_LPSC_IMCOP]                  = sys_dsp_clk,
 214        [TNETV107X_LPSC_SPARE]                  = sys_half_clk,
 215        [TNETV107X_LPSC_SDIO1]                  = sys_half_clk,
 216        [TNETV107X_LPSC_USB1]                   = sys_half_clk,
 217        [TNETV107X_LPSC_USBSS]                  = sys_half_clk,
 218        [TNETV107X_LPSC_DDR2_EMIF1_VRST]        = sys_ddr_clk,
 219        [TNETV107X_LPSC_DDR2_EMIF2_VCTL_RST]    = sys_ddr_clk,
 220};
 221
 222static const unsigned long pll_ext_freq[] = {
 223        [SYS_PLL] = CONFIG_PLL_SYS_EXT_FREQ,
 224        [ETH_PLL] = CONFIG_PLL_ETH_EXT_FREQ,
 225        [TDM_PLL] = CONFIG_PLL_TDM_EXT_FREQ,
 226};
 227
 228static unsigned long pll_freq_get(int pll)
 229{
 230        unsigned long mult = 1, prediv = 1, postdiv = 1;
 231        unsigned long ref = CONFIG_SYS_INT_OSC_FREQ;
 232        unsigned long ret;
 233        u32 bypass;
 234
 235        bypass = __raw_readl((u32 *)(CLOCK_BASE));
 236        if (!(bypass & pll_bypass_mask[pll])) {
 237                mult    = sspll_reg_read(pll, mult_factor);
 238                prediv  = sspll_reg_read(pll, prediv) + 1;
 239                postdiv = sspll_reg_read(pll, postdiv) + 1;
 240        }
 241
 242        if (pllctl_reg_read(pll, ctl) & PLLCTL_CLKMODE)
 243                ref = pll_ext_freq[pll];
 244
 245        if (!(pllctl_reg_read(pll, ctl) & PLLCTL_PLLEN))
 246                return ref;
 247
 248        ret = (unsigned long)(ref + ((unsigned long long)ref * mult) / 256);
 249        ret /= (prediv * postdiv);
 250
 251        return ret;
 252}
 253
 254static unsigned long __pll_div_freq_get(int pll, unsigned int fpll,
 255                                        int div)
 256{
 257        int divider = 1;
 258        unsigned long divreg;
 259
 260        divreg = __raw_readl((void *)pllctl_regs[pll] + pll_div_offset[div]);
 261
 262        if (divreg & PLLDIV_ENABLE)
 263                divider = (divreg & pll_div_mask[pll]) + 1;
 264
 265        return fpll / divider;
 266}
 267
 268static unsigned long pll_div_freq_get(int pll, int div)
 269{
 270        unsigned int fpll = pll_freq_get(pll);
 271
 272        return __pll_div_freq_get(pll, fpll, div);
 273}
 274
 275static void __pll_div_freq_set(int pll, unsigned int fpll, int div,
 276                               unsigned long hz)
 277{
 278        int divider = (fpll / hz - 1);
 279
 280        divider &= pll_div_mask[pll];
 281        divider |= PLLDIV_ENABLE;
 282
 283        __raw_writel(divider, (void *)pllctl_regs[pll] + pll_div_offset[div]);
 284        pllctl_reg_setbits(pll, alnctl, (1 << div));
 285        pllctl_reg_setbits(pll, dchange, (1 << div));
 286}
 287
 288static unsigned long pll_div_freq_set(int pll, int div, unsigned long hz)
 289{
 290        unsigned int fpll = pll_freq_get(pll);
 291
 292        __pll_div_freq_set(pll, fpll, div, hz);
 293
 294        pllctl_reg_write(pll, cmd, 1);
 295
 296        /* Wait until new divider takes effect */
 297        while (pllctl_reg_read(pll, stat) & 0x01);
 298
 299        return __pll_div_freq_get(pll, fpll, div);
 300}
 301
 302unsigned long clk_get_rate(unsigned int clk)
 303{
 304        return pll_div_freq_get(lpsc_clk_map[clk].pll, lpsc_clk_map[clk].div);
 305}
 306
 307unsigned long clk_round_rate(unsigned int clk, unsigned long hz)
 308{
 309        unsigned long fpll, divider, pll;
 310
 311        pll = lpsc_clk_map[clk].pll;
 312        fpll = pll_freq_get(pll);
 313        divider = (fpll / hz - 1);
 314        divider &= pll_div_mask[pll];
 315
 316        return fpll / (divider + 1);
 317}
 318
 319int clk_set_rate(unsigned int clk, unsigned long _hz)
 320{
 321        unsigned long hz;
 322
 323        hz = clk_round_rate(clk, _hz);
 324        if (hz != _hz)
 325                return -EINVAL; /* Cannot set to target freq */
 326
 327        pll_div_freq_set(lpsc_clk_map[clk].pll, lpsc_clk_map[clk].div, hz);
 328        return 0;
 329}
 330
 331void lpsc_control(int mod, unsigned long state, int lrstz)
 332{
 333        u32 mdctl;
 334
 335        mdctl = psc_reg_read(PSC_MDCTL(mod));
 336        mdctl &= ~0x1f;
 337        mdctl |= state;
 338
 339        if (lrstz == 0)
 340                mdctl &= ~PSC_MDCTL_LRSTZ;
 341        else if (lrstz == 1)
 342                mdctl |= PSC_MDCTL_LRSTZ;
 343
 344        psc_reg_write(PSC_MDCTL(mod), mdctl);
 345
 346        psc_reg_write(PSC_PTCMD, 1);
 347
 348        /* wait for power domain transition to end */
 349        while (psc_reg_read(PSC_PTSTAT) & 1);
 350
 351        /* Wait for module state change */
 352        while ((psc_reg_read(PSC_MDSTAT(mod)) & 0x1f) != state);
 353}
 354
 355int lpsc_status(unsigned int id)
 356{
 357        return psc_reg_read(PSC_MDSTAT(id)) & 0x1f;
 358}
 359
 360static void init_pll(const struct pll_init_data *data)
 361{
 362        unsigned long fpll;
 363        unsigned long best_pre = 0, best_post = 0, best_mult = 0;
 364        unsigned long div, prediv, postdiv, mult;
 365        unsigned long delta, actual;
 366        long best_delta = -1;
 367        int i;
 368        u32 tmp;
 369
 370        if (data->pll == SYS_PLL)
 371                return; /* cannot reconfigure system pll on the fly */
 372
 373        tmp = pllctl_reg_read(data->pll, ctl);
 374        if (data->internal_osc) {
 375                tmp &= ~PLLCTL_CLKMODE;
 376                fpll = CONFIG_SYS_INT_OSC_FREQ;
 377        } else {
 378                tmp |= PLLCTL_CLKMODE;
 379                fpll = pll_ext_freq[data->pll];
 380        }
 381        pllctl_reg_write(data->pll, ctl, tmp);
 382
 383        mult = data->pll_freq / fpll;
 384        for (mult = MAX(mult, 1); mult <= MAX_MULT; mult++) {
 385                div = (fpll * mult) / data->pll_freq;
 386                if (div < 1 || div > MAX_DIV)
 387                        continue;
 388
 389                for (postdiv = 1; postdiv <= min(div, MAX_POSTDIV); postdiv++) {
 390                        prediv = div / postdiv;
 391                        if (prediv < 1 || prediv > MAX_PREDIV)
 392                                continue;
 393
 394                        actual = (fpll / prediv) * (mult / postdiv);
 395                        delta = (actual - data->pll_freq);
 396                        if (delta < 0)
 397                                delta = -delta;
 398                        if ((delta < best_delta) || (best_delta == -1)) {
 399                                best_delta = delta;
 400                                best_mult = mult;
 401                                best_pre = prediv;
 402                                best_post = postdiv;
 403                                if (delta == 0)
 404                                        goto done;
 405                        }
 406                }
 407        }
 408done:
 409
 410        if (best_delta == -1) {
 411                printf("pll cannot derive %lu from %lu\n",
 412                                data->pll_freq, fpll);
 413                return;
 414        }
 415
 416        fpll = fpll * best_mult;
 417        fpll /= best_pre * best_post;
 418
 419        pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLENSRC);
 420        pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLEN);
 421
 422        pllctl_reg_setbits(data->pll, ctl, PLLCTL_PLLRST);
 423
 424        pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLPWRDN);
 425        pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLDIS);
 426
 427        sspll_reg_write(data->pll, mult_factor, (best_mult - 1) << 8);
 428        sspll_reg_write(data->pll, prediv,      best_pre - 1);
 429        sspll_reg_write(data->pll, postdiv,     best_post - 1);
 430
 431        for (i = 0; i < 10; i++)
 432                if (data->div_freq[i])
 433                        __pll_div_freq_set(data->pll, fpll, i,
 434                                           data->div_freq[i]);
 435
 436        pllctl_reg_write(data->pll, cmd, 1);
 437
 438        /* Wait until pll "go" operation completes */
 439        while (pllctl_reg_read(data->pll, stat) & 0x01);
 440
 441        pllctl_reg_clrbits(data->pll, ctl, PLLCTL_PLLRST);
 442        pllctl_reg_setbits(data->pll, ctl, PLLCTL_PLLEN);
 443}
 444
 445void init_plls(int num_pll, struct pll_init_data *config)
 446{
 447        int i;
 448
 449        for (i = 0; i < num_pll; i++)
 450                init_pll(&config[i]);
 451}
 452