uboot/arch/arm/cpu/arm1136/mx31/generic.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2007
   3 * Sascha Hauer, Pengutronix
   4 *
   5 * SPDX-License-Identifier:     GPL-2.0+
   6 */
   7
   8#include <common.h>
   9#include <div64.h>
  10#include <asm/arch/imx-regs.h>
  11#include <asm/arch/clock.h>
  12#include <asm/io.h>
  13#include <asm/arch/sys_proto.h>
  14
  15static u32 mx31_decode_pll(u32 reg, u32 infreq)
  16{
  17        u32 mfi = GET_PLL_MFI(reg);
  18        s32 mfn = GET_PLL_MFN(reg);
  19        u32 mfd = GET_PLL_MFD(reg);
  20        u32 pd =  GET_PLL_PD(reg);
  21
  22        mfi = mfi <= 5 ? 5 : mfi;
  23        mfn = mfn >= 512 ? mfn - 1024 : mfn;
  24        mfd += 1;
  25        pd += 1;
  26
  27        return lldiv(2 * (u64)infreq * (mfi * mfd + mfn),
  28                mfd * pd);
  29}
  30
  31static u32 mx31_get_mpl_dpdgck_clk(void)
  32{
  33        u32 infreq;
  34
  35        if ((readl(CCM_CCMR) & CCMR_PRCS_MASK) == CCMR_FPM)
  36                infreq = MXC_CLK32 * 1024;
  37        else
  38                infreq = MXC_HCLK;
  39
  40        return mx31_decode_pll(readl(CCM_MPCTL), infreq);
  41}
  42
  43static u32 mx31_get_mcu_main_clk(void)
  44{
  45        /* For now we assume mpl_dpdgck_clk == mcu_main_clk
  46         * which should be correct for most boards
  47         */
  48        return mx31_get_mpl_dpdgck_clk();
  49}
  50
  51static u32 mx31_get_ipg_clk(void)
  52{
  53        u32 freq = mx31_get_mcu_main_clk();
  54        u32 pdr0 = readl(CCM_PDR0);
  55
  56        freq /= GET_PDR0_MAX_PODF(pdr0) + 1;
  57        freq /= GET_PDR0_IPG_PODF(pdr0) + 1;
  58
  59        return freq;
  60}
  61
  62/* hsp is the clock for the ipu */
  63static u32 mx31_get_hsp_clk(void)
  64{
  65        u32 freq = mx31_get_mcu_main_clk();
  66        u32 pdr0 = readl(CCM_PDR0);
  67
  68        freq /= GET_PDR0_HSP_PODF(pdr0) + 1;
  69
  70        return freq;
  71}
  72
  73void mx31_dump_clocks(void)
  74{
  75        u32 cpufreq = mx31_get_mcu_main_clk();
  76        printf("mx31 cpu clock: %dMHz\n", cpufreq / 1000000);
  77        printf("ipg clock     : %dHz\n", mx31_get_ipg_clk());
  78        printf("hsp clock     : %dHz\n", mx31_get_hsp_clk());
  79}
  80
  81unsigned int mxc_get_clock(enum mxc_clock clk)
  82{
  83        switch (clk) {
  84        case MXC_ARM_CLK:
  85                return mx31_get_mcu_main_clk();
  86        case MXC_IPG_CLK:
  87        case MXC_IPG_PERCLK:
  88        case MXC_CSPI_CLK:
  89        case MXC_UART_CLK:
  90        case MXC_ESDHC_CLK:
  91        case MXC_I2C_CLK:
  92                return mx31_get_ipg_clk();
  93        case MXC_IPU_CLK:
  94                return mx31_get_hsp_clk();
  95        }
  96        return -1;
  97}
  98
  99u32 imx_get_uartclk(void)
 100{
 101        return mxc_get_clock(MXC_UART_CLK);
 102}
 103
 104void mx31_gpio_mux(unsigned long mode)
 105{
 106        unsigned long reg, shift, tmp;
 107
 108        reg = IOMUXC_BASE + (mode & 0x1fc);
 109        shift = (~mode & 0x3) * 8;
 110
 111        tmp = readl(reg);
 112        tmp &= ~(0xff << shift);
 113        tmp |= ((mode >> IOMUX_MODE_POS) & 0xff) << shift;
 114        writel(tmp, reg);
 115}
 116
 117void mx31_set_pad(enum iomux_pins pin, u32 config)
 118{
 119        u32 field, l, reg;
 120
 121        pin &= IOMUX_PADNUM_MASK;
 122        reg = (IOMUXC_BASE + 0x154) + (pin + 2) / 3 * 4;
 123        field = (pin + 2) % 3;
 124
 125        l = readl(reg);
 126        l &= ~(0x1ff << (field * 10));
 127        l |= config << (field * 10);
 128        writel(l, reg);
 129
 130}
 131
 132void mx31_set_gpr(enum iomux_gp_func gp, char en)
 133{
 134        u32 l;
 135        struct iomuxc_regs *iomuxc = (struct iomuxc_regs *)IOMUXC_BASE;
 136
 137        l = readl(&iomuxc->gpr);
 138        if (en)
 139                l |= gp;
 140        else
 141                l &= ~gp;
 142
 143        writel(l, &iomuxc->gpr);
 144}
 145
 146void mxc_setup_weimcs(int cs, const struct mxc_weimcs *weimcs)
 147{
 148        struct mx31_weim *weim = (struct mx31_weim *) WEIM_BASE;
 149        struct mx31_weim_cscr *cscr = &weim->cscr[cs];
 150
 151        writel(weimcs->upper, &cscr->upper);
 152        writel(weimcs->lower, &cscr->lower);
 153        writel(weimcs->additional, &cscr->additional);
 154}
 155
 156struct mx3_cpu_type mx31_cpu_type[] = {
 157        { .srev = 0x00, .v = 0x10 },
 158        { .srev = 0x10, .v = 0x11 },
 159        { .srev = 0x11, .v = 0x11 },
 160        { .srev = 0x12, .v = 0x1F },
 161        { .srev = 0x13, .v = 0x1F },
 162        { .srev = 0x14, .v = 0x12 },
 163        { .srev = 0x15, .v = 0x12 },
 164        { .srev = 0x28, .v = 0x20 },
 165        { .srev = 0x29, .v = 0x20 },
 166};
 167
 168u32 get_cpu_rev(void)
 169{
 170        u32 i, srev;
 171
 172        /* read SREV register from IIM module */
 173        struct iim_regs *iim = (struct iim_regs *)MX31_IIM_BASE_ADDR;
 174        srev = readl(&iim->iim_srev);
 175
 176        for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++)
 177                if (srev == mx31_cpu_type[i].srev)
 178                        return mx31_cpu_type[i].v | (MXC_CPU_MX31 << 12);
 179
 180        return srev | 0x8000;
 181}
 182
 183static char *get_reset_cause(void)
 184{
 185        /* read RCSR register from CCM module */
 186        struct clock_control_regs *ccm =
 187                (struct clock_control_regs *)CCM_BASE;
 188
 189        u32 cause = readl(&ccm->rcsr) & 0x07;
 190
 191        switch (cause) {
 192        case 0x0000:
 193                return "POR";
 194        case 0x0001:
 195                return "RST";
 196        case 0x0002:
 197                return "WDOG";
 198        case 0x0006:
 199                return "JTAG";
 200        case 0x0007:
 201                return "ARM11P power gating";
 202        default:
 203                return "unknown reset";
 204        }
 205}
 206
 207#if defined(CONFIG_DISPLAY_CPUINFO)
 208int print_cpuinfo(void)
 209{
 210        u32 srev = get_cpu_rev();
 211
 212        printf("CPU:   Freescale i.MX31 rev %d.%d%s at %d MHz.\n",
 213                        (srev & 0xF0) >> 4, (srev & 0x0F),
 214                        ((srev & 0x8000) ? " unknown" : ""),
 215                        mx31_get_mcu_main_clk() / 1000000);
 216        printf("Reset cause: %s\n", get_reset_cause());
 217        return 0;
 218}
 219#endif
 220