mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-03 18:10:13 +00:00
83d290c56f
When U-Boot started using SPDX tags we were among the early adopters and there weren't a lot of other examples to borrow from. So we picked the area of the file that usually had a full license text and replaced it with an appropriate SPDX-License-Identifier: entry. Since then, the Linux Kernel has adopted SPDX tags and they place it as the very first line in a file (except where shebangs are used, then it's second line) and with slightly different comment styles than us. In part due to community overlap, in part due to better tag visibility and in part for other minor reasons, switch over to that style. This commit changes all instances where we have a single declared license in the tag as both the before and after are identical in tag contents. There's also a few places where I found we did not have a tag and have introduced one. Signed-off-by: Tom Rini <trini@konsulko.com>
477 lines
11 KiB
C
477 lines
11 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* (C) Copyright 2007
|
|
* Sascha Hauer, Pengutronix
|
|
*
|
|
* (C) Copyright 2009 Freescale Semiconductor, Inc.
|
|
*/
|
|
|
|
#include <bootm.h>
|
|
#include <common.h>
|
|
#include <netdev.h>
|
|
#include <linux/errno.h>
|
|
#include <asm/io.h>
|
|
#include <asm/arch/imx-regs.h>
|
|
#include <asm/arch/clock.h>
|
|
#include <asm/arch/sys_proto.h>
|
|
#include <asm/arch/crm_regs.h>
|
|
#include <asm/mach-imx/boot_mode.h>
|
|
#include <imx_thermal.h>
|
|
#include <ipu_pixfmt.h>
|
|
#include <thermal.h>
|
|
#include <sata.h>
|
|
|
|
#ifdef CONFIG_FSL_ESDHC
|
|
#include <fsl_esdhc.h>
|
|
#endif
|
|
|
|
#if defined(CONFIG_DISPLAY_CPUINFO) && !defined(CONFIG_SPL_BUILD)
|
|
static u32 reset_cause = -1;
|
|
|
|
static char *get_reset_cause(void)
|
|
{
|
|
u32 cause;
|
|
struct src *src_regs = (struct src *)SRC_BASE_ADDR;
|
|
|
|
cause = readl(&src_regs->srsr);
|
|
writel(cause, &src_regs->srsr);
|
|
reset_cause = cause;
|
|
|
|
switch (cause) {
|
|
case 0x00001:
|
|
case 0x00011:
|
|
return "POR";
|
|
case 0x00004:
|
|
return "CSU";
|
|
case 0x00008:
|
|
return "IPP USER";
|
|
case 0x00010:
|
|
#ifdef CONFIG_MX7
|
|
return "WDOG1";
|
|
#else
|
|
return "WDOG";
|
|
#endif
|
|
case 0x00020:
|
|
return "JTAG HIGH-Z";
|
|
case 0x00040:
|
|
return "JTAG SW";
|
|
case 0x00080:
|
|
return "WDOG3";
|
|
#ifdef CONFIG_MX7
|
|
case 0x00100:
|
|
return "WDOG4";
|
|
case 0x00200:
|
|
return "TEMPSENSE";
|
|
#elif defined(CONFIG_MX8M)
|
|
case 0x00100:
|
|
return "WDOG2";
|
|
case 0x00200:
|
|
return "TEMPSENSE";
|
|
#else
|
|
case 0x00100:
|
|
return "TEMPSENSE";
|
|
case 0x10000:
|
|
return "WARM BOOT";
|
|
#endif
|
|
default:
|
|
return "unknown reset";
|
|
}
|
|
}
|
|
|
|
u32 get_imx_reset_cause(void)
|
|
{
|
|
return reset_cause;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_MX53) || defined(CONFIG_MX6)
|
|
#if defined(CONFIG_MX53)
|
|
#define MEMCTL_BASE ESDCTL_BASE_ADDR
|
|
#else
|
|
#define MEMCTL_BASE MMDC_P0_BASE_ADDR
|
|
#endif
|
|
static const unsigned char col_lookup[] = {9, 10, 11, 8, 12, 9, 9, 9};
|
|
static const unsigned char bank_lookup[] = {3, 2};
|
|
|
|
/* these MMDC registers are common to the IMX53 and IMX6 */
|
|
struct esd_mmdc_regs {
|
|
uint32_t ctl;
|
|
uint32_t pdc;
|
|
uint32_t otc;
|
|
uint32_t cfg0;
|
|
uint32_t cfg1;
|
|
uint32_t cfg2;
|
|
uint32_t misc;
|
|
};
|
|
|
|
#define ESD_MMDC_CTL_GET_ROW(mdctl) ((ctl >> 24) & 7)
|
|
#define ESD_MMDC_CTL_GET_COLUMN(mdctl) ((ctl >> 20) & 7)
|
|
#define ESD_MMDC_CTL_GET_WIDTH(mdctl) ((ctl >> 16) & 3)
|
|
#define ESD_MMDC_CTL_GET_CS1(mdctl) ((ctl >> 30) & 1)
|
|
#define ESD_MMDC_MISC_GET_BANK(mdmisc) ((misc >> 5) & 1)
|
|
|
|
/*
|
|
* imx_ddr_size - return size in bytes of DRAM according MMDC config
|
|
* The MMDC MDCTL register holds the number of bits for row, col, and data
|
|
* width and the MMDC MDMISC register holds the number of banks. Combine
|
|
* all these bits to determine the meme size the MMDC has been configured for
|
|
*/
|
|
unsigned imx_ddr_size(void)
|
|
{
|
|
struct esd_mmdc_regs *mem = (struct esd_mmdc_regs *)MEMCTL_BASE;
|
|
unsigned ctl = readl(&mem->ctl);
|
|
unsigned misc = readl(&mem->misc);
|
|
int bits = 11 + 0 + 0 + 1; /* row + col + bank + width */
|
|
|
|
bits += ESD_MMDC_CTL_GET_ROW(ctl);
|
|
bits += col_lookup[ESD_MMDC_CTL_GET_COLUMN(ctl)];
|
|
bits += bank_lookup[ESD_MMDC_MISC_GET_BANK(misc)];
|
|
bits += ESD_MMDC_CTL_GET_WIDTH(ctl);
|
|
bits += ESD_MMDC_CTL_GET_CS1(ctl);
|
|
|
|
/* The MX6 can do only 3840 MiB of DRAM */
|
|
if (bits == 32)
|
|
return 0xf0000000;
|
|
|
|
return 1 << bits;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_DISPLAY_CPUINFO) && !defined(CONFIG_SPL_BUILD)
|
|
|
|
const char *get_imx_type(u32 imxtype)
|
|
{
|
|
switch (imxtype) {
|
|
case MXC_CPU_MX8MQ:
|
|
return "8MQ"; /* Quad-core version of the mx8m */
|
|
case MXC_CPU_MX7S:
|
|
return "7S"; /* Single-core version of the mx7 */
|
|
case MXC_CPU_MX7D:
|
|
return "7D"; /* Dual-core version of the mx7 */
|
|
case MXC_CPU_MX6QP:
|
|
return "6QP"; /* Quad-Plus version of the mx6 */
|
|
case MXC_CPU_MX6DP:
|
|
return "6DP"; /* Dual-Plus version of the mx6 */
|
|
case MXC_CPU_MX6Q:
|
|
return "6Q"; /* Quad-core version of the mx6 */
|
|
case MXC_CPU_MX6D:
|
|
return "6D"; /* Dual-core version of the mx6 */
|
|
case MXC_CPU_MX6DL:
|
|
return "6DL"; /* Dual Lite version of the mx6 */
|
|
case MXC_CPU_MX6SOLO:
|
|
return "6SOLO"; /* Solo version of the mx6 */
|
|
case MXC_CPU_MX6SL:
|
|
return "6SL"; /* Solo-Lite version of the mx6 */
|
|
case MXC_CPU_MX6SLL:
|
|
return "6SLL"; /* SLL version of the mx6 */
|
|
case MXC_CPU_MX6SX:
|
|
return "6SX"; /* SoloX version of the mx6 */
|
|
case MXC_CPU_MX6UL:
|
|
return "6UL"; /* Ultra-Lite version of the mx6 */
|
|
case MXC_CPU_MX6ULL:
|
|
return "6ULL"; /* ULL version of the mx6 */
|
|
case MXC_CPU_MX51:
|
|
return "51";
|
|
case MXC_CPU_MX53:
|
|
return "53";
|
|
default:
|
|
return "??";
|
|
}
|
|
}
|
|
|
|
int print_cpuinfo(void)
|
|
{
|
|
u32 cpurev;
|
|
__maybe_unused u32 max_freq;
|
|
|
|
cpurev = get_cpu_rev();
|
|
|
|
#if defined(CONFIG_IMX_THERMAL)
|
|
struct udevice *thermal_dev;
|
|
int cpu_tmp, minc, maxc, ret;
|
|
|
|
printf("CPU: Freescale i.MX%s rev%d.%d",
|
|
get_imx_type((cpurev & 0xFF000) >> 12),
|
|
(cpurev & 0x000F0) >> 4,
|
|
(cpurev & 0x0000F) >> 0);
|
|
max_freq = get_cpu_speed_grade_hz();
|
|
if (!max_freq || max_freq == mxc_get_clock(MXC_ARM_CLK)) {
|
|
printf(" at %dMHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000000);
|
|
} else {
|
|
printf(" %d MHz (running at %d MHz)\n", max_freq / 1000000,
|
|
mxc_get_clock(MXC_ARM_CLK) / 1000000);
|
|
}
|
|
#else
|
|
printf("CPU: Freescale i.MX%s rev%d.%d at %d MHz\n",
|
|
get_imx_type((cpurev & 0xFF000) >> 12),
|
|
(cpurev & 0x000F0) >> 4,
|
|
(cpurev & 0x0000F) >> 0,
|
|
mxc_get_clock(MXC_ARM_CLK) / 1000000);
|
|
#endif
|
|
|
|
#if defined(CONFIG_IMX_THERMAL)
|
|
puts("CPU: ");
|
|
switch (get_cpu_temp_grade(&minc, &maxc)) {
|
|
case TEMP_AUTOMOTIVE:
|
|
puts("Automotive temperature grade ");
|
|
break;
|
|
case TEMP_INDUSTRIAL:
|
|
puts("Industrial temperature grade ");
|
|
break;
|
|
case TEMP_EXTCOMMERCIAL:
|
|
puts("Extended Commercial temperature grade ");
|
|
break;
|
|
default:
|
|
puts("Commercial temperature grade ");
|
|
break;
|
|
}
|
|
printf("(%dC to %dC)", minc, maxc);
|
|
ret = uclass_get_device(UCLASS_THERMAL, 0, &thermal_dev);
|
|
if (!ret) {
|
|
ret = thermal_get_temp(thermal_dev, &cpu_tmp);
|
|
|
|
if (!ret)
|
|
printf(" at %dC\n", cpu_tmp);
|
|
else
|
|
debug(" - invalid sensor data\n");
|
|
} else {
|
|
debug(" - invalid sensor device\n");
|
|
}
|
|
#endif
|
|
|
|
printf("Reset cause: %s\n", get_reset_cause());
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int cpu_eth_init(bd_t *bis)
|
|
{
|
|
int rc = -ENODEV;
|
|
|
|
#if defined(CONFIG_FEC_MXC)
|
|
rc = fecmxc_initialize(bis);
|
|
#endif
|
|
|
|
return rc;
|
|
}
|
|
|
|
#ifdef CONFIG_FSL_ESDHC
|
|
/*
|
|
* Initializes on-chip MMC controllers.
|
|
* to override, implement board_mmc_init()
|
|
*/
|
|
int cpu_mmc_init(bd_t *bis)
|
|
{
|
|
return fsl_esdhc_mmc_init(bis);
|
|
}
|
|
#endif
|
|
|
|
#if !(defined(CONFIG_MX7) || defined(CONFIG_MX8M))
|
|
u32 get_ahb_clk(void)
|
|
{
|
|
struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
|
|
u32 reg, ahb_podf;
|
|
|
|
reg = __raw_readl(&imx_ccm->cbcdr);
|
|
reg &= MXC_CCM_CBCDR_AHB_PODF_MASK;
|
|
ahb_podf = reg >> MXC_CCM_CBCDR_AHB_PODF_OFFSET;
|
|
|
|
return get_periph_clk() / (ahb_podf + 1);
|
|
}
|
|
#endif
|
|
|
|
void arch_preboot_os(void)
|
|
{
|
|
#if defined(CONFIG_PCIE_IMX)
|
|
imx_pcie_remove();
|
|
#endif
|
|
#if defined(CONFIG_SATA)
|
|
sata_remove(0);
|
|
#if defined(CONFIG_MX6)
|
|
disable_sata_clock();
|
|
#endif
|
|
#endif
|
|
#if defined(CONFIG_VIDEO_IPUV3)
|
|
/* disable video before launching O/S */
|
|
ipuv3_fb_shutdown();
|
|
#endif
|
|
#if defined(CONFIG_VIDEO_MXS)
|
|
lcdif_power_down();
|
|
#endif
|
|
}
|
|
|
|
#ifndef CONFIG_MX8M
|
|
void set_chipselect_size(int const cs_size)
|
|
{
|
|
unsigned int reg;
|
|
struct iomuxc *iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
|
|
reg = readl(&iomuxc_regs->gpr[1]);
|
|
|
|
switch (cs_size) {
|
|
case CS0_128:
|
|
reg &= ~0x7; /* CS0=128MB, CS1=0, CS2=0, CS3=0 */
|
|
reg |= 0x5;
|
|
break;
|
|
case CS0_64M_CS1_64M:
|
|
reg &= ~0x3F; /* CS0=64MB, CS1=64MB, CS2=0, CS3=0 */
|
|
reg |= 0x1B;
|
|
break;
|
|
case CS0_64M_CS1_32M_CS2_32M:
|
|
reg &= ~0x1FF; /* CS0=64MB, CS1=32MB, CS2=32MB, CS3=0 */
|
|
reg |= 0x4B;
|
|
break;
|
|
case CS0_32M_CS1_32M_CS2_32M_CS3_32M:
|
|
reg &= ~0xFFF; /* CS0=32MB, CS1=32MB, CS2=32MB, CS3=32MB */
|
|
reg |= 0x249;
|
|
break;
|
|
default:
|
|
printf("Unknown chip select size: %d\n", cs_size);
|
|
break;
|
|
}
|
|
|
|
writel(reg, &iomuxc_regs->gpr[1]);
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_MX7) || defined(CONFIG_MX8M)
|
|
/*
|
|
* OCOTP_TESTER3[9:8] (see Fusemap Description Table offset 0x440)
|
|
* defines a 2-bit SPEED_GRADING
|
|
*/
|
|
#define OCOTP_TESTER3_SPEED_SHIFT 8
|
|
enum cpu_speed {
|
|
OCOTP_TESTER3_SPEED_GRADE0,
|
|
OCOTP_TESTER3_SPEED_GRADE1,
|
|
OCOTP_TESTER3_SPEED_GRADE2,
|
|
OCOTP_TESTER3_SPEED_GRADE3,
|
|
};
|
|
|
|
u32 get_cpu_speed_grade_hz(void)
|
|
{
|
|
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
|
struct fuse_bank *bank = &ocotp->bank[1];
|
|
struct fuse_bank1_regs *fuse =
|
|
(struct fuse_bank1_regs *)bank->fuse_regs;
|
|
uint32_t val;
|
|
|
|
val = readl(&fuse->tester3);
|
|
val >>= OCOTP_TESTER3_SPEED_SHIFT;
|
|
val &= 0x3;
|
|
|
|
switch(val) {
|
|
case OCOTP_TESTER3_SPEED_GRADE0:
|
|
return 800000000;
|
|
case OCOTP_TESTER3_SPEED_GRADE1:
|
|
return is_mx7() ? 500000000 : 1000000000;
|
|
case OCOTP_TESTER3_SPEED_GRADE2:
|
|
return is_mx7() ? 1000000000 : 1300000000;
|
|
case OCOTP_TESTER3_SPEED_GRADE3:
|
|
return is_mx7() ? 1200000000 : 1500000000;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* OCOTP_TESTER3[7:6] (see Fusemap Description Table offset 0x440)
|
|
* defines a 2-bit SPEED_GRADING
|
|
*/
|
|
#define OCOTP_TESTER3_TEMP_SHIFT 6
|
|
|
|
u32 get_cpu_temp_grade(int *minc, int *maxc)
|
|
{
|
|
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
|
struct fuse_bank *bank = &ocotp->bank[1];
|
|
struct fuse_bank1_regs *fuse =
|
|
(struct fuse_bank1_regs *)bank->fuse_regs;
|
|
uint32_t val;
|
|
|
|
val = readl(&fuse->tester3);
|
|
val >>= OCOTP_TESTER3_TEMP_SHIFT;
|
|
val &= 0x3;
|
|
|
|
if (minc && maxc) {
|
|
if (val == TEMP_AUTOMOTIVE) {
|
|
*minc = -40;
|
|
*maxc = 125;
|
|
} else if (val == TEMP_INDUSTRIAL) {
|
|
*minc = -40;
|
|
*maxc = 105;
|
|
} else if (val == TEMP_EXTCOMMERCIAL) {
|
|
*minc = -20;
|
|
*maxc = 105;
|
|
} else {
|
|
*minc = 0;
|
|
*maxc = 95;
|
|
}
|
|
}
|
|
return val;
|
|
}
|
|
#endif
|
|
|
|
#if defined(CONFIG_MX7) || defined(CONFIG_MX8M)
|
|
enum boot_device get_boot_device(void)
|
|
{
|
|
struct bootrom_sw_info **p =
|
|
(struct bootrom_sw_info **)(ulong)ROM_SW_INFO_ADDR;
|
|
|
|
enum boot_device boot_dev = SD1_BOOT;
|
|
u8 boot_type = (*p)->boot_dev_type;
|
|
u8 boot_instance = (*p)->boot_dev_instance;
|
|
|
|
switch (boot_type) {
|
|
case BOOT_TYPE_SD:
|
|
boot_dev = boot_instance + SD1_BOOT;
|
|
break;
|
|
case BOOT_TYPE_MMC:
|
|
boot_dev = boot_instance + MMC1_BOOT;
|
|
break;
|
|
case BOOT_TYPE_NAND:
|
|
boot_dev = NAND_BOOT;
|
|
break;
|
|
case BOOT_TYPE_QSPI:
|
|
boot_dev = QSPI_BOOT;
|
|
break;
|
|
case BOOT_TYPE_WEIM:
|
|
boot_dev = WEIM_NOR_BOOT;
|
|
break;
|
|
case BOOT_TYPE_SPINOR:
|
|
boot_dev = SPI_NOR_BOOT;
|
|
break;
|
|
#ifdef CONFIG_MX8M
|
|
case BOOT_TYPE_USB:
|
|
boot_dev = USB_BOOT;
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return boot_dev;
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_NXP_BOARD_REVISION
|
|
int nxp_board_rev(void)
|
|
{
|
|
/*
|
|
* Get Board ID information from OCOTP_GP1[15:8]
|
|
* RevA: 0x1
|
|
* RevB: 0x2
|
|
* RevC: 0x3
|
|
*/
|
|
struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
|
|
struct fuse_bank *bank = &ocotp->bank[4];
|
|
struct fuse_bank4_regs *fuse =
|
|
(struct fuse_bank4_regs *)bank->fuse_regs;
|
|
|
|
return (readl(&fuse->gp1) >> 8 & 0x0F);
|
|
}
|
|
|
|
char nxp_board_rev_string(void)
|
|
{
|
|
const char *rev = "A";
|
|
|
|
return (*rev + nxp_board_rev() - 1);
|
|
}
|
|
#endif
|