xref: /rk3399_rockchip-uboot/arch/arm/cpu/arm1136/mx31/generic.c (revision 0ffadab1b9ab59816a0f71c927604bb6c402d863)
184ad6884SPeter Tyser /*
284ad6884SPeter Tyser  * (C) Copyright 2007
384ad6884SPeter Tyser  * Sascha Hauer, Pengutronix
484ad6884SPeter Tyser  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
684ad6884SPeter Tyser  */
784ad6884SPeter Tyser 
884ad6884SPeter Tyser #include <common.h>
9697191d5SBenoît Thébaudeau #include <div64.h>
1086271115SStefano Babic #include <asm/arch/imx-regs.h>
119f008bb4SStefano Babic #include <asm/arch/clock.h>
12f76888c2SStefano Babic #include <asm/io.h>
1347c5455aSHelmut Raiger #include <asm/arch/sys_proto.h>
1484ad6884SPeter Tyser 
mx31_decode_pll(u32 reg,u32 infreq)1584ad6884SPeter Tyser static u32 mx31_decode_pll(u32 reg, u32 infreq)
1684ad6884SPeter Tyser {
17f0029198SHelmut Raiger 	u32 mfi = GET_PLL_MFI(reg);
18697191d5SBenoît Thébaudeau 	s32 mfn = GET_PLL_MFN(reg);
19f0029198SHelmut Raiger 	u32 mfd = GET_PLL_MFD(reg);
20f0029198SHelmut Raiger 	u32 pd =  GET_PLL_PD(reg);
2184ad6884SPeter Tyser 
2284ad6884SPeter Tyser 	mfi = mfi <= 5 ? 5 : mfi;
23697191d5SBenoît Thébaudeau 	mfn = mfn >= 512 ? mfn - 1024 : mfn;
2484ad6884SPeter Tyser 	mfd += 1;
2584ad6884SPeter Tyser 	pd += 1;
2684ad6884SPeter Tyser 
27697191d5SBenoît Thébaudeau 	return lldiv(2 * (u64)infreq * (mfi * mfd + mfn),
28697191d5SBenoît Thébaudeau 		mfd * pd);
2984ad6884SPeter Tyser }
3084ad6884SPeter Tyser 
mx31_get_mpl_dpdgck_clk(void)3184ad6884SPeter Tyser static u32 mx31_get_mpl_dpdgck_clk(void)
3284ad6884SPeter Tyser {
3384ad6884SPeter Tyser 	u32 infreq;
3484ad6884SPeter Tyser 
35f0029198SHelmut Raiger 	if ((readl(CCM_CCMR) & CCMR_PRCS_MASK) == CCMR_FPM)
360dc7b82eSBenoît Thébaudeau 		infreq = MXC_CLK32 * 1024;
3784ad6884SPeter Tyser 	else
380dc7b82eSBenoît Thébaudeau 		infreq = MXC_HCLK;
3984ad6884SPeter Tyser 
40f0029198SHelmut Raiger 	return mx31_decode_pll(readl(CCM_MPCTL), infreq);
4184ad6884SPeter Tyser }
4284ad6884SPeter Tyser 
mx31_get_mcu_main_clk(void)4384ad6884SPeter Tyser static u32 mx31_get_mcu_main_clk(void)
4484ad6884SPeter Tyser {
4584ad6884SPeter Tyser 	/* For now we assume mpl_dpdgck_clk == mcu_main_clk
4684ad6884SPeter Tyser 	 * which should be correct for most boards
4784ad6884SPeter Tyser 	 */
4884ad6884SPeter Tyser 	return mx31_get_mpl_dpdgck_clk();
4984ad6884SPeter Tyser }
5084ad6884SPeter Tyser 
mx31_get_ipg_clk(void)519f008bb4SStefano Babic static u32 mx31_get_ipg_clk(void)
5284ad6884SPeter Tyser {
5384ad6884SPeter Tyser 	u32 freq = mx31_get_mcu_main_clk();
54f0029198SHelmut Raiger 	u32 pdr0 = readl(CCM_PDR0);
5584ad6884SPeter Tyser 
56f0029198SHelmut Raiger 	freq /= GET_PDR0_MAX_PODF(pdr0) + 1;
57f0029198SHelmut Raiger 	freq /= GET_PDR0_IPG_PODF(pdr0) + 1;
58f0029198SHelmut Raiger 
59f0029198SHelmut Raiger 	return freq;
60f0029198SHelmut Raiger }
61f0029198SHelmut Raiger 
62f0029198SHelmut Raiger /* hsp is the clock for the ipu */
mx31_get_hsp_clk(void)63f0029198SHelmut Raiger static u32 mx31_get_hsp_clk(void)
64f0029198SHelmut Raiger {
65f0029198SHelmut Raiger 	u32 freq = mx31_get_mcu_main_clk();
66f0029198SHelmut Raiger 	u32 pdr0 = readl(CCM_PDR0);
67f0029198SHelmut Raiger 
68f0029198SHelmut Raiger 	freq /= GET_PDR0_HSP_PODF(pdr0) + 1;
6984ad6884SPeter Tyser 
7084ad6884SPeter Tyser 	return freq;
7184ad6884SPeter Tyser }
7284ad6884SPeter Tyser 
mx31_dump_clocks(void)7384ad6884SPeter Tyser void mx31_dump_clocks(void)
7484ad6884SPeter Tyser {
7584ad6884SPeter Tyser 	u32 cpufreq = mx31_get_mcu_main_clk();
7684ad6884SPeter Tyser 	printf("mx31 cpu clock: %dMHz\n", cpufreq / 1000000);
7784ad6884SPeter Tyser 	printf("ipg clock     : %dHz\n", mx31_get_ipg_clk());
78f0029198SHelmut Raiger 	printf("hsp clock     : %dHz\n", mx31_get_hsp_clk());
7984ad6884SPeter Tyser }
8084ad6884SPeter Tyser 
mxc_get_clock(enum mxc_clock clk)819f008bb4SStefano Babic unsigned int mxc_get_clock(enum mxc_clock clk)
829f008bb4SStefano Babic {
839f008bb4SStefano Babic 	switch (clk) {
849f008bb4SStefano Babic 	case MXC_ARM_CLK:
859f008bb4SStefano Babic 		return mx31_get_mcu_main_clk();
869f008bb4SStefano Babic 	case MXC_IPG_CLK:
8767f463b0SStefano Babic 	case MXC_IPG_PERCLK:
889f008bb4SStefano Babic 	case MXC_CSPI_CLK:
899f008bb4SStefano Babic 	case MXC_UART_CLK:
90fa47a286SHelmut Raiger 	case MXC_ESDHC_CLK:
91e7bed5c2SMatthias Weisser 	case MXC_I2C_CLK:
929f008bb4SStefano Babic 		return mx31_get_ipg_clk();
93f0029198SHelmut Raiger 	case MXC_IPU_CLK:
94f0029198SHelmut Raiger 		return mx31_get_hsp_clk();
959f008bb4SStefano Babic 	}
969f008bb4SStefano Babic 	return -1;
979f008bb4SStefano Babic }
989f008bb4SStefano Babic 
imx_get_uartclk(void)999f008bb4SStefano Babic u32 imx_get_uartclk(void)
1009f008bb4SStefano Babic {
1019f008bb4SStefano Babic 	return mxc_get_clock(MXC_UART_CLK);
1029f008bb4SStefano Babic }
1039f008bb4SStefano Babic 
mx31_gpio_mux(unsigned long mode)10484ad6884SPeter Tyser void mx31_gpio_mux(unsigned long mode)
10584ad6884SPeter Tyser {
10684ad6884SPeter Tyser 	unsigned long reg, shift, tmp;
10784ad6884SPeter Tyser 
10884ad6884SPeter Tyser 	reg = IOMUXC_BASE + (mode & 0x1fc);
10984ad6884SPeter Tyser 	shift = (~mode & 0x3) * 8;
11084ad6884SPeter Tyser 
111f0029198SHelmut Raiger 	tmp = readl(reg);
11284ad6884SPeter Tyser 	tmp &= ~(0xff << shift);
11384ad6884SPeter Tyser 	tmp |= ((mode >> IOMUX_MODE_POS) & 0xff) << shift;
114f0029198SHelmut Raiger 	writel(tmp, reg);
11584ad6884SPeter Tyser }
11684ad6884SPeter Tyser 
mx31_set_pad(enum iomux_pins pin,u32 config)117f76888c2SStefano Babic void mx31_set_pad(enum iomux_pins pin, u32 config)
118f76888c2SStefano Babic {
119d078b7c2SStefano Babic 	u32 field, l, reg;
120f76888c2SStefano Babic 
121f76888c2SStefano Babic 	pin &= IOMUX_PADNUM_MASK;
122f76888c2SStefano Babic 	reg = (IOMUXC_BASE + 0x154) + (pin + 2) / 3 * 4;
123f76888c2SStefano Babic 	field = (pin + 2) % 3;
124f76888c2SStefano Babic 
125f0029198SHelmut Raiger 	l = readl(reg);
126f76888c2SStefano Babic 	l &= ~(0x1ff << (field * 10));
127f76888c2SStefano Babic 	l |= config << (field * 10);
128f0029198SHelmut Raiger 	writel(l, reg);
129f76888c2SStefano Babic 
130f76888c2SStefano Babic }
131f76888c2SStefano Babic 
mx31_set_gpr(enum iomux_gp_func gp,char en)1326d0fb3dbSFabio Estevam void mx31_set_gpr(enum iomux_gp_func gp, char en)
1336d0fb3dbSFabio Estevam {
1346d0fb3dbSFabio Estevam 	u32 l;
135ce93dc9bSFabio Estevam 	struct iomuxc_regs *iomuxc = (struct iomuxc_regs *)IOMUXC_BASE;
1366d0fb3dbSFabio Estevam 
137ce93dc9bSFabio Estevam 	l = readl(&iomuxc->gpr);
1386d0fb3dbSFabio Estevam 	if (en)
1396d0fb3dbSFabio Estevam 		l |= gp;
1406d0fb3dbSFabio Estevam 	else
1416d0fb3dbSFabio Estevam 		l &= ~gp;
1426d0fb3dbSFabio Estevam 
143ce93dc9bSFabio Estevam 	writel(l, &iomuxc->gpr);
1446d0fb3dbSFabio Estevam }
1456d0fb3dbSFabio Estevam 
mxc_setup_weimcs(int cs,const struct mxc_weimcs * weimcs)14647c5455aSHelmut Raiger void mxc_setup_weimcs(int cs, const struct mxc_weimcs *weimcs)
14747c5455aSHelmut Raiger {
14847c5455aSHelmut Raiger 	struct mx31_weim *weim = (struct mx31_weim *) WEIM_BASE;
14947c5455aSHelmut Raiger 	struct mx31_weim_cscr *cscr = &weim->cscr[cs];
15047c5455aSHelmut Raiger 
15147c5455aSHelmut Raiger 	writel(weimcs->upper, &cscr->upper);
15247c5455aSHelmut Raiger 	writel(weimcs->lower, &cscr->lower);
15347c5455aSHelmut Raiger 	writel(weimcs->additional, &cscr->additional);
15447c5455aSHelmut Raiger }
15547c5455aSHelmut Raiger 
1564adaf9bfSFabio Estevam struct mx3_cpu_type mx31_cpu_type[] = {
1572f22045bSStefano Babic 	{ .srev = 0x00, .v = 0x10 },
1582f22045bSStefano Babic 	{ .srev = 0x10, .v = 0x11 },
1592f22045bSStefano Babic 	{ .srev = 0x11, .v = 0x11 },
1602f22045bSStefano Babic 	{ .srev = 0x12, .v = 0x1F },
1612f22045bSStefano Babic 	{ .srev = 0x13, .v = 0x1F },
1622f22045bSStefano Babic 	{ .srev = 0x14, .v = 0x12 },
1632f22045bSStefano Babic 	{ .srev = 0x15, .v = 0x12 },
1642f22045bSStefano Babic 	{ .srev = 0x28, .v = 0x20 },
1652f22045bSStefano Babic 	{ .srev = 0x29, .v = 0x20 },
1664adaf9bfSFabio Estevam };
1674adaf9bfSFabio Estevam 
get_cpu_rev(void)1682f22045bSStefano Babic u32 get_cpu_rev(void)
1694adaf9bfSFabio Estevam {
1704adaf9bfSFabio Estevam 	u32 i, srev;
1714adaf9bfSFabio Estevam 
1724adaf9bfSFabio Estevam 	/* read SREV register from IIM module */
1734adaf9bfSFabio Estevam 	struct iim_regs *iim = (struct iim_regs *)MX31_IIM_BASE_ADDR;
1744adaf9bfSFabio Estevam 	srev = readl(&iim->iim_srev);
1754adaf9bfSFabio Estevam 
1764adaf9bfSFabio Estevam 	for (i = 0; i < ARRAY_SIZE(mx31_cpu_type); i++)
1774adaf9bfSFabio Estevam 		if (srev == mx31_cpu_type[i].srev)
178*2af896abSPeng Fan 			return mx31_cpu_type[i].v | (MXC_CPU_MX31 << 12);
1792f22045bSStefano Babic 
1802f22045bSStefano Babic 	return srev | 0x8000;
1814adaf9bfSFabio Estevam }
1824adaf9bfSFabio Estevam 
get_reset_cause(void)183d43458d2SStefano Babic static char *get_reset_cause(void)
18425d8e1bbSFabio Estevam {
18525d8e1bbSFabio Estevam 	/* read RCSR register from CCM module */
18625d8e1bbSFabio Estevam 	struct clock_control_regs *ccm =
18725d8e1bbSFabio Estevam 		(struct clock_control_regs *)CCM_BASE;
18825d8e1bbSFabio Estevam 
18925d8e1bbSFabio Estevam 	u32 cause = readl(&ccm->rcsr) & 0x07;
19025d8e1bbSFabio Estevam 
19125d8e1bbSFabio Estevam 	switch (cause) {
19225d8e1bbSFabio Estevam 	case 0x0000:
19325d8e1bbSFabio Estevam 		return "POR";
19425d8e1bbSFabio Estevam 	case 0x0001:
19525d8e1bbSFabio Estevam 		return "RST";
19625d8e1bbSFabio Estevam 	case 0x0002:
19725d8e1bbSFabio Estevam 		return "WDOG";
19825d8e1bbSFabio Estevam 	case 0x0006:
19925d8e1bbSFabio Estevam 		return "JTAG";
20082081406SHelmut Raiger 	case 0x0007:
20182081406SHelmut Raiger 		return "ARM11P power gating";
20225d8e1bbSFabio Estevam 	default:
20325d8e1bbSFabio Estevam 		return "unknown reset";
20425d8e1bbSFabio Estevam 	}
20525d8e1bbSFabio Estevam }
20625d8e1bbSFabio Estevam 
20784ad6884SPeter Tyser #if defined(CONFIG_DISPLAY_CPUINFO)
print_cpuinfo(void)20884ad6884SPeter Tyser int print_cpuinfo(void)
20984ad6884SPeter Tyser {
2102f22045bSStefano Babic 	u32 srev = get_cpu_rev();
2112f22045bSStefano Babic 
212b6ce4796SFabio Estevam 	printf("CPU:   Freescale i.MX31 rev %d.%d%s at %d MHz.\n",
2132f22045bSStefano Babic 			(srev & 0xF0) >> 4, (srev & 0x0F),
2142f22045bSStefano Babic 			((srev & 0x8000) ? " unknown" : ""),
2152f22045bSStefano Babic 			mx31_get_mcu_main_clk() / 1000000);
21625d8e1bbSFabio Estevam 	printf("Reset cause: %s\n", get_reset_cause());
21784ad6884SPeter Tyser 	return 0;
21884ad6884SPeter Tyser }
21984ad6884SPeter Tyser #endif
220