uboot/arch/arm/mach-imx/cpu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * (C) Copyright 2007
   4 * Sascha Hauer, Pengutronix
   5 *
   6 * (C) Copyright 2009 Freescale Semiconductor, Inc.
   7 */
   8
   9#include <bootm.h>
  10#include <common.h>
  11#include <dm.h>
  12#include <init.h>
  13#include <log.h>
  14#include <net.h>
  15#include <netdev.h>
  16#include <linux/errno.h>
  17#include <asm/io.h>
  18#include <asm/arch/imx-regs.h>
  19#include <asm/arch/clock.h>
  20#include <asm/arch/sys_proto.h>
  21#include <asm/arch/crm_regs.h>
  22#include <asm/mach-imx/boot_mode.h>
  23#include <imx_thermal.h>
  24#include <ipu_pixfmt.h>
  25#include <thermal.h>
  26#include <sata.h>
  27#include <dm/device-internal.h>
  28#include <dm/uclass-internal.h>
  29
  30#ifdef CONFIG_FSL_ESDHC_IMX
  31#include <fsl_esdhc_imx.h>
  32#endif
  33
  34static u32 reset_cause = -1;
  35
  36u32 get_imx_reset_cause(void)
  37{
  38        struct src *src_regs = (struct src *)SRC_BASE_ADDR;
  39
  40        if (reset_cause == -1) {
  41                reset_cause = readl(&src_regs->srsr);
  42/* preserve the value for U-Boot proper */
  43#if !defined(CONFIG_SPL_BUILD)
  44                writel(reset_cause, &src_regs->srsr);
  45#endif
  46        }
  47
  48        return reset_cause;
  49}
  50
  51#if defined(CONFIG_DISPLAY_CPUINFO) && !defined(CONFIG_SPL_BUILD)
  52static char *get_reset_cause(void)
  53{
  54        switch (get_imx_reset_cause()) {
  55        case 0x00001:
  56        case 0x00011:
  57                return "POR";
  58        case 0x00004:
  59                return "CSU";
  60        case 0x00008:
  61                return "IPP USER";
  62        case 0x00010:
  63#ifdef  CONFIG_MX7
  64                return "WDOG1";
  65#else
  66                return "WDOG";
  67#endif
  68        case 0x00020:
  69                return "JTAG HIGH-Z";
  70        case 0x00040:
  71                return "JTAG SW";
  72        case 0x00080:
  73                return "WDOG3";
  74#ifdef CONFIG_MX7
  75        case 0x00100:
  76                return "WDOG4";
  77        case 0x00200:
  78                return "TEMPSENSE";
  79#elif defined(CONFIG_IMX8M)
  80        case 0x00100:
  81                return "WDOG2";
  82        case 0x00200:
  83                return "TEMPSENSE";
  84#else
  85        case 0x00100:
  86                return "TEMPSENSE";
  87        case 0x10000:
  88                return "WARM BOOT";
  89#endif
  90        default:
  91                return "unknown reset";
  92        }
  93}
  94#endif
  95
  96#if defined(CONFIG_DISPLAY_CPUINFO) && !defined(CONFIG_SPL_BUILD)
  97
  98const char *get_imx_type(u32 imxtype)
  99{
 100        switch (imxtype) {
 101        case MXC_CPU_IMX8MP:
 102                return "8MP[8]";        /* Quad-core version of the imx8mp */
 103        case MXC_CPU_IMX8MPD:
 104                return "8MP Dual[3]";   /* Dual-core version of the imx8mp */
 105        case MXC_CPU_IMX8MPL:
 106                return "8MP Lite[4]";   /* Quad-core Lite version of the imx8mp */
 107        case MXC_CPU_IMX8MP6:
 108                return "8MP[6]";        /* Quad-core version of the imx8mp, NPU fused */
 109        case MXC_CPU_IMX8MN:
 110                return "8MNano Quad"; /* Quad-core version */
 111        case MXC_CPU_IMX8MND:
 112                return "8MNano Dual"; /* Dual-core version */
 113        case MXC_CPU_IMX8MNS:
 114                return "8MNano Solo"; /* Single-core version */
 115        case MXC_CPU_IMX8MNL:
 116                return "8MNano QuadLite"; /* Quad-core Lite version */
 117        case MXC_CPU_IMX8MNDL:
 118                return "8MNano DualLite"; /* Dual-core Lite version */
 119        case MXC_CPU_IMX8MNSL:
 120                return "8MNano SoloLite";/* Single-core Lite version of the imx8mn */
 121        case MXC_CPU_IMX8MNUQ:
 122                return "8MNano UltraLite Quad";/* Quad-core UltraLite version of the imx8mn */
 123        case MXC_CPU_IMX8MNUD:
 124                return "8MNano UltraLite Dual";/* Dual-core UltraLite version of the imx8mn */
 125        case MXC_CPU_IMX8MNUS:
 126                return "8MNano UltraLite Solo";/* Single-core UltraLite version of the imx8mn */
 127        case MXC_CPU_IMX8MM:
 128                return "8MMQ";  /* Quad-core version of the imx8mm */
 129        case MXC_CPU_IMX8MML:
 130                return "8MMQL"; /* Quad-core Lite version of the imx8mm */
 131        case MXC_CPU_IMX8MMD:
 132                return "8MMD";  /* Dual-core version of the imx8mm */
 133        case MXC_CPU_IMX8MMDL:
 134                return "8MMDL"; /* Dual-core Lite version of the imx8mm */
 135        case MXC_CPU_IMX8MMS:
 136                return "8MMS";  /* Single-core version of the imx8mm */
 137        case MXC_CPU_IMX8MMSL:
 138                return "8MMSL"; /* Single-core Lite version of the imx8mm */
 139        case MXC_CPU_IMX8MQ:
 140                return "8MQ";   /* Quad-core version of the imx8mq */
 141        case MXC_CPU_IMX8MQL:
 142                return "8MQLite";       /* Quad-core Lite version of the imx8mq */
 143        case MXC_CPU_IMX8MD:
 144                return "8MD";   /* Dual-core version of the imx8mq */
 145        case MXC_CPU_MX7S:
 146                return "7S";    /* Single-core version of the mx7 */
 147        case MXC_CPU_MX7D:
 148                return "7D";    /* Dual-core version of the mx7 */
 149        case MXC_CPU_MX6QP:
 150                return "6QP";   /* Quad-Plus version of the mx6 */
 151        case MXC_CPU_MX6DP:
 152                return "6DP";   /* Dual-Plus version of the mx6 */
 153        case MXC_CPU_MX6Q:
 154                return "6Q";    /* Quad-core version of the mx6 */
 155        case MXC_CPU_MX6D:
 156                return "6D";    /* Dual-core version of the mx6 */
 157        case MXC_CPU_MX6DL:
 158                return "6DL";   /* Dual Lite version of the mx6 */
 159        case MXC_CPU_MX6SOLO:
 160                return "6SOLO"; /* Solo version of the mx6 */
 161        case MXC_CPU_MX6SL:
 162                return "6SL";   /* Solo-Lite version of the mx6 */
 163        case MXC_CPU_MX6SLL:
 164                return "6SLL";  /* SLL version of the mx6 */
 165        case MXC_CPU_MX6SX:
 166                return "6SX";   /* SoloX version of the mx6 */
 167        case MXC_CPU_MX6UL:
 168                return "6UL";   /* Ultra-Lite version of the mx6 */
 169        case MXC_CPU_MX6ULL:
 170                return "6ULL";  /* ULL version of the mx6 */
 171        case MXC_CPU_MX6ULZ:
 172                return "6ULZ";  /* ULZ version of the mx6 */
 173        case MXC_CPU_MX51:
 174                return "51";
 175        case MXC_CPU_MX53:
 176                return "53";
 177        default:
 178                return "??";
 179        }
 180}
 181
 182int print_cpuinfo(void)
 183{
 184        u32 cpurev;
 185        __maybe_unused u32 max_freq;
 186
 187        cpurev = get_cpu_rev();
 188
 189#if defined(CONFIG_IMX_THERMAL) || defined(CONFIG_IMX_TMU)
 190        struct udevice *thermal_dev;
 191        int cpu_tmp, minc, maxc, ret;
 192
 193        printf("CPU:   Freescale i.MX%s rev%d.%d",
 194               get_imx_type((cpurev & 0x1FF000) >> 12),
 195               (cpurev & 0x000F0) >> 4,
 196               (cpurev & 0x0000F) >> 0);
 197        max_freq = get_cpu_speed_grade_hz();
 198        if (!max_freq || max_freq == mxc_get_clock(MXC_ARM_CLK)) {
 199                printf(" at %dMHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
 200        } else {
 201                printf(" %d MHz (running at %d MHz)\n", max_freq / 1000000,
 202                       mxc_get_clock(MXC_ARM_CLK) / 1000000);
 203        }
 204#else
 205        printf("CPU:   Freescale i.MX%s rev%d.%d at %d MHz\n",
 206                get_imx_type((cpurev & 0x1FF000) >> 12),
 207                (cpurev & 0x000F0) >> 4,
 208                (cpurev & 0x0000F) >> 0,
 209                mxc_get_clock(MXC_ARM_CLK) / 1000000);
 210#endif
 211
 212#if defined(CONFIG_IMX_THERMAL) || defined(CONFIG_IMX_TMU)
 213        puts("CPU:   ");
 214        switch (get_cpu_temp_grade(&minc, &maxc)) {
 215        case TEMP_AUTOMOTIVE:
 216                puts("Automotive temperature grade ");
 217                break;
 218        case TEMP_INDUSTRIAL:
 219                puts("Industrial temperature grade ");
 220                break;
 221        case TEMP_EXTCOMMERCIAL:
 222                puts("Extended Commercial temperature grade ");
 223                break;
 224        default:
 225                puts("Commercial temperature grade ");
 226                break;
 227        }
 228        printf("(%dC to %dC)", minc, maxc);
 229        ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev);
 230        if (!ret) {
 231                ret = thermal_get_temp(thermal_dev, &cpu_tmp);
 232
 233                if (!ret)
 234                        printf(" at %dC", cpu_tmp);
 235                else
 236                        debug(" - invalid sensor data\n");
 237        } else {
 238                debug(" - invalid sensor device\n");
 239        }
 240        puts("\n");
 241#endif
 242
 243        printf("Reset cause: %s\n", get_reset_cause());
 244        return 0;
 245}
 246#endif
 247
 248int cpu_eth_init(struct bd_info *bis)
 249{
 250        int rc = -ENODEV;
 251
 252#if defined(CONFIG_FEC_MXC)
 253        rc = fecmxc_initialize(bis);
 254#endif
 255
 256        return rc;
 257}
 258
 259#ifdef CONFIG_FSL_ESDHC_IMX
 260/*
 261 * Initializes on-chip MMC controllers.
 262 * to override, implement board_mmc_init()
 263 */
 264int cpu_mmc_init(struct bd_info *bis)
 265{
 266        return fsl_esdhc_mmc_init(bis);
 267}
 268#endif
 269
 270#if !(defined(CONFIG_MX7) || defined(CONFIG_IMX8M))
 271u32 get_ahb_clk(void)
 272{
 273        struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
 274        u32 reg, ahb_podf;
 275
 276        reg = __raw_readl(&imx_ccm->cbcdr);
 277        reg &= MXC_CCM_CBCDR_AHB_PODF_MASK;
 278        ahb_podf = reg >> MXC_CCM_CBCDR_AHB_PODF_OFFSET;
 279
 280        return get_periph_clk() / (ahb_podf + 1);
 281}
 282#endif
 283
 284void arch_preboot_os(void)
 285{
 286#if defined(CONFIG_IMX_AHCI)
 287        struct udevice *dev;
 288        int rc;
 289
 290        rc = uclass_find_device(UCLASS_AHCI, 0, &dev);
 291        if (!rc && dev) {
 292                rc = device_remove(dev, DM_REMOVE_NORMAL);
 293                if (rc)
 294                        printf("Cannot remove SATA device '%s' (err=%d)\n",
 295                                dev->name, rc);
 296        }
 297#endif
 298
 299#if defined(CONFIG_SATA)
 300        if (!is_mx6sdl()) {
 301                sata_remove(0);
 302#if defined(CONFIG_MX6)
 303                disable_sata_clock();
 304#endif
 305        }
 306#endif
 307#if defined(CONFIG_VIDEO_IPUV3)
 308        /* disable video before launching O/S */
 309        ipuv3_fb_shutdown();
 310#endif
 311#if defined(CONFIG_VIDEO_MXS) && !defined(CONFIG_DM_VIDEO)
 312        lcdif_power_down();
 313#endif
 314}
 315
 316#ifndef CONFIG_IMX8M
 317void set_chipselect_size(int const cs_size)
 318{
 319        unsigned int reg;
 320        struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
 321        reg = readl(&iomuxc_regs->gpr[1]);
 322
 323        switch (cs_size) {
 324        case CS0_128:
 325                reg &= ~0x7;    /* CS0=128MB, CS1=0, CS2=0, CS3=0 */
 326                reg |= 0x5;
 327                break;
 328        case CS0_64M_CS1_64M:
 329                reg &= ~0x3F;   /* CS0=64MB, CS1=64MB, CS2=0, CS3=0 */
 330                reg |= 0x1B;
 331                break;
 332        case CS0_64M_CS1_32M_CS2_32M:
 333                reg &= ~0x1FF;  /* CS0=64MB, CS1=32MB, CS2=32MB, CS3=0 */
 334                reg |= 0x4B;
 335                break;
 336        case CS0_32M_CS1_32M_CS2_32M_CS3_32M:
 337                reg &= ~0xFFF;  /* CS0=32MB, CS1=32MB, CS2=32MB, CS3=32MB */
 338                reg |= 0x249;
 339                break;
 340        default:
 341                printf("Unknown chip select size: %d\n", cs_size);
 342                break;
 343        }
 344
 345        writel(reg, &iomuxc_regs->gpr[1]);
 346}
 347#endif
 348
 349#if defined(CONFIG_MX7) || defined(CONFIG_IMX8M)
 350/*
 351 * OCOTP_TESTER3[9:8] (see Fusemap Description Table offset 0x440)
 352 * defines a 2-bit SPEED_GRADING
 353 */
 354#define OCOTP_TESTER3_SPEED_SHIFT       8
 355enum cpu_speed {
 356        OCOTP_TESTER3_SPEED_GRADE0,
 357        OCOTP_TESTER3_SPEED_GRADE1,
 358        OCOTP_TESTER3_SPEED_GRADE2,
 359        OCOTP_TESTER3_SPEED_GRADE3,
 360        OCOTP_TESTER3_SPEED_GRADE4,
 361};
 362
 363u32 get_cpu_speed_grade_hz(void)
 364{
 365        struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
 366        struct fuse_bank *bank = &ocotp->bank[1];
 367        struct fuse_bank1_regs *fuse =
 368                (struct fuse_bank1_regs *)bank->fuse_regs;
 369        uint32_t val;
 370
 371        val = readl(&fuse->tester3);
 372        val >>= OCOTP_TESTER3_SPEED_SHIFT;
 373
 374        if (is_imx8mn() || is_imx8mp()) {
 375                val &= 0xf;
 376                return 2300000000 - val * 100000000;
 377        }
 378
 379        if (is_imx8mm())
 380                val &= 0x7;
 381        else
 382                val &= 0x3;
 383
 384        switch(val) {
 385        case OCOTP_TESTER3_SPEED_GRADE0:
 386                return 800000000;
 387        case OCOTP_TESTER3_SPEED_GRADE1:
 388                return (is_mx7() ? 500000000 : (is_imx8mq() ? 1000000000 : 1200000000));
 389        case OCOTP_TESTER3_SPEED_GRADE2:
 390                return (is_mx7() ? 1000000000 : (is_imx8mq() ? 1300000000 : 1600000000));
 391        case OCOTP_TESTER3_SPEED_GRADE3:
 392                return (is_mx7() ? 1200000000 : (is_imx8mq() ? 1500000000 : 1800000000));
 393        case OCOTP_TESTER3_SPEED_GRADE4:
 394                return 2000000000;
 395        }
 396
 397        return 0;
 398}
 399
 400/*
 401 * OCOTP_TESTER3[7:6] (see Fusemap Description Table offset 0x440)
 402 * defines a 2-bit SPEED_GRADING
 403 */
 404#define OCOTP_TESTER3_TEMP_SHIFT        6
 405
 406/* iMX8MP uses OCOTP_TESTER3[6:5] for Market segment */
 407#define IMX8MP_OCOTP_TESTER3_TEMP_SHIFT 5
 408
 409u32 get_cpu_temp_grade(int *minc, int *maxc)
 410{
 411        struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
 412        struct fuse_bank *bank = &ocotp->bank[1];
 413        struct fuse_bank1_regs *fuse =
 414                (struct fuse_bank1_regs *)bank->fuse_regs;
 415        uint32_t val;
 416
 417        val = readl(&fuse->tester3);
 418        if (is_imx8mp())
 419                val >>= IMX8MP_OCOTP_TESTER3_TEMP_SHIFT;
 420        else
 421                val >>= OCOTP_TESTER3_TEMP_SHIFT;
 422        val &= 0x3;
 423
 424        if (minc && maxc) {
 425                if (val == TEMP_AUTOMOTIVE) {
 426                        *minc = -40;
 427                        *maxc = 125;
 428                } else if (val == TEMP_INDUSTRIAL) {
 429                        *minc = -40;
 430                        *maxc = 105;
 431                } else if (val == TEMP_EXTCOMMERCIAL) {
 432                        *minc = -20;
 433                        *maxc = 105;
 434                } else {
 435                        *minc = 0;
 436                        *maxc = 95;
 437                }
 438        }
 439        return val;
 440}
 441#endif
 442
 443#if defined(CONFIG_MX7) || defined(CONFIG_IMX8MQ) || defined(CONFIG_IMX8MM)
 444enum boot_device get_boot_device(void)
 445{
 446        struct bootrom_sw_info **p =
 447                (struct bootrom_sw_info **)(ulong)ROM_SW_INFO_ADDR;
 448
 449        enum boot_device boot_dev = SD1_BOOT;
 450        u8 boot_type = (*p)->boot_dev_type;
 451        u8 boot_instance = (*p)->boot_dev_instance;
 452
 453        switch (boot_type) {
 454        case BOOT_TYPE_SD:
 455                boot_dev = boot_instance + SD1_BOOT;
 456                break;
 457        case BOOT_TYPE_MMC:
 458                boot_dev = boot_instance + MMC1_BOOT;
 459                break;
 460        case BOOT_TYPE_NAND:
 461                boot_dev = NAND_BOOT;
 462                break;
 463        case BOOT_TYPE_QSPI:
 464                boot_dev = QSPI_BOOT;
 465                break;
 466        case BOOT_TYPE_WEIM:
 467                boot_dev = WEIM_NOR_BOOT;
 468                break;
 469        case BOOT_TYPE_SPINOR:
 470                boot_dev = SPI_NOR_BOOT;
 471                break;
 472        case BOOT_TYPE_USB:
 473                boot_dev = USB_BOOT;
 474                break;
 475        default:
 476#ifdef CONFIG_IMX8M
 477                if (((readl(SRC_BASE_ADDR + 0x58) & 0x00007FFF) >> 12) == 0x4)
 478                        boot_dev = QSPI_BOOT;
 479#endif
 480                break;
 481        }
 482
 483        return boot_dev;
 484}
 485#endif
 486
 487#ifdef CONFIG_NXP_BOARD_REVISION
 488int nxp_board_rev(void)
 489{
 490        /*
 491         * Get Board ID information from OCOTP_GP1[15:8]
 492         * RevA: 0x1
 493         * RevB: 0x2
 494         * RevC: 0x3
 495         */
 496        struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
 497        struct fuse_bank *bank = &ocotp->bank[4];
 498        struct fuse_bank4_regs *fuse =
 499                        (struct fuse_bank4_regs *)bank->fuse_regs;
 500
 501        return (readl(&fuse->gp1) >> 8 & 0x0F);
 502}
 503
 504char nxp_board_rev_string(void)
 505{
 506        const char *rev = "A";
 507
 508        return (*rev + nxp_board_rev() - 1);
 509}
 510#endif
 511