arm: imx: initial support for colibri imx6

This adds board support for the Toradex module family Colibri iMX6.
The familiy consists of a module with i.MX6 DualLite, i.MX6 Solo, both
with a version for commercial and industrial temperature range.

Signed-off-by: Max Krummenacher <max.krummenacher@toradex.com>
This commit is contained in:
Max Krummenacher
2016-11-30 19:43:09 +01:00
committed by Stefano Babic
parent 592f4aed6d
commit a02d517b01
17 changed files with 2449 additions and 0 deletions
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2013 Boundary Devices
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*/
DATA 4, MX6_MMDC_P0_MDPDC, 0x0002002D
DATA 4, MX6_MMDC_P0_MDCFG0, 0x2C305503
DATA 4, MX6_MMDC_P0_MDCFG1, 0xB66D8D63
DATA 4, MX6_MMDC_P0_MDCFG2, 0x01FF00DB
DATA 4, MX6_MMDC_P0_MDRWD, 0x000026D2
DATA 4, MX6_MMDC_P0_MDOR, 0x00301023
DATA 4, MX6_MMDC_P0_MDOTC, 0x00333030
DATA 4, MX6_MMDC_P0_MDPDC, 0x0002556D
/* CS0 End: 7MSB of ((0x10000000 + 512M) -1) >> 25 */
DATA 4, MX6_MMDC_P0_MDASP, 0x00000017
/* DDR3 DATA BUS SIZE: 64BIT */
/* DATA 4, MX6_MMDC_P0_MDCTL, 0x821A0000 */
/* DDR3 DATA BUS SIZE: 32BIT */
DATA 4, MX6_MMDC_P0_MDCTL, 0x82190000
/* Write commands to DDR */
/* Load Mode Registers */
/* TODO Use Auto Self-Refresh mode (Extended Temperature)*/
/* DATA 4, MX6_MMDC_P0_MDSCR, 0x04408032 */
DATA 4, MX6_MMDC_P0_MDSCR, 0x04008032
DATA 4, MX6_MMDC_P0_MDSCR, 0x00008033
DATA 4, MX6_MMDC_P0_MDSCR, 0x00048031
DATA 4, MX6_MMDC_P0_MDSCR, 0x13208030
/* ZQ calibration */
DATA 4, MX6_MMDC_P0_MDSCR, 0x04008040
DATA 4, MX6_MMDC_P0_MPZQHWCTRL, 0xA1390003
DATA 4, MX6_MMDC_P1_MPZQHWCTRL, 0xA1390003
DATA 4, MX6_MMDC_P0_MDREF, 0x00005800
DATA 4, MX6_MMDC_P0_MPODTCTRL, 0x00000000
DATA 4, MX6_MMDC_P1_MPODTCTRL, 0x00000000
DATA 4, MX6_MMDC_P0_MPDGCTRL0, 0x42360232
DATA 4, MX6_MMDC_P0_MPDGCTRL1, 0x021F022A
DATA 4, MX6_MMDC_P1_MPDGCTRL0, 0x421E0224
DATA 4, MX6_MMDC_P1_MPDGCTRL1, 0x02110218
DATA 4, MX6_MMDC_P0_MPRDDLCTL, 0x41434344
DATA 4, MX6_MMDC_P1_MPRDDLCTL, 0x4345423E
DATA 4, MX6_MMDC_P0_MPWRDLCTL, 0x39383339
DATA 4, MX6_MMDC_P1_MPWRDLCTL, 0x3E363930
DATA 4, MX6_MMDC_P0_MPWLDECTRL0, 0x00340039
DATA 4, MX6_MMDC_P0_MPWLDECTRL1, 0x002C002D
DATA 4, MX6_MMDC_P1_MPWLDECTRL0, 0x00120019
DATA 4, MX6_MMDC_P1_MPWLDECTRL1, 0x0012002D
DATA 4, MX6_MMDC_P0_MPMUR0, 0x00000800
DATA 4, MX6_MMDC_P1_MPMUR0, 0x00000800
DATA 4, MX6_MMDC_P0_MDSCR, 0x00000000
DATA 4, MX6_MMDC_P0_MAPSR, 0x00011006
@@ -0,0 +1,59 @@
/*
* Copyright (C) 2013 Boundary Devices
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*/
DATA 4, MX6_MMDC_P0_MDPDC, 0x0002002D
DATA 4, MX6_MMDC_P0_MDCFG0, 0x2C305503
DATA 4, MX6_MMDC_P0_MDCFG1, 0xB66D8D63
DATA 4, MX6_MMDC_P0_MDCFG2, 0x01FF00DB
DATA 4, MX6_MMDC_P0_MDRWD, 0x000026D2
DATA 4, MX6_MMDC_P0_MDOR, 0x00301023
DATA 4, MX6_MMDC_P0_MDOTC, 0x00333030
DATA 4, MX6_MMDC_P0_MDPDC, 0x0002556D
/* CS0 End: 7MSB of ((0x10000000 + 512M) -1) >> 25 */
DATA 4, MX6_MMDC_P0_MDASP, 0x00000017
/* DDR3 DATA BUS SIZE: 64BIT */
DATA 4, MX6_MMDC_P0_MDCTL, 0x821A0000
/* DDR3 DATA BUS SIZE: 32BIT */
/* DATA 4, MX6_MMDC_P0_MDCTL, 0x82190000 */
/* Write commands to DDR */
/* Load Mode Registers */
/* TODO Use Auto Self-Refresh mode (Extended Temperature)*/
/* DATA 4, MX6_MMDC_P0_MDSCR, 0x04408032 */
DATA 4, MX6_MMDC_P0_MDSCR, 0x04008032
DATA 4, MX6_MMDC_P0_MDSCR, 0x00008033
DATA 4, MX6_MMDC_P0_MDSCR, 0x00048031
DATA 4, MX6_MMDC_P0_MDSCR, 0x13208030
/* ZQ calibration */
DATA 4, MX6_MMDC_P0_MDSCR, 0x04008040
DATA 4, MX6_MMDC_P0_MPZQHWCTRL, 0xA1390003
DATA 4, MX6_MMDC_P1_MPZQHWCTRL, 0xA1390003
DATA 4, MX6_MMDC_P0_MDREF, 0x00005800
DATA 4, MX6_MMDC_P0_MPODTCTRL, 0x00000000
DATA 4, MX6_MMDC_P1_MPODTCTRL, 0x00000000
DATA 4, MX6_MMDC_P0_MPDGCTRL0, 0x42360232
DATA 4, MX6_MMDC_P0_MPDGCTRL1, 0x021F022A
DATA 4, MX6_MMDC_P1_MPDGCTRL0, 0x421E0224
DATA 4, MX6_MMDC_P1_MPDGCTRL1, 0x02110218
DATA 4, MX6_MMDC_P0_MPRDDLCTL, 0x41434344
DATA 4, MX6_MMDC_P1_MPRDDLCTL, 0x4345423E
DATA 4, MX6_MMDC_P0_MPWRDLCTL, 0x39383339
DATA 4, MX6_MMDC_P1_MPWRDLCTL, 0x3E363930
DATA 4, MX6_MMDC_P0_MPWLDECTRL0, 0x00340039
DATA 4, MX6_MMDC_P0_MPWLDECTRL1, 0x002C002D
DATA 4, MX6_MMDC_P1_MPWLDECTRL0, 0x00120019
DATA 4, MX6_MMDC_P1_MPWLDECTRL1, 0x0012002D
DATA 4, MX6_MMDC_P0_MPMUR0, 0x00000800
DATA 4, MX6_MMDC_P1_MPMUR0, 0x00000800
DATA 4, MX6_MMDC_P0_MDSCR, 0x00000000
DATA 4, MX6_MMDC_P0_MAPSR, 0x00011006
+44
View File
@@ -0,0 +1,44 @@
if TARGET_COLIBRI_IMX6
config SYS_BOARD
default "colibri_imx6"
config SYS_CONFIG_NAME
default "colibri_imx6"
config SYS_CPU
default "armv7"
config SYS_SOC
default "mx6"
config SYS_VENDOR
default "toradex"
config TDX_CFG_BLOCK
default y
config TDX_HAVE_MMC
default y
config TDX_CFG_BLOCK_DEV
default "0"
config TDX_CFG_BLOCK_PART
default "1"
# Toradex config block in eMMC, at the end of 1st "boot sector"
config TDX_CFG_BLOCK_OFFSET
default "-512"
config TDX_CMD_IMX_MFGR
bool "Enable factory testing commands for Toradex iMX 6 modules"
help
This adds the commands
pf0100_otp_prog - Program the OTP fuses on the PMIC PF0100
If executed on already fused modules it doesn't change any fuse setting.
default y
source "board/toradex/common/Kconfig"
endif
+8
View File
@@ -0,0 +1,8 @@
Colibri iMX6
M: Max Krummenacher <max.krummenacher@toradex.com>
W: http://developer.toradex.com/software/linux/linux-software
S: Maintained
F: board/toradex/colibri_imx6/
F: include/configs/colibri_imx6.h
F: configs/colibri_imx6_defconfig
F: configs/colibri_imx6_nospl_defconfig
+5
View File
@@ -0,0 +1,5 @@
# Copyright (c) 2012-2014 Toradex, Inc.
# SPDX-License-Identifier: GPL-2.0+
obj-y := colibri_imx6.o do_fuse.o
obj-$(CONFIG_TDX_CMD_IMX_MFGR) += pf0100.o
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (C) 2013 Boundary Devices
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*
* Device Configuration Data (DCD)
*
* Each entry must have the format:
* Addr-type Address Value
*
* where:
* Addr-type register length (1,2 or 4 bytes)
* Address absolute address of the register
* value value to be stored in the register
*/
/* set the default clock gate to save power */
DATA 4, CCM_CCGR0, 0x00C03F3F
DATA 4, CCM_CCGR1, 0x0030FC03
DATA 4, CCM_CCGR2, 0x0FFFC000
DATA 4, CCM_CCGR3, 0x3FF00000
DATA 4, CCM_CCGR4, 0x00FFF300
DATA 4, CCM_CCGR5, 0x0F0000C3
DATA 4, CCM_CCGR6, 0x000003FF
/* enable AXI cache for VDOA/VPU/IPU */
DATA 4, MX6_IOMUXC_GPR4, 0xF00000CF
/* set IPU AXI-id0 Qos=0xf(bypass) AXI-id1 Qos=0x7 */
DATA 4, MX6_IOMUXC_GPR6, 0x007F007F
DATA 4, MX6_IOMUXC_GPR7, 0x007F007F
/*
* Setup CCM_CCOSR register as follows:
*
* cko1_en = 1 --> CKO1 enabled
* cko1_div = 111 --> divide by 8
* cko1_sel = 1011 --> ahb_clk_root
*
* This sets CKO1 at ahb_clk_root/8 = 132/8 = 16.5 MHz
*/
DATA 4, CCM_CCOSR, 0x000000fb
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,38 @@
/*
* Copyright (C) 2013 Boundary Devices
* Copyright (C) 2014 Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*
* Refer doc/README.imximage for more details about how-to configure
* and create imximage boot image
*
* The syntax is taken as close as possible with the kwbimage
*/
/* image version */
IMAGE_VERSION 2
/*
* Boot Device : one of
* spi, sd (the board has no nand neither onenand)
*/
BOOT_FROM sd
#define __ASSEMBLY__
#include <config.h>
#include "asm/arch/mx6-ddr.h"
#include "asm/arch/iomux.h"
#include "asm/arch/crm_regs.h"
#include "ddr-setup.cfg"
#if CONFIG_DDR_MB == 256
#include "800mhz_2x64mx16.cfg"
#elif CONFIG_DDR_MB == 512
#include "800mhz_4x64mx16.cfg"
#else
#error "unknown DDR size"
#endif
#include "clocks.cfg"
+98
View File
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2013 Boundary Devices
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*
* Device Configuration Data (DCD)
*
* Each entry must have the format:
* Addr-type Address Value
*
* where:
* Addr-type register length (1,2 or 4 bytes)
* Address absolute address of the register
* value value to be stored in the register
*/
/*
* DDR3 settings
* MX6Q ddr is limited to 1066 Mhz currently 1056 MHz(528 MHz clock),
* memory bus width: 64 bits x16/x32/x64
* MX6DL ddr is limited to 800 MHz(400 MHz clock)
* memory bus width: 64 bits x16/x32/x64
* MX6SOLO ddr is limited to 800 MHz(400 MHz clock)
* memory bus width: 32 bits x16/x32
*/
DATA 4, MX6_IOM_DRAM_SDQS0, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS1, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS2, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS3, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS4, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS5, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS6, 0x00000030
DATA 4, MX6_IOM_DRAM_SDQS7, 0x00000030
DATA 4, MX6_IOM_GRP_B0DS, 0x00000030
DATA 4, MX6_IOM_GRP_B1DS, 0x00000030
DATA 4, MX6_IOM_GRP_B2DS, 0x00000030
DATA 4, MX6_IOM_GRP_B3DS, 0x00000030
DATA 4, MX6_IOM_GRP_B4DS, 0x00000030
DATA 4, MX6_IOM_GRP_B5DS, 0x00000030
DATA 4, MX6_IOM_GRP_B6DS, 0x00000030
DATA 4, MX6_IOM_GRP_B7DS, 0x00000030
DATA 4, MX6_IOM_GRP_ADDDS, 0x00000030
/* 40 Ohm drive strength for cs0/1,sdba2,cke0/1,sdwe */
DATA 4, MX6_IOM_GRP_CTLDS, 0x00000030
DATA 4, MX6_IOM_DRAM_DQM0, 0x00020030
DATA 4, MX6_IOM_DRAM_DQM1, 0x00020030
DATA 4, MX6_IOM_DRAM_DQM2, 0x00020030
DATA 4, MX6_IOM_DRAM_DQM3, 0x00020030
DATA 4, MX6_IOM_DRAM_DQM4, 0x00020030
DATA 4, MX6_IOM_DRAM_DQM5, 0x00020030
DATA 4, MX6_IOM_DRAM_DQM6, 0x00020030
DATA 4, MX6_IOM_DRAM_DQM7, 0x00020030
DATA 4, MX6_IOM_DRAM_CAS, 0x00020030
DATA 4, MX6_IOM_DRAM_RAS, 0x00020030
DATA 4, MX6_IOM_DRAM_SDCLK_0, 0x00020030
DATA 4, MX6_IOM_DRAM_SDCLK_1, 0x00020030
DATA 4, MX6_IOM_DRAM_RESET, 0x00020030
DATA 4, MX6_IOM_DRAM_SDCKE0, 0x00003000
DATA 4, MX6_IOM_DRAM_SDCKE1, 0x00003000
DATA 4, MX6_IOM_DRAM_SDODT0, 0x00003030
DATA 4, MX6_IOM_DRAM_SDODT1, 0x00003030
/* (differential input) */
DATA 4, MX6_IOM_DDRMODE_CTL, 0x00020000
/* (differential input) */
DATA 4, MX6_IOM_GRP_DDRMODE, 0x00020000
/* disable ddr pullups */
DATA 4, MX6_IOM_GRP_DDRPKE, 0x00000000
DATA 4, MX6_IOM_DRAM_SDBA2, 0x00000000
/* 40 Ohm drive strength for cs0/1,sdba2,cke0/1,sdwe */
DATA 4, MX6_IOM_GRP_DDR_TYPE, 0x000C0000
/* Read data DQ Byte0-3 delay */
DATA 4, MX6_MMDC_P0_MPRDDQBY0DL, 0x33333333
DATA 4, MX6_MMDC_P0_MPRDDQBY1DL, 0x33333333
DATA 4, MX6_MMDC_P0_MPRDDQBY2DL, 0x33333333
DATA 4, MX6_MMDC_P0_MPRDDQBY3DL, 0x33333333
DATA 4, MX6_MMDC_P1_MPRDDQBY0DL, 0x33333333
DATA 4, MX6_MMDC_P1_MPRDDQBY1DL, 0x33333333
DATA 4, MX6_MMDC_P1_MPRDDQBY2DL, 0x33333333
DATA 4, MX6_MMDC_P1_MPRDDQBY3DL, 0x33333333
/*
* MDMISC mirroring interleaved (row/bank/col)
*/
/* TODO: check what the RALAT field does */
DATA 4, MX6_MMDC_P0_MDMISC, 0x00081740
/*
* MDSCR con_req
*/
DATA 4, MX6_MMDC_P0_MDSCR, 0x00008000
+98
View File
@@ -0,0 +1,98 @@
/*
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* Helpers for i.MX OTP fusing during module production
*/
#include <common.h>
#ifndef CONFIG_SPL_BUILD
#include <console.h>
#include <fuse.h>
static int mfgr_fuse(void)
{
unsigned val, val6;
fuse_sense(0, 5, &val);
printf("Fuse 0, 5: %8x\n", val);
fuse_sense(0, 6, &val6);
printf("Fuse 0, 6: %8x\n", val6);
fuse_sense(4, 3, &val);
printf("Fuse 4, 3: %8x\n", val);
fuse_sense(4, 2, &val);
printf("Fuse 4, 2: %8x\n", val);
if (val6 & 0x10) {
puts("BT_FUSE_SEL already fused, will do nothing\n");
return CMD_RET_FAILURE;
}
/* boot cfg */
fuse_prog(0, 5, 0x00005072);
/* BT_FUSE_SEL */
fuse_prog(0, 6, 0x00000010);
return CMD_RET_SUCCESS;
}
int do_mfgr_fuse(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
int ret;
puts("Fusing...\n");
ret = mfgr_fuse();
if (ret == CMD_RET_SUCCESS)
puts("done.\n");
else
puts("failed.\n");
return ret;
}
int do_updt_fuse(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
unsigned val;
int ret;
int confirmed = argc >= 1 && !strcmp(argv[1], "-y");
/* can be used in scripts for command availability check */
if (argc >= 1 && !strcmp(argv[1], "-n"))
return CMD_RET_SUCCESS;
/* boot cfg */
fuse_sense(0, 5, &val);
printf("Fuse 0, 5: %8x\n", val);
if (val & 0x10) {
puts("Fast boot mode already fused, no need to fuse\n");
return CMD_RET_SUCCESS;
}
if (!confirmed) {
puts("Warning: Programming fuses is an irreversible operation!\n"
" Updating to fast boot mode prevents easy\n"
" downgrading to previous BSP versions.\n"
"\nReally perform this fuse programming? <y/N>\n");
if (!confirm_yesno())
return CMD_RET_FAILURE;
}
puts("Fusing fast boot mode...\n");
ret = fuse_prog(0, 5, 0x00005072);
if (ret == CMD_RET_SUCCESS)
puts("done.\n");
else
puts("failed.\n");
return ret;
}
U_BOOT_CMD(
mfgr_fuse, 1, 0, do_mfgr_fuse,
"OTP fusing during module production",
""
);
U_BOOT_CMD(
updt_fuse, 2, 0, do_updt_fuse,
"OTP fusing during module update",
"updt_fuse [-n] [-y] - boot cfg fast boot mode fusing"
);
#endif /* CONFIG_SPL_BUILD */
+211
View File
@@ -0,0 +1,211 @@
/*
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* Helpers for Freescale PMIC PF0100
*/
#include <common.h>
#include <i2c.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/iomux.h>
#include <asm/arch/mx6-pins.h>
#include <asm/gpio.h>
#include <asm/imx-common/iomux-v3.h>
#include "pf0100_otp.inc"
#include "pf0100.h"
/* define for PMIC register dump */
/*#define DEBUG */
/* use GPIO: EXT_IO1 to switch on VPGM, ON: 1 */
static iomux_v3_cfg_t const pmic_prog_pads[] = {
MX6_PAD_NANDF_D3__GPIO2_IO03 | MUX_PAD_CTRL(NO_PAD_CTRL),
# define PMIC_PROG_VOLTAGE IMX_GPIO_NR(2, 3)
};
unsigned pmic_init(void)
{
unsigned programmed = 0;
uchar bus = 1;
uchar devid, revid, val;
puts("PMIC: ");
if (!((0 == i2c_set_bus_num(bus)) &&
(0 == i2c_probe(PFUZE100_I2C_ADDR)))) {
puts("i2c bus failed\n");
return 0;
}
/* get device ident */
if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_DEVICEID, 1, &devid, 1) < 0) {
puts("i2c pmic devid read failed\n");
return 0;
}
if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_REVID, 1, &revid, 1) < 0) {
puts("i2c pmic revid read failed\n");
return 0;
}
printf("device id: 0x%.2x, revision id: 0x%.2x\n", devid, revid);
#ifdef DEBUG
{
unsigned i, j;
for (i = 0; i < 16; i++)
printf("\t%x", i);
for (j = 0; j < 0x80; ) {
printf("\n%2x", j);
for (i = 0; i < 16; i++) {
i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1);
printf("\t%2x", val);
}
j += 0x10;
}
printf("\nEXT Page 1");
val = PFUZE100_PAGE_REGISTER_PAGE1;
if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1,
&val, 1)) {
puts("i2c write failed\n");
return 0;
}
for (j = 0x80; j < 0x100; ) {
printf("\n%2x", j);
for (i = 0; i < 16; i++) {
i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1);
printf("\t%2x", val);
}
j += 0x10;
}
printf("\nEXT Page 2");
val = PFUZE100_PAGE_REGISTER_PAGE2;
if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1,
&val, 1)) {
puts("i2c write failed\n");
return 0;
}
for (j = 0x80; j < 0x100; ) {
printf("\n%2x", j);
for (i = 0; i < 16; i++) {
i2c_read(PFUZE100_I2C_ADDR, j+i, 1, &val, 1);
printf("\t%2x", val);
}
j += 0x10;
}
printf("\n");
}
#endif
/* get device programmed state */
val = PFUZE100_PAGE_REGISTER_PAGE1;
if (i2c_write(PFUZE100_I2C_ADDR, PFUZE100_PAGE_REGISTER, 1, &val, 1)) {
puts("i2c write failed\n");
return 0;
}
if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR1, 1, &val, 1) < 0) {
puts("i2c fuse_por read failed\n");
return 0;
}
if (val & PFUZE100_FUSE_POR_M)
programmed++;
if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR2, 1, &val, 1) < 0) {
puts("i2c fuse_por read failed\n");
return programmed;
}
if (val & PFUZE100_FUSE_POR_M)
programmed++;
if (i2c_read(PFUZE100_I2C_ADDR, PFUZE100_FUSE_POR3, 1, &val, 1) < 0) {
puts("i2c fuse_por read failed\n");
return programmed;
}
if (val & PFUZE100_FUSE_POR_M)
programmed++;
switch (programmed) {
case 0:
printf("PMIC: not programmed\n");
break;
case 3:
printf("PMIC: programmed\n");
break;
default:
printf("PMIC: undefined programming state\n");
break;
}
return programmed;
}
int pf0100_prog(void)
{
unsigned char bus = 1;
unsigned char val;
unsigned int i;
if (pmic_init() == 3) {
puts("PMIC already programmed, exiting\n");
return CMD_RET_FAILURE;
}
/* set up gpio to manipulate vprog, initially off */
imx_iomux_v3_setup_multiple_pads(pmic_prog_pads,
ARRAY_SIZE(pmic_prog_pads));
gpio_direction_output(PMIC_PROG_VOLTAGE, 0);
if (!((0 == i2c_set_bus_num(bus)) &&
(0 == i2c_probe(PFUZE100_I2C_ADDR)))) {
puts("i2c bus failed\n");
return CMD_RET_FAILURE;
}
for (i = 0; i < ARRAY_SIZE(pmic_otp_prog); i++) {
switch (pmic_otp_prog[i].cmd) {
case pmic_i2c:
val = (unsigned char) (pmic_otp_prog[i].value & 0xff);
if (i2c_write(PFUZE100_I2C_ADDR, pmic_otp_prog[i].reg,
1, &val, 1)) {
printf("i2c write failed, reg 0x%2x, value 0x%2x\n",
pmic_otp_prog[i].reg, val);
return CMD_RET_FAILURE;
}
break;
case pmic_delay:
udelay(pmic_otp_prog[i].value * 1000);
break;
case pmic_vpgm:
gpio_direction_output(PMIC_PROG_VOLTAGE,
pmic_otp_prog[i].value);
break;
case pmic_pwr:
/* TODO */
break;
}
}
return CMD_RET_SUCCESS;
}
int do_pf0100_prog(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
int ret;
puts("Programming PMIC OTP...");
ret = pf0100_prog();
if (ret == CMD_RET_SUCCESS)
puts("done.\n");
else
puts("failed.\n");
return ret;
}
U_BOOT_CMD(
pf0100_otp_prog, 1, 0, do_pf0100_prog,
"Program the OTP fuses on the PMIC PF0100",
""
);
+56
View File
@@ -0,0 +1,56 @@
/*
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*/
/*
* Helpers for Freescale PMIC PF0100
*/
#ifndef PF0100_H_
#define PF0100_H_
/* 7-bit I2C bus slave address */
#define PFUZE100_I2C_ADDR (0x08)
/* Register Addresses */
#define PFUZE100_DEVICEID (0x0)
#define PFUZE100_REVID (0x3)
#define PFUZE100_SW1AMODE (0x23)
#define PFUZE100_SW1ACON 36
#define PFUZE100_SW1ACON_SPEED_VAL (0x1<<6) /*default */
#define PFUZE100_SW1ACON_SPEED_M (0x3<<6)
#define PFUZE100_SW1CCON 49
#define PFUZE100_SW1CCON_SPEED_VAL (0x1<<6) /*default */
#define PFUZE100_SW1CCON_SPEED_M (0x3<<6)
#define PFUZE100_SW1AVOL 32
#define PFUZE100_SW1AVOL_VSEL_M (0x3f<<0)
#define PFUZE100_SW1CVOL 46
#define PFUZE100_SW1CVOL_VSEL_M (0x3f<<0)
#define PFUZE100_VGEN1CTL (0x6c)
#define PFUZE100_VGEN1_VAL (0x30 + 0x08) /* Always ON, 1.2V */
#define PFUZE100_SWBSTCTL (0x66)
/* Always ON, Auto Switching Mode, 5.0V */
#define PFUZE100_SWBST_VAL (0x40 + 0x08 + 0x00)
/* chooses the extended page (registers 0x80..0xff) */
#define PFUZE100_PAGE_REGISTER 0x7f
#define PFUZE100_PAGE_REGISTER_PAGE_M (0x1f << 0)
#define PFUZE100_PAGE_REGISTER_PAGE1 (0x01 & PFUZE100_PAGE_REGISTER_PAGE_M)
#define PFUZE100_PAGE_REGISTER_PAGE2 (0x02 & PFUZE100_PAGE_REGISTER_PAGE_M)
/* extended page 1 */
#define PFUZE100_FUSE_POR1 0xe4
#define PFUZE100_FUSE_POR2 0xe5
#define PFUZE100_FUSE_POR3 0xe6
#define PFUZE100_FUSE_POR_M (0x1 << 1)
/* output some informational messages, return the number FUSE_POR=1 */
/* i.e. 0: unprogrammed, 3: programmed, other: undefined prog. state */
unsigned pmic_init(void);
/* programmes OTP fuses to values required on a Toradex Apalis iMX6 */
int pf0100_prog(void);
#endif /* PF0100_H_ */
+189
View File
@@ -0,0 +1,189 @@
/*
* Copyright (C) 2014-2016, Toradex AG
*
* SPDX-License-Identifier: GPL-2.0+
*/
// Register Output for PF0100 programmer
// Customer: Toradex AG
// Program: Colibri iMX6
// Sample marking:
// Date: 24.07.2015
// Time: 10:52:58
// Generated from Spreadsheet Revision: P1.8
/* sed commands to get from programmer script to struct */
/* sed -e 's/^WRITE_I2C:\(..\):\(..\)/\{pmic_i2c, 0x\1, 0x\2\},/g' -e 's/^DELAY:\([0-9]*\)/\{pmic_delay, 0, \1\},/g' pf0100_otp_Colibri_iMX6.txt > pf0100_otp.inc
sed -i -e 's/^VPGM:ON/\{pmic_vpgm, 0, 1},/g' -e 's/^VPGM:OFF/\{pmic_vpgm, 0, 0},/g' pf0100_otp.inc
sed -i -e 's/^PWRON: HIGH/\{pmic_pwr, 0, 1},/g' -e 's/^PWRON:LOW/\{pmic_pwr, 0, 0},/g' pf0100_otp.inc */
enum { pmic_i2c, pmic_delay, pmic_vpgm, pmic_pwr };
struct pmic_otp_prog_t{
unsigned char cmd;
unsigned char reg;
unsigned short value;
};
struct pmic_otp_prog_t pmic_otp_prog[] = {
{pmic_i2c, 0x7F, 0x01}, // Access FSL EXT Page 1
{pmic_i2c, 0xA0, 0x2B}, // Auto gen from Row94
{pmic_i2c, 0xA1, 0x01}, // Auto gen from Row95
{pmic_i2c, 0xA2, 0x05}, // Auto gen from Row96
{pmic_i2c, 0xA8, 0x2B}, // Auto gen from Row102
{pmic_i2c, 0xA9, 0x02}, // Auto gen from Row103
{pmic_i2c, 0xAA, 0x01}, // Auto gen from Row104
{pmic_i2c, 0xAC, 0x18}, // Auto gen from Row106
{pmic_i2c, 0xAE, 0x01}, // Auto gen from Row108
{pmic_i2c, 0xB0, 0x2C}, // Auto gen from Row110
{pmic_i2c, 0xB1, 0x04}, // Auto gen from Row111
{pmic_i2c, 0xB2, 0x01}, // Auto gen from Row112
{pmic_i2c, 0xB4, 0x2C}, // Auto gen from Row114
{pmic_i2c, 0xB5, 0x04}, // Auto gen from Row115
{pmic_i2c, 0xB6, 0x01}, // Auto gen from Row116
{pmic_i2c, 0xB8, 0x18}, // Auto gen from Row118
{pmic_i2c, 0xBA, 0x01}, // Auto gen from Row120
{pmic_i2c, 0xBD, 0x0E}, // Auto gen from Row123
{pmic_i2c, 0xC0, 0x06}, // Auto gen from Row126
{pmic_i2c, 0xC4, 0x04}, // Auto gen from Row130
{pmic_i2c, 0xC8, 0x0E}, // Auto gen from Row134
{pmic_i2c, 0xCC, 0x0E}, // Auto gen from Row138
{pmic_i2c, 0xCD, 0x05}, // Auto gen from Row139
{pmic_i2c, 0xD0, 0x0C}, // Auto gen from Row142
{pmic_i2c, 0xD5, 0x07}, // Auto gen from Row147
{pmic_i2c, 0xD8, 0x07}, // Auto gen from Row150
{pmic_i2c, 0xD9, 0x06}, // Auto gen from Row151
{pmic_i2c, 0xDC, 0x0A}, // Auto gen from Row154
{pmic_i2c, 0xDD, 0x03}, // Auto gen from Row155
{pmic_i2c, 0xE0, 0x05}, // Auto gen from Row158
#if 0 /* TBB mode */
{pmic_i2c, 0xE4, 0x80}, // TBB_POR = 1
{pmic_delay, 0, 10},
#else
// Write OTP
{pmic_i2c, 0xE4, 0x02}, // FUSE POR1=1
{pmic_i2c, 0xE5, 0x02}, // FUSE POR2=1
{pmic_i2c, 0xE6, 0x02}, // FUSE POR3=1
{pmic_i2c, 0xF0, 0x1F}, // Enable ECC for fuse banks 1 to 5 by writing to OTP EN ECC0 register
{pmic_i2c, 0xF1, 0x1F}, // Enable ECC for fuse banks 6 to 10 by writing to OTP EN ECC1 register
{pmic_i2c, 0x7F, 0x02}, // Access PF0100 EXT Page2
{pmic_i2c, 0xD0, 0x1F}, // Set Auto ECC for fuse banks 1 to 5 by writing to OTP AUTO ECC0 register
{pmic_i2c, 0xD1, 0x1F}, // Set Auto ECC for fuse banks 6 to 10 by writing to OTP AUTO ECC1 register
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF1, 0x00}, // Reset Bank 1 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF2, 0x00}, // Reset Bank 2 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF3, 0x00}, // Reset Bank 3 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF4, 0x00}, // Reset Bank 4 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF5, 0x00}, // Reset Bank 5 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF6, 0x00}, // Reset Bank 6 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF7, 0x00}, // Reset Bank 7 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF8, 0x00}, // Reset Bank 8 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF9, 0x00}, // Reset Bank 9 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xFA, 0x00}, // Reset Bank 10 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
{pmic_vpgm, 0, 1}, // Turn ON 8V SWBST
//VPGM:DOWN:n
//VPGM:UP:n
{pmic_delay, 0, 500}, // Adds 500msec delay to allow VPGM time to ramp up
//-----------------------------------------------------------------------------------
// PF0100 OTP MANUAL-PROGRAMMING (BANK 1 thru 10)
//-----------------------------------------------------------------------------------
// BANK 1
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF1, 0x00}, // Reset Bank 1 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF1, 0x03}, // Set Bank 1 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF1, 0x0B}, // Set Bank 1 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF1, 0x03}, // Reset Bank 1 ANTIFUSE_EN
{pmic_i2c, 0xF1, 0x00}, // Reset Bank 1 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 2
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF2, 0x00}, // Reset Bank 2 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF2, 0x03}, // Set Bank 2 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF2, 0x0B}, // Set Bank 2 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF2, 0x03}, // Reset Bank 2 ANTIFUSE_EN
{pmic_i2c, 0xF2, 0x00}, // Reset Bank 2 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 3
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF3, 0x00}, // Reset Bank 3 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF3, 0x03}, // Set Bank 3 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF3, 0x0B}, // Set Bank 3 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF3, 0x03}, // Reset Bank 3 ANTIFUSE_EN
{pmic_i2c, 0xF3, 0x00}, // Reset Bank 3 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 4
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF4, 0x00}, // Reset Bank 4 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF4, 0x03}, // Set Bank 4 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF4, 0x0B}, // Set Bank 4 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF4, 0x03}, // Reset Bank 4 ANTIFUSE_EN
{pmic_i2c, 0xF4, 0x00}, // Reset Bank 4 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 5
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF5, 0x00}, // Reset Bank 5 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF5, 0x03}, // Set Bank 5 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF5, 0x0B}, // Set Bank 5 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF5, 0x03}, // Reset Bank 5 ANTIFUSE_EN
{pmic_i2c, 0xF5, 0x00}, // Reset Bank 5 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 6
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF6, 0x00}, // Reset Bank 6 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF6, 0x03}, // Set Bank 6 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF6, 0x0B}, // Set Bank 6 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF6, 0x03}, // Reset Bank 6 ANTIFUSE_EN
{pmic_i2c, 0xF6, 0x00}, // Reset Bank 6 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 7
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF7, 0x00}, // Reset Bank 7 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF7, 0x03}, // Set Bank 7 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF7, 0x0B}, // Set Bank 7 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF7, 0x03}, // Reset Bank 7 ANTIFUSE_EN
{pmic_i2c, 0xF7, 0x00}, // Reset Bank 7 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 8
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF8, 0x00}, // Reset Bank 8 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF8, 0x03}, // Set Bank 8 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF8, 0x0B}, // Set Bank 8 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF8, 0x03}, // Reset Bank 8 ANTIFUSE_EN
{pmic_i2c, 0xF8, 0x00}, // Reset Bank 8 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 9
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xF9, 0x00}, // Reset Bank 9 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF9, 0x03}, // Set Bank 9 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xF9, 0x0B}, // Set Bank 9 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xF9, 0x03}, // Reset Bank 9 ANTIFUSE_EN
{pmic_i2c, 0xF9, 0x00}, // Reset Bank 9 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
// BANK 10
//-----------------------------------------------------------------------------------
{pmic_i2c, 0xFA, 0x00}, // Reset Bank 10 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xFA, 0x03}, // Set Bank 10 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
{pmic_i2c, 0xFA, 0x0B}, // Set Bank 10 ANTIFUSE_EN
{pmic_delay, 0, 10}, // Allow time for bank programming to complete
{pmic_i2c, 0xFA, 0x03}, // Reset Bank 10 ANTIFUSE_EN
{pmic_i2c, 0xFA, 0x00}, // Reset Bank 10 ANTIFUSE_RW and ANTIFUSE_BYPASS bits
//-----------------------------------------------------------------------------------
{pmic_vpgm, 0, 0}, // Turn off 8V SWBST
{pmic_delay, 0, 500}, // Adds delay to allow VPGM to bleed off
{pmic_i2c, 0xD0, 0x00}, // Clear
{pmic_i2c, 0xD1, 0x00}, // Clear
{pmic_pwr, 0, 0}, // PWRON LOW to reload new OTP data
{pmic_delay, 0, 500},
{pmic_pwr, 0, 1},
#endif
};