ITOP4412----Uboot移植记录
- 1、 在board/samsung/目录下添加itop4412目录,准备添加板级文件。
- 2、在arch/arm/include/asm/mach-types.h中添加4412机器码
- 3、添加board.c实现s_init()拉高电源芯片hold引脚和点亮led灯。
- 4、修改dmc_init_exynos4.c、clock_init_exynos4.c,添加itop4412_setup.h
- 5、修改arch/arm/mach-exynos/clock.c中对clock的操作
- 7、修改arch/arm/mach-exynos/power.c中的set_ps_hold_ctrl,添加4412支持
- 临门一脚
- 经验之谈
gitee: 本工程代码托管于gitee,仅供参考学习使用,不保证任何出现的问题。
1、 在board/samsung/目录下添加itop4412目录,准备添加板级文件。
复制origen开发板内文件,到board/samsung/itop4412。开始修改修改。
上述文件全部来自origen开发板目录下。
mkitop4412spl.c
/*
* Copyright (C) 2011 Samsung Electronics
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#define BUFSIZE (16*1024)
#define IMG_SIZE (14*1024) //16*1024 14k BL2
#define SPL_HEADER_SIZE 0 //16 不保留、在sdfuse中烧录
#define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP \
| S_IWGRP | S_IROTH | S_IWOTH)
#define SPL_HEADER "S5PC210 HEADER "
/*
* Requirement:
* IROM code reads first 14K bytes from boot device.
* IROM的出厂烧录的代码会从启动设备中读取起始14K字节
* It then calculates the checksum of 14K-4 bytes
* and compare with data at 14K-4 offset.
* 它会计算这14k减去4字节的代码的校验和,(这里减去的4字节内容存放着开发人员自己对代码计算的校验和,这个文件就是用来干这个的)。IROM会用这4字节的校验和与自己计算的校验和比较,如果不匹配,程序不会正常运行。
* This function takes two filenames:
* 这个文件需要两个参数
* IN "u-boot-spl.bin" and
* OUT "$(BOARD)-spl.bin as filenames.
* 输入u-boot-spl.bin文件,输出$(BOARD)-spl.bin,$(BOARD)是目标板名称例如
* 输出itop4412-spl.bin
* It reads the "u-boot-spl.bin" in 16K buffer.
* 这个文件会读取u-boot-spl.bin到一个16k的缓冲区中
* It calculates checksum of 14K-4 Bytes and stores at 14K-4 offset in buffer.
* 然后计算14k-4字节代码的校验和,储存在偏移为14K-4的缓冲区中,最后写到$(BOARD)-spl.bin里
* It writes the buffer to "$(BOARD)-spl.bin" file.
*/
int main(int argc, char **argv)
{
int i, len;
unsigned char buffer[BUFSIZE] = {
0};
int ifd, ofd;
unsigned int checksum = 0, count;
if (argc != 3) {
printf(" %d Wrong number of arguments\n", argc);
exit(EXIT_FAILURE);
}
ifd = open(argv[1], O_RDONLY);
if (ifd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
argv[0], argv[1], strerror(errno));
exit(EXIT_FAILURE);
}
ofd = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC, FILE_PERM);
if (ofd < 0) {
fprintf(stderr, "%s: Can't open %s: %s\n",
argv[0], argv[2], strerror(errno));
if (ifd)
close(ifd);
exit(EXIT_FAILURE);
}
len = lseek(ifd, 0, SEEK_END);
lseek(ifd, 0, SEEK_SET);
memcpy(&buffer[0], SPL_HEADER, SPL_HEADER_SIZE);
count = (len < (IMG_SIZE - SPL_HEADER_SIZE))
? len : (IMG_SIZE - SPL_HEADER_SIZE);
if (read(ifd, buffer + SPL_HEADER_SIZE, count) != count) {
fprintf(stderr, "%s: Can't read %s: %s\n",
argv[0], argv[1], strerror(errno));
if (ifd)
close(ifd);
if (ofd)
close(ofd);
exit(EXIT_FAILURE);
}
#if 0
for (i = 0; i < IMG_SIZE - SPL_HEADER_SIZE; i++)
checksum += buffer[i+16];
*(unsigned long *)buffer ^= 0x1f;
*(unsigned long *)(buffer+4) ^= checksum;
for (i = 1; i < SPL_HEADER_SIZE; i++)
buffer[i] ^= buffer[i-1];
#endif
for (i = 0; i < IMG_SIZE - 4; i++)
checksum += (unsigned char)buffer[i];
*(unsigned int *)&buffer[i] = checksum;
if (write(ofd, buffer, BUFSIZE) != BUFSIZE) {
fprintf(stderr, "%s: Can't write %s: %s\n",
argv[0], argv[2], strerror(errno));
if (ifd)
close(ifd);
if (ofd)
close(ofd);
exit(EXIT_FAILURE);
}
if (ifd)
close(ifd);
if (ofd)
close(ofd);
return EXIT_SUCCESS;
}
这个文件会被编译成BL2工具,在最终生成uboot的时候自动被调用,代码如下
./spl/board/samsung/itop4412/tools/mkitop4412spl spl/u-boot-spl.bin spl/itop4412-spl.bin
itop4412.c
如果要对板子做一些特殊的初始化,可以添加在这里,点个灯什么的。
// SPDX-License-Identifier: GPL-2.0+
/*
* Copyright (C) 2011 Samsung Electronics
*/
#include <common.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/arch/cpu.h>
#include <asm/arch/mmc.h>
#include <asm/arch/periph.h>
#include <asm/arch/pinmux.h>
#include <usb.h>
u32 get_board_rev(void)
{
return 0;
}
int exynos_init(void)
{
return 0;
}
int board_usb_init(int index, enum usb_init_type init)
{
return 0;
}
#ifdef CONFIG_BOARD_EARLY_INIT_F
int exynos_early_init_f(void)
{
return 0;
}
#endif
Kconfig
用于make menuconfig的配置选项,图形化配置需要。
if TARGET_ITOP4412
config SYS_BOARD
default "itop4412"
config SYS_VENDOR
default "samsung"
config SYS_CONFIG_NAME
default "itop4412"
endif
Maintained
一些声明
ITOP4412 BOARD
M: Chander Kashyap <k.chander@samsung.com>
S: Maintained
F: board/samsung/itop4412/
F: include/configs/itop4412.h
F: configs/itop4412_defconfig
Makefile
编译脚本
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2011 Samsung Electronics
ifdef CONFIG_SPL_BUILD
# necessary to create built-in.o
obj- := __dummy__.o
hostprogs-y := tools/mkitop4412spl
always := $(hostprogs-y)
# omit -O2 option to suppress
# warning: dereferencing type-punned pointer will break strict-aliasing rules
#
# TODO:
# Fix the root cause in tools/mkorigenspl.c and delete the following work-around
$(obj)/tools/mkitop4412spl: HOSTCFLAGS:=$(filter-out -O2,$(HOSTCFLAGS))
else
obj-y += itop4412.o
endif
2、在arch/arm/include/asm/mach-types.h中添加4412机器码
#define MACH_TYPE_ITOP4412 5115//在最后面+1
3、添加board.c实现s_init()拉高电源芯片hold引脚和点亮led灯。
board.c
#include <common.h>
#include <config.h>
#include <asm/io.h>
void s_init(void)
{
writel(readl(0x1002330c) | 0x300, 0x1002330c);
writel(0, 0x11000c08);
/* led test */
writel(0x10, 0x11000060);
writel(0x2, 0x11000064);
writel(0x1, 0x11000100);
writel(0x1, 0x11000104);
}
修改arch/arm/mach-exynos/Makefile
为编译board.c、dmc内存管理、clock时钟配置提供支持。
# SPDX-License-Identifier: GPL-2.0+
#
# Copyright (C) 2009 Samsung Electronics
# Minkyu Kang <mk7.kang@samsung.com>
obj-y += board.o
obj-y += soc.o
obj-$(CONFIG_CPU_V7A) += clock.o pinmux.o power.o system.o
obj-$(CONFIG_ARM64) += mmu-arm64.o
obj-$(CONFIG_EXYNOS5420) += sec_boot.o
ifdef CONFIG_SPL_BUILD
obj-$(CONFIG_EXYNOS5) += clock_init_exynos5.o
obj-$(CONFIG_EXYNOS5) += dmc_common.o dmc_init_ddr3.o
obj-$(CONFIG_EXYNOS4210)+= dmc_init_exynos4.o clock_init_exynos4.o
ifneq (,$(filter y, $(CONFIG_EXYNOS4210) $(CONFIG_TARGET_ITOP4412)))
obj-y += dmc_init_exynos4.o clock_init_exynos4.o
endif
obj-y += spl_boot.o tzpc.o
obj-y += lowlevel_init.o
endif
4、修改dmc_init_exynos4.c、clock_init_exynos4.c,添加itop4412_setup.h
时钟和内存控制器的寄存器很难配,需要对照手册一点一点的弄。有不少前辈已经做好了工作,直接copy。
dmc_init_exynos4.c
内存控制器配置
/*
* Memory setup for board based on EXYNOS4210
*
* Copyright (C) 2013 Samsung Electronics
* Rajeshwari Shinde <rajeshwari.s@samsung.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <asm/arch/dmc.h>
#include "common_setup.h"
#ifdef CONFIG_ITOP4412
#include "itop4412_setup.h"
#else
#include "exynos4_setup.h"
#endif
struct mem_timings mem = {
.direct_cmd_msr = {
DIRECT_CMD1, DIRECT_CMD2, DIRECT_CMD3, DIRECT_CMD4
},
.timingref = TIMINGREF_VAL,
.timingrow = TIMINGROW_VAL,
.timingdata = TIMINGDATA_VAL,
.timingpower = TIMINGPOWER_VAL,
.zqcontrol = ZQ_CONTROL_VAL,
.control0 = CONTROL0_VAL,
.control1 = CONTROL1_VAL,
.control2 = CONTROL2_VAL,
.concontrol = CONCONTROL_VAL,
.prechconfig = PRECHCONFIG,
.memcontrol = MEMCONTROL_VAL,
.memconfig0 = MEMCONFIG0_VAL,
.memconfig1 = MEMCONFIG1_VAL,
.dll_resync = FORCE_DLL_RESYNC,
.dll_on = DLL_CONTROL_ON,
};
static void phy_control_reset(int ctrl_no, struct exynos4_dmc *dmc)
{
if (ctrl_no) {
writel((mem.control1 | (1 << mem.dll_resync)),
&dmc->phycontrol1);
writel((mem.control1 | (0 << mem.dll_resync)),
&dmc->phycontrol1);
} else {
writel((mem.control0 | (0 << mem.dll_on)),
&dmc->phycontrol0);
writel((mem.control0 | (1 << mem.dll_on)),
&dmc->phycontrol0);
}
}
static void dmc_config_mrs(struct exynos4_dmc *dmc, int chip)
{
int i;
unsigned long mask = 0;
if (chip)
mask = DIRECT_CMD_CHIP1_SHIFT;
for (i = 0; i < MEM_TIMINGS_MSR_COUNT; i++) {
writel(mem.direct_cmd_msr[i] | mask,
&dmc->directcmd);
}
}
static void dmc_init(struct exynos4_dmc *dmc)
{
/*
* DLL Parameter Setting:
* Termination: Enable R/W
* Phase Delay for DQS Cleaning: 180' Shift
*/
writel(mem.control1, &dmc->phycontrol1);
/*
* ZQ Calibration
* Termination: Disable
* Auto Calibration Start: Enable
*/
writel(mem.zqcontrol, &dmc->phyzqcontrol);
sdelay(0x100000);
/*
* Update DLL Information:
* Force DLL Resyncronization
*/
phy_control_reset(1, dmc);
phy_control_reset(0, dmc);
/* Set DLL Parameters */
writel(mem.control1, &dmc->phycontrol1);
/* DLL Start */
writel((mem.control0 | CTRL_START | CTRL_DLL_ON), &dmc->phycontrol0);
writel(mem.control2, &dmc->phycontrol2);
/* Set Clock Ratio of Bus clock to Memory Clock */
writel(mem.concontrol, &dmc->concontrol);
/*
* Memor Burst length: 8
* Number of chips: 2
* Memory Bus width: 32 bit
* Memory Type: DDR3
* Additional Latancy for PLL: 1 Cycle
*/
writel(mem.memcontrol, &dmc->memcontrol);
writel(mem.memconfig0, &dmc->memconfig0);
writel(mem.memconfig1, &dmc->memconfig1);
/* Config Precharge Policy */
writel(mem.prechconfig, &dmc->prechconfig);
/*
* TimingAref, TimingRow, TimingData, TimingPower Setting:
* Values as per Memory AC Parameters
*/
writel(mem.timingref, &dmc->timingref);
writel(mem.timingrow, &dmc->timingrow);
writel(mem.timingdata, &dmc->timingdata);
writel(mem.timingpower, &dmc->timingpower);
/* Chip0: NOP Command: Assert and Hold CKE to high level */
writel(DIRECT_CMD_NOP, &dmc->directcmd);
sdelay(0x100000);
/* Chip0: EMRS2, EMRS3, EMRS, MRS Commands Using Direct Command */
dmc_config_mrs(dmc, 0);
sdelay(0x100000);
/* Chip0: ZQINIT */
writel(DIRECT_CMD_ZQ, &dmc->directcmd);
sdelay(0x100000);
writel((DIRECT_CMD_NOP | DIRECT_CMD_CHIP1_SHIFT), &dmc->directcmd);
sdelay(0x100000);
/* Chip1: EMRS2, EMRS3, EMRS, MRS Commands Using Direct Command */
dmc_config_mrs(dmc, 1);
sdelay(0x100000);
/* Chip1: ZQINIT */
writel((DIRECT_CMD_ZQ | DIRECT_CMD_CHIP1_SHIFT), &dmc->directcmd);
sdelay(0x100000);
phy_control_reset(1, dmc);
sdelay(0x100000);
/* turn on DREX0, DREX1 */
writel((mem.concontrol | AREF_EN), &dmc->concontrol);
}
void mem_ctrl_init(int reset)
{
struct exynos4_dmc *dmc;
/*
* Async bridge configuration at CPU_core:
* 1: half_sync
* 0: full_sync
*/
writel(1, ASYNC_CONFIG);
#ifdef CONFIG_ITOP4412
/* Interleave: 2Bit, Interleave_bit1: 0x15, Interleave_bit0: 0x7 */
writel(APB_SFR_INTERLEAVE_CONF_VAL, EXYNOS4_MIU_BASE +
APB_SFR_INTERLEAVE_CONF_OFFSET);
/* Update MIU Configuration */
writel(APB_SFR_ARBRITATION_CONF_VAL, EXYNOS4_MIU_BASE +
APB_SFR_ARBRITATION_CONF_OFFSET);
#else
writel(APB_SFR_INTERLEAVE_CONF_VAL, EXYNOS4_MIU_BASE +
APB_SFR_INTERLEAVE_CONF_OFFSET);
writel(INTERLEAVE_ADDR_MAP_START_ADDR, EXYNOS4_MIU_BASE +
ABP_SFR_INTERLEAVE_ADDRMAP_START_OFFSET);
writel(INTERLEAVE_ADDR_MAP_END_ADDR, EXYNOS4_MIU_BASE +
ABP_SFR_INTERLEAVE_ADDRMAP_END_OFFSET);
writel(INTERLEAVE_ADDR_MAP_EN, EXYNOS4_MIU_BASE +
ABP_SFR_SLV_ADDRMAP_CONF_OFFSET);
#ifdef CONFIG_MIU_LINEAR
writel(SLAVE0_SINGLE_ADDR_MAP_START_ADDR, EXYNOS4_MIU_BASE +
ABP_SFR_SLV0_SINGLE_ADDRMAP_START_OFFSET);
writel(SLAVE0_SINGLE_ADDR_MAP_END_ADDR, EXYNOS4_MIU_BASE +
ABP_SFR_SLV0_SINGLE_ADDRMAP_END_OFFSET);
writel(SLAVE1_SINGLE_ADDR_MAP_START_ADDR, EXYNOS4_MIU_BASE +
ABP_SFR_SLV1_SINGLE_ADDRMAP_START_OFFSET);
writel(SLAVE1_SINGLE_ADDR_MAP_END_ADDR, EXYNOS4_MIU_BASE +
ABP_SFR_SLV1_SINGLE_ADDRMAP_END_OFFSET);
writel(APB_SFR_SLV_ADDR_MAP_CONF_VAL, EXYNOS4_MIU_BASE +
ABP_SFR_SLV_ADDRMAP_CONF_OFFSET);
#endif
#endif
/* DREX0 */
dmc = (struct exynos4_dmc *)samsung_get_base_dmc_ctrl();
dmc_init(dmc);
dmc = (struct exynos4_dmc *)(samsung_get_base_dmc_ctrl()
+ DMC_OFFSET);
dmc_init(dmc);
}
clock_init_exynos4.c
时钟配置
/*
* Clock Initialization for board based on EXYNOS4210
*
* Copyright (C) 2013 Samsung Electronics
* Rajeshwari Shinde <rajeshwari.s@samsung.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <common.h>
#include <config.h>
#include <asm/io.h>
#include <asm/arch/cpu.h>
#include <asm/arch/clk.h>
#include <asm/arch/clock.h>
#include "common_setup.h"
#ifdef CONFIG_ITOP4412
#include "itop4412_setup.h"
#else
#include "exynos4_setup.h"
#endif
/*
* system_clock_init: Initialize core clock and bus clock.
* void system_clock_init(void)
*/
/**
* freq (ARMCLK) = 1400 MHz at 1.3 V
* freq (ACLK_COREM0) = 350 MHz at 1.3V
* freq (ACLK_COREM1) = 188 MHz at 1.3 V
* freq (PERIPHCLK) = 1400 MHz at 1.3 V
* freq (ATCLK) = 214 MHz at 1.3 V
* freq (PCLK_DBG) = 107 MHz at 1.3 V
* freq (SCLK_DMC) = 400 MHz at 1.0 V
* freq (ACLK_DMCD) = 200 MHz at 1.0 V
* freq (ACLK_DMCP) = 100 MHz at 1.0 V
* freq (ACLK_ACP) = 200 MHz at 1.0 V
* freq (PCLK_ACP) = 100 MHz at 1.0 V
* freq (SCLK_C2C) = 400 MHz at 1.0 V
* freq (ACLK_C2C) = 200 MHz at 1.0 V
* freq (ACLK_GDL) = 200 MHz at 1.0 V
* freq (ACLK_GPL) = 100 MHz at 1.0 V
* freq (ACLK_GDR) = 200 MHz at 1.0 V
* freq (ACLK_GPR) = 100 MHz at 1.0 V
* freq (ACLK_400_MCUISP) = 400 MHz at 1.0 V
* freq (ACLK_200) = 160 MHz at 1.0 V
* freq (ACLK_100) = 100 MHz at 1.0 V
* freq (ACLK_160) = 160 MHz at 1.0 V
* freq (ACLK_133) = 133 MHz at 1.0 V
* freq (SCLK_ONENAND) = 160 MHz at 1.0 V
*/
void system_clock_init(void)
{
unsigned int set, clr, clr_src_cpu, clr_pll_con0, clr_src_dmc;
struct exynos4x12_clock *clk = (struct exynos4x12_clock *)
samsung_get_base_clock();
/************************************************************
* Step 1:
*
* Set PDIV, MDIV, and SDIV values (Refer to (A, M, E, V)
* Change other PLL control values
************************************************************/
/**
* Set dividers for MOUTcore = 1000 MHz
*
* DOUTcore = MOUTcore / (CORE_RATIO +1) = 1000 MHz (0)
* ACLK_COREM0 = ARMCLK / (COREM0_RATIO +1) = 250 MHz (3)
* ACLK_COREM1 = ARMCLK / (COREM1_RATIO +1) = 125 MHz (7)
* PERIPHCLK = DOUTcore / (PERIPH_RATIO + 1) = 1000 MHz (0)
* ATCLK = MOUTcore / (ATB_RATIO + 1) = 200 MHz (4)
* PCLK_DBG = ATCLK / (PCLK_DBG_RATIO + 1) = 100 MHz (1)
* SCLKapll = MOUTapll / (APLL_RATIO + 1) = 500 MHz (1)
* ARMCLK = DOUTcore / (CORE2_RATIO + 1) = 1000 MHz (0)
*/
/** CLK_DIV_CPU0 */
clr = CORE_RATIO(7) | COREM0_RATIO(7) | COREM1_RATIO(7) |
PERIPH_RATIO(7) | ATB_RATIO(7) | PCLK_DBG_RATIO(7) |
APLL_RATIO(7) | CORE2_RATIO(7);
set = CORE_RATIO(0) | COREM0_RATIO(3) | COREM1_RATIO(7) |
PERIPH_RATIO(0) | ATB_RATIO(4) | PCLK_DBG_RATIO(1) |
APLL_RATIO(1) | CORE2_RATIO(0);
clrsetbits_le32(&clk->div_cpu0, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_cpu0) & DIV_STAT_CPU0_CHANGING)
continue;
/**
* Set dividers for MOUThpm = 1000 MHz (MOUTapll)
*
* DOUTcopy = MOUThpm / (COPY_RATIO + 1) = 200 MHz (4)
* SCLK_HPM = DOUTcopy / (HPM_RATIO + 1) = 200 MHz (0)
* ACLK_CORES = ARMCLK / (CORES_RATIO + 1) = 1000 MHz (0)
*/
/** CLK_DIV_CPU1 */
clr = COPY_RATIO(7) | HPM_RATIO(7) | CORES_RATIO(7);
set = COPY_RATIO(4) | HPM_RATIO(0) | CORES_RATIO(0);
clrsetbits_le32(&clk->div_cpu1, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_cpu1) & DIV_STAT_CPU1_CHANGING)
continue;
/**
* Set dividers for -->
* MOUTdmc = 800 MHz
* MOUTdphy = 800 MHz
*
* ACLK_ACP = MOUTdmc / (ACP_RATIO + 1) = 200 MHz (3)
* PCLK_ACP = ACLK_ACP / (ACP_PCLK_RATIO + 1) = 100 MHz (1)
* SCLK_DPHY = MOUTdphy / (DPHY_RATIO + 1) = 400 MHz (1)
* SCLK_DMC = MOUTdmc / (DMC_RATIO + 1) = 400 MHz (1)
* ACLK_DMCD = SCLK_DMC / (DMCD_RATIO + 1) = 200 MHz (1)
* ACLK_DMCP = ACLK_DMCD / (DMCP_RATIO + 1) = 100 MHz (1)
*/
/** CLK_DIV_DMC0 */
clr = ACP_RATIO(7) | ACP_PCLK_RATIO(7) | DPHY_RATIO(7) |
DMC_RATIO(7) | DMCD_RATIO(7) | DMCP_RATIO(7);
set = ACP_RATIO(3) | ACP_PCLK_RATIO(1) | DPHY_RATIO(1) |
DMC_RATIO(1) | DMCD_RATIO(1) | DMCP_RATIO(1);
clrsetbits_le32(&clk->div_dmc0, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_dmc0) & DIV_STAT_DMC0_CHANGING)
continue;
/**
* For:
* MOUTg2d = 800 MHz
* MOUTc2c = 800 Mhz
* MOUTpwi = 24 MHz
*
* SCLK_G2D_ACP = MOUTg2d / (G2D_ACP_RATIO + 1) = 200 MHz (3)
* SCLK_C2C = MOUTc2c / (C2C_RATIO + 1) = 400 MHz (1)
* SCLK_PWI = MOUTpwi / (PWI_RATIO + 1) = 24 MHz (0)
* ACLK_C2C = SCLK_C2C / (C2C_ACLK_RATIO + 1) = 200 MHz (1)
* DVSEM_RATIO : It decides frequency for PWM frame time slot in DVS emulation mode.
* DPM_RATIO : It decides frequency of DPM channel clock.
*/
/** CLK_DIV_DMC1 */
clr = G2D_ACP_RATIO(15) | C2C_RATIO(7) | PWI_RATIO(15) |
C2C_ACLK_RATIO(7) | DVSEM_RATIO(127) | DPM_RATIO(127);
set = G2D_ACP_RATIO(3) | C2C_RATIO(1) | PWI_RATIO(0) |
C2C_ACLK_RATIO(1) | DVSEM_RATIO(1) | DPM_RATIO(1);
clrsetbits_le32(&clk->div_dmc1, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_dmc1) & DIV_STAT_DMC1_CHANGING)
continue;
/**
* MOUTmpll = 800 MHz
* MOUTvpll = 54 MHz
*
* ACLK_200 = MOUTACLK_200 / (ACLK_200_RATIO + 1) = 200 MHz (3)
* ACLK_100 = MOUTACLK_100 / (ACLK_100_RATIO + 1) = 100 MHz (7)
* ACLK_160 = MOUTACLK_160 / (ACLK_160_RATIO + 1) = 160 MHz (4)
* ACLK_133 = MOUTACLK_133 / (ACLK_133_RATIO + 1) = 133 MHz (5)
* ONENAND = MOUTONENAND_1 / (ONENAND_RATIO + 1) = 160 MHz (0)
* ACLK_266_GPS = MOUTACLK_266_GPS / (ACLK_266_GPS_RATIO + 1) = 266 MHz (2)
* ACLK_400_MCUISP = MOUTACLK_400_MCUISP / (ACLK_400_MCUISP_RATIO + 1) = 400 MHz (1)
*/
/** CLK_DIV_TOP */
clr = ACLK_200_RATIO(7) | ACLK_100_RATIO(15) | ACLK_160_RATIO(7) |
ACLK_133_RATIO(7) | ONENAND_RATIO(7) | ACLK_266_GPS_RATIO(7) | ACLK_400_MCUISP_RATIO(7);
set = ACLK_200_RATIO(3) | ACLK_100_RATIO(7) | ACLK_160_RATIO(4) |
ACLK_133_RATIO(5) | ONENAND_RATIO(0) | ACLK_266_GPS_RATIO(2) | ACLK_400_MCUISP_RATIO(1);
clrsetbits_le32(&clk->div_top, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_top) & DIV_STAT_TOP_CHANGING)
continue;
/**
* ACLK_GDL = MOUTGDL / (GDL_RATIO + 1) = 200 MHz (3)
* ACLK_GPL = MOUTGPL / (GPL_RATIO + 1) = 100 MHz (1)
*/
/** CLK_DIV_LEFTBUS */
clr = GDL_RATIO(7) | GPL_RATIO(7);
set = GDL_RATIO(3) | GPL_RATIO(1);
clrsetbits_le32(&clk->div_leftbus, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_leftbus) & DIV_STAT_LEFTBUS_CHANGING)
continue;
/**
* ACLK_GDR = MOUTGDR / (GDR_RATIO + 1) = 200 MHz (3)
* ACLK_GPR = MOUTGPR / (GPR_RATIO + 1) = 100 MHz (1)
*/
/** CLK_DIV_RIGHTBUS */
clr = GPR_RATIO(7) | GDR_RATIO(7);
set = GPR_RATIO(3) | GDR_RATIO(1);
clrsetbits_le32(&clk->div_rightbus, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_rightbus) & DIV_STAT_RIGHTBUS_CHANGING)
continue;
/**
* MOUTUART[1-4] = 800 Mhz (MPLL)
*
* SCLK_UART0 = MOUTUART0 / (UART0_RATIO + 1) = 100 MHz (7)
* SCLK_UART1 = MOUTUART1 / (UART1_RATIO + 1) = 100 MHz (7)
* SCLK_UART2 = MOUTUART2 / (UART2_RATIO + 1) = 100 MHz (7)
* SCLK_UART3 = MOUTUART3 / (UART3_RATIO + 1) = 100 MHz (7)
* SCLK_UART4 = MOUTUART4 / (UART4_RATIO + 1) = 100 MHz (7)
*/
/** CLK_DIV_PERIL0 */
clr = UART0_RATIO(15) | UART1_RATIO(15) | UART2_RATIO(15) |
UART3_RATIO(15) | UART4_RATIO(15);
set = UART0_RATIO(7) | UART1_RATIO(7) | UART2_RATIO(7) |
UART3_RATIO(7) | UART4_RATIO(7);
clrsetbits_le32(&clk->div_peril0, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_peril0) & DIV_STAT_PERIL0_CHANGING)
continue;
/**
* For MOUTMMC0-3 = 800 MHz (MPLL)
*
* SCLK_MIPIHSI = MOUTMIPIHSI / (MIPIHSI_RATIO + 1) = 200 MHz (3)
*/
/* CLK_DIV_FSYS0 */
clr = MIPIHSI_RATIO(15);
set = MIPIHSI_RATIO(3);
clrsetbits_le32(&clk->div_fsys0, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_fsys0) & DIV_STAT_FSYS0_CHANGING)
continue;
/**
* For MOUTMMC0-3 = 800 MHz (MPLL)
*
* DOUTMMC0 = MOUTMMC0 / (MMC0_RATIO + 1) = 100 MHz (7)
* SCLK_MMC0 = DOUTMMC0 / (MMC0_PRE_RATIO + 1) = 50 MHz (1)
* DOUTMMC1 = MOUTMMC1 / (MMC1_RATIO + 1) = 100 MHz (7)
* SCLK_MMC1 = DOUTMMC1 / (MMC1_PRE_RATIO + 1) = 50 MHz (1)
*/
/* CLK_DIV_FSYS1 */
clr = MMC0_RATIO(15) | MMC0_PRE_RATIO(255) | MMC1_RATIO(15) |
MMC1_PRE_RATIO(255);
set = MMC0_RATIO(7) | MMC0_PRE_RATIO(1) | MMC1_RATIO(7) |
MMC1_PRE_RATIO(1);
clrsetbits_le32(&clk->div_fsys1, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_fsys1) & DIV_STAT_FSYS1_CHANGING)
continue;
/**
* For MOUTmmc0-3 = 800 MHz (MPLL)
*
* DOUTmmc3 = MOUTmmc3 / (MMC2_RATIO + 1) = 100 MHz (7)
* sclk_mmc3 = DOUTmmc3 / (MMC2_PRE_RATIO + 1) = 50 MHz (1)
* DOUTmmc2 = MOUTmmc2 / (MMC3_RATIO + 1) = 100 MHz (7)
* sclk_mmc2 = DOUTmmc2 / (MMC3_PRE_RATIO + 1) = 50 MHz (1)
*/
/* CLK_DIV_FSYS2 */
clr = MMC2_RATIO(15) | MMC2_PRE_RATIO(255) | MMC3_RATIO(15) |
MMC3_PRE_RATIO(255);
set = MMC2_RATIO(7) | MMC2_PRE_RATIO(1) | MMC3_RATIO(7) |
MMC3_PRE_RATIO(1);
clrsetbits_le32(&clk->div_fsys2, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_fsys2) & DIV_STAT_FSYS2_CHANGING)
continue;
/**
* For MOUTmmc4 = 800 MHz (MPLL)
*
* DOUTmmc4 = MOUTmmc4 / (MMC4_RATIO + 1) = 100 MHz (7)
* sclk_mmc4 = DOUTmmc4 / (MMC4_PRE_RATIO + 1) = 50 MHz (1)
*/
/* CLK_DIV_FSYS3 */
clr = MMC4_RATIO(15) | MMC4_PRE_RATIO(255);
set = MMC4_RATIO(7) | MMC4_PRE_RATIO(1);
clrsetbits_le32(&clk->div_fsys3, clr, set);
/* Wait for divider ready status */
while (readl(&clk->div_stat_fsys3) & DIV_STAT_FSYS3_CHANGING)
continue;
/************************************************************
* Step 2:
*
* Set K, AFC, MRR, MFR values if necessary
* (Refer to (A, M, E, V)PLL_CON1 SFRs)
* Turn on a PLL (Refer to (A, M, E, V) PLL_CON0 SFRs)
************************************************************/
/* Set APLL to 1000MHz */
/** APLL_CON1 */
clr = AFC(31) | LOCK_CON_DLY(31) | LOCK_CON_IN(3) |
LOCK_CON_OUT(3) |FEED_EN(1)| AFC_ENB(1) |
DCC_ENB(1) | BYPASS(1) |RESV0(1) | RESV1(1);
set = AFC(0) | LOCK_CON_DLY(8) | LOCK_CON_IN(3) |
LOCK_CON_OUT(0) |FEED_EN(0)| AFC_ENB(0) |
DCC_ENB(1) | BYPASS(0) |RESV0(0) | RESV1(0);
clrsetbits_le32(&clk->apll_con1, clr, set);
/** APLL_CON0 */
clr_pll_con0 = SDIV(7) | PDIV(63) | MDIV(1023) | FSEL(1) | PLL_ENABLE(1);
set = SDIV(0) | PDIV(3) | MDIV<