soc.c 13.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11
/* Copyright 2017 NXP
 *
 * Peng Fan <peng.fan@nxp.com>
 *
 * SPDX-License-Identifier:     GPL-2.0+
 */
#include <common.h>
#include <asm/arch/imx-regs.h>
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/sys_proto.h>
12
#include <asm/imx-common/hab.h>
13
#include <asm/imx-common/boot_mode.h>
14 15
#include <asm/armv8/mmu.h>
#include <errno.h>
16
#include <fdt_support.h>
17
#include <fsl_wdog.h>
18
#include <generated/version_autogenerated.h>
19 20 21

DECLARE_GLOBAL_DATA_PTR;

22 23 24 25 26 27 28
#if defined(CONFIG_SECURE_BOOT)
struct imx_sec_config_fuse_t const imx_sec_config_fuse = {
	.bank = 1,
	.word = 3,
};
#endif

29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52
/*
 * OCOTP_TESTER3[9:8] (see Fusemap Description Table offset 0x440)
 * defines a 2-bit SPEED_GRADING
 */
#define OCOTP_TESTER3_SPEED_SHIFT	8
#define OCOTP_TESTER3_SPEED_800MHZ	0
#define OCOTP_TESTER3_SPEED_1GHZ	1
#define OCOTP_TESTER3_SPEED_1300HZ	2
#define OCOTP_TESTER3_SPEED_1500HZ	3

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_800MHZ:
53
		return 800000000;
54
	case OCOTP_TESTER3_SPEED_1GHZ:
55
		return 1000000000;
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
	case OCOTP_TESTER3_SPEED_1300HZ:
		return 1300000000;
	case OCOTP_TESTER3_SPEED_1500HZ:
		return 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

/* CPU Temperature Grades */
#define TEMP_COMMERCIAL         0
#define TEMP_EXTCOMMERCIAL      1
#define TEMP_INDUSTRIAL         2
#define TEMP_AUTOMOTIVE         3


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;
}

107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
int timer_init(void)
{
#ifdef CONFIG_SPL_BUILD
	void __iomem *sctr_base = (void __iomem *)SCTR_BASE_ADDR;
	unsigned long freq;
	u32 val;

	freq = readl(sctr_base + CNTFID0_OFF);

	/* Update with accurate clock frequency */
	asm volatile("msr cntfrq_el0, %0" : : "r" (freq) : "memory");

	val = readl(sctr_base + CNTCR_OFF);
	val &= ~(SC_CNTCR_FREQ0 | SC_CNTCR_FREQ1);
	val |= SC_CNTCR_FREQ0 | SC_CNTCR_ENABLE | SC_CNTCR_HDBG;
	writel(val, sctr_base + CNTCR_OFF);
#endif

	gd->arch.tbl = 0;
	gd->arch.tbu = 0;

	return 0;
}

131 132 133 134 135 136 137
void enable_tzc380(void)
{
	u32 val;

	/* Enable TZASC and lock setting */
	val = readl(IOMUXC_GPR10);
	val |= GPR_TZASC_EN;
138 139 140
#ifdef CONFIG_IMX8MM
	val |= GPR_TZASC_SWAP_ID;
#endif
141 142 143 144 145
	writel(val, IOMUXC_GPR10);
	val |= GPR_TZASC_EN_LOCK;
	writel(val, IOMUXC_GPR10);
}

146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
void set_wdog_reset(struct wdog_regs *wdog)
{
	u32 reg = readw(&wdog->wcr);
	/*
	 * Output WDOG_B signal to reset external pmic or POR_B decided by
	 * the board desgin. Without external reset, the peripherals/DDR/
	 * PMIC are not reset, that may cause system working abnormal.
	 */
	reg = readw(&wdog->wcr);
	reg |= 1 << 3;
	/*
	 * WDZST bit is write-once only bit. Align this bit in kernel,
	 * otherwise kernel code will have no chance to set this bit.
	 */
	reg |= 1 << 0;
	writew(reg, &wdog->wcr);
}

164 165 166 167
static struct mm_region imx8m_mem_map[] = {
	{
		.virt = 0x0UL,
		.phys = 0x0UL,
Peng Fan's avatar
Peng Fan committed
168 169 170
		.size = 0x100000UL,
		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
			 PTE_BLOCK_OUTER_SHARE
171 172 173 174 175 176 177
	}, {
		.virt = 0x100000UL,
		.phys = 0x100000UL,
		.size = 0x8000UL,
		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
			 PTE_BLOCK_NON_SHARE |
			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
Peng Fan's avatar
Peng Fan committed
178 179 180 181 182 183 184 185 186 187 188
	}, {
		.virt = 0x7C0000UL,
		.phys = 0x7C0000UL,
		.size = 0x80000UL,
		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
			 PTE_BLOCK_NON_SHARE |
			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
	}, {
		.virt = 0x900000UL,
		.phys = 0x900000UL,
		.size = 0x200000UL,
189 190 191 192 193 194 195 196 197 198
		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
			 PTE_BLOCK_OUTER_SHARE
	}, {
		.virt = 0xB00000UL,
		.phys = 0xB00000UL,
		.size = 0x3f500000UL,
		.attrs = PTE_BLOCK_MEMTYPE(MT_DEVICE_NGNRNE) |
			 PTE_BLOCK_NON_SHARE |
			 PTE_BLOCK_PXN | PTE_BLOCK_UXN
	}, {
199 200 201
		.virt = 0x40000000UL,
		.phys = 0x40000000UL,
		.size = 0xC0000000UL,
202 203 204 205 206
		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
			 PTE_BLOCK_OUTER_SHARE
	}, {
		.virt = 0x100000000UL,
		.phys = 0x100000000UL,
207
		.size = 0x140000000UL,
208 209 210 211 212 213 214 215 216 217 218
		.attrs = PTE_BLOCK_MEMTYPE(MT_NORMAL) |
			 PTE_BLOCK_OUTER_SHARE
	}, {
		/* List terminator */
		0,
	}
};
struct mm_region *mem_map = imx8m_mem_map;

u32 get_cpu_rev(void)
{
219 220
	u32 reg = readl((void __iomem *)DIGPROG);
	u32 type = (reg >> 16) & 0xff;
221
	u32 major_low = (reg >> 8) & 0xff;
222 223 224

	reg &= 0xff;

225 226 227 228 229 230 231
	/* iMX8MM */
	 if (major_low == 0x41) {
		return ((type + 1) << 12) | reg;
	} else {
		/* iMX8MQ */
		if (reg == 0x10) {
			/* For B0 chip, the DIGPROG is not updated, still TO1.0.
232
			 * we have to check ROM version or OCOTP_READ_FUSE_DATA
233
			 */
234 235 236 237 238 239
			if (readl((void __iomem *)(OCOTP_BASE_ADDR + 0x40))
				== 0xff0055aa) {
				/* 0xff0055aa is magic number for B1 */
				reg = 0x21;
			} else {
				uint32_t rom_version;
240
				rom_version = readb((void __iomem *)0x800);
241
				if (rom_version != 0x10) {
242
					rom_version = readb((void __iomem *)0x83c);
243 244 245
					if (rom_version == 0x20)
						reg = 0x20;
				}
246
			}
247 248
		}

249 250
		return (type << 12) | reg;
	}
251 252
}

253 254 255 256 257 258 259 260 261 262 263 264
void imx_set_wdog_powerdown(bool enable)
{
	struct wdog_regs *wdog1 = (struct wdog_regs *)WDOG1_BASE_ADDR;
	struct wdog_regs *wdog2 = (struct wdog_regs *)WDOG2_BASE_ADDR;
	struct wdog_regs *wdog3 = (struct wdog_regs *)WDOG3_BASE_ADDR;

	/* Write to the PDE (Power Down Enable) bit */
	writew(enable, &wdog1->wmcr);
	writew(enable, &wdog2->wmcr);
	writew(enable, &wdog3->wmcr);
}

265 266 267
int arch_cpu_init(void)
{
	/*
268 269
	 * Init timer at very early state, because pll setting will use it,
	 * Rom Turnned off SCTR, enable it before timer_init
270
	 */
271 272

	clock_enable(CCGR_SCTR, 1);
273
	timer_init();
274
#ifdef CONFIG_SPL_BUILD
275
	clock_init();
276
#endif
277

278 279
	imx_set_wdog_powerdown(false);

280 281 282 283 284
#if defined(CONFIG_ANDROID_SUPPORT)
	/* Enable RTC */
	writel(0x21, 0x30370038);
#endif

285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
	return 0;
}

#if defined(CONFIG_FEC_MXC)
void imx_get_mac_from_fuse(int dev_id, unsigned char *mac)
{
	struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
	struct fuse_bank *bank = &ocotp->bank[9];
	struct fuse_bank9_regs *fuse =
		(struct fuse_bank9_regs *)bank->fuse_regs;

	u32 value = readl(&fuse->mac_addr1);
	mac[0] = (value >> 8);
	mac[1] = value;

	value = readl(&fuse->mac_addr0);
	mac[2] = value >> 24;
	mac[3] = value >> 16;
	mac[4] = value >> 8;
	mac[5] = value;
}
#endif

#ifdef CONFIG_IMX_BOOTAUX
309 310 311
#define FSL_SIP_SRC		0xC2000005
#define FSL_SIP_SRC_M4_START	0x00
#define FSL_SIP_SRC_M4_STARTED	0x01
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326
int arch_auxiliary_core_up(u32 core_id, ulong boot_private_data)
{
	u32 stack, pc;

	if (!boot_private_data)
		return -EINVAL;

	stack = *(u32 *)boot_private_data;
	pc = *(u32 *)(boot_private_data + 4);

	/* Set the stack and pc to M4 bootROM */
	writel(stack, M4_BOOTROM_BASE_ADDR);
	writel(pc, M4_BOOTROM_BASE_ADDR + 4);

	/* Enable M4 */
327
	call_imx_sip(FSL_SIP_SRC, FSL_SIP_SRC_M4_START, 0, 0, 0);
328 329 330 331 332 333

	return 0;
}

int arch_auxiliary_core_check_up(u32 core_id)
{
334
	return call_imx_sip(FSL_SIP_SRC, FSL_SIP_SRC_M4_STARTED, 0, 0, 0);
335 336
}
#endif
337

338 339
enum boot_device get_boot_device(void)
{
340
	u32 soc_sbmr = readl(SRC_BASE_ADDR + 0x58);
341 342 343 344
#ifdef CONFIG_IMX8MM
	struct bootrom_sw_info **p =
		(struct bootrom_sw_info **)ROM_SW_INFO_ADDR;
#else
345
	struct bootrom_sw_info **p =
346
		is_soc_rev(CHIP_REV_1_0)? (struct bootrom_sw_info **)ROM_SW_INFO_ADDR_A0 :
347
		(struct bootrom_sw_info **)ROM_SW_INFO_ADDR;
348
#endif
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372

	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;
Peng Fan's avatar
Peng Fan committed
373 374 375
	case BOOT_TYPE_USB:
		boot_dev = USB_BOOT;
		break;
376
	default:
377 378
		if (((soc_sbmr & 0x00007FFF) >> 12) == 0x4)
			boot_dev = QSPI_BOOT;
379 380 381 382 383 384
		break;
	}

	return boot_dev;
}

Peng Fan's avatar
Peng Fan committed
385 386 387 388 389
bool is_usb_boot(void)
{
	return get_boot_device() == USB_BOOT;
}

390 391 392 393 394 395 396 397
__weak int board_mmc_get_env_dev(int devno)
{
	return CONFIG_SYS_MMC_ENV_DEV;
}

int mmc_get_env_dev(void)
{
	struct bootrom_sw_info **p =
398
		is_soc_rev(CHIP_REV_1_0)? (struct bootrom_sw_info **)ROM_SW_INFO_ADDR_A0 :
399 400 401 402 403 404
		(struct bootrom_sw_info **)ROM_SW_INFO_ADDR;
	int devno = (*p)->boot_dev_instance;
	u8 boot_type = (*p)->boot_dev_type;

	/* If not boot from sd/mmc, use default value */
	if ((boot_type != BOOT_TYPE_SD) && (boot_type != BOOT_TYPE_MMC))
405
		return getenv_ulong("mmcdev", 10, CONFIG_SYS_MMC_ENV_DEV);
406 407 408 409

	return board_mmc_get_env_dev(devno);
}

410 411 412
#ifdef CONFIG_SERIAL_TAG
void get_board_serial(struct tag_serialnr *serialnr)
{
413 414 415 416 417 418 419
	struct ocotp_regs *ocotp = (struct ocotp_regs *)OCOTP_BASE_ADDR;
	struct fuse_bank *bank = &ocotp->bank[0];
	struct fuse_bank0_regs *fuse =
		(struct fuse_bank0_regs *)bank->fuse_regs;

	serialnr->low = fuse->uid_low;
	serialnr->high = fuse->uid_high;
420 421
}
#endif
422 423

#ifdef CONFIG_OF_SYSTEM_SETUP
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
static int ft_add_optee_node(void *fdt, bd_t *bd)
{
	const char *path, *subpath;
	int offs;

	/*
	 * No TEE space allocated indicating no TEE running, so no
	 * need to add optee node in dts
	 */
	if (!rom_pointer[1])
		return 0;

	offs = fdt_increase_size(fdt, 512);
	if (offs) {
		printf("No Space for dtb\n");
		return 1;
	}

	path = "/firmware";
	offs = fdt_path_offset(fdt, path);
	if (offs < 0) {
		path = "/";
		offs = fdt_path_offset(fdt, path);

		if (offs < 0) {
			printf("Could not find root node.\n");
			return 1;
		}

		subpath = "firmware";
		offs = fdt_add_subnode(fdt, offs, subpath);
		if (offs < 0) {
			printf("Could not create %s node.\n", subpath);
		}
	}

	subpath = "optee";
	offs = fdt_add_subnode(fdt, offs, subpath);
	if (offs < 0) {
		printf("Could not create %s node.\n", subpath);
	}

	fdt_setprop_string(fdt, offs, "compatible", "linaro,optee-tz");
	fdt_setprop_string(fdt, offs, "method", "smc");

	return 0;
}

472 473
int ft_system_setup(void *blob, bd_t *bd)
{
474
#ifndef CONFIG_IMX8MM
475 476 477 478
	if (get_boot_device() == USB_BOOT) {
		const char *nodes_path[] = {
			"/dcss@32e00000",
			"/hdmi@32c00000",
479 480 481 482
			"/hdmi_cec@32c33800",
			"/hdmi_drm@32c00000",
			"/display-subsystem",
			"/sound-hdmi"
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
		};

		int i = 0;
		int rc;
		int nodeoff;
		const char *status = "disabled";

		for (i = 0; i < ARRAY_SIZE(nodes_path); i++) {
			nodeoff = fdt_path_offset(blob, nodes_path[i]);
			if (nodeoff < 0)
				continue; /* Not found, skip it */

			printf("Found %s node\n", nodes_path[i]);

add_status:
			rc = fdt_setprop(blob, nodeoff, "status", status, strlen(status) + 1);
			if (rc) {
				if (rc == -FDT_ERR_NOSPACE) {
					rc = fdt_increase_size(blob, 512);
					if (!rc)
						goto add_status;
				}
				printf("Unable to update property %s:%s, err=%s\n",
					nodes_path[i], "status", fdt_strerror(rc));
			} else {
				printf("Modify %s:%s disabled\n",
					nodes_path[i], "status");
			}
		}
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536

		const char *usb_dwc3_path = "/usb@38100000/dwc3";
		nodeoff = fdt_path_offset(blob, usb_dwc3_path);
		if (nodeoff >= 0) {
			const char *speed = "high-speed";
			printf("Found %s node\n", usb_dwc3_path);

usb_modify_speed:

			rc = fdt_setprop(blob, nodeoff, "maximum-speed", speed, strlen(speed) + 1);
			if (rc) {
				if (rc == -FDT_ERR_NOSPACE) {
					rc = fdt_increase_size(blob, 512);
					if (!rc)
						goto usb_modify_speed;
				}
				printf("Unable to set property %s:%s, err=%s\n",
					usb_dwc3_path, "maximum-speed", fdt_strerror(rc));
			} else {
				printf("Modify %s:%s = %s\n",
					usb_dwc3_path, "maximum-speed", speed);
			}
		}else {
			printf("Can't found %s node\n", usb_dwc3_path);
		}
537
	}
538

539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
	/* Disable the CPU idle for A0 chip since the HW does not support it */
	if (is_soc_rev(CHIP_REV_1_0)) {
		const char *nodes_path[] = {
			"/cpus/cpu@0",
			"/cpus/cpu@1",
			"/cpus/cpu@2",
			"/cpus/cpu@3",
		};

		int i = 0;
		int rc;
		int nodeoff;

		for (i = 0; i < ARRAY_SIZE(nodes_path); i++) {
			nodeoff = fdt_path_offset(blob, nodes_path[i]);
			if (nodeoff < 0)
				continue; /* Not found, skip it */

			printf("Found %s node\n", nodes_path[i]);

			rc = fdt_delprop(blob, nodeoff, "cpu-idle-states");
			if (rc) {
				printf("Unable to update property %s:%s, err=%s\n",
					nodes_path[i], "status", fdt_strerror(rc));
			} else {
				printf("Remove %s:%s\n",
					nodes_path[i], "cpu-idle-states");
			}
		}
	}
569
#endif
570
	return ft_add_optee_node(blob, bd);
571 572
}
#endif
573 574 575 576 577 578 579 580 581 582 583 584 585 586

void reset_cpu(ulong addr)
{
	struct watchdog_regs *wdog = (struct watchdog_regs *)WDOG1_BASE_ADDR;

	/* Clear WDA to trigger WDOG_B immediately */
	writew((WCR_WDE | WCR_SRS), &wdog->wcr);

	while (1) {
		/*
		 * spin for .5 seconds before reset
		 */
	}
}
587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613

#if defined(CONFIG_ARCH_MISC_INIT)
#define FSL_SIP_BUILDINFO			0xC2000003
#define FSL_SIP_BUILDINFO_GET_COMMITHASH	0x00
static void acquire_buildinfo(void)
{
	uint64_t atf_commit = 0;

	/* Get ARM Trusted Firmware commit id */
	atf_commit = call_imx_sip(FSL_SIP_BUILDINFO,
				  FSL_SIP_BUILDINFO_GET_COMMITHASH, 0, 0, 0);
	if (atf_commit == 0xffffffff) {
		debug("ATF does not support build info\n");
		atf_commit = 0x30; /* Display 0, 0 ascii is 0x30 */
	}

	printf("\n BuildInfo:\n  - ATF %s\n  - %s\n\n", (char *)&atf_commit,
	       U_BOOT_VERSION);
}

int arch_misc_init(void)
{
	acquire_buildinfo();

	return 0;
}
#endif
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630

#define FSL_SIP_GPC			0xC2000000
#define FSL_SIP_CONFIG_GPC_PM_DOMAIN	0x03
int imx8m_usb_power(int usb_id, bool on)
{
	unsigned long ret;

	if (usb_id > 1)
		return -EINVAL;

	ret = call_imx_sip(FSL_SIP_GPC,
			FSL_SIP_CONFIG_GPC_PM_DOMAIN, 2 + usb_id, on, 0);
	if (ret)
		return -EPERM;

	return 0;
}