uboot/arch/arm/cpu/arm926ejs/mx25/generic.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2009 DENX Software Engineering
   4 * Author: John Rigby <jrigby@gmail.com>
   5 *
   6 * Based on mx27/generic.c:
   7 *  Copyright (c) 2008 Eric Jarrige <eric.jarrige@armadeus.org>
   8 *  Copyright (c) 2009 Ilya Yanok <yanok@emcraft.com>
   9 */
  10
  11#include <common.h>
  12#include <clock_legacy.h>
  13#include <div64.h>
  14#include <init.h>
  15#include <net.h>
  16#include <netdev.h>
  17#include <vsprintf.h>
  18#include <asm/global_data.h>
  19#include <asm/io.h>
  20#include <asm/arch-imx/cpu.h>
  21#include <asm/arch/imx-regs.h>
  22#include <asm/arch/clock.h>
  23
  24#ifdef CONFIG_FSL_ESDHC_IMX
  25#include <fsl_esdhc_imx.h>
  26
  27DECLARE_GLOBAL_DATA_PTR;
  28#endif
  29
  30/*
  31 *  get the system pll clock in Hz
  32 *
  33 *                  mfi + mfn / (mfd +1)
  34 *  f = 2 * f_ref * --------------------
  35 *                        pd + 1
  36 */
  37static unsigned int imx_decode_pll(unsigned int pll, unsigned int f_ref)
  38{
  39        unsigned int mfi = (pll >> CCM_PLL_MFI_SHIFT)
  40            & CCM_PLL_MFI_MASK;
  41        int mfn = (pll >> CCM_PLL_MFN_SHIFT)
  42            & CCM_PLL_MFN_MASK;
  43        unsigned int mfd = (pll >> CCM_PLL_MFD_SHIFT)
  44            & CCM_PLL_MFD_MASK;
  45        unsigned int pd = (pll >> CCM_PLL_PD_SHIFT)
  46            & CCM_PLL_PD_MASK;
  47
  48        mfi = mfi <= 5 ? 5 : mfi;
  49        mfn = mfn >= 512 ? mfn - 1024 : mfn;
  50        mfd += 1;
  51        pd += 1;
  52
  53        return lldiv(2 * (u64) f_ref * (mfi * mfd + mfn),
  54                     mfd * pd);
  55}
  56
  57static ulong imx_get_mpllclk(void)
  58{
  59        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
  60        ulong fref = MXC_HCLK;
  61
  62        return imx_decode_pll(readl(&ccm->mpctl), fref);
  63}
  64
  65static ulong imx_get_upllclk(void)
  66{
  67        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
  68        ulong fref = MXC_HCLK;
  69
  70        return imx_decode_pll(readl(&ccm->upctl), fref);
  71}
  72
  73static ulong imx_get_armclk(void)
  74{
  75        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
  76        ulong cctl = readl(&ccm->cctl);
  77        ulong fref = imx_get_mpllclk();
  78        ulong div;
  79
  80        if (cctl & CCM_CCTL_ARM_SRC)
  81                fref = lldiv((u64) fref * 3, 4);
  82
  83        div = ((cctl >> CCM_CCTL_ARM_DIV_SHIFT)
  84               & CCM_CCTL_ARM_DIV_MASK) + 1;
  85
  86        return fref / div;
  87}
  88
  89static ulong imx_get_ahbclk(void)
  90{
  91        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
  92        ulong cctl = readl(&ccm->cctl);
  93        ulong fref = imx_get_armclk();
  94        ulong div;
  95
  96        div = ((cctl >> CCM_CCTL_AHB_DIV_SHIFT)
  97               & CCM_CCTL_AHB_DIV_MASK) + 1;
  98
  99        return fref / div;
 100}
 101
 102static ulong imx_get_ipgclk(void)
 103{
 104        return imx_get_ahbclk() / 2;
 105}
 106
 107static ulong imx_get_perclk(int clk)
 108{
 109        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
 110        ulong fref = readl(&ccm->mcr) & (1 << clk) ? imx_get_upllclk() :
 111                                                     imx_get_ahbclk();
 112        ulong div;
 113
 114        div = readl(&ccm->pcdr[CCM_PERCLK_REG(clk)]);
 115        div = ((div >> CCM_PERCLK_SHIFT(clk)) & CCM_PERCLK_MASK) + 1;
 116
 117        return fref / div;
 118}
 119
 120int imx_set_perclk(enum mxc_clock clk, bool from_upll, unsigned int freq)
 121{
 122        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
 123        ulong fref = from_upll ? imx_get_upllclk() : imx_get_ahbclk();
 124        ulong div = (fref + freq - 1) / freq;
 125
 126        if (clk > MXC_UART_CLK || !div || --div > CCM_PERCLK_MASK)
 127                return -EINVAL;
 128
 129        clrsetbits_le32(&ccm->pcdr[CCM_PERCLK_REG(clk)],
 130                        CCM_PERCLK_MASK << CCM_PERCLK_SHIFT(clk),
 131                        div << CCM_PERCLK_SHIFT(clk));
 132        if (from_upll)
 133                setbits_le32(&ccm->mcr, 1 << clk);
 134        else
 135                clrbits_le32(&ccm->mcr, 1 << clk);
 136        return 0;
 137}
 138
 139unsigned int mxc_get_clock(enum mxc_clock clk)
 140{
 141        if (clk >= MXC_CLK_NUM)
 142                return -1;
 143        switch (clk) {
 144        case MXC_ARM_CLK:
 145                return imx_get_armclk();
 146        case MXC_AHB_CLK:
 147                return imx_get_ahbclk();
 148        case MXC_IPG_CLK:
 149        case MXC_CSPI_CLK:
 150        case MXC_FEC_CLK:
 151                return imx_get_ipgclk();
 152        default:
 153                return imx_get_perclk(clk);
 154        }
 155}
 156
 157u32 get_cpu_rev(void)
 158{
 159        u32 srev;
 160        u32 system_rev = 0x25000;
 161
 162        /* read SREV register from IIM module */
 163        struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
 164        srev = readl(&iim->iim_srev);
 165
 166        switch (srev) {
 167        case 0x00:
 168                system_rev |= CHIP_REV_1_0;
 169                break;
 170        case 0x01:
 171                system_rev |= CHIP_REV_1_1;
 172                break;
 173        case 0x02:
 174                system_rev |= CHIP_REV_1_2;
 175                break;
 176        default:
 177                system_rev |= 0x8000;
 178                break;
 179        }
 180
 181        return system_rev;
 182}
 183
 184#if defined(CONFIG_DISPLAY_CPUINFO)
 185static char *get_reset_cause(void)
 186{
 187        /* read RCSR register from CCM module */
 188        struct ccm_regs *ccm =
 189                (struct ccm_regs *)IMX_CCM_BASE;
 190
 191        u32 cause = readl(&ccm->rcsr) & 0x0f;
 192
 193        if (cause == 0)
 194                return "POR";
 195        else if (cause == 1)
 196                return "RST";
 197        else if ((cause & 2) == 2)
 198                return "WDOG";
 199        else if ((cause & 4) == 4)
 200                return "SW RESET";
 201        else if ((cause & 8) == 8)
 202                return "JTAG";
 203        else
 204                return "unknown reset";
 205
 206}
 207
 208int print_cpuinfo(void)
 209{
 210        char buf[32];
 211        u32 cpurev = get_cpu_rev();
 212
 213        printf("CPU:   Freescale i.MX25 rev%d.%d%s at %s MHz\n",
 214                (cpurev & 0xF0) >> 4, (cpurev & 0x0F),
 215                ((cpurev & 0x8000) ? " unknown" : ""),
 216                strmhz(buf, imx_get_armclk()));
 217        printf("Reset cause: %s\n", get_reset_cause());
 218        return 0;
 219}
 220#endif
 221
 222#if defined(CONFIG_FEC_MXC)
 223/*
 224 * Initializes on-chip ethernet controllers.
 225 * to override, implement board_eth_init()
 226 */
 227int cpu_eth_init(struct bd_info *bis)
 228{
 229        struct ccm_regs *ccm = (struct ccm_regs *)IMX_CCM_BASE;
 230        ulong val;
 231
 232        val = readl(&ccm->cgr0);
 233        val |= (1 << 23);
 234        writel(val, &ccm->cgr0);
 235        return fecmxc_initialize(bis);
 236}
 237#endif
 238
 239int get_clocks(void)
 240{
 241#ifdef CONFIG_FSL_ESDHC_IMX
 242#if CONFIG_SYS_FSL_ESDHC_ADDR == IMX_MMC_SDHC2_BASE
 243        gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC2_CLK);
 244#else
 245        gd->arch.sdhc_clk = mxc_get_clock(MXC_ESDHC1_CLK);
 246#endif
 247#endif
 248        return 0;
 249}
 250
 251#ifdef CONFIG_FSL_ESDHC_IMX
 252/*
 253 * Initializes on-chip MMC controllers.
 254 * to override, implement board_mmc_init()
 255 */
 256int cpu_mmc_init(struct bd_info *bis)
 257{
 258        return fsl_esdhc_mmc_init(bis);
 259}
 260#endif
 261
 262#ifdef CONFIG_FEC_MXC
 263void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
 264{
 265        int i;
 266        struct iim_regs *iim = (struct iim_regs *)IMX_IIM_BASE;
 267        struct fuse_bank *bank = &iim->bank[0];
 268        struct fuse_bank0_regs *fuse =
 269                        (struct fuse_bank0_regs *)bank->fuse_regs;
 270
 271        for (i = 0; i < 6; i++)
 272                mac[i] = readl(&fuse->mac_addr[i]) & 0xff;
 273}
 274#endif /* CONFIG_FEC_MXC */
 275