diff options
Diffstat (limited to 'roms/u-boot/arch/arm/cpu/armv7/mx6')
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/armv7/mx6/Makefile | 11 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/armv7/mx6/clock.c | 590 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/armv7/mx6/hab.c | 104 | ||||
| -rw-r--r-- | roms/u-boot/arch/arm/cpu/armv7/mx6/soc.c | 435 | 
4 files changed, 1140 insertions, 0 deletions
diff --git a/roms/u-boot/arch/arm/cpu/armv7/mx6/Makefile b/roms/u-boot/arch/arm/cpu/armv7/mx6/Makefile new file mode 100644 index 00000000..d7285fc2 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/armv7/mx6/Makefile @@ -0,0 +1,11 @@ +# +# (C) Copyright 2000-2006 +# Wolfgang Denk, DENX Software Engineering, wd@denx.de. +# +# (C) Copyright 2011 Freescale Semiconductor, Inc. +# +# SPDX-License-Identifier:	GPL-2.0+ +# + +obj-y	:= soc.o clock.o +obj-$(CONFIG_SECURE_BOOT)    += hab.o diff --git a/roms/u-boot/arch/arm/cpu/armv7/mx6/clock.c b/roms/u-boot/arch/arm/cpu/armv7/mx6/clock.c new file mode 100644 index 00000000..bd65a08b --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/armv7/mx6/clock.c @@ -0,0 +1,590 @@ +/* + * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <div64.h> +#include <asm/io.h> +#include <asm/errno.h> +#include <asm/arch/imx-regs.h> +#include <asm/arch/crm_regs.h> +#include <asm/arch/clock.h> +#include <asm/arch/sys_proto.h> + +enum pll_clocks { +	PLL_SYS,	/* System PLL */ +	PLL_BUS,	/* System Bus PLL*/ +	PLL_USBOTG,	/* OTG USB PLL */ +	PLL_ENET,	/* ENET PLL */ +}; + +struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + +#ifdef CONFIG_MXC_OCOTP +void enable_ocotp_clk(unsigned char enable) +{ +	u32 reg; + +	reg = __raw_readl(&imx_ccm->CCGR2); +	if (enable) +		reg |= MXC_CCM_CCGR2_OCOTP_CTRL_MASK; +	else +		reg &= ~MXC_CCM_CCGR2_OCOTP_CTRL_MASK; +	__raw_writel(reg, &imx_ccm->CCGR2); +} +#endif + +void enable_usboh3_clk(unsigned char enable) +{ +	u32 reg; + +	reg = __raw_readl(&imx_ccm->CCGR6); +	if (enable) +		reg |= MXC_CCM_CCGR6_USBOH3_MASK; +	else +		reg &= ~(MXC_CCM_CCGR6_USBOH3_MASK); +	__raw_writel(reg, &imx_ccm->CCGR6); + +} + +#ifdef CONFIG_SYS_I2C_MXC +/* i2c_num can be from 0 - 2 */ +int enable_i2c_clk(unsigned char enable, unsigned i2c_num) +{ +	u32 reg; +	u32 mask; + +	if (i2c_num > 2) +		return -EINVAL; + +	mask = MXC_CCM_CCGR_CG_MASK +		<< (MXC_CCM_CCGR2_I2C1_SERIAL_OFFSET + (i2c_num << 1)); +	reg = __raw_readl(&imx_ccm->CCGR2); +	if (enable) +		reg |= mask; +	else +		reg &= ~mask; +	__raw_writel(reg, &imx_ccm->CCGR2); +	return 0; +} +#endif + +static u32 decode_pll(enum pll_clocks pll, u32 infreq) +{ +	u32 div; + +	switch (pll) { +	case PLL_SYS: +		div = __raw_readl(&imx_ccm->analog_pll_sys); +		div &= BM_ANADIG_PLL_SYS_DIV_SELECT; + +		return infreq * (div >> 1); +	case PLL_BUS: +		div = __raw_readl(&imx_ccm->analog_pll_528); +		div &= BM_ANADIG_PLL_528_DIV_SELECT; + +		return infreq * (20 + (div << 1)); +	case PLL_USBOTG: +		div = __raw_readl(&imx_ccm->analog_usb1_pll_480_ctrl); +		div &= BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT; + +		return infreq * (20 + (div << 1)); +	case PLL_ENET: +		div = __raw_readl(&imx_ccm->analog_pll_enet); +		div &= BM_ANADIG_PLL_ENET_DIV_SELECT; + +		return 25000000 * (div + (div >> 1) + 1); +	default: +		return 0; +	} +	/* NOTREACHED */ +} +static u32 mxc_get_pll_pfd(enum pll_clocks pll, int pfd_num) +{ +	u32 div; +	u64 freq; + +	switch (pll) { +	case PLL_BUS: +		if (pfd_num == 3) { +			/* No PFD3 on PPL2 */ +			return 0; +		} +		div = __raw_readl(&imx_ccm->analog_pfd_528); +		freq = (u64)decode_pll(PLL_BUS, MXC_HCLK); +		break; +	case PLL_USBOTG: +		div = __raw_readl(&imx_ccm->analog_pfd_480); +		freq = (u64)decode_pll(PLL_USBOTG, MXC_HCLK); +		break; +	default: +		/* No PFD on other PLL					     */ +		return 0; +	} + +	return lldiv(freq * 18, (div & ANATOP_PFD_FRAC_MASK(pfd_num)) >> +			      ANATOP_PFD_FRAC_SHIFT(pfd_num)); +} + +static u32 get_mcu_main_clk(void) +{ +	u32 reg, freq; + +	reg = __raw_readl(&imx_ccm->cacrr); +	reg &= MXC_CCM_CACRR_ARM_PODF_MASK; +	reg >>= MXC_CCM_CACRR_ARM_PODF_OFFSET; +	freq = decode_pll(PLL_SYS, MXC_HCLK); + +	return freq / (reg + 1); +} + +u32 get_periph_clk(void) +{ +	u32 reg, freq = 0; + +	reg = __raw_readl(&imx_ccm->cbcdr); +	if (reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL) { +		reg = __raw_readl(&imx_ccm->cbcmr); +		reg &= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK; +		reg >>= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET; + +		switch (reg) { +		case 0: +			freq = decode_pll(PLL_USBOTG, MXC_HCLK); +			break; +		case 1: +		case 2: +			freq = MXC_HCLK; +			break; +		default: +			break; +		} +	} else { +		reg = __raw_readl(&imx_ccm->cbcmr); +		reg &= MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK; +		reg >>= MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET; + +		switch (reg) { +		case 0: +			freq = decode_pll(PLL_BUS, MXC_HCLK); +			break; +		case 1: +			freq = mxc_get_pll_pfd(PLL_BUS, 2); +			break; +		case 2: +			freq = mxc_get_pll_pfd(PLL_BUS, 0); +			break; +		case 3: +			/* static / 2 divider */ +			freq = mxc_get_pll_pfd(PLL_BUS, 2) / 2; +			break; +		default: +			break; +		} +	} + +	return freq; +} + +static u32 get_ipg_clk(void) +{ +	u32 reg, ipg_podf; + +	reg = __raw_readl(&imx_ccm->cbcdr); +	reg &= MXC_CCM_CBCDR_IPG_PODF_MASK; +	ipg_podf = reg >> MXC_CCM_CBCDR_IPG_PODF_OFFSET; + +	return get_ahb_clk() / (ipg_podf + 1); +} + +static u32 get_ipg_per_clk(void) +{ +	u32 reg, perclk_podf; + +	reg = __raw_readl(&imx_ccm->cscmr1); +	perclk_podf = reg & MXC_CCM_CSCMR1_PERCLK_PODF_MASK; + +	return get_ipg_clk() / (perclk_podf + 1); +} + +static u32 get_uart_clk(void) +{ +	u32 reg, uart_podf; +	u32 freq = decode_pll(PLL_USBOTG, MXC_HCLK) / 6; /* static divider */ +	reg = __raw_readl(&imx_ccm->cscdr1); +#ifdef CONFIG_MX6SL +	if (reg & MXC_CCM_CSCDR1_UART_CLK_SEL) +		freq = MXC_HCLK; +#endif +	reg &= MXC_CCM_CSCDR1_UART_CLK_PODF_MASK; +	uart_podf = reg >> MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET; + +	return freq / (uart_podf + 1); +} + +static u32 get_cspi_clk(void) +{ +	u32 reg, cspi_podf; + +	reg = __raw_readl(&imx_ccm->cscdr2); +	reg &= MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK; +	cspi_podf = reg >> MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET; + +	return	decode_pll(PLL_USBOTG, MXC_HCLK) / (8 * (cspi_podf + 1)); +} + +static u32 get_axi_clk(void) +{ +	u32 root_freq, axi_podf; +	u32 cbcdr =  __raw_readl(&imx_ccm->cbcdr); + +	axi_podf = cbcdr & MXC_CCM_CBCDR_AXI_PODF_MASK; +	axi_podf >>= MXC_CCM_CBCDR_AXI_PODF_OFFSET; + +	if (cbcdr & MXC_CCM_CBCDR_AXI_SEL) { +		if (cbcdr & MXC_CCM_CBCDR_AXI_ALT_SEL) +			root_freq = mxc_get_pll_pfd(PLL_BUS, 2); +		else +			root_freq = mxc_get_pll_pfd(PLL_USBOTG, 1); +	} else +		root_freq = get_periph_clk(); + +	return  root_freq / (axi_podf + 1); +} + +static u32 get_emi_slow_clk(void) +{ +	u32 emi_clk_sel, emi_slow_podf, cscmr1, root_freq = 0; + +	cscmr1 =  __raw_readl(&imx_ccm->cscmr1); +	emi_clk_sel = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK; +	emi_clk_sel >>= MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET; +	emi_slow_podf = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK; +	emi_slow_podf >>= MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET; + +	switch (emi_clk_sel) { +	case 0: +		root_freq = get_axi_clk(); +		break; +	case 1: +		root_freq = decode_pll(PLL_USBOTG, MXC_HCLK); +		break; +	case 2: +		root_freq =  mxc_get_pll_pfd(PLL_BUS, 2); +		break; +	case 3: +		root_freq =  mxc_get_pll_pfd(PLL_BUS, 0); +		break; +	} + +	return root_freq / (emi_slow_podf + 1); +} + +#ifdef CONFIG_MX6SL +static u32 get_mmdc_ch0_clk(void) +{ +	u32 cbcmr = __raw_readl(&imx_ccm->cbcmr); +	u32 cbcdr = __raw_readl(&imx_ccm->cbcdr); +	u32 freq, podf; + +	podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK) \ +			>> MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET; + +	switch ((cbcmr & MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK) >> +		MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET) { +	case 0: +		freq = decode_pll(PLL_BUS, MXC_HCLK); +		break; +	case 1: +		freq = mxc_get_pll_pfd(PLL_BUS, 2); +		break; +	case 2: +		freq = mxc_get_pll_pfd(PLL_BUS, 0); +		break; +	case 3: +		/* static / 2 divider */ +		freq =  mxc_get_pll_pfd(PLL_BUS, 2) / 2; +	} + +	return freq / (podf + 1); + +} +#else +static u32 get_mmdc_ch0_clk(void) +{ +	u32 cbcdr = __raw_readl(&imx_ccm->cbcdr); +	u32 mmdc_ch0_podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >> +				MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET; + +	return get_periph_clk() / (mmdc_ch0_podf + 1); +} +#endif + +#ifdef CONFIG_FEC_MXC +int enable_fec_anatop_clock(enum enet_freq freq) +{ +	u32 reg = 0; +	s32 timeout = 100000; + +	struct anatop_regs __iomem *anatop = +		(struct anatop_regs __iomem *)ANATOP_BASE_ADDR; + +	if (freq < ENET_25MHz || freq > ENET_125MHz) +		return -EINVAL; + +	reg = readl(&anatop->pll_enet); +	reg &= ~BM_ANADIG_PLL_ENET_DIV_SELECT; +	reg |= freq; + +	if ((reg & BM_ANADIG_PLL_ENET_POWERDOWN) || +	    (!(reg & BM_ANADIG_PLL_ENET_LOCK))) { +		reg &= ~BM_ANADIG_PLL_ENET_POWERDOWN; +		writel(reg, &anatop->pll_enet); +		while (timeout--) { +			if (readl(&anatop->pll_enet) & BM_ANADIG_PLL_ENET_LOCK) +				break; +		} +		if (timeout < 0) +			return -ETIMEDOUT; +	} + +	/* Enable FEC clock */ +	reg |= BM_ANADIG_PLL_ENET_ENABLE; +	reg &= ~BM_ANADIG_PLL_ENET_BYPASS; +	writel(reg, &anatop->pll_enet); + +	return 0; +} +#endif + +static u32 get_usdhc_clk(u32 port) +{ +	u32 root_freq = 0, usdhc_podf = 0, clk_sel = 0; +	u32 cscmr1 = __raw_readl(&imx_ccm->cscmr1); +	u32 cscdr1 = __raw_readl(&imx_ccm->cscdr1); + +	switch (port) { +	case 0: +		usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC1_PODF_MASK) >> +					MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET; +		clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC1_CLK_SEL; + +		break; +	case 1: +		usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC2_PODF_MASK) >> +					MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET; +		clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC2_CLK_SEL; + +		break; +	case 2: +		usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC3_PODF_MASK) >> +					MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET; +		clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC3_CLK_SEL; + +		break; +	case 3: +		usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC4_PODF_MASK) >> +					MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET; +		clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC4_CLK_SEL; + +		break; +	default: +		break; +	} + +	if (clk_sel) +		root_freq = mxc_get_pll_pfd(PLL_BUS, 0); +	else +		root_freq = mxc_get_pll_pfd(PLL_BUS, 2); + +	return root_freq / (usdhc_podf + 1); +} + +u32 imx_get_uartclk(void) +{ +	return get_uart_clk(); +} + +u32 imx_get_fecclk(void) +{ +	return mxc_get_clock(MXC_IPG_CLK); +} + +static int enable_enet_pll(uint32_t en) +{ +	struct mxc_ccm_reg *const imx_ccm +		= (struct mxc_ccm_reg *) CCM_BASE_ADDR; +	s32 timeout = 100000; +	u32 reg = 0; + +	/* Enable PLLs */ +	reg = readl(&imx_ccm->analog_pll_enet); +	reg &= ~BM_ANADIG_PLL_SYS_POWERDOWN; +	writel(reg, &imx_ccm->analog_pll_enet); +	reg |= BM_ANADIG_PLL_SYS_ENABLE; +	while (timeout--) { +		if (readl(&imx_ccm->analog_pll_enet) & BM_ANADIG_PLL_SYS_LOCK) +			break; +	} +	if (timeout <= 0) +		return -EIO; +	reg &= ~BM_ANADIG_PLL_SYS_BYPASS; +	writel(reg, &imx_ccm->analog_pll_enet); +	reg |= en; +	writel(reg, &imx_ccm->analog_pll_enet); +	return 0; +} + +static void ungate_sata_clock(void) +{ +	struct mxc_ccm_reg *const imx_ccm = +		(struct mxc_ccm_reg *)CCM_BASE_ADDR; + +	/* Enable SATA clock. */ +	setbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK); +} + +static void ungate_pcie_clock(void) +{ +	struct mxc_ccm_reg *const imx_ccm = +		(struct mxc_ccm_reg *)CCM_BASE_ADDR; + +	/* Enable PCIe clock. */ +	setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_PCIE_MASK); +} + +int enable_sata_clock(void) +{ +	ungate_sata_clock(); +	return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA); +} + +int enable_pcie_clock(void) +{ +	struct anatop_regs *anatop_regs = +		(struct anatop_regs *)ANATOP_BASE_ADDR; +	struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + +	/* +	 * Here be dragons! +	 * +	 * The register ANATOP_MISC1 is not documented in the Freescale +	 * MX6RM. The register that is mapped in the ANATOP space and +	 * marked as ANATOP_MISC1 is actually documented in the PMU section +	 * of the datasheet as PMU_MISC1. +	 * +	 * Switch LVDS clock source to SATA (0xb), disable clock INPUT and +	 * enable clock OUTPUT. This is important for PCI express link that +	 * is clocked from the i.MX6. +	 */ +#define ANADIG_ANA_MISC1_LVDSCLK1_IBEN		(1 << 12) +#define ANADIG_ANA_MISC1_LVDSCLK1_OBEN		(1 << 10) +#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK	0x0000001F +	clrsetbits_le32(&anatop_regs->ana_misc1, +			ANADIG_ANA_MISC1_LVDSCLK1_IBEN | +			ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK, +			ANADIG_ANA_MISC1_LVDSCLK1_OBEN | 0xb); + +	/* PCIe reference clock sourced from AXI. */ +	clrbits_le32(&ccm_regs->cbcmr, MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL); + +	/* Party time! Ungate the clock to the PCIe. */ +	ungate_sata_clock(); +	ungate_pcie_clock(); + +	return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA | +			       BM_ANADIG_PLL_ENET_ENABLE_PCIE); +} + +unsigned int mxc_get_clock(enum mxc_clock clk) +{ +	switch (clk) { +	case MXC_ARM_CLK: +		return get_mcu_main_clk(); +	case MXC_PER_CLK: +		return get_periph_clk(); +	case MXC_AHB_CLK: +		return get_ahb_clk(); +	case MXC_IPG_CLK: +		return get_ipg_clk(); +	case MXC_IPG_PERCLK: +	case MXC_I2C_CLK: +		return get_ipg_per_clk(); +	case MXC_UART_CLK: +		return get_uart_clk(); +	case MXC_CSPI_CLK: +		return get_cspi_clk(); +	case MXC_AXI_CLK: +		return get_axi_clk(); +	case MXC_EMI_SLOW_CLK: +		return get_emi_slow_clk(); +	case MXC_DDR_CLK: +		return get_mmdc_ch0_clk(); +	case MXC_ESDHC_CLK: +		return get_usdhc_clk(0); +	case MXC_ESDHC2_CLK: +		return get_usdhc_clk(1); +	case MXC_ESDHC3_CLK: +		return get_usdhc_clk(2); +	case MXC_ESDHC4_CLK: +		return get_usdhc_clk(3); +	case MXC_SATA_CLK: +		return get_ahb_clk(); +	default: +		break; +	} + +	return -1; +} + +/* + * Dump some core clockes. + */ +int do_mx6_showclocks(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	u32 freq; +	freq = decode_pll(PLL_SYS, MXC_HCLK); +	printf("PLL_SYS    %8d MHz\n", freq / 1000000); +	freq = decode_pll(PLL_BUS, MXC_HCLK); +	printf("PLL_BUS    %8d MHz\n", freq / 1000000); +	freq = decode_pll(PLL_USBOTG, MXC_HCLK); +	printf("PLL_OTG    %8d MHz\n", freq / 1000000); +	freq = decode_pll(PLL_ENET, MXC_HCLK); +	printf("PLL_NET    %8d MHz\n", freq / 1000000); + +	printf("\n"); +	printf("IPG        %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000); +	printf("UART       %8d kHz\n", mxc_get_clock(MXC_UART_CLK) / 1000); +#ifdef CONFIG_MXC_SPI +	printf("CSPI       %8d kHz\n", mxc_get_clock(MXC_CSPI_CLK) / 1000); +#endif +	printf("AHB        %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000); +	printf("AXI        %8d kHz\n", mxc_get_clock(MXC_AXI_CLK) / 1000); +	printf("DDR        %8d kHz\n", mxc_get_clock(MXC_DDR_CLK) / 1000); +	printf("USDHC1     %8d kHz\n", mxc_get_clock(MXC_ESDHC_CLK) / 1000); +	printf("USDHC2     %8d kHz\n", mxc_get_clock(MXC_ESDHC2_CLK) / 1000); +	printf("USDHC3     %8d kHz\n", mxc_get_clock(MXC_ESDHC3_CLK) / 1000); +	printf("USDHC4     %8d kHz\n", mxc_get_clock(MXC_ESDHC4_CLK) / 1000); +	printf("EMI SLOW   %8d kHz\n", mxc_get_clock(MXC_EMI_SLOW_CLK) / 1000); +	printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000); + +	return 0; +} + +void enable_ipu_clock(void) +{ +	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; +	int reg; +	reg = readl(&mxc_ccm->CCGR3); +	reg |= MXC_CCM_CCGR3_IPU1_IPU_MASK; +	writel(reg, &mxc_ccm->CCGR3); +} +/***************************************************/ + +U_BOOT_CMD( +	clocks,	CONFIG_SYS_MAXARGS, 1, do_mx6_showclocks, +	"display clocks", +	"" +); diff --git a/roms/u-boot/arch/arm/cpu/armv7/mx6/hab.c b/roms/u-boot/arch/arm/cpu/armv7/mx6/hab.c new file mode 100644 index 00000000..51877753 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/armv7/mx6/hab.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2010-2013 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier:    GPL-2.0+ + */ + +#include <common.h> +#include <asm/io.h> +#include <asm/arch/hab.h> + +/* -------- start of HAB API updates ------------*/ +#define hab_rvt_report_event ((hab_rvt_report_event_t *)HAB_RVT_REPORT_EVENT) +#define hab_rvt_report_status ((hab_rvt_report_status_t *)HAB_RVT_REPORT_STATUS) +#define hab_rvt_authenticate_image \ +	((hab_rvt_authenticate_image_t *)HAB_RVT_AUTHENTICATE_IMAGE) +#define hab_rvt_entry ((hab_rvt_entry_t *)HAB_RVT_ENTRY) +#define hab_rvt_exit ((hab_rvt_exit_t *)HAB_RVT_EXIT) +#define hab_rvt_clock_init HAB_RVT_CLOCK_INIT + +bool is_hab_enabled(void) +{ +	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; +	uint32_t reg = readl(&fuse->cfg5); + +	return (reg & 0x2) == 0x2; +} + +void display_event(uint8_t *event_data, size_t bytes) +{ +	uint32_t i; + +	if (!(event_data && bytes > 0)) +		return; + +	for (i = 0; i < bytes; i++) { +		if (i == 0) +			printf("\t0x%02x", event_data[i]); +		else if ((i % 8) == 0) +			printf("\n\t0x%02x", event_data[i]); +		else +			printf(" 0x%02x", event_data[i]); +	} +} + +int get_hab_status(void) +{ +	uint32_t index = 0; /* Loop index */ +	uint8_t event_data[128]; /* Event data buffer */ +	size_t bytes = sizeof(event_data); /* Event size in bytes */ +	enum hab_config config = 0; +	enum hab_state state = 0; + +	if (is_hab_enabled()) +		puts("\nSecure boot enabled\n"); +	else +		puts("\nSecure boot disabled\n"); + +	/* Check HAB status */ +	if (hab_rvt_report_status(&config, &state) != HAB_SUCCESS) { +		printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n", +		       config, state); + +		/* Display HAB Error events */ +		while (hab_rvt_report_event(HAB_FAILURE, index, event_data, +					&bytes) == HAB_SUCCESS) { +			puts("\n"); +			printf("--------- HAB Event %d -----------------\n", +			       index + 1); +			puts("event data:\n"); +			display_event(event_data, bytes); +			puts("\n"); +			bytes = sizeof(event_data); +			index++; +		} +	} +	/* Display message if no HAB events are found */ +	else { +		printf("\nHAB Configuration: 0x%02x, HAB State: 0x%02x\n", +		       config, state); +		puts("No HAB Events Found!\n\n"); +	} +	return 0; +} + +int do_hab_status(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +{ +	if ((argc != 1)) { +		cmd_usage(cmdtp); +		return 1; +	} + +	get_hab_status(); + +	return 0; +} + +U_BOOT_CMD( +		hab_status, CONFIG_SYS_MAXARGS, 1, do_hab_status, +		"display HAB status", +		"" +	  ); diff --git a/roms/u-boot/arch/arm/cpu/armv7/mx6/soc.c b/roms/u-boot/arch/arm/cpu/armv7/mx6/soc.c new file mode 100644 index 00000000..17252798 --- /dev/null +++ b/roms/u-boot/arch/arm/cpu/armv7/mx6/soc.c @@ -0,0 +1,435 @@ +/* + * (C) Copyright 2007 + * Sascha Hauer, Pengutronix + * + * (C) Copyright 2009 Freescale Semiconductor, Inc. + * + * SPDX-License-Identifier:	GPL-2.0+ + */ + +#include <common.h> +#include <asm/armv7.h> +#include <asm/pl310.h> +#include <asm/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/imx-common/boot_mode.h> +#include <asm/imx-common/dma.h> +#include <stdbool.h> +#include <asm/arch/mxc_hdmi.h> +#include <asm/arch/crm_regs.h> + +enum ldo_reg { +	LDO_ARM, +	LDO_SOC, +	LDO_PU, +}; + +struct scu_regs { +	u32	ctrl; +	u32	config; +	u32	status; +	u32	invalidate; +	u32	fpga_rev; +}; + +u32 get_cpu_rev(void) +{ +	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; +	u32 reg = readl(&anatop->digprog_sololite); +	u32 type = ((reg >> 16) & 0xff); + +	if (type != MXC_CPU_MX6SL) { +		reg = readl(&anatop->digprog); +		struct scu_regs *scu = (struct scu_regs *)SCU_BASE_ADDR; +		u32 cfg = readl(&scu->config) & 3; +		type = ((reg >> 16) & 0xff); +		if (type == MXC_CPU_MX6DL) { +			if (!cfg) +				type = MXC_CPU_MX6SOLO; +		} + +		if (type == MXC_CPU_MX6Q) { +			if (cfg == 1) +				type = MXC_CPU_MX6D; +		} + +	} +	reg &= 0xff;		/* mx6 silicon revision */ +	return (type << 12) | (reg + 0x10); +} + +#ifdef CONFIG_REVISION_TAG +u32 __weak get_board_rev(void) +{ +	u32 cpurev = get_cpu_rev(); +	u32 type = ((cpurev >> 12) & 0xff); +	if (type == MXC_CPU_MX6SOLO) +		cpurev = (MXC_CPU_MX6DL) << 12 | (cpurev & 0xFFF); + +	if (type == MXC_CPU_MX6D) +		cpurev = (MXC_CPU_MX6Q) << 12 | (cpurev & 0xFFF); + +	return cpurev; +} +#endif + +void init_aips(void) +{ +	struct aipstz_regs *aips1, *aips2; + +	aips1 = (struct aipstz_regs *)AIPS1_BASE_ADDR; +	aips2 = (struct aipstz_regs *)AIPS2_BASE_ADDR; + +	/* +	 * Set all MPROTx to be non-bufferable, trusted for R/W, +	 * not forced to user-mode. +	 */ +	writel(0x77777777, &aips1->mprot0); +	writel(0x77777777, &aips1->mprot1); +	writel(0x77777777, &aips2->mprot0); +	writel(0x77777777, &aips2->mprot1); + +	/* +	 * Set all OPACRx to be non-bufferable, not require +	 * supervisor privilege level for access,allow for +	 * write access and untrusted master access. +	 */ +	writel(0x00000000, &aips1->opacr0); +	writel(0x00000000, &aips1->opacr1); +	writel(0x00000000, &aips1->opacr2); +	writel(0x00000000, &aips1->opacr3); +	writel(0x00000000, &aips1->opacr4); +	writel(0x00000000, &aips2->opacr0); +	writel(0x00000000, &aips2->opacr1); +	writel(0x00000000, &aips2->opacr2); +	writel(0x00000000, &aips2->opacr3); +	writel(0x00000000, &aips2->opacr4); +} + +static void clear_ldo_ramp(void) +{ +	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; +	int reg; + +	/* ROM may modify LDO ramp up time according to fuse setting, so in +	 * order to be in the safe side we neeed to reset these settings to +	 * match the reset value: 0'b00 +	 */ +	reg = readl(&anatop->ana_misc2); +	reg &= ~(0x3f << 24); +	writel(reg, &anatop->ana_misc2); +} + +/* + * Set the VDDSOC + * + * Mask out the REG_CORE[22:18] bits (REG2_TRIG) and set + * them to the specified millivolt level. + * Possible values are from 0.725V to 1.450V in steps of + * 0.025V (25mV). + */ +static int set_ldo_voltage(enum ldo_reg ldo, u32 mv) +{ +	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; +	u32 val, step, old, reg = readl(&anatop->reg_core); +	u8 shift; + +	if (mv < 725) +		val = 0x00;	/* Power gated off */ +	else if (mv > 1450) +		val = 0x1F;	/* Power FET switched full on. No regulation */ +	else +		val = (mv - 700) / 25; + +	clear_ldo_ramp(); + +	switch (ldo) { +	case LDO_SOC: +		shift = 18; +		break; +	case LDO_PU: +		shift = 9; +		break; +	case LDO_ARM: +		shift = 0; +		break; +	default: +		return -EINVAL; +	} + +	old = (reg & (0x1F << shift)) >> shift; +	step = abs(val - old); +	if (step == 0) +		return 0; + +	reg = (reg & ~(0x1F << shift)) | (val << shift); +	writel(reg, &anatop->reg_core); + +	/* +	 * The LDO ramp-up is based on 64 clock cycles of 24 MHz = 2.6 us per +	 * step +	 */ +	udelay(3 * step); + +	return 0; +} + +static 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; + +	/* Write to the PDE (Power Down Enable) bit */ +	writew(enable, &wdog1->wmcr); +	writew(enable, &wdog2->wmcr); +} + +static void set_ahb_rate(u32 val) +{ +	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; +	u32 reg, div; + +	div = get_periph_clk() / val - 1; +	reg = readl(&mxc_ccm->cbcdr); + +	writel((reg & (~MXC_CCM_CBCDR_AHB_PODF_MASK)) | +		(div << MXC_CCM_CBCDR_AHB_PODF_OFFSET), &mxc_ccm->cbcdr); +} + +static void clear_mmdc_ch_mask(void) +{ +	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; + +	/* Clear MMDC channel mask */ +	writel(0, &mxc_ccm->ccdr); +} + +int arch_cpu_init(void) +{ +	init_aips(); + +	/* Need to clear MMDC_CHx_MASK to make warm reset work. */ +	clear_mmdc_ch_mask(); + +	/* +	 * When low freq boot is enabled, ROM will not set AHB +	 * freq, so we need to ensure AHB freq is 132MHz in such +	 * scenario. +	 */ +	if (mxc_get_clock(MXC_ARM_CLK) == 396000000) +		set_ahb_rate(132000000); + +	imx_set_wdog_powerdown(false); /* Disable PDE bit of WMCR register */ + +#ifdef CONFIG_APBH_DMA +	/* Start APBH DMA */ +	mxs_dma_init(); +#endif + +	return 0; +} + +int board_postclk_init(void) +{ +	set_ldo_voltage(LDO_SOC, 1175);	/* Set VDDSOC to 1.175V */ + +	return 0; +} + +#ifndef CONFIG_SYS_DCACHE_OFF +void enable_caches(void) +{ +	/* Avoid random hang when download by usb */ +	invalidate_dcache_all(); +	/* Enable D-cache. I-cache is already enabled in start.S */ +	dcache_enable(); +} +#endif + +#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[4]; +	struct fuse_bank4_regs *fuse = +			(struct fuse_bank4_regs *)bank->fuse_regs; + +	u32 value = readl(&fuse->mac_addr_high); +	mac[0] = (value >> 8); +	mac[1] = value ; + +	value = readl(&fuse->mac_addr_low); +	mac[2] = value >> 24 ; +	mac[3] = value >> 16 ; +	mac[4] = value >> 8 ; +	mac[5] = value ; + +} +#endif + +void boot_mode_apply(unsigned cfg_val) +{ +	unsigned reg; +	struct src *psrc = (struct src *)SRC_BASE_ADDR; +	writel(cfg_val, &psrc->gpr9); +	reg = readl(&psrc->gpr10); +	if (cfg_val) +		reg |= 1 << 28; +	else +		reg &= ~(1 << 28); +	writel(reg, &psrc->gpr10); +} +/* + * cfg_val will be used for + * Boot_cfg4[7:0]:Boot_cfg3[7:0]:Boot_cfg2[7:0]:Boot_cfg1[7:0] + * After reset, if GPR10[28] is 1, ROM will copy GPR9[25:0] + * to SBMR1, which will determine the boot device. + */ +const struct boot_mode soc_boot_modes[] = { +	{"normal",	MAKE_CFGVAL(0x00, 0x00, 0x00, 0x00)}, +	/* reserved value should start rom usb */ +	{"usb",		MAKE_CFGVAL(0x01, 0x00, 0x00, 0x00)}, +	{"sata",	MAKE_CFGVAL(0x20, 0x00, 0x00, 0x00)}, +	{"escpi1:0",	MAKE_CFGVAL(0x30, 0x00, 0x00, 0x08)}, +	{"escpi1:1",	MAKE_CFGVAL(0x30, 0x00, 0x00, 0x18)}, +	{"escpi1:2",	MAKE_CFGVAL(0x30, 0x00, 0x00, 0x28)}, +	{"escpi1:3",	MAKE_CFGVAL(0x30, 0x00, 0x00, 0x38)}, +	/* 4 bit bus width */ +	{"esdhc1",	MAKE_CFGVAL(0x40, 0x20, 0x00, 0x00)}, +	{"esdhc2",	MAKE_CFGVAL(0x40, 0x28, 0x00, 0x00)}, +	{"esdhc3",	MAKE_CFGVAL(0x40, 0x30, 0x00, 0x00)}, +	{"esdhc4",	MAKE_CFGVAL(0x40, 0x38, 0x00, 0x00)}, +	{NULL,		0}, +}; + +void s_init(void) +{ +	struct anatop_regs *anatop = (struct anatop_regs *)ANATOP_BASE_ADDR; +	int is_6q = is_cpu_type(MXC_CPU_MX6Q); +	u32 mask480; +	u32 mask528; + +	/* Due to hardware limitation, on MX6Q we need to gate/ungate all PFDs +	 * to make sure PFD is working right, otherwise, PFDs may +	 * not output clock after reset, MX6DL and MX6SL have added 396M pfd +	 * workaround in ROM code, as bus clock need it +	 */ + +	mask480 = ANATOP_PFD_CLKGATE_MASK(0) | +		ANATOP_PFD_CLKGATE_MASK(1) | +		ANATOP_PFD_CLKGATE_MASK(2) | +		ANATOP_PFD_CLKGATE_MASK(3); +	mask528 = ANATOP_PFD_CLKGATE_MASK(0) | +		ANATOP_PFD_CLKGATE_MASK(1) | +		ANATOP_PFD_CLKGATE_MASK(3); + +	/* +	 * Don't reset PFD2 on DL/S +	 */ +	if (is_6q) +		mask528 |= ANATOP_PFD_CLKGATE_MASK(2); +	writel(mask480, &anatop->pfd_480_set); +	writel(mask528, &anatop->pfd_528_set); +	writel(mask480, &anatop->pfd_480_clr); +	writel(mask528, &anatop->pfd_528_clr); +} + +#ifdef CONFIG_IMX_HDMI +void imx_enable_hdmi_phy(void) +{ +	struct hdmi_regs *hdmi = (struct hdmi_regs *)HDMI_ARB_BASE_ADDR; +	u8 reg; +	reg = readb(&hdmi->phy_conf0); +	reg |= HDMI_PHY_CONF0_PDZ_MASK; +	writeb(reg, &hdmi->phy_conf0); +	udelay(3000); +	reg |= HDMI_PHY_CONF0_ENTMDS_MASK; +	writeb(reg, &hdmi->phy_conf0); +	udelay(3000); +	reg |= HDMI_PHY_CONF0_GEN2_TXPWRON_MASK; +	writeb(reg, &hdmi->phy_conf0); +	writeb(HDMI_MC_PHYRSTZ_ASSERT, &hdmi->mc_phyrstz); +} + +void imx_setup_hdmi(void) +{ +	struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR; +	struct hdmi_regs *hdmi  = (struct hdmi_regs *)HDMI_ARB_BASE_ADDR; +	int reg; + +	/* Turn on HDMI PHY clock */ +	reg = readl(&mxc_ccm->CCGR2); +	reg |=  MXC_CCM_CCGR2_HDMI_TX_IAHBCLK_MASK| +		 MXC_CCM_CCGR2_HDMI_TX_ISFRCLK_MASK; +	writel(reg, &mxc_ccm->CCGR2); +	writeb(HDMI_MC_PHYRSTZ_DEASSERT, &hdmi->mc_phyrstz); +	reg = readl(&mxc_ccm->chsccdr); +	reg &= ~(MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_MASK| +		 MXC_CCM_CHSCCDR_IPU1_DI0_PODF_MASK| +		 MXC_CCM_CHSCCDR_IPU1_DI0_CLK_SEL_MASK); +	reg |= (CHSCCDR_PODF_DIVIDE_BY_3 +		 << MXC_CCM_CHSCCDR_IPU1_DI0_PODF_OFFSET) +		 |(CHSCCDR_IPU_PRE_CLK_540M_PFD +		 << MXC_CCM_CHSCCDR_IPU1_DI0_PRE_CLK_SEL_OFFSET); +	writel(reg, &mxc_ccm->chsccdr); +} +#endif + +#ifndef CONFIG_SYS_L2CACHE_OFF +#define IOMUXC_GPR11_L2CACHE_AS_OCRAM 0x00000002 +void v7_outer_cache_enable(void) +{ +	struct pl310_regs *const pl310 = (struct pl310_regs *)L2_PL310_BASE; +	unsigned int val; + +#if defined CONFIG_MX6SL +	struct iomuxc *iomux = (struct iomuxc *)IOMUXC_BASE_ADDR; +	val = readl(&iomux->gpr[11]); +	if (val & IOMUXC_GPR11_L2CACHE_AS_OCRAM) { +		/* L2 cache configured as OCRAM, reset it */ +		val &= ~IOMUXC_GPR11_L2CACHE_AS_OCRAM; +		writel(val, &iomux->gpr[11]); +	} +#endif + +	writel(0x132, &pl310->pl310_tag_latency_ctrl); +	writel(0x132, &pl310->pl310_data_latency_ctrl); + +	val = readl(&pl310->pl310_prefetch_ctrl); + +	/* Turn on the L2 I/D prefetch */ +	val |= 0x30000000; + +	/* +	 * The L2 cache controller(PL310) version on the i.MX6D/Q is r3p1-50rel0 +	 * The L2 cache controller(PL310) version on the i.MX6DL/SOLO/SL is r3p2 +	 * But according to ARM PL310 errata: 752271 +	 * ID: 752271: Double linefill feature can cause data corruption +	 * Fault Status: Present in: r3p0, r3p1, r3p1-50rel0. Fixed in r3p2 +	 * Workaround: The only workaround to this erratum is to disable the +	 * double linefill feature. This is the default behavior. +	 */ + +#ifndef CONFIG_MX6Q +	val |= 0x40800000; +#endif +	writel(val, &pl310->pl310_prefetch_ctrl); + +	val = readl(&pl310->pl310_power_ctrl); +	val |= L2X0_DYNAMIC_CLK_GATING_EN; +	val |= L2X0_STNDBY_MODE_EN; +	writel(val, &pl310->pl310_power_ctrl); + +	setbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); +} + +void v7_outer_cache_disable(void) +{ +	struct pl310_regs *const pl310 = (struct pl310_regs *)L2_PL310_BASE; + +	clrbits_le32(&pl310->pl310_ctrl, L2X0_CTRL_EN); +} +#endif /* !CONFIG_SYS_L2CACHE_OFF */  | 
