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