uboot/arch/arm/mach-at91/armv7/clock.c
<<
>>
Prefs
   1/*
   2 * [origin: Linux kernel linux/arch/arm/mach-at91/clock.c]
   3 *
   4 * Copyright (C) 2005 David Brownell
   5 * Copyright (C) 2005 Ivan Kokshaysky
   6 * Copyright (C) 2009 Jean-Christophe PLAGNIOL-VILLARD <plagnioj@jcrosoft.com>
   7 * Copyright (C) 2013 Bo Shen <voice.shen@atmel.com>
   8 * Copyright (C) 2015 Wenyou Yang <wenyou.yang@atmel.com>
   9 *
  10 * SPDX-License-Identifier:     GPL-2.0+
  11 */
  12
  13#include <common.h>
  14#include <asm/errno.h>
  15#include <asm/io.h>
  16#include <asm/arch/hardware.h>
  17#include <asm/arch/at91_pmc.h>
  18#include <asm/arch/clk.h>
  19
  20#if !defined(CONFIG_AT91FAMILY)
  21# error You need to define CONFIG_AT91FAMILY in your board config!
  22#endif
  23
  24DECLARE_GLOBAL_DATA_PTR;
  25
  26static unsigned long at91_css_to_rate(unsigned long css)
  27{
  28        switch (css) {
  29        case AT91_PMC_MCKR_CSS_SLOW:
  30                return CONFIG_SYS_AT91_SLOW_CLOCK;
  31        case AT91_PMC_MCKR_CSS_MAIN:
  32                return gd->arch.main_clk_rate_hz;
  33        case AT91_PMC_MCKR_CSS_PLLA:
  34                return gd->arch.plla_rate_hz;
  35        }
  36
  37        return 0;
  38}
  39
  40static u32 at91_pll_rate(u32 freq, u32 reg)
  41{
  42        unsigned mul, div;
  43
  44        div = reg & 0xff;
  45        mul = (reg >> 18) & 0x7f;
  46        if (div && mul) {
  47                freq /= div;
  48                freq *= mul + 1;
  49        } else {
  50                freq = 0;
  51        }
  52
  53        return freq;
  54}
  55
  56int at91_clock_init(unsigned long main_clock)
  57{
  58        unsigned freq, mckr;
  59        struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
  60#ifndef CONFIG_SYS_AT91_MAIN_CLOCK
  61        unsigned tmp;
  62        /*
  63         * When the bootloader initialized the main oscillator correctly,
  64         * there's no problem using the cycle counter.  But if it didn't,
  65         * or when using oscillator bypass mode, we must be told the speed
  66         * of the main clock.
  67         */
  68        if (!main_clock) {
  69                do {
  70                        tmp = readl(&pmc->mcfr);
  71                } while (!(tmp & AT91_PMC_MCFR_MAINRDY));
  72                tmp &= AT91_PMC_MCFR_MAINF_MASK;
  73                main_clock = tmp * (CONFIG_SYS_AT91_SLOW_CLOCK / 16);
  74        }
  75#endif
  76        gd->arch.main_clk_rate_hz = main_clock;
  77
  78        /* report if PLLA is more than mildly overclocked */
  79        gd->arch.plla_rate_hz = at91_pll_rate(main_clock, readl(&pmc->pllar));
  80
  81        /*
  82         * MCK and CPU derive from one of those primary clocks.
  83         * For now, assume this parentage won't change.
  84         */
  85        mckr = readl(&pmc->mckr);
  86
  87        /* plla divisor by 2 */
  88        if (mckr & (1 << 12))
  89                gd->arch.plla_rate_hz >>= 1;
  90
  91        gd->arch.mck_rate_hz = at91_css_to_rate(mckr & AT91_PMC_MCKR_CSS_MASK);
  92        freq = gd->arch.mck_rate_hz;
  93
  94        /* prescale */
  95        freq >>= mckr & AT91_PMC_MCKR_PRES_MASK;
  96
  97        switch (mckr & AT91_PMC_MCKR_MDIV_MASK) {
  98        case AT91_PMC_MCKR_MDIV_2:
  99                gd->arch.mck_rate_hz = freq / 2;
 100                break;
 101        case AT91_PMC_MCKR_MDIV_3:
 102                gd->arch.mck_rate_hz = freq / 3;
 103                break;
 104        case AT91_PMC_MCKR_MDIV_4:
 105                gd->arch.mck_rate_hz = freq / 4;
 106                break;
 107        default:
 108                break;
 109        }
 110
 111        gd->arch.cpu_clk_rate_hz = freq;
 112
 113        return 0;
 114}
 115
 116void at91_plla_init(u32 pllar)
 117{
 118        struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
 119
 120        writel(pllar, &pmc->pllar);
 121        while (!(readl(&pmc->sr) & (AT91_PMC_LOCKA | AT91_PMC_MCKRDY)))
 122                ;
 123}
 124
 125void at91_mck_init(u32 mckr)
 126{
 127        struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
 128        u32 tmp;
 129
 130        tmp = readl(&pmc->mckr);
 131        tmp &= ~(AT91_PMC_MCKR_CSS_MASK  |
 132                 AT91_PMC_MCKR_PRES_MASK |
 133                 AT91_PMC_MCKR_MDIV_MASK |
 134                 AT91_PMC_MCKR_PLLADIV_2);
 135#ifdef CPU_HAS_H32MXDIV
 136        tmp &= ~AT91_PMC_MCKR_H32MXDIV;
 137#endif
 138
 139        tmp |= mckr & (AT91_PMC_MCKR_CSS_MASK  |
 140                       AT91_PMC_MCKR_PRES_MASK |
 141                       AT91_PMC_MCKR_MDIV_MASK |
 142                       AT91_PMC_MCKR_PLLADIV_2);
 143#ifdef CPU_HAS_H32MXDIV
 144        tmp |= mckr & AT91_PMC_MCKR_H32MXDIV;
 145#endif
 146
 147        writel(tmp, &pmc->mckr);
 148
 149        while (!(readl(&pmc->sr) & AT91_PMC_MCKRDY))
 150                ;
 151}
 152
 153int at91_enable_periph_generated_clk(u32 id, u32 clk_source, u32 div)
 154{
 155        struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
 156        u32 regval, status;
 157        u32 timeout = 1000;
 158
 159        if (id > AT91_PMC_PCR_PID_MASK)
 160                return -EINVAL;
 161
 162        if (div > 0xff)
 163                return -EINVAL;
 164
 165        if (clk_source == GCK_CSS_UPLL_CLK) {
 166                if (at91_upll_clk_enable())
 167                        return -ENODEV;
 168        }
 169
 170        writel(id, &pmc->pcr);
 171        regval = readl(&pmc->pcr);
 172        regval &= ~AT91_PMC_PCR_GCKCSS;
 173        regval &= ~AT91_PMC_PCR_GCKDIV;
 174
 175        switch (clk_source) {
 176        case GCK_CSS_SLOW_CLK:
 177                regval |= AT91_PMC_PCR_GCKCSS_SLOW_CLK;
 178                break;
 179        case GCK_CSS_MAIN_CLK:
 180                regval |= AT91_PMC_PCR_GCKCSS_MAIN_CLK;
 181                break;
 182        case GCK_CSS_PLLA_CLK:
 183                regval |= AT91_PMC_PCR_GCKCSS_PLLA_CLK;
 184                break;
 185        case GCK_CSS_UPLL_CLK:
 186                regval |= AT91_PMC_PCR_GCKCSS_UPLL_CLK;
 187                break;
 188        case GCK_CSS_MCK_CLK:
 189                regval |= AT91_PMC_PCR_GCKCSS_MCK_CLK;
 190                break;
 191        case GCK_CSS_AUDIO_CLK:
 192                regval |= AT91_PMC_PCR_GCKCSS_AUDIO_CLK;
 193                break;
 194        default:
 195                printf("Error GCK clock source selection!\n");
 196                return -EINVAL;
 197        }
 198
 199        regval |= AT91_PMC_PCR_CMD_WRITE |
 200                  AT91_PMC_PCR_GCKDIV_(div) |
 201                  AT91_PMC_PCR_GCKEN;
 202
 203        writel(regval, &pmc->pcr);
 204
 205        do {
 206                udelay(1);
 207                status = readl(&pmc->sr);
 208        } while ((!!(--timeout)) && (!(status & AT91_PMC_GCKRDY)));
 209
 210        if (!timeout)
 211                printf("Timeout waiting for GCK ready!\n");
 212
 213        return 0;
 214}
 215
 216u32 at91_get_periph_generated_clk(u32 id)
 217{
 218        struct at91_pmc *pmc = (struct at91_pmc *)ATMEL_BASE_PMC;
 219        u32 regval, clk_source, div;
 220        u32 freq;
 221
 222        if (id > AT91_PMC_PCR_PID_MASK)
 223                return 0;
 224
 225        writel(id, &pmc->pcr);
 226        regval = readl(&pmc->pcr);
 227
 228        clk_source = regval & AT91_PMC_PCR_GCKCSS;
 229        switch (clk_source) {
 230        case AT91_PMC_PCR_GCKCSS_SLOW_CLK:
 231                freq = CONFIG_SYS_AT91_SLOW_CLOCK;
 232                break;
 233        case AT91_PMC_PCR_GCKCSS_MAIN_CLK:
 234                freq = gd->arch.main_clk_rate_hz;
 235                break;
 236        case AT91_PMC_PCR_GCKCSS_PLLA_CLK:
 237                freq = gd->arch.plla_rate_hz;
 238                break;
 239        case AT91_PMC_PCR_GCKCSS_UPLL_CLK:
 240                freq = AT91_UTMI_PLL_CLK_FREQ;
 241                break;
 242        case AT91_PMC_PCR_GCKCSS_MCK_CLK:
 243                freq = gd->arch.mck_rate_hz;
 244                break;
 245        default:
 246                printf("Improper GCK clock source selection!\n");
 247                freq = 0;
 248                break;
 249        }
 250
 251        div = ((regval & AT91_PMC_PCR_GCKDIV) >> AT91_PMC_PCR_GCKDIV_OFFSET);
 252        div += 1;
 253
 254        return freq / div;
 255}
 256