194 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			194 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C
		
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * Copyright (C) 2020 MediaTek Inc. All Rights Reserved.
 | 
						|
 *
 | 
						|
 * Author:  Weijie Gao <weijie.gao@mediatek.com>
 | 
						|
 */
 | 
						|
 | 
						|
#include <config.h>
 | 
						|
#include <asm/global_data.h>
 | 
						|
#include <linux/io.h>
 | 
						|
#include "mt7620.h"
 | 
						|
 | 
						|
DECLARE_GLOBAL_DATA_PTR;
 | 
						|
 | 
						|
static const char * const dram_type[] = {
 | 
						|
	"SDRAM", "DDR", "DDR2", "SDRAM"
 | 
						|
};
 | 
						|
 | 
						|
static const char * const boot_mode[(CHIP_MODE_M >> CHIP_MODE_S) + 1] = {
 | 
						|
	[1] = "NAND 4-cycles 2KB-page",
 | 
						|
	[2] = "SPI-NOR 3-Byte Addr",
 | 
						|
	[3] = "SPI-NOR 4-Byte Addr",
 | 
						|
	[10] = "NAND 4-cycles 512B-page",
 | 
						|
	[11] = "NAND 5-cycles 2KB-page",
 | 
						|
	[12] = "NAND 3-cycles 512B-page",
 | 
						|
};
 | 
						|
 | 
						|
static void cpu_pll_init(void)
 | 
						|
{
 | 
						|
	void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
 | 
						|
	u32 pllmul = CONFIG_CPU_FREQ_MULTI;
 | 
						|
 | 
						|
	/* Make sure the pll multiplier is valid */
 | 
						|
	if (pllmul > 7)
 | 
						|
		pllmul = 7;
 | 
						|
 | 
						|
	/* Set init CPU clock to 480MHz */
 | 
						|
	clrsetbits_32(sysc + SYSCTL_CPLL_CFG1_REG, CPU_CLK_AUX1, CPU_CLK_AUX0);
 | 
						|
 | 
						|
	/* Enable software control of CPU PLL */
 | 
						|
	setbits_32(sysc + SYSCTL_CPLL_CFG0_REG, CPLL_SW_CFG);
 | 
						|
 | 
						|
	/* CPU PLL power down */
 | 
						|
	setbits_32(sysc + SYSCTL_CPLL_CFG1_REG, CPLL_PD);
 | 
						|
 | 
						|
	/* PLL configuration */
 | 
						|
	clrsetbits_32(sysc + SYSCTL_CPLL_CFG0_REG, PLL_MULT_RATIO_M |
 | 
						|
		      PLL_DIV_RATIO_M | SSC_UP_BOUND_M | SSC_EN,
 | 
						|
		      (pllmul << PLL_MULT_RATIO_S) | SSC_SWING_M);
 | 
						|
 | 
						|
	/* CPU PLL power up */
 | 
						|
	clrbits_32(sysc + SYSCTL_CPLL_CFG1_REG, CPLL_PD);
 | 
						|
 | 
						|
	/* Wait for CPU PLL locked */
 | 
						|
	while (!(readl(sysc + SYSCTL_CPLL_CFG1_REG) & CPLL_LD))
 | 
						|
		;
 | 
						|
 | 
						|
	/* Set final CPU clock source */
 | 
						|
	clrbits_32(sysc + SYSCTL_CPLL_CFG1_REG, CPU_CLK_AUX1 | CPU_CLK_AUX0);
 | 
						|
 | 
						|
	/* Adjust CPU clock */
 | 
						|
	clrsetbits_32(sysc + SYSCTL_CPU_SYS_CLKCFG_REG,
 | 
						|
		      CPU_FDIV_M | CPU_FFRAC_M,
 | 
						|
		      (1 << CPU_FDIV_S) | (1 << CPU_FFRAC_S));
 | 
						|
}
 | 
						|
 | 
						|
void mt7620_init(void)
 | 
						|
{
 | 
						|
	u32 cpu_clk;
 | 
						|
 | 
						|
	cpu_pll_init();
 | 
						|
 | 
						|
	/*
 | 
						|
	 * Set timer freq, which will be used during DRAM initialization
 | 
						|
	 * Note that this function is using a temporary gd which will be
 | 
						|
	 * destroyed after leaving this function.
 | 
						|
	 */
 | 
						|
	mt7620_get_clks(&cpu_clk, NULL, NULL);
 | 
						|
	gd->arch.timer_freq = cpu_clk / 2;
 | 
						|
 | 
						|
	mt7620_dram_init();
 | 
						|
}
 | 
						|
 | 
						|
void mt7620_get_clks(u32 *cpu_clk, u32 *sys_clk, u32 *xtal_clk)
 | 
						|
{
 | 
						|
	void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
 | 
						|
	u32 val, multi, div, fdiv, ffrac, dram_type, sys_div;
 | 
						|
	u32 cpu_freq, xtal_freq;
 | 
						|
 | 
						|
	static const u32 div_ratio_table[] = {2, 3, 4, 8};
 | 
						|
 | 
						|
	val = readl(sysc + SYSCTL_SYSCFG0_REG);
 | 
						|
 | 
						|
	dram_type = (val & DRAM_TYPE_M) >> DRAM_TYPE_S;
 | 
						|
 | 
						|
	if (val & XTAL_FREQ_SEL)
 | 
						|
		xtal_freq = 40000000;
 | 
						|
	else
 | 
						|
		xtal_freq = 20000000;
 | 
						|
 | 
						|
	val = readl(sysc + SYSCTL_CPLL_CFG1_REG);
 | 
						|
	if (val & CPU_CLK_AUX1) {
 | 
						|
		cpu_freq = xtal_freq;
 | 
						|
	} else if (val & CPU_CLK_AUX0) {
 | 
						|
		cpu_freq = 480000000;
 | 
						|
	} else {
 | 
						|
		val = readl(sysc + SYSCTL_CPLL_CFG0_REG);
 | 
						|
		if (val & CPLL_SW_CFG) {
 | 
						|
			multi = (val & PLL_MULT_RATIO_M) >> PLL_MULT_RATIO_S;
 | 
						|
			div = (val & PLL_DIV_RATIO_M) >> PLL_DIV_RATIO_S;
 | 
						|
			cpu_freq = (multi + 24) * 40000000 /
 | 
						|
					div_ratio_table[div];
 | 
						|
		} else {
 | 
						|
			cpu_freq = 600000000;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	val = readl(sysc + SYSCTL_CUR_CLK_STS_REG);
 | 
						|
	ffrac = (val & CUR_CPU_FFRAC_M) >> CUR_CPU_FFRAC_S;
 | 
						|
	fdiv = (val & CUR_CPU_FDIV_M) >> CUR_CPU_FDIV_S;
 | 
						|
	cpu_freq = (cpu_freq * ffrac) / fdiv;
 | 
						|
 | 
						|
	switch (dram_type) {
 | 
						|
	case DRAM_SDRAM_E1:
 | 
						|
		sys_div = 4;
 | 
						|
		break;
 | 
						|
	case DRAM_DDR1:
 | 
						|
	case DRAM_DDR2:
 | 
						|
		sys_div = 3;
 | 
						|
		break;
 | 
						|
	case DRAM_SDRAM:
 | 
						|
		sys_div = 5;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (cpu_clk)
 | 
						|
		*cpu_clk = cpu_freq;
 | 
						|
 | 
						|
	if (sys_clk)
 | 
						|
		*sys_clk = cpu_freq / sys_div;
 | 
						|
 | 
						|
	if (xtal_clk)
 | 
						|
		*xtal_clk = xtal_freq;
 | 
						|
}
 | 
						|
 | 
						|
int print_cpuinfo(void)
 | 
						|
{
 | 
						|
	void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
 | 
						|
	u32 cpu_clk, bus_clk, xtal_clk;
 | 
						|
	u32 val, ver, eco, pkg, dram, chipmode;
 | 
						|
	const char *bootdev;
 | 
						|
 | 
						|
	val = readl(sysc + SYSCTL_CHIP_REV_ID_REG);
 | 
						|
	ver = (val & VER_M) >> VER_S;
 | 
						|
	eco = (val & ECO_M) >> ECO_S;
 | 
						|
	pkg = !!(val & PKG_ID);
 | 
						|
 | 
						|
	val = readl(sysc + SYSCTL_SYSCFG0_REG);
 | 
						|
	dram = (val & DRAM_TYPE_M) >> DRAM_TYPE_S;
 | 
						|
	chipmode = (val & CHIP_MODE_M) >> CHIP_MODE_S;
 | 
						|
 | 
						|
	bootdev = boot_mode[chipmode];
 | 
						|
	if (!bootdev)
 | 
						|
		bootdev = "Unsupported boot mode";
 | 
						|
 | 
						|
	printf("CPU:   MediaTek MT7620%c ver:%u eco:%u\n",
 | 
						|
	       pkg ? 'A' : 'N', ver, eco);
 | 
						|
 | 
						|
	printf("Boot:  %s, %s\n", dram_type[dram], bootdev);
 | 
						|
 | 
						|
	mt7620_get_clks(&cpu_clk, &bus_clk, &xtal_clk);
 | 
						|
 | 
						|
	/* Set final timer frequency */
 | 
						|
	gd->arch.timer_freq = cpu_clk / 2;
 | 
						|
 | 
						|
	printf("Clock: CPU: %uMHz, Bus: %uMHz, XTAL: %uMHz\n",
 | 
						|
	       cpu_clk / 1000000, bus_clk / 1000000, xtal_clk / 1000000);
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
ulong notrace get_tbclk(void)
 | 
						|
{
 | 
						|
	return gd->arch.timer_freq;
 | 
						|
}
 | 
						|
 | 
						|
void _machine_restart(void)
 | 
						|
{
 | 
						|
	void __iomem *sysc = ioremap_nocache(SYSCTL_BASE, SYSCTL_SIZE);
 | 
						|
 | 
						|
	while (1)
 | 
						|
		writel(SYS_RST, sysc + SYSCTL_RSTCTL_REG);
 | 
						|
}
 |