arm: imx: Add somdevices board files based on freescale/mx6ullevk board files and...
authorJosep Orga <jorga@somdevices.com>
Sat, 25 Apr 2020 07:43:31 +0000 (09:43 +0200)
committerJosep Orga <jorga@somdevices.com>
Sat, 25 Apr 2020 07:43:31 +0000 (09:43 +0200)
Signed-off-by: Josep Orga <jorga@somdevices.com>
69 files changed:
board/somdevices/common/Kconfig [new file with mode: 0644]
board/somdevices/common/Makefile [new file with mode: 0644]
board/somdevices/common/arm_sleep.c [new file with mode: 0644]
board/somdevices/common/cadmus.c [new file with mode: 0644]
board/somdevices/common/cadmus.h [new file with mode: 0644]
board/somdevices/common/cds_pci_ft.c [new file with mode: 0644]
board/somdevices/common/cds_via.c [new file with mode: 0644]
board/somdevices/common/cmd_esbc_validate.c [new file with mode: 0644]
board/somdevices/common/dcu_sii9022a.c [new file with mode: 0644]
board/somdevices/common/dcu_sii9022a.h [new file with mode: 0644]
board/somdevices/common/diu_ch7301.c [new file with mode: 0644]
board/somdevices/common/diu_ch7301.h [new file with mode: 0644]
board/somdevices/common/eeprom.h [new file with mode: 0644]
board/somdevices/common/emc2305.c [new file with mode: 0644]
board/somdevices/common/emc2305.h [new file with mode: 0644]
board/somdevices/common/epdc_setup.c [new file with mode: 0644]
board/somdevices/common/fman.c [new file with mode: 0644]
board/somdevices/common/fman.h [new file with mode: 0644]
board/somdevices/common/fsl_chain_of_trust.c [new file with mode: 0644]
board/somdevices/common/fsl_validate.c [new file with mode: 0644]
board/somdevices/common/ics307_clk.c [new file with mode: 0644]
board/somdevices/common/ics307_clk.h [new file with mode: 0644]
board/somdevices/common/idt8t49n222a_serdes_clk.c [new file with mode: 0644]
board/somdevices/common/idt8t49n222a_serdes_clk.h [new file with mode: 0644]
board/somdevices/common/ls102xa_stream_id.c [new file with mode: 0644]
board/somdevices/common/mc34vr500.c [new file with mode: 0644]
board/somdevices/common/mmc.c [new file with mode: 0644]
board/somdevices/common/mpc85xx_sleep.c [new file with mode: 0644]
board/somdevices/common/ngpixis.c [new file with mode: 0644]
board/somdevices/common/ngpixis.h [new file with mode: 0644]
board/somdevices/common/ns_access.c [new file with mode: 0644]
board/somdevices/common/p_corenet/Makefile [new file with mode: 0644]
board/somdevices/common/p_corenet/law.c [new file with mode: 0644]
board/somdevices/common/p_corenet/pci.c [new file with mode: 0644]
board/somdevices/common/p_corenet/tlb.c [new file with mode: 0644]
board/somdevices/common/pfuze.c [new file with mode: 0644]
board/somdevices/common/pfuze.h [new file with mode: 0644]
board/somdevices/common/pixis.c [new file with mode: 0644]
board/somdevices/common/pixis.h [new file with mode: 0644]
board/somdevices/common/pq-mds-pib.c [new file with mode: 0644]
board/somdevices/common/pq-mds-pib.h [new file with mode: 0644]
board/somdevices/common/qixis.c [new file with mode: 0644]
board/somdevices/common/qixis.h [new file with mode: 0644]
board/somdevices/common/qspi_header [new file with mode: 0644]
board/somdevices/common/recovery_keypad.c [new file with mode: 0644]
board/somdevices/common/recovery_keypad.h [new file with mode: 0644]
board/somdevices/common/sdhc_boot.c [new file with mode: 0644]
board/somdevices/common/sgmii_riser.c [new file with mode: 0644]
board/somdevices/common/sgmii_riser.h [new file with mode: 0644]
board/somdevices/common/sleep.h [new file with mode: 0644]
board/somdevices/common/spl.h [new file with mode: 0644]
board/somdevices/common/sys_eeprom.c [new file with mode: 0644]
board/somdevices/common/tcpc.c [new file with mode: 0644]
board/somdevices/common/tcpc.h [new file with mode: 0644]
board/somdevices/common/via.h [new file with mode: 0644]
board/somdevices/common/vid.c [new file with mode: 0644]
board/somdevices/common/vid.h [new file with mode: 0644]
board/somdevices/common/vsc3316_3308.c [new file with mode: 0644]
board/somdevices/common/vsc3316_3308.h [new file with mode: 0644]
board/somdevices/common/zm7300.c [new file with mode: 0644]
board/somdevices/common/zm7300.h [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/Kconfig [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/MAINTAINERS [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/Makefile [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/README [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/imximage.cfg [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/imximage_lpddr2.cfg [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/mx6ullevk.c [new file with mode: 0644]
board/somdevices/imx6ull_somdevices/plugin.S [new file with mode: 0644]

diff --git a/board/somdevices/common/Kconfig b/board/somdevices/common/Kconfig
new file mode 100644 (file)
index 0000000..5c205bd
--- /dev/null
@@ -0,0 +1,48 @@
+if !ARCH_IMX8M && !ARCH_IMX8
+
+config CHAIN_OF_TRUST
+       depends on !FIT_SIGNATURE && SECURE_BOOT
+       imply CMD_BLOB
+       imply CMD_HASH if ARM
+       select FSL_CAAM
+       select SPL_BOARD_INIT if (ARM && SPL)
+       select SHA_HW_ACCEL
+       select SHA_PROG_HW_ACCEL
+       select ENV_IS_NOWHERE
+       select CMD_EXT4 if ARM
+       select CMD_EXT4_WRITE if ARM
+       bool
+       default y
+
+config CMD_ESBC_VALIDATE
+       bool "Enable the 'esbc_validate' and 'esbc_halt' commands"
+       default y if CHAIN_OF_TRUST
+       help
+         This option enables two commands used for secure booting:
+
+           esbc_validate - validate signature using RSA verification
+           esbc_halt - put the core in spin loop (Secure Boot Only)
+
+endif
+
+config VOL_MONITOR_LTC3882_READ
+       depends on VID
+       bool "Enable the LTC3882 voltage monitor read"
+       default n
+       help
+        This option enables LTC3882 voltage monitor read
+        functionality. It is used by common VID driver.
+
+config VOL_MONITOR_LTC3882_SET
+       depends on VID
+       bool "Enable the LTC3882 voltage monitor set"
+       default n
+       help
+        This option enables LTC3882 voltage monitor set
+        functionality. It is used by common VID driver.
+
+config USB_TCPC
+       bool "USB Typec port controller simple driver"
+       default n
+       help
+         Enable USB type-c port controller (TCPC) driver
diff --git a/board/somdevices/common/Makefile b/board/somdevices/common/Makefile
new file mode 100644 (file)
index 0000000..05c0e7a
--- /dev/null
@@ -0,0 +1,92 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+MINIMAL=
+
+ifdef CONFIG_SPL_BUILD
+ifdef CONFIG_SPL_INIT_MINIMAL
+MINIMAL=y
+endif
+endif
+
+ifdef MINIMAL
+# necessary to create built-in.o
+obj- := __dummy__.o
+else
+obj-$(CONFIG_FSL_CADMUS)       += cadmus.o
+obj-$(CONFIG_FSL_VIA)          += cds_via.o
+obj-$(CONFIG_FMAN_ENET)        += fman.o
+obj-$(CONFIG_FSL_PIXIS)        += pixis.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_FSL_NGPIXIS)      += ngpixis.o
+endif
+obj-$(CONFIG_VID)              += vid.o
+obj-$(CONFIG_FSL_QIXIS)        += qixis.o
+obj-$(CONFIG_PQ_MDS_PIB)       += pq-mds-pib.o
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_ID_EEPROM)        += sys_eeprom.o
+endif
+obj-$(CONFIG_FSL_SGMII_RISER)  += sgmii_riser.o
+ifndef CONFIG_RAMBOOT_PBL
+obj-$(CONFIG_FSL_FIXED_MMC_LOCATION)   += sdhc_boot.o
+endif
+
+obj-$(CONFIG_FSL_DIU_CH7301)   += diu_ch7301.o
+
+ifdef CONFIG_ARM
+obj-$(CONFIG_DEEP_SLEEP)               += arm_sleep.o
+else
+obj-$(CONFIG_DEEP_SLEEP)               += mpc85xx_sleep.o
+endif
+
+obj-$(CONFIG_FSL_DCU_SII9022A)    += dcu_sii9022a.o
+
+obj-$(CONFIG_TARGET_MPC8541CDS)        += cds_pci_ft.o
+obj-$(CONFIG_TARGET_MPC8548CDS)        += cds_pci_ft.o
+obj-$(CONFIG_TARGET_MPC8555CDS)        += cds_pci_ft.o
+
+obj-$(CONFIG_TARGET_MPC8536DS) += ics307_clk.o
+obj-$(CONFIG_TARGET_MPC8572DS) += ics307_clk.o
+obj-$(CONFIG_TARGET_P1022DS)           += ics307_clk.o
+obj-$(CONFIG_P2020DS)          += ics307_clk.o
+obj-$(CONFIG_TARGET_P3041DS)           += ics307_clk.o
+obj-$(CONFIG_TARGET_P4080DS)           += ics307_clk.o
+obj-$(CONFIG_TARGET_P5020DS)           += ics307_clk.o
+obj-$(CONFIG_TARGET_P5040DS)           += ics307_clk.o
+obj-$(CONFIG_VSC_CROSSBAR)    += vsc3316_3308.o
+obj-$(CONFIG_IDT8T49N222A)     += idt8t49n222a_serdes_clk.o
+obj-$(CONFIG_ZM7300)           += zm7300.o
+obj-$(CONFIG_POWER_PFUZE100)   += pfuze.o
+obj-$(CONFIG_$(SPL_)DM_PMIC_PFUZE100)  += pfuze.o
+obj-$(CONFIG_POWER_MC34VR500)  += mc34vr500.o
+obj-$(CONFIG_MXC_EPDC)         += epdc_setup.o
+obj-y                          += mmc.o
+ifdef CONFIG_FSL_FASTBOOT
+obj-${CONFIG_ANDROID_RECOVERY} += recovery_keypad.o
+endif
+
+obj-$(CONFIG_LS102XA_STREAM_ID)        += ls102xa_stream_id.o
+
+obj-$(CONFIG_EMC2305)              += emc2305.o
+
+# deal with common files for P-series corenet based devices
+obj-$(CONFIG_TARGET_P2041RDB)  += p_corenet/
+obj-$(CONFIG_TARGET_P3041DS)   += p_corenet/
+obj-$(CONFIG_TARGET_P4080DS)   += p_corenet/
+obj-$(CONFIG_TARGET_P5020DS)   += p_corenet/
+obj-$(CONFIG_TARGET_P5040DS)   += p_corenet/
+
+obj-$(CONFIG_LAYERSCAPE_NS_ACCESS)     += ns_access.o
+
+ifdef CONFIG_SECURE_BOOT
+obj-$(CONFIG_CMD_ESBC_VALIDATE) += fsl_validate.o cmd_esbc_validate.o
+endif
+obj-$(CONFIG_CHAIN_OF_TRUST) += fsl_chain_of_trust.o
+
+ifndef CONFIG_SPL_BUILD
+obj-$(CONFIG_USB_TCPC) += tcpc.o
+endif
+
+endif
diff --git a/board/somdevices/common/arm_sleep.c b/board/somdevices/common/arm_sleep.c
new file mode 100644 (file)
index 0000000..d18b4fc
--- /dev/null
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#ifndef CONFIG_ARMV7_NONSEC
+#error " Deep sleep needs non-secure mode support. "
+#else
+#include <asm/secure.h>
+#endif
+#include <asm/armv7.h>
+
+#if defined(CONFIG_ARCH_LS1021A)
+#include <asm/arch/immap_ls102xa.h>
+#endif
+
+#include "sleep.h"
+#ifdef CONFIG_U_QE
+#include <fsl_qe.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void __weak board_mem_sleep_setup(void)
+{
+}
+
+void __weak board_sleep_prepare(void)
+{
+}
+
+bool is_warm_boot(void)
+{
+       struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
+
+       if (in_be32(&gur->crstsr) & DCFG_CCSR_CRSTSR_WDRFR)
+               return 1;
+
+       return 0;
+}
+
+void fsl_dp_disable_console(void)
+{
+       gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE;
+}
+
+/*
+ * When wakeup from deep sleep, the first 128 bytes space
+ * will be used to do DDR training which corrupts the data
+ * in there. This function will restore them.
+ */
+static void dp_ddr_restore(void)
+{
+       u64 *src, *dst;
+       int i;
+       struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
+
+       /* get the address of ddr date from SPARECR3 */
+       src = (u64 *)in_le32(&scfg->sparecr[2]);
+       dst = (u64 *)CONFIG_SYS_SDRAM_BASE;
+
+       for (i = 0; i < DDR_BUFF_LEN / 8; i++)
+               *dst++ = *src++;
+}
+
+#if defined(CONFIG_ARMV7_PSCI) && defined(CONFIG_ARCH_LS1021A)
+void ls1_psci_resume_fixup(void)
+{
+       u32 tmp;
+       struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
+
+#ifdef QIXIS_BASE
+       void *qixis_base = (void *)QIXIS_BASE;
+
+       /* Pull on PCIe RST# */
+       out_8(qixis_base + QIXIS_RST_FORCE_3, 0);
+
+       /* disable deep sleep signals in FPGA */
+       tmp = in_8(qixis_base + QIXIS_PWR_CTL2);
+       tmp &= ~QIXIS_PWR_CTL2_PCTL;
+       out_8(qixis_base + QIXIS_PWR_CTL2, tmp);
+#endif
+
+       /* Disable wakeup interrupt during deep sleep */
+       out_be32(&scfg->pmcintecr, 0);
+       /* Clear PMC interrupt status */
+       out_be32(&scfg->pmcintsr, 0xffffffff);
+
+       /* Disable Warm Device Reset */
+       tmp = in_be32(&scfg->dpslpcr);
+       tmp &= ~SCFG_DPSLPCR_WDRR_EN;
+       out_be32(&scfg->dpslpcr, tmp);
+}
+#endif
+
+static void dp_resume_prepare(void)
+{
+       dp_ddr_restore();
+       board_sleep_prepare();
+       armv7_init_nonsec();
+#ifdef CONFIG_U_QE
+       u_qe_resume();
+#endif
+#if defined(CONFIG_ARMV7_PSCI) && defined(CONFIG_ARCH_LS1021A)
+       ls1_psci_resume_fixup();
+#endif
+}
+
+int fsl_dp_resume(void)
+{
+       u32 start_addr;
+       void (*kernel_resume)(void);
+       struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
+
+       if (!is_warm_boot())
+               return 0;
+
+       dp_resume_prepare();
+
+       /* Get the entry address and jump to kernel */
+       start_addr = in_le32(&scfg->sparecr[3]);
+       debug("Entry address is 0x%08x\n", start_addr);
+       kernel_resume = (void (*)(void))start_addr;
+       secure_ram_addr(_do_nonsec_entry)(kernel_resume, 0, 0, 0);
+
+       return 0;
+}
diff --git a/board/somdevices/common/cadmus.c b/board/somdevices/common/cadmus.c
new file mode 100644 (file)
index 0000000..7e7394f
--- /dev/null
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2004, 2011 Freescale Semiconductor.
+ */
+
+
+#include <common.h>
+
+
+/*
+ * CADMUS Board System Registers
+ */
+#ifndef CONFIG_SYS_CADMUS_BASE_REG
+#define CONFIG_SYS_CADMUS_BASE_REG     (CADMUS_BASE_ADDR + 0x4000)
+#endif
+
+typedef struct cadmus_reg {
+    u_char cm_ver;             /* Board version */
+    u_char cm_csr;             /* General control/status */
+    u_char cm_rst;             /* Reset control */
+    u_char cm_hsclk;           /* High speed clock */
+    u_char cm_hsxclk;          /* High speed clock extended */
+    u_char cm_led;             /* LED data */
+    u_char cm_pci;             /* PCI control/status */
+    u_char cm_dma;             /* DMA control */
+    u_char cm_reserved[248];   /* Total 256 bytes */
+} cadmus_reg_t;
+
+
+unsigned int
+get_board_version(void)
+{
+       volatile cadmus_reg_t *cadmus = (cadmus_reg_t *)CONFIG_SYS_CADMUS_BASE_REG;
+
+       return cadmus->cm_ver;
+}
+
+
+unsigned long
+get_clock_freq(void)
+{
+       volatile cadmus_reg_t *cadmus = (cadmus_reg_t *)CONFIG_SYS_CADMUS_BASE_REG;
+
+       uint pci1_speed = (cadmus->cm_pci >> 2) & 0x3; /* PSPEED in [4:5] */
+
+       if (pci1_speed == 0) {
+               return 33333333;
+       } else if (pci1_speed == 1) {
+               return 66666666;
+       } else {
+               /* Really, unknown. Be safe? */
+               return 33333333;
+       }
+}
+
+
+unsigned int
+get_pci_slot(void)
+{
+       volatile cadmus_reg_t *cadmus = (cadmus_reg_t *)CONFIG_SYS_CADMUS_BASE_REG;
+
+       /*
+        * PCI slot in USER bits CSR[6:7] by convention.
+        */
+       return ((cadmus->cm_csr >> 6) & 0x3) + 1;
+}
+
+
+unsigned int
+get_pci_dual(void)
+{
+       volatile cadmus_reg_t *cadmus = (cadmus_reg_t *)CONFIG_SYS_CADMUS_BASE_REG;
+
+       /*
+        * PCI DUAL in CM_PCI[3]
+        */
+       return cadmus->cm_pci & 0x10;
+}
diff --git a/board/somdevices/common/cadmus.h b/board/somdevices/common/cadmus.h
new file mode 100644 (file)
index 0000000..ddc2bb6
--- /dev/null
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ */
+
+#ifndef __CADMUS_H_
+#define __CADMUS_H_
+
+
+/*
+ * CADMUS Board System Register interface.
+ */
+
+/*
+ * Returns board version register.
+ */
+extern unsigned int get_board_version(void);
+
+/*
+ * Returns either 33000000 or 66000000 as the SYS_CLK_FREQ.
+ */
+extern unsigned long get_clock_freq(void);
+
+
+/*
+ * Returns 1 - 4, as found in the USER CSR[6:7] bits.
+ */
+extern unsigned int get_pci_slot(void);
+
+
+/*
+ * Returns PCI DUAL as found in CM_PCI[3].
+ */
+extern unsigned int get_pci_dual(void);
+
+
+#endif /* __CADMUS_H_ */
diff --git a/board/somdevices/common/cds_pci_ft.c b/board/somdevices/common/cds_pci_ft.c
new file mode 100644 (file)
index 0000000..3ff2fa4
--- /dev/null
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ */
+
+#include <common.h>
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+#include "cadmus.h"
+
+#if defined(CONFIG_OF_BOARD_SETUP)
+static void cds_pci_fixup(void *blob)
+{
+       int node;
+       const char *path;
+       int len, slot, i;
+       u32 *map = NULL, *piccells = NULL;
+       int off, cells;
+
+       node = fdt_path_offset(blob, "/aliases");
+       if (node >= 0) {
+               path = fdt_getprop(blob, node, "pci0", NULL);
+               if (path) {
+                       node = fdt_path_offset(blob, path);
+                       if (node >= 0) {
+                               map = fdt_getprop_w(blob, node, "interrupt-map", &len);
+                       }
+                       /* Each item in "interrupt-map" property is translated with
+                        * following cells:
+                        * PCI #address-cells, PCI #interrupt-cells,
+                        * PIC address, PIC #address-cells, PIC #interrupt-cells.
+                        */
+                       cells = fdt_getprop_u32_default(blob, path, "#address-cells", 1);
+                       cells += fdt_getprop_u32_default(blob, path, "#interrupt-cells", 1);
+                       off = fdt_node_offset_by_phandle(blob, fdt32_to_cpu(*(map+cells)));
+                       if (off <= 0)
+                               return;
+                       cells += 1;
+                       piccells = (u32 *)fdt_getprop(blob, off, "#address-cells", NULL);
+                       if (piccells == NULL)
+                               return;
+                       cells += *piccells;
+                       piccells = (u32 *)fdt_getprop(blob, off, "#interrupt-cells", NULL);
+                       if (piccells == NULL)
+                               return;
+                       cells += *piccells;
+               }
+       }
+
+       if (map) {
+               len /= sizeof(u32);
+
+               slot = get_pci_slot();
+
+               for (i=0;i<len;i+=cells) {
+                       /* We rotate the interrupt pins so that the mapping
+                        * changes depending on the slot the carrier card is in.
+                        */
+                       map[3] = ((map[3] + slot - 2) % 4) + 1;
+                       map+=cells;
+               }
+       }
+}
+
+int ft_board_setup(void *blob, bd_t *bd)
+{
+       ft_cpu_setup(blob, bd);
+#ifdef CONFIG_PCI
+       ft_pci_setup(blob, bd);
+       cds_pci_fixup(blob);
+#endif
+
+       return 0;
+}
+#endif
diff --git a/board/somdevices/common/cds_via.c b/board/somdevices/common/cds_via.c
new file mode 100644 (file)
index 0000000..8f8f0d1
--- /dev/null
@@ -0,0 +1,92 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2006 Freescale Semiconductor.
+ */
+
+#include <common.h>
+#include <pci.h>
+
+/* Config the VIA chip */
+void mpc85xx_config_via(struct pci_controller *hose,
+                       pci_dev_t dev, struct pci_config_table *tab)
+{
+       pci_dev_t bridge;
+       unsigned int cmdstat;
+
+       /* Enable USB and IDE functions */
+       pci_hose_write_config_byte(hose, dev, 0x48, 0x08);
+
+       pci_hose_read_config_dword(hose, dev, PCI_COMMAND, &cmdstat);
+       cmdstat |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY| PCI_COMMAND_MASTER;
+       pci_hose_write_config_dword(hose, dev, PCI_COMMAND, cmdstat);
+       pci_hose_write_config_byte(hose, dev, PCI_CACHE_LINE_SIZE, 0x08);
+       pci_hose_write_config_byte(hose, dev, PCI_LATENCY_TIMER, 0x80);
+
+       /*
+        * Force the backplane P2P bridge to have a window
+        * open from 0x00000000-0x00001fff in PCI I/O space.
+        * This allows legacy I/O (i8259, etc) on the VIA
+        * southbridge to be accessed.
+        */
+       bridge = PCI_BDF(0,BRIDGE_ID,0);
+       pci_hose_write_config_byte(hose, bridge, PCI_IO_BASE, 0);
+       pci_hose_write_config_word(hose, bridge, PCI_IO_BASE_UPPER16, 0);
+       pci_hose_write_config_byte(hose, bridge, PCI_IO_LIMIT, 0x10);
+       pci_hose_write_config_word(hose, bridge, PCI_IO_LIMIT_UPPER16, 0);
+}
+
+/* Function 1, IDE */
+void mpc85xx_config_via_usbide(struct pci_controller *hose,
+                              pci_dev_t dev, struct pci_config_table *tab)
+{
+       pciauto_config_device(hose, dev);
+       /*
+        * Since the P2P window was forced to cover the fixed
+        * legacy I/O addresses, it is necessary to manually
+        * place the base addresses for the IDE and USB functions
+        * within this window.
+        */
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0x1ff8);
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_1, 0x1ff4);
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_2, 0x1fe8);
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_3, 0x1fe4);
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_4, 0x1fd0);
+}
+
+/* Function 2, USB ports 0-1 */
+void mpc85xx_config_via_usb(struct pci_controller *hose,
+                           pci_dev_t dev, struct pci_config_table *tab)
+{
+       pciauto_config_device(hose, dev);
+
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_4, 0x1fa0);
+}
+
+/* Function 3, USB ports 2-3 */
+void mpc85xx_config_via_usb2(struct pci_controller *hose,
+                            pci_dev_t dev, struct pci_config_table *tab)
+{
+       pciauto_config_device(hose, dev);
+
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_4, 0x1f80);
+}
+
+/* Function 5, Power Management */
+void mpc85xx_config_via_power(struct pci_controller *hose,
+                             pci_dev_t dev, struct pci_config_table *tab)
+{
+       pciauto_config_device(hose, dev);
+
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0x1e00);
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_1, 0x1dfc);
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_2, 0x1df8);
+}
+
+/* Function 6, AC97 Interface */
+void mpc85xx_config_via_ac97(struct pci_controller *hose,
+                            pci_dev_t dev, struct pci_config_table *tab)
+{
+       pciauto_config_device(hose, dev);
+
+       pci_hose_write_config_dword(hose, dev, PCI_BASE_ADDRESS_0, 0x1c00);
+}
diff --git a/board/somdevices/common/cmd_esbc_validate.c b/board/somdevices/common/cmd_esbc_validate.c
new file mode 100644 (file)
index 0000000..b06235f
--- /dev/null
@@ -0,0 +1,85 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <fsl_validate.h>
+
+int do_esbc_halt(cmd_tbl_t *cmdtp, int flag, int argc,
+                               char * const argv[])
+{
+       if (fsl_check_boot_mode_secure() == 0) {
+               printf("Boot Mode is Non-Secure. Not entering spin loop.\n");
+               return 0;
+       }
+
+       printf("Core is entering spin loop.\n");
+loop:
+       goto loop;
+
+       return 0;
+}
+
+#ifndef CONFIG_SPL_BUILD
+static int do_esbc_validate(cmd_tbl_t *cmdtp, int flag, int argc,
+                               char * const argv[])
+{
+       char *hash_str = NULL;
+       uintptr_t haddr;
+       int ret;
+       uintptr_t img_addr = 0;
+       char buf[20];
+
+       if (argc < 2)
+               return cmd_usage(cmdtp);
+       else if (argc > 2)
+               /* Second arg - Optional - Hash Str*/
+               hash_str = argv[2];
+
+       /* First argument - header address -32/64bit */
+       haddr = (uintptr_t)simple_strtoul(argv[1], NULL, 16);
+
+       /* With esbc_validate command, Image address must be
+        * part of header. So, the function is called
+        * by passing this argument as 0.
+        */
+       ret = fsl_secboot_validate(haddr, hash_str, &img_addr);
+
+       /* Need to set "img_addr" even if validation failure.
+        * Required when SB_EN in RCW set and non-fatal error
+        * to continue U-Boot
+        */
+       sprintf(buf, "%lx", img_addr);
+       env_set("img_addr", buf);
+
+       if (ret)
+               return 1;
+
+       printf("esbc_validate command successful\n");
+       return 0;
+}
+
+/***************************************************/
+static char esbc_validate_help_text[] =
+       "esbc_validate hdr_addr <hash_val> - Validates signature using\n"
+       "                          RSA verification\n"
+       "                          $hdr_addr Address of header of the image\n"
+       "                          to be validated.\n"
+       "                          $hash_val -Optional\n"
+       "                          It provides Hash of public/srk key to be\n"
+       "                          used to verify signature.\n";
+
+U_BOOT_CMD(
+       esbc_validate,  3,      0,      do_esbc_validate,
+       "Validates signature on a given image using RSA verification",
+       esbc_validate_help_text
+);
+
+U_BOOT_CMD(
+       esbc_halt,      1,      0,      do_esbc_halt,
+       "Put the core in spin loop (Secure Boot Only)",
+       ""
+);
+#endif
diff --git a/board/somdevices/common/dcu_sii9022a.c b/board/somdevices/common/dcu_sii9022a.c
new file mode 100644 (file)
index 0000000..3bf71ab
--- /dev/null
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#include <asm/io.h>
+#include <common.h>
+#include <fsl_dcu_fb.h>
+#include <i2c.h>
+#include <linux/fb.h>
+
+#define PIXEL_CLK_LSB_REG              0x00
+#define PIXEL_CLK_MSB_REG              0x01
+#define VERT_FREQ_LSB_REG              0x02
+#define VERT_FREQ_MSB_REG              0x03
+#define TOTAL_PIXELS_LSB_REG           0x04
+#define TOTAL_PIXELS_MSB_REG           0x05
+#define TOTAL_LINES_LSB_REG            0x06
+#define TOTAL_LINES_MSB_REG            0x07
+#define TPI_INBUS_FMT_REG              0x08
+#define TPI_INPUT_FMT_REG              0x09
+#define TPI_OUTPUT_FMT_REG             0x0A
+#define TPI_SYS_CTRL_REG               0x1A
+#define TPI_PWR_STAT_REG               0x1E
+#define TPI_AUDIO_HANDING_REG          0x25
+#define TPI_AUDIO_INTF_REG             0x26
+#define TPI_AUDIO_FREQ_REG             0x27
+#define TPI_SET_PAGE_REG               0xBC
+#define TPI_SET_OFFSET_REG             0xBD
+#define TPI_RW_ACCESS_REG              0xBE
+#define TPI_TRANS_MODE_REG             0xC7
+
+#define TPI_INBUS_CLOCK_RATIO_1                (1 << 6)
+#define TPI_INBUS_FULL_PIXEL_WIDE      (1 << 5)
+#define TPI_INBUS_RISING_EDGE          (1 << 4)
+#define TPI_INPUT_CLR_DEPTH_8BIT       (0 << 6)
+#define TPI_INPUT_VRANGE_EXPAN_AUTO    (0 << 2)
+#define TPI_INPUT_CLR_RGB              (0 << 0)
+#define TPI_OUTPUT_CLR_DEPTH_8BIT      (0 << 6)
+#define TPI_OUTPUT_VRANGE_COMPRE_AUTO  (0 << 2)
+#define TPI_OUTPUT_CLR_HDMI_RGB                (0 << 0)
+#define TPI_SYS_TMDS_OUTPUT            (0 << 4)
+#define TPI_SYS_AV_NORAML              (0 << 3)
+#define TPI_SYS_AV_MUTE                        (1 << 3)
+#define TPI_SYS_DVI_MODE               (0 << 0)
+#define TPI_SYS_HDMI_MODE              (1 << 0)
+#define TPI_PWR_STAT_MASK              (3 << 0)
+#define TPI_PWR_STAT_D0                        (0 << 0)
+#define TPI_AUDIO_PASS_BASIC           (0 << 0)
+#define TPI_AUDIO_INTF_I2S             (2 << 6)
+#define TPI_AUDIO_INTF_NORMAL          (0 << 4)
+#define TPI_AUDIO_TYPE_PCM             (1 << 0)
+#define TPI_AUDIO_SAMP_SIZE_16BIT      (1 << 6)
+#define TPI_AUDIO_SAMP_FREQ_44K                (2 << 3)
+#define TPI_SET_PAGE_SII9022A          0x01
+#define TPI_SET_OFFSET_SII9022A                0x82
+#define TPI_RW_EN_SRC_TERMIN           (1 << 0)
+#define TPI_TRANS_MODE_ENABLE          (0 << 7)
+
+/* Programming of Silicon SIi9022a HDMI Transmitter */
+int dcu_set_dvi_encoder(struct fb_videomode *videomode)
+{
+       u8 temp;
+       u16 temp1, temp2;
+       u32 temp3;
+
+       i2c_set_bus_num(CONFIG_SYS_I2C_DVI_BUS_NUM);
+
+       /* Enable TPI transmitter mode */
+       temp = TPI_TRANS_MODE_ENABLE;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_TRANS_MODE_REG, 1, &temp, 1);
+
+       /* Enter into D0 state, full operation */
+       i2c_read(CONFIG_SYS_I2C_DVI_ADDR, TPI_PWR_STAT_REG, 1, &temp, 1);
+       temp &= ~TPI_PWR_STAT_MASK;
+       temp |= TPI_PWR_STAT_D0;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_PWR_STAT_REG, 1, &temp, 1);
+
+       /* Enable source termination */
+       temp = TPI_SET_PAGE_SII9022A;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_SET_PAGE_REG, 1, &temp, 1);
+       temp = TPI_SET_OFFSET_SII9022A;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_SET_OFFSET_REG, 1, &temp, 1);
+
+       i2c_read(CONFIG_SYS_I2C_DVI_ADDR, TPI_RW_ACCESS_REG, 1, &temp, 1);
+       temp |= TPI_RW_EN_SRC_TERMIN;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_RW_ACCESS_REG, 1, &temp, 1);
+
+       /* Set TPI system control */
+       temp = TPI_SYS_TMDS_OUTPUT | TPI_SYS_AV_NORAML | TPI_SYS_DVI_MODE;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_SYS_CTRL_REG, 1, &temp, 1);
+
+       /* Set pixel clock */
+       temp1 = PICOS2KHZ(videomode->pixclock) / 10;
+       temp = (u8)(temp1 & 0xFF);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, PIXEL_CLK_LSB_REG, 1, &temp, 1);
+       temp = (u8)(temp1 >> 8);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, PIXEL_CLK_MSB_REG, 1, &temp, 1);
+
+       /* Set total pixels per line */
+       temp1 = videomode->hsync_len + videomode->left_margin +
+               videomode->xres + videomode->right_margin;
+       temp = (u8)(temp1 & 0xFF);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_PIXELS_LSB_REG, 1, &temp, 1);
+       temp = (u8)(temp1 >> 8);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_PIXELS_MSB_REG, 1, &temp, 1);
+
+       /* Set total lines */
+       temp2 = videomode->vsync_len + videomode->upper_margin +
+               videomode->yres + videomode->lower_margin;
+       temp = (u8)(temp2 & 0xFF);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_LINES_LSB_REG, 1, &temp, 1);
+       temp = (u8)(temp2 >> 8);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TOTAL_LINES_MSB_REG, 1, &temp, 1);
+
+       /* Set vertical frequency in Hz */
+       temp3 = temp1 * temp2;
+       temp3 = (PICOS2KHZ(videomode->pixclock) * 1000) / temp3;
+       temp1 = (u16)temp3 * 100;
+       temp = (u8)(temp1 & 0xFF);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, VERT_FREQ_LSB_REG, 1, &temp, 1);
+       temp = (u8)(temp1 >> 8);
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, VERT_FREQ_MSB_REG, 1, &temp, 1);
+
+       /* Set TPI input bus and pixel repetition data */
+       temp = TPI_INBUS_CLOCK_RATIO_1 | TPI_INBUS_FULL_PIXEL_WIDE |
+               TPI_INBUS_RISING_EDGE;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_INBUS_FMT_REG, 1, &temp, 1);
+
+       /* Set TPI AVI Input format data */
+       temp = TPI_INPUT_CLR_DEPTH_8BIT | TPI_INPUT_VRANGE_EXPAN_AUTO |
+               TPI_INPUT_CLR_RGB;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_INPUT_FMT_REG, 1, &temp, 1);
+
+       /* Set TPI AVI Output format data */
+       temp = TPI_OUTPUT_CLR_DEPTH_8BIT | TPI_OUTPUT_VRANGE_COMPRE_AUTO |
+               TPI_OUTPUT_CLR_HDMI_RGB;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_OUTPUT_FMT_REG, 1, &temp, 1);
+
+       /* Set TPI audio configuration write data */
+       temp = TPI_AUDIO_PASS_BASIC;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_AUDIO_HANDING_REG, 1, &temp, 1);
+
+       temp = TPI_AUDIO_INTF_I2S | TPI_AUDIO_INTF_NORMAL |
+               TPI_AUDIO_TYPE_PCM;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_AUDIO_INTF_REG, 1, &temp, 1);
+
+       temp = TPI_AUDIO_SAMP_SIZE_16BIT | TPI_AUDIO_SAMP_FREQ_44K;
+       i2c_write(CONFIG_SYS_I2C_DVI_ADDR, TPI_AUDIO_FREQ_REG, 1, &temp, 1);
+
+       return 0;
+}
diff --git a/board/somdevices/common/dcu_sii9022a.h b/board/somdevices/common/dcu_sii9022a.h
new file mode 100644 (file)
index 0000000..7851775
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __DCU_HDMI_SII9022A__
+#define __DCU_HDMI_SII9022A__
+
+/* Programming of Silicon SII9022A connector HDMI Transmitter*/
+int dcu_set_dvi_encoder(struct fb_videomode *videomode);
+
+#endif
diff --git a/board/somdevices/common/diu_ch7301.c b/board/somdevices/common/diu_ch7301.c
new file mode 100644 (file)
index 0000000..435b4a3
--- /dev/null
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ * Authors: Priyanka Jain <Priyanka.Jain@freescale.com>
+ *         Wang Dongsheng <dongsheng.wang@freescale.com>
+ *
+ * This file is copied and modified from the original t1040qds/diu.c.
+ * Encoder can be used in T104x and LSx Platform.
+ */
+
+#include <common.h>
+#include <stdio_dev.h>
+#include <i2c.h>
+
+#define I2C_DVI_INPUT_DATA_FORMAT_REG          0x1F
+#define I2C_DVI_PLL_CHARGE_CNTL_REG            0x33
+#define I2C_DVI_PLL_DIVIDER_REG                        0x34
+#define I2C_DVI_PLL_SUPPLY_CNTL_REG            0x35
+#define I2C_DVI_PLL_FILTER_REG                 0x36
+#define I2C_DVI_TEST_PATTERN_REG               0x48
+#define I2C_DVI_POWER_MGMT_REG                 0x49
+#define I2C_DVI_LOCK_STATE_REG                 0x4D
+#define I2C_DVI_SYNC_POLARITY_REG              0x56
+
+/*
+ * Set VSYNC/HSYNC to active high. This is polarity of sync signals
+ * from DIU->DVI. The DIU default is active igh, so DVI is set to
+ * active high.
+ */
+#define I2C_DVI_INPUT_DATA_FORMAT_VAL          0x98
+
+#define I2C_DVI_PLL_CHARGE_CNTL_HIGH_SPEED_VAL 0x06
+#define I2C_DVI_PLL_DIVIDER_HIGH_SPEED_VAL     0x26
+#define I2C_DVI_PLL_FILTER_HIGH_SPEED_VAL      0xA0
+#define I2C_DVI_PLL_CHARGE_CNTL_LOW_SPEED_VAL  0x08
+#define I2C_DVI_PLL_DIVIDER_LOW_SPEED_VAL      0x16
+#define I2C_DVI_PLL_FILTER_LOW_SPEED_VAL       0x60
+
+/* Clear test pattern */
+#define I2C_DVI_TEST_PATTERN_VAL               0x18
+/* Exit Power-down mode */
+#define I2C_DVI_POWER_MGMT_VAL                 0xC0
+
+/* Monitor polarity is handled via DVI Sync Polarity Register */
+#define I2C_DVI_SYNC_POLARITY_VAL              0x00
+
+/* Programming of HDMI Chrontel CH7301 connector */
+int diu_set_dvi_encoder(unsigned int pixclock)
+{
+       int ret;
+       u8 temp;
+
+       temp = I2C_DVI_TEST_PATTERN_VAL;
+       ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_TEST_PATTERN_REG, 1,
+                       &temp, 1);
+       if (ret) {
+               puts("I2C: failed to select proper dvi test pattern\n");
+               return ret;
+       }
+       temp = I2C_DVI_INPUT_DATA_FORMAT_VAL;
+       ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_INPUT_DATA_FORMAT_REG,
+                       1, &temp, 1);
+       if (ret) {
+               puts("I2C: failed to select dvi input data format\n");
+               return ret;
+       }
+
+       /* Set Sync polarity register */
+       temp = I2C_DVI_SYNC_POLARITY_VAL;
+       ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_SYNC_POLARITY_REG, 1,
+                       &temp, 1);
+       if (ret) {
+               puts("I2C: failed to select dvi syc polarity\n");
+               return ret;
+       }
+
+       /* Set PLL registers based on pixel clock rate*/
+       if (pixclock > 65000000) {
+               temp = I2C_DVI_PLL_CHARGE_CNTL_HIGH_SPEED_VAL;
+               ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
+                               I2C_DVI_PLL_CHARGE_CNTL_REG, 1, &temp, 1);
+               if (ret) {
+                       puts("I2C: failed to select dvi pll charge_cntl\n");
+                       return ret;
+               }
+               temp = I2C_DVI_PLL_DIVIDER_HIGH_SPEED_VAL;
+               ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
+                               I2C_DVI_PLL_DIVIDER_REG, 1, &temp, 1);
+               if (ret) {
+                       puts("I2C: failed to select dvi pll divider\n");
+                       return ret;
+               }
+               temp = I2C_DVI_PLL_FILTER_HIGH_SPEED_VAL;
+               ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
+                               I2C_DVI_PLL_FILTER_REG, 1, &temp, 1);
+               if (ret) {
+                       puts("I2C: failed to select dvi pll filter\n");
+                       return ret;
+               }
+       } else {
+               temp = I2C_DVI_PLL_CHARGE_CNTL_LOW_SPEED_VAL;
+               ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
+                               I2C_DVI_PLL_CHARGE_CNTL_REG, 1, &temp, 1);
+               if (ret) {
+                       puts("I2C: failed to select dvi pll charge_cntl\n");
+                       return ret;
+               }
+               temp = I2C_DVI_PLL_DIVIDER_LOW_SPEED_VAL;
+               ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
+                               I2C_DVI_PLL_DIVIDER_REG, 1, &temp, 1);
+               if (ret) {
+                       puts("I2C: failed to select dvi pll divider\n");
+                       return ret;
+               }
+               temp = I2C_DVI_PLL_FILTER_LOW_SPEED_VAL;
+               ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR,
+                               I2C_DVI_PLL_FILTER_REG, 1, &temp, 1);
+               if (ret) {
+                       puts("I2C: failed to select dvi pll filter\n");
+                       return ret;
+               }
+       }
+
+       temp = I2C_DVI_POWER_MGMT_VAL;
+       ret = i2c_write(CONFIG_SYS_I2C_DVI_ADDR, I2C_DVI_POWER_MGMT_REG, 1,
+                       &temp, 1);
+       if (ret) {
+               puts("I2C: failed to select dvi power mgmt\n");
+               return ret;
+       }
+
+       udelay(500);
+
+       return 0;
+}
diff --git a/board/somdevices/common/diu_ch7301.h b/board/somdevices/common/diu_ch7301.h
new file mode 100644 (file)
index 0000000..f35661c
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __DIU_HDMI_CH7301__
+#define __DIU_HDMI_CH7301__
+
+/* Programming of HDMI Chrontel CH7301 connector */
+int diu_set_dvi_encoder(unsigned int pixclock);
+
+#endif
diff --git a/board/somdevices/common/eeprom.h b/board/somdevices/common/eeprom.h
new file mode 100644 (file)
index 0000000..328fd39
--- /dev/null
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2004 Freescale Semiconductor.
+ */
+
+#ifndef __EEPROM_H_
+#define __EEPROM_H_
+
+
+/*
+ * EEPROM Board System Register interface.
+ */
+
+
+/*
+ * CPU Board Revision
+ */
+#define MPC85XX_CPU_BOARD_REV(maj, min)        ((((maj)&0xff) << 8) | ((min) & 0xff))
+#define MPC85XX_CPU_BOARD_MAJOR(rev)   (((rev) >> 8) & 0xff)
+#define MPC85XX_CPU_BOARD_MINOR(rev)   ((rev) & 0xff)
+
+#define MPC85XX_CPU_BOARD_REV_UNKNOWN  MPC85XX_CPU_BOARD_REV(0,0)
+#define MPC85XX_CPU_BOARD_REV_1_0      MPC85XX_CPU_BOARD_REV(1,0)
+#define MPC85XX_CPU_BOARD_REV_1_1      MPC85XX_CPU_BOARD_REV(1,1)
+
+/*
+ * Returns CPU board revision register as a 16-bit value with
+ * the Major in the high byte, and Minor in the low byte.
+ */
+extern unsigned int get_cpu_board_revision(void);
+
+
+#endif /* __CADMUS_H_ */
diff --git a/board/somdevices/common/emc2305.c b/board/somdevices/common/emc2305.c
new file mode 100644 (file)
index 0000000..8523084
--- /dev/null
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP.
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <asm/io.h>
+
+#include "emc2305.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void set_fan_speed(u8 data)
+{
+       u8 index;
+       u8 Fan[NUM_OF_FANS] = {I2C_EMC2305_FAN1,
+                              I2C_EMC2305_FAN2,
+                              I2C_EMC2305_FAN3,
+                              I2C_EMC2305_FAN4,
+                              I2C_EMC2305_FAN5};
+
+       for (index = 0; index < NUM_OF_FANS; index++) {
+               if (i2c_write(I2C_EMC2305_ADDR, Fan[index], 1, &data, 1) != 0) {
+                       printf("Error: failed to change fan speed @%x\n",
+                              Fan[index]);
+               }
+       }
+}
+
+void emc2305_init(void)
+{
+       u8 data;
+
+       data = I2C_EMC2305_CMD;
+       if (i2c_write(I2C_EMC2305_ADDR, I2C_EMC2305_CONF, 1, &data, 1) != 0)
+               printf("Error: failed to configure EMC2305\n");
+}
diff --git a/board/somdevices/common/emc2305.h b/board/somdevices/common/emc2305.h
new file mode 100644 (file)
index 0000000..eddf537
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 NXP
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __EMC2305_H_
+#define __EMC2305_H_
+
+#define I2C_EMC2305_CONF               0x20
+#define I2C_EMC2305_FAN1               0x30
+#define I2C_EMC2305_FAN2               0x40
+#define I2C_EMC2305_FAN3               0x50
+#define I2C_EMC2305_FAN4               0x60
+#define I2C_EMC2305_FAN5               0x70
+
+#define NUM_OF_FANS                    5
+
+void emc2305_init(void);
+void set_fan_speed(u8 data);
+
+#endif  /* __EMC2305_H_ */
diff --git a/board/somdevices/common/epdc_setup.c b/board/somdevices/common/epdc_setup.c
new file mode 100644 (file)
index 0000000..9b12096
--- /dev/null
@@ -0,0 +1,222 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Peng Fan <Peng.Fan@freescale.com>
+ */
+#include <common.h>
+#include <lcd.h>
+#include <linux/err.h>
+#include <linux/types.h>
+#include <malloc.h>
+#include <mxc_epdc_fb.h>
+
+#define is_digit(c)    ((c) >= '0' && (c) <= '9')
+__weak int mmc_get_env_devno(void)
+{
+       return 0;
+}
+__weak int check_mmc_autodetect(void)
+{
+       return 0;
+}
+
+int board_setup_waveform_file(ulong waveform_buf)
+{
+       char *fs_argv[5];
+       char addr[17];
+       ulong file_len, mmc_dev;
+
+       if (!check_mmc_autodetect())
+               mmc_dev = env_get_ulong("mmcdev", 10, 0);
+       else
+               mmc_dev = mmc_get_env_devno();
+
+       sprintf(addr, "%lx", (ulong)CONFIG_SYS_LOAD_ADDR);
+
+       fs_argv[0] = "fatload";
+       fs_argv[1] = "mmc";
+       fs_argv[2] = simple_itoa(mmc_dev);
+       fs_argv[3] = addr;
+       fs_argv[4] = env_get("epdc_waveform");
+
+       if (!fs_argv[4])
+               fs_argv[4] = "epdc_splash.bin";
+
+       if (do_fat_fsload(NULL, 0, 5, fs_argv)) {
+               printf("File %s not found on MMC Device %lu!\n", fs_argv[4], mmc_dev);
+               return -1;
+       }
+
+       file_len = env_get_hex("filesize", 0);
+       if (!file_len)
+               return -1;
+
+       memcpy((void *)waveform_buf, (const void *)CONFIG_SYS_LOAD_ADDR, file_len);
+
+       flush_cache(waveform_buf, roundup(file_len, ARCH_DMA_MINALIGN));
+
+       return 0;
+}
+
+int board_setup_logo_file(void *display_buf)
+{
+       int logo_width, logo_height;
+       char *fs_argv[5];
+       char addr[17];
+       int array[3];
+       ulong file_len, mmc_dev;
+       char *buf, *s;
+       int arg = 0, val = 0, pos = 0;
+       int i, j, max_check_length;
+       int row, col, row_end, col_end;
+
+       if (!display_buf)
+               return -EINVAL;
+
+       /* Assume PGM header not exceeds 128 bytes */
+       max_check_length = 128;
+
+       if (!check_mmc_autodetect())
+               mmc_dev = env_get_ulong("mmcdev", 10, 0);
+       else
+               mmc_dev = mmc_get_env_devno();
+
+       memset(display_buf, 0xFF, panel_info.vl_col * panel_info.vl_row);
+
+       fs_argv[0] = "fatsize";
+       fs_argv[1] = "mmc";
+       fs_argv[2] = simple_itoa(mmc_dev);
+       fs_argv[3] = env_get("epdc_logo");
+       if (!fs_argv[3])
+               fs_argv[3] = "epdc_logo.pgm";
+       if (do_fat_size(NULL, 0, 4, fs_argv)) {
+               debug("File %s not found on MMC Device %lu, use black border\n", fs_argv[3], mmc_dev);
+               /* Draw black border around framebuffer*/
+               memset(display_buf, 0x0, 24 * panel_info.vl_col);
+               for (i = 24; i < (panel_info.vl_row - 24); i++) {
+                       memset((u8 *)display_buf + i * panel_info.vl_col,
+                              0x00, 24);
+                       memset((u8 *)display_buf + i * panel_info.vl_col
+                               + panel_info.vl_col - 24, 0x00, 24);
+               }
+               memset((u8 *)display_buf +
+                      panel_info.vl_col * (panel_info.vl_row - 24),
+                      0x00, 24 * panel_info.vl_col);
+               return 0;
+       }
+
+       file_len = env_get_hex("filesize", 0);
+       if (!file_len)
+               return -EINVAL;
+
+       buf = memalign(ARCH_DMA_MINALIGN, file_len);
+       if (!buf)
+               return -ENOMEM;
+
+       sprintf(addr, "%lx", (ulong)CONFIG_SYS_LOAD_ADDR);
+
+       fs_argv[0] = "fatload";
+       fs_argv[1] = "mmc";
+       fs_argv[2] = simple_itoa(mmc_dev);
+       fs_argv[3] = addr;
+       fs_argv[4] = env_get("epdc_logo");
+
+       if (!fs_argv[4])
+               fs_argv[4] = "epdc_logo.pgm";
+
+       if (do_fat_fsload(NULL, 0, 5, fs_argv)) {
+               printf("File %s not found on MMC Device %lu!\n", fs_argv[4], mmc_dev);
+               free(buf);
+               return -1;
+       }
+
+       memcpy((void *)buf, (const void *)CONFIG_SYS_LOAD_ADDR, file_len);
+
+       if (strncmp(buf, "P5", 2)) {
+               printf("Wrong format for epdc logo, use PGM-P5 format.\n");
+               free(buf);
+               return -EINVAL;
+       }
+       /* Skip P5\n */
+       pos += 3;
+       arg = 0;
+       for (i = 3; i < max_check_length; ) {
+               /* skip \n \t and space */
+               if ((buf[i] == '\n') || (buf[i] == '\t') || (buf[i] == ' ')) {
+                       i++;
+                       continue;
+               }
+               /* skip comment */
+               if (buf[i] == '#') {
+                       while (buf[i++] != '\n')
+                               ;
+                       continue;
+               }
+
+               /* HEIGTH, WIDTH, MAX PIXEL VLAUE total 3 args */
+               if (arg > 2)
+                       break;
+               val = 0;
+               while (is_digit(buf[i])) {
+                       val = val * 10 + buf[i] - '0';
+                       i++;
+               }
+               array[arg++] = val;
+
+               i++;
+       }
+
+       /* Point to data area */
+       pos = i;
+
+       logo_width = array[0];
+       logo_height = array[1];
+
+       if ((logo_width > panel_info.vl_col) ||
+           (logo_height > panel_info.vl_row)) {
+               printf("Picture: too big\n");
+               free(buf);
+               return -EINVAL;
+       }
+
+       /* m,m means center of screen */
+       row = 0;
+       col = 0;
+       s = env_get("splashpos");
+       if (s) {
+               if (s[0] == 'm')
+                       col = (panel_info.vl_col  - logo_width) >> 1;
+               else
+                       col = simple_strtol(s, NULL, 0);
+               s = strchr(s + 1, ',');
+               if (s != NULL) {
+                       if (s[1] == 'm')
+                               row = (panel_info.vl_row  - logo_height) >> 1;
+                       else
+                               row = simple_strtol(s + 1, NULL, 0);
+               }
+       }
+       if ((col + logo_width > panel_info.vl_col) ||
+           (row + logo_height > panel_info.vl_row)) {
+               printf("Incorrect pos, use (0, 0)\n");
+               row = 0;
+               col = 0;
+       }
+
+       /* Draw picture at the center of screen */
+       row_end = row + logo_height;
+       col_end = col + logo_width;
+       for (i = row; i < row_end; i++) {
+               for (j = col; j < col_end; j++) {
+                       *((u8 *)display_buf + i * (panel_info.vl_col) + j) =
+                                buf[pos++];
+               }
+       }
+
+       free(buf);
+
+       flush_cache((ulong)display_buf, file_len - pos - 1);
+
+       return 0;
+}
diff --git a/board/somdevices/common/fman.c b/board/somdevices/common/fman.c
new file mode 100644 (file)
index 0000000..3583031
--- /dev/null
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2011-2015 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <linux/libfdt.h>
+#include <linux/libfdt_env.h>
+#include <fdt_support.h>
+
+#include <fm_eth.h>
+#ifdef CONFIG_FSL_LAYERSCAPE
+#include <asm/arch/fsl_serdes.h>
+#else
+#include <asm/fsl_serdes.h>
+#endif
+
+/*
+ * Given the following ...
+ *
+ * 1) A pointer to an Fman Ethernet node (as identified by the 'compat'
+ * compatible string and 'addr' physical address)
+ *
+ * 2) The name of an alias that points to the ethernet-phy node (usually inside
+ * a virtual MDIO node)
+ *
+ * ... update that Ethernet node's phy-handle property to point to the
+ * ethernet-phy node.  This is how we link an Ethernet node to its PHY, so each
+ * PHY in a virtual MDIO node must have an alias.
+ *
+ * Returns 0 on success, or a negative FDT error code on error.
+ */
+int fdt_set_phy_handle(void *fdt, char *compat, phys_addr_t addr,
+                       const char *alias)
+{
+       int offset;
+       unsigned int ph;
+       const char *path;
+
+       /* Get a path to the node that 'alias' points to */
+       path = fdt_get_alias(fdt, alias);
+       if (!path)
+               return -FDT_ERR_BADPATH;
+
+       /* Get the offset of that node */
+       offset = fdt_path_offset(fdt, path);
+       if (offset < 0)
+               return offset;
+
+       ph = fdt_create_phandle(fdt, offset);
+       if (!ph)
+               return -FDT_ERR_BADPHANDLE;
+
+       ph = cpu_to_fdt32(ph);
+
+       offset = fdt_node_offset_by_compat_reg(fdt, compat, addr);
+       if (offset < 0)
+               return offset;
+
+       return fdt_setprop(fdt, offset, "phy-handle", &ph, sizeof(ph));
+}
+
+/*
+ * Return the SerDes device enum for a given Fman port
+ *
+ * This function just maps the fm_port namespace to the srds_prtcl namespace.
+ */
+enum srds_prtcl serdes_device_from_fm_port(enum fm_port port)
+{
+       static const enum srds_prtcl srds_table[] = {
+               [FM1_DTSEC1] = SGMII_FM1_DTSEC1,
+               [FM1_DTSEC2] = SGMII_FM1_DTSEC2,
+               [FM1_DTSEC3] = SGMII_FM1_DTSEC3,
+               [FM1_DTSEC4] = SGMII_FM1_DTSEC4,
+               [FM1_DTSEC5] = SGMII_FM1_DTSEC5,
+               [FM1_10GEC1] = XAUI_FM1,
+               [FM2_DTSEC1] = SGMII_FM2_DTSEC1,
+               [FM2_DTSEC2] = SGMII_FM2_DTSEC2,
+               [FM2_DTSEC3] = SGMII_FM2_DTSEC3,
+               [FM2_DTSEC4] = SGMII_FM2_DTSEC4,
+               [FM2_DTSEC5] = SGMII_FM2_DTSEC5,
+               [FM2_10GEC1] = XAUI_FM2,
+       };
+
+       if ((port < FM1_DTSEC1) || (port > FM2_10GEC1))
+               return NONE;
+       else
+               return srds_table[port];
+}
diff --git a/board/somdevices/common/fman.h b/board/somdevices/common/fman.h
new file mode 100644 (file)
index 0000000..16afc34
--- /dev/null
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __FMAN_BOARD_HELPER__
+#define __FMAN_BOARD_HELPER__
+
+int fdt_set_phy_handle(void *fdt, char *compat, phys_addr_t addr,
+                       const char *alias);
+
+enum srds_prtcl serdes_device_from_fm_port(enum fm_port port);
+
+#endif
diff --git a/board/somdevices/common/fsl_chain_of_trust.c b/board/somdevices/common/fsl_chain_of_trust.c
new file mode 100644 (file)
index 0000000..97376c4
--- /dev/null
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fsl_validate.h>
+#include <fsl_secboot_err.h>
+#include <fsl_sfp.h>
+#include <dm/root.h>
+
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_FRAMEWORK)
+#include <spl.h>
+#endif
+
+#ifdef CONFIG_ADDR_MAP
+#include <asm/mmu.h>
+#endif
+
+#ifdef CONFIG_FSL_CORENET
+#include <asm/fsl_pamu.h>
+#endif
+
+#ifdef CONFIG_ARCH_LS1021A
+#include <asm/arch/immap_ls102xa.h>
+#endif
+
+#if defined(CONFIG_MPC85xx)
+#define CONFIG_DCFG_ADDR       CONFIG_SYS_MPC85xx_GUTS_ADDR
+#else
+#define CONFIG_DCFG_ADDR       CONFIG_SYS_FSL_GUTS_ADDR
+#endif
+
+#ifdef CONFIG_SYS_FSL_CCSR_GUR_LE
+#define gur_in32(a)       in_le32(a)
+#else
+#define gur_in32(a)       in_be32(a)
+#endif
+
+/* Check the Boot Mode. If Secure, return 1 else return 0 */
+int fsl_check_boot_mode_secure(void)
+{
+       uint32_t val;
+       struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+       struct ccsr_gur __iomem *gur = (void *)(CONFIG_DCFG_ADDR);
+
+       val = sfp_in32(&sfp_regs->ospr) & ITS_MASK;
+       if (val == ITS_MASK)
+               return 1;
+
+#if defined(CONFIG_FSL_CORENET) || !defined(CONFIG_MPC85xx)
+       /* For PBL based platforms check the SB_EN bit in RCWSR */
+       val = gur_in32(&gur->rcwsr[RCW_SB_EN_REG_INDEX - 1]) & RCW_SB_EN_MASK;
+       if (val == RCW_SB_EN_MASK)
+               return 1;
+#endif
+
+#if defined(CONFIG_MPC85xx) && !defined(CONFIG_FSL_CORENET)
+       /* For Non-PBL Platforms, check the Device Status register 2*/
+       val = gur_in32(&gur->pordevsr2) & MPC85xx_PORDEVSR2_SBC_MASK;
+       if (val != MPC85xx_PORDEVSR2_SBC_MASK)
+               return 1;
+
+#endif
+       return 0;
+}
+
+#ifndef CONFIG_SPL_BUILD
+int fsl_setenv_chain_of_trust(void)
+{
+       /* Check Boot Mode
+        * If Boot Mode is Non-Secure, no changes are required
+        */
+       if (fsl_check_boot_mode_secure() == 0)
+               return 0;
+
+       /* If Boot mode is Secure, set the environment variables
+        * bootdelay = 0 (To disable Boot Prompt)
+        * bootcmd = CONFIG_CHAIN_BOOT_CMD (Validate and execute Boot script)
+        */
+       env_set("bootdelay", "0");
+
+#ifdef CONFIG_ARM
+       env_set("secureboot", "y");
+#else
+       env_set("bootcmd", CONFIG_CHAIN_BOOT_CMD);
+#endif
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_SPL_BUILD
+void spl_validate_uboot(uint32_t hdr_addr, uintptr_t img_addr)
+{
+       int res;
+
+       /*
+        * Check Boot Mode
+        * If Boot Mode is Non-Secure, skip validation
+        */
+       if (fsl_check_boot_mode_secure() == 0)
+               return;
+
+       printf("SPL: Validating U-Boot image\n");
+
+#ifdef CONFIG_ADDR_MAP
+       init_addr_map();
+#endif
+
+#ifdef CONFIG_FSL_CORENET
+       if (pamu_init() < 0)
+               fsl_secboot_handle_error(ERROR_ESBC_PAMU_INIT);
+#endif
+
+#ifdef CONFIG_FSL_CAAM
+       if (sec_init() < 0)
+               fsl_secboot_handle_error(ERROR_ESBC_SEC_INIT);
+#endif
+
+/*
+ * dm_init_and_scan() is called as part of common SPL framework, so no
+ * need to call it again but in case of powerpc platforms which currently
+ * do not use common SPL framework, so need to call this function here.
+ */
+#if defined(CONFIG_SPL_DM) && (!defined(CONFIG_SPL_FRAMEWORK))
+       dm_init_and_scan(true);
+#endif
+       res = fsl_secboot_validate(hdr_addr, CONFIG_SPL_UBOOT_KEY_HASH,
+                                  &img_addr);
+
+       if (res == 0)
+               printf("SPL: Validation of U-boot successful\n");
+}
+
+#ifdef CONFIG_SPL_FRAMEWORK
+/* Override weak funtion defined in SPL framework to enable validation
+ * of main u-boot image before jumping to u-boot image.
+ */
+void __noreturn jump_to_image_no_args(struct spl_image_info *spl_image)
+{
+       typedef void __noreturn (*image_entry_noargs_t)(void);
+       uint32_t hdr_addr;
+
+       image_entry_noargs_t image_entry =
+               (image_entry_noargs_t)(unsigned long)spl_image->entry_point;
+
+       hdr_addr = (spl_image->entry_point + spl_image->size -
+                       CONFIG_U_BOOT_HDR_SIZE);
+       spl_validate_uboot(hdr_addr, (uintptr_t)spl_image->entry_point);
+       /*
+        * In case of failure in validation, spl_validate_uboot would
+        * not return back in case of Production environment with ITS=1.
+        * Thus U-Boot will not start.
+        * In Development environment (ITS=0 and SB_EN=1), the function
+        * may return back in case of non-fatal failures.
+        */
+
+       debug("image entry point: 0x%lX\n", spl_image->entry_point);
+       image_entry();
+}
+#endif /* ifdef CONFIG_SPL_FRAMEWORK */
+#endif /* ifdef CONFIG_SPL_BUILD */
diff --git a/board/somdevices/common/fsl_validate.c b/board/somdevices/common/fsl_validate.c
new file mode 100644 (file)
index 0000000..2bf9d58
--- /dev/null
@@ -0,0 +1,962 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fsl_validate.h>
+#include <fsl_secboot_err.h>
+#include <fsl_sfp.h>
+#include <fsl_sec.h>
+#include <command.h>
+#include <malloc.h>
+#include <u-boot/rsa-mod-exp.h>
+#include <hash.h>
+#include <fsl_secboot_err.h>
+#ifdef CONFIG_ARCH_LS1021A
+#include <asm/arch/immap_ls102xa.h>
+#endif
+
+#define SHA256_BITS    256
+#define SHA256_BYTES   (256/8)
+#define SHA256_NIBBLES (256/4)
+#define NUM_HEX_CHARS  (sizeof(ulong) * 2)
+
+#define CHECK_KEY_LEN(key_len) (((key_len) == 2 * KEY_SIZE_BYTES / 4) || \
+                                ((key_len) == 2 * KEY_SIZE_BYTES / 2) || \
+                                ((key_len) == 2 * KEY_SIZE_BYTES))
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+/* Global data structure */
+static struct fsl_secboot_glb glb;
+#endif
+
+/* This array contains DER value for SHA-256 */
+static const u8 hash_identifier[] = { 0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60,
+               0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00,
+               0x04, 0x20
+               };
+
+static u8 hash_val[SHA256_BYTES];
+
+#ifdef CONFIG_ESBC_HDR_LS
+/* New Barker Code for LS ESBC Header */
+static const u8 barker_code[ESBC_BARKER_LEN] = { 0x12, 0x19, 0x20, 0x01 };
+#else
+static const u8 barker_code[ESBC_BARKER_LEN] = { 0x68, 0x39, 0x27, 0x81 };
+#endif
+
+void branch_to_self(void) __attribute__ ((noreturn));
+
+/*
+ * This function will put core in infinite loop.
+ * This will be called when the ESBC can not proceed further due
+ * to some unknown errors.
+ */
+void branch_to_self(void)
+{
+       printf("Core is in infinite loop due to errors.\n");
+self:
+       goto self;
+}
+
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+static u32 check_ie(struct fsl_secboot_img_priv *img)
+{
+       if (img->hdr.ie_flag & IE_FLAG_MASK)
+               return 1;
+
+       return 0;
+}
+
+/* This function returns the CSF Header Address of uboot
+ * For MPC85xx based platforms, the LAW mapping for NOR
+ * flash changes in uboot code. Hence the offset needs
+ * to be calculated and added to the new NOR flash base
+ * address
+ */
+#if defined(CONFIG_MPC85xx)
+int get_csf_base_addr(u32 *csf_addr, u32 *flash_base_addr)
+{
+       struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+       u32 csf_hdr_addr = in_be32(&gur->scratchrw[0]);
+       u32 csf_flash_offset = csf_hdr_addr & ~(CONFIG_SYS_PBI_FLASH_BASE);
+       u32 flash_addr, addr;
+       int found = 0;
+       int i = 0;
+
+       for (i = 0; i < CONFIG_SYS_MAX_FLASH_BANKS; i++) {
+               flash_addr = flash_info[i].start[0];
+               addr = flash_info[i].start[0] + csf_flash_offset;
+               if (memcmp((u8 *)addr, barker_code, ESBC_BARKER_LEN) == 0) {
+                       debug("Barker found on addr %x\n", addr);
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               return -1;
+
+       *csf_addr = addr;
+       *flash_base_addr = flash_addr;
+
+       return 0;
+}
+#else
+/* For platforms like LS1020, correct flash address is present in
+ * the header. So the function reqturns flash base address as 0
+ */
+int get_csf_base_addr(u32 *csf_addr, u32 *flash_base_addr)
+{
+       struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+       u32 csf_hdr_addr = in_be32(&gur->scratchrw[0]);
+
+       if (memcmp((u8 *)(uintptr_t)csf_hdr_addr,
+                  barker_code, ESBC_BARKER_LEN))
+               return -1;
+
+       *csf_addr = csf_hdr_addr;
+       *flash_base_addr = 0;
+       return 0;
+}
+#endif
+
+#if defined(CONFIG_ESBC_HDR_LS)
+static int get_ie_info_addr(uintptr_t *ie_addr)
+{
+       struct ccsr_gur __iomem *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+       /* For LS-CH3, the address of IE Table is
+        * stated in Scratch13 and scratch14 of DCFG.
+        * Bootrom validates this table while validating uboot.
+        * DCFG is LE*/
+       *ie_addr = in_le32(&gur->scratchrw[SCRATCH_IE_HIGH_ADR - 1]);
+       *ie_addr = *ie_addr << 32;
+       *ie_addr |= in_le32(&gur->scratchrw[SCRATCH_IE_LOW_ADR - 1]);
+       return 0;
+}
+#else /* CONFIG_ESBC_HDR_LS */
+static int get_ie_info_addr(uintptr_t *ie_addr)
+{
+       struct fsl_secboot_img_hdr *hdr;
+       struct fsl_secboot_sg_table *sg_tbl;
+       u32 flash_base_addr, csf_addr;
+
+       if (get_csf_base_addr(&csf_addr, &flash_base_addr))
+               return -1;
+
+       hdr = (struct fsl_secboot_img_hdr *)(uintptr_t)csf_addr;
+
+       /* For SoC's with Trust Architecture v1 with corenet bus
+        * the sg table field in CSF header has absolute address
+        * for sg table in memory. In other Trust Architecture,
+        * this field specifies the offset of sg table from the
+        * base address of CSF Header
+        */
+#if defined(CONFIG_FSL_TRUST_ARCH_v1) && defined(CONFIG_FSL_CORENET)
+       sg_tbl = (struct fsl_secboot_sg_table *)
+                (((u32)hdr->psgtable & ~(CONFIG_SYS_PBI_FLASH_BASE)) +
+                 flash_base_addr);
+#else
+       sg_tbl = (struct fsl_secboot_sg_table *)(uintptr_t)(csf_addr +
+                                                (u32)hdr->psgtable);
+#endif
+
+       /* IE Key Table is the first entry in the SG Table */
+#if defined(CONFIG_MPC85xx)
+       *ie_addr = (uintptr_t)((sg_tbl->src_addr &
+                       ~(CONFIG_SYS_PBI_FLASH_BASE)) +
+                       flash_base_addr);
+#else
+       *ie_addr = (uintptr_t)sg_tbl->src_addr;
+#endif
+
+       debug("IE Table address is %lx\n", *ie_addr);
+       return 0;
+}
+#endif /* CONFIG_ESBC_HDR_LS */
+#endif
+
+#ifdef CONFIG_KEY_REVOCATION
+/* This function checks srk_table_flag in header and set/reset srk_flag.*/
+static u32 check_srk(struct fsl_secboot_img_priv *img)
+{
+#ifdef CONFIG_ESBC_HDR_LS
+       /* In LS, No SRK Flag as SRK is always present if IE not present*/
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+       return !check_ie(img);
+#endif
+       return 1;
+#else
+       if (img->hdr.len_kr.srk_table_flag & SRK_FLAG)
+               return 1;
+
+       return 0;
+#endif
+}
+
+/* This function returns ospr's key_revoc values.*/
+static u32 get_key_revoc(void)
+{
+       struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+       return (sfp_in32(&sfp_regs->ospr) & OSPR_KEY_REVOC_MASK) >>
+               OSPR_KEY_REVOC_SHIFT;
+}
+
+/* This function checks if selected key is revoked or not.*/
+static u32 is_key_revoked(u32 keynum, u32 rev_flag)
+{
+       if (keynum == UNREVOCABLE_KEY)
+               return 0;
+
+       if ((u32)(1 << (ALIGN_REVOC_KEY - keynum)) & rev_flag)
+               return 1;
+
+       return 0;
+}
+
+/* It read validates srk_table key lengths.*/
+static u32 read_validate_srk_tbl(struct fsl_secboot_img_priv *img)
+{
+       int i = 0;
+       u32 ret, key_num, key_revoc_flag, size;
+       struct fsl_secboot_img_hdr *hdr = &img->hdr;
+       void *esbc = (u8 *)(uintptr_t)img->ehdrloc;
+
+       if ((hdr->len_kr.num_srk == 0) ||
+           (hdr->len_kr.num_srk > MAX_KEY_ENTRIES))
+               return ERROR_ESBC_CLIENT_HEADER_INVALID_SRK_NUM_ENTRY;
+
+       key_num = hdr->len_kr.srk_sel;
+       if (key_num == 0 || key_num > hdr->len_kr.num_srk)
+               return ERROR_ESBC_CLIENT_HEADER_INVALID_KEY_NUM;
+
+       /* Get revoc key from sfp */
+       key_revoc_flag = get_key_revoc();
+       ret = is_key_revoked(key_num, key_revoc_flag);
+       if (ret)
+               return ERROR_ESBC_CLIENT_HEADER_KEY_REVOKED;
+
+       size = hdr->len_kr.num_srk * sizeof(struct srk_table);
+
+       memcpy(&img->srk_tbl, esbc + hdr->srk_tbl_off, size);
+
+       for (i = 0; i < hdr->len_kr.num_srk; i++) {
+               if (!CHECK_KEY_LEN(img->srk_tbl[i].key_len))
+                       return ERROR_ESBC_CLIENT_HEADER_INV_SRK_ENTRY_KEYLEN;
+       }
+
+       img->key_len = img->srk_tbl[key_num - 1].key_len;
+
+       memcpy(&img->img_key, &(img->srk_tbl[key_num - 1].pkey),
+              img->key_len);
+
+       return 0;
+}
+#endif
+
+#ifndef CONFIG_ESBC_HDR_LS
+static u32 read_validate_single_key(struct fsl_secboot_img_priv *img)
+{
+       struct fsl_secboot_img_hdr *hdr = &img->hdr;
+       void *esbc = (u8 *)(uintptr_t)img->ehdrloc;
+
+       /* check key length */
+       if (!CHECK_KEY_LEN(hdr->key_len))
+               return ERROR_ESBC_CLIENT_HEADER_KEY_LEN;
+
+       memcpy(&img->img_key, esbc + hdr->pkey, hdr->key_len);
+
+       img->key_len = hdr->key_len;
+
+       return 0;
+}
+#endif /* CONFIG_ESBC_HDR_LS */
+
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+
+static void install_ie_tbl(uintptr_t ie_tbl_addr,
+               struct fsl_secboot_img_priv *img)
+{
+       /* Copy IE tbl to Global Data */
+       memcpy(&glb.ie_tbl, (u8 *)ie_tbl_addr, sizeof(struct ie_key_info));
+       img->ie_addr = (uintptr_t)&glb.ie_tbl;
+       glb.ie_addr = img->ie_addr;
+}
+
+static u32 read_validate_ie_tbl(struct fsl_secboot_img_priv *img)
+{
+       struct fsl_secboot_img_hdr *hdr = &img->hdr;
+       u32 ie_key_len, ie_revoc_flag, ie_num;
+       struct ie_key_info *ie_info;
+
+       if (!img->ie_addr) {
+               if (get_ie_info_addr(&img->ie_addr))
+                       return ERROR_IE_TABLE_NOT_FOUND;
+               else
+                       install_ie_tbl(img->ie_addr, img);
+               }
+
+       ie_info = (struct ie_key_info *)(uintptr_t)img->ie_addr;
+       if (ie_info->num_keys == 0 || ie_info->num_keys > 32)
+               return ERROR_ESBC_CLIENT_HEADER_INVALID_IE_NUM_ENTRY;
+
+       ie_num = hdr->ie_key_sel;
+       if (ie_num == 0 || ie_num > ie_info->num_keys)
+               return ERROR_ESBC_CLIENT_HEADER_INVALID_IE_KEY_NUM;
+
+       ie_revoc_flag = ie_info->key_revok;
+       if ((u32)(1 << (ie_num - 1)) & ie_revoc_flag)
+               return ERROR_ESBC_CLIENT_HEADER_IE_KEY_REVOKED;
+
+       ie_key_len = ie_info->ie_key_tbl[ie_num - 1].key_len;
+
+       if (!CHECK_KEY_LEN(ie_key_len))
+               return ERROR_ESBC_CLIENT_HEADER_INV_IE_ENTRY_KEYLEN;
+
+       memcpy(&img->img_key, &(ie_info->ie_key_tbl[ie_num - 1].pkey),
+              ie_key_len);
+
+       img->key_len = ie_key_len;
+       return 0;
+}
+#endif
+
+
+/* This function return length of public key.*/
+static inline u32 get_key_len(struct fsl_secboot_img_priv *img)
+{
+       return img->key_len;
+}
+
+/*
+ * Handles the ESBC uboot client header verification failure.
+ * This  function  handles all the errors which might occur in the
+ * parsing and checking of ESBC uboot client header. It will also
+ * set the error bits in the SEC_MON.
+ */
+static void fsl_secboot_header_verification_failure(void)
+{
+       struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+
+       /* 29th bit of OSPR is ITS */
+       u32 its = sfp_in32(&sfp_regs->ospr) >> 2;
+
+       if (its == 1)
+               set_sec_mon_state(HPSR_SSM_ST_SOFT_FAIL);
+       else
+               set_sec_mon_state(HPSR_SSM_ST_NON_SECURE);
+
+       printf("Generating reset request\n");
+       do_reset(NULL, 0, 0, NULL);
+       /* If reset doesn't coocur, halt execution */
+       do_esbc_halt(NULL, 0, 0, NULL);
+}
+
+/*
+ * Handles the ESBC uboot client image verification failure.
+ * This  function  handles all the errors which might occur in the
+ * public key hash comparison and signature verification of
+ * ESBC uboot client image. It will also
+ * set the error bits in the SEC_MON.
+ */
+static void fsl_secboot_image_verification_failure(void)
+{
+       struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+
+       u32 its = (sfp_in32(&sfp_regs->ospr) & ITS_MASK) >> ITS_BIT;
+
+       if (its == 1) {
+               set_sec_mon_state(HPSR_SSM_ST_SOFT_FAIL);
+
+               printf("Generating reset request\n");
+               do_reset(NULL, 0, 0, NULL);
+               /* If reset doesn't coocur, halt execution */
+               do_esbc_halt(NULL, 0, 0, NULL);
+
+       } else {
+               set_sec_mon_state(HPSR_SSM_ST_NON_SECURE);
+       }
+}
+
+static void fsl_secboot_bootscript_parse_failure(void)
+{
+       fsl_secboot_header_verification_failure();
+}
+
+/*
+ * Handles the errors in esbc boot.
+ * This  function  handles all the errors which might occur in the
+ * esbc boot phase. It will call the appropriate api to log the
+ * errors and set the error bits in the SEC_MON.
+ */
+void fsl_secboot_handle_error(int error)
+{
+#ifndef CONFIG_SPL_BUILD
+       const struct fsl_secboot_errcode *e;
+
+       for (e = fsl_secboot_errcodes; e->errcode != ERROR_ESBC_CLIENT_MAX;
+               e++) {
+               if (e->errcode == error)
+                       printf("ERROR :: %x :: %s\n", error, e->name);
+       }
+#else
+       printf("ERROR :: %x\n", error);
+#endif
+
+       /* If Boot Mode is secure, transition the SNVS state and issue
+        * reset based on type of failure and ITS setting.
+        * If Boot mode is non-secure, return from this function.
+        */
+       if (fsl_check_boot_mode_secure() == 0)
+               return;
+
+       switch (error) {
+       case ERROR_ESBC_CLIENT_HEADER_BARKER:
+       case ERROR_ESBC_CLIENT_HEADER_IMG_SIZE:
+       case ERROR_ESBC_CLIENT_HEADER_KEY_LEN:
+       case ERROR_ESBC_CLIENT_HEADER_SIG_LEN:
+       case ERROR_ESBC_CLIENT_HEADER_KEY_LEN_NOT_TWICE_SIG_LEN:
+       case ERROR_ESBC_CLIENT_HEADER_KEY_MOD_1:
+       case ERROR_ESBC_CLIENT_HEADER_KEY_MOD_2:
+       case ERROR_ESBC_CLIENT_HEADER_SIG_KEY_MOD:
+       case ERROR_ESBC_CLIENT_HEADER_SG_ESBC_EP:
+       case ERROR_ESBC_CLIENT_HEADER_SG_ENTIRES_BAD:
+       case ERROR_KEY_TABLE_NOT_FOUND:
+#ifdef CONFIG_KEY_REVOCATION
+       case ERROR_ESBC_CLIENT_HEADER_KEY_REVOKED:
+       case ERROR_ESBC_CLIENT_HEADER_INVALID_SRK_NUM_ENTRY:
+       case ERROR_ESBC_CLIENT_HEADER_INVALID_KEY_NUM:
+       case ERROR_ESBC_CLIENT_HEADER_INV_SRK_ENTRY_KEYLEN:
+#endif
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+       /*@fallthrough@*/
+       case ERROR_ESBC_CLIENT_HEADER_IE_KEY_REVOKED:
+       case ERROR_ESBC_CLIENT_HEADER_INVALID_IE_NUM_ENTRY:
+       case ERROR_ESBC_CLIENT_HEADER_INVALID_IE_KEY_NUM:
+       case ERROR_ESBC_CLIENT_HEADER_INV_IE_ENTRY_KEYLEN:
+       case ERROR_IE_TABLE_NOT_FOUND:
+#endif
+               fsl_secboot_header_verification_failure();
+               break;
+       case ERROR_ESBC_SEC_RESET:
+       case ERROR_ESBC_SEC_DEQ:
+       case ERROR_ESBC_SEC_ENQ:
+       case ERROR_ESBC_SEC_DEQ_TO:
+       case ERROR_ESBC_SEC_JOBQ_STATUS:
+       case ERROR_ESBC_CLIENT_HASH_COMPARE_KEY:
+       case ERROR_ESBC_CLIENT_HASH_COMPARE_EM:
+               fsl_secboot_image_verification_failure();
+               break;
+       case ERROR_ESBC_MISSING_BOOTM:
+               fsl_secboot_bootscript_parse_failure();
+               break;
+       case ERROR_ESBC_WRONG_CMD:
+       default:
+               branch_to_self();
+               break;
+       }
+}
+
+static void fsl_secblk_handle_error(int error)
+{
+       switch (error) {
+       case ERROR_ESBC_SEC_ENQ:
+               fsl_secboot_handle_error(ERROR_ESBC_SEC_ENQ);
+               break;
+       case ERROR_ESBC_SEC_DEQ:
+               fsl_secboot_handle_error(ERROR_ESBC_SEC_DEQ);
+               break;
+       case ERROR_ESBC_SEC_DEQ_TO:
+               fsl_secboot_handle_error(ERROR_ESBC_SEC_DEQ_TO);
+               break;
+       default:
+               printf("Job Queue Output status %x\n", error);
+               fsl_secboot_handle_error(ERROR_ESBC_SEC_JOBQ_STATUS);
+               break;
+       }
+}
+
+/*
+ * Calculate hash of key obtained via offset present in ESBC uboot
+ * client hdr. This function calculates the hash of key which is obtained
+ * through offset present in ESBC uboot client header.
+ */
+static int calc_img_key_hash(struct fsl_secboot_img_priv *img)
+{
+       struct hash_algo *algo;
+       void *ctx;
+       int i, srk = 0;
+       int ret = 0;
+       const char *algo_name = "sha256";
+
+       /* Calculate hash of the esbc key */
+       ret = hash_progressive_lookup_algo(algo_name, &algo);
+       if (ret)
+               return ret;
+
+       ret = algo->hash_init(algo, &ctx);
+       if (ret)
+               return ret;
+
+       /* Update hash for ESBC key */
+#ifdef CONFIG_KEY_REVOCATION
+       if (check_srk(img)) {
+               ret = algo->hash_update(algo, ctx,
+                     (u8 *)(uintptr_t)(img->ehdrloc + img->hdr.srk_tbl_off),
+                     img->hdr.len_kr.num_srk * sizeof(struct srk_table), 1);
+               srk = 1;
+       }
+#endif
+       if (!srk)
+               ret = algo->hash_update(algo, ctx,
+                       img->img_key, img->key_len, 1);
+       if (ret)
+               return ret;
+
+       /* Copy hash at destination buffer */
+       ret = algo->hash_finish(algo, ctx, hash_val, algo->digest_size);
+       if (ret)
+               return ret;
+
+       for (i = 0; i < SHA256_BYTES; i++)
+               img->img_key_hash[i] = hash_val[i];
+
+       return 0;
+}
+
+/*
+ * Calculate hash of ESBC hdr and ESBC. This function calculates the
+ * single hash of ESBC header and ESBC image. If SG flag is on, all
+ * SG entries are also hashed alongwith the complete SG table.
+ */
+static int calc_esbchdr_esbc_hash(struct fsl_secboot_img_priv *img)
+{
+       struct hash_algo *algo;
+       void *ctx;
+       int ret = 0;
+       int key_hash = 0;
+       const char *algo_name = "sha256";
+
+       /* Calculate the hash of the ESBC */
+       ret = hash_progressive_lookup_algo(algo_name, &algo);
+       if (ret)
+               return ret;
+
+       ret = algo->hash_init(algo, &ctx);
+       /* Copy hash at destination buffer */
+       if (ret)
+               return ret;
+
+       /* Update hash for CSF Header */
+       ret = algo->hash_update(algo, ctx,
+               (u8 *)&img->hdr, sizeof(struct fsl_secboot_img_hdr), 0);
+       if (ret)
+               return ret;
+
+       /* Update the hash with that of srk table if srk flag is 1
+        * If IE Table is selected, key is not added in the hash
+        * If neither srk table nor IE key table available, add key
+        * from header in the hash calculation
+        */
+#ifdef CONFIG_KEY_REVOCATION
+       if (check_srk(img)) {
+               ret = algo->hash_update(algo, ctx,
+                     (u8 *)(uintptr_t)(img->ehdrloc + img->hdr.srk_tbl_off),
+                     img->hdr.len_kr.num_srk * sizeof(struct srk_table), 0);
+               key_hash = 1;
+       }
+#endif
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+       if (!key_hash && check_ie(img))
+               key_hash = 1;
+#endif
+#ifndef CONFIG_ESBC_HDR_LS
+/* No single key support in LS ESBC header */
+       if (!key_hash) {
+               ret = algo->hash_update(algo, ctx,
+                       img->img_key, img->hdr.key_len, 0);
+               key_hash = 1;
+       }
+#endif
+       if (ret)
+               return ret;
+       if (!key_hash)
+               return ERROR_KEY_TABLE_NOT_FOUND;
+
+       /* Update hash for actual Image */
+       ret = algo->hash_update(algo, ctx,
+               (u8 *)(*(img->img_addr_ptr)), img->img_size, 1);
+       if (ret)
+               return ret;
+
+       /* Copy hash at destination buffer */
+       ret = algo->hash_finish(algo, ctx, hash_val, algo->digest_size);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * Construct encoded hash EM' wrt PKCSv1.5. This function calculates the
+ * pointers for padding, DER value and hash. And finally, constructs EM'
+ * which includes hash of complete CSF header and ESBC image. If SG flag
+ * is on, hash of SG table and entries is also included.
+ */
+static void construct_img_encoded_hash_second(struct fsl_secboot_img_priv *img)
+{
+       /*
+        * RSA PKCSv1.5 encoding format for encoded message is below
+        * EM = 0x0 || 0x1 || PS || 0x0 || DER || Hash
+        * PS is Padding String
+        * DER is DER value for SHA-256
+        * Hash is SHA-256 hash
+        * *********************************************************
+        * representative points to first byte of EM initially and is
+        * filled with 0x0
+        * representative is incremented by 1 and second byte is filled
+        * with 0x1
+        * padding points to third byte of EM
+        * digest points to full length of EM - 32 bytes
+        * hash_id (DER value) points to 19 bytes before pDigest
+        * separator is one byte which separates padding and DER
+        */
+
+       size_t len;
+       u8 *representative;
+       u8 *padding, *digest;
+       u8 *hash_id, *separator;
+       int i;
+
+       len = (get_key_len(img) / 2) - 1;
+       representative = img->img_encoded_hash_second;
+       representative[0] = 0;
+       representative[1] = 1;  /* block type 1 */
+
+       padding = &representative[2];
+       digest = &representative[1] + len - 32;
+       hash_id = digest - sizeof(hash_identifier);
+       separator = hash_id - 1;
+
+       /* fill padding area pointed by padding with 0xff */
+       memset(padding, 0xff, separator - padding);
+
+       /* fill byte pointed by separator */
+       *separator = 0;
+
+       /* fill SHA-256 DER value  pointed by HashId */
+       memcpy(hash_id, hash_identifier, sizeof(hash_identifier));
+
+       /* fill hash pointed by Digest */
+       for (i = 0; i < SHA256_BYTES; i++)
+               digest[i] = hash_val[i];
+}
+
+/*
+ * Reads and validates the ESBC client header.
+ * This function reads key and signature from the ESBC client header.
+ * If Scatter/Gather flag is on, lengths and offsets of images
+ * present as SG entries are also read. This function also checks
+ * whether the header is valid or not.
+ */
+static int read_validate_esbc_client_header(struct fsl_secboot_img_priv *img)
+{
+       struct fsl_secboot_img_hdr *hdr = &img->hdr;
+       void *esbc = (u8 *)(uintptr_t)img->ehdrloc;
+       u8 *k, *s;
+       u32 ret = 0;
+
+       int  key_found = 0;
+
+       /* check barker code */
+       if (memcmp(hdr->barker, barker_code, ESBC_BARKER_LEN))
+               return ERROR_ESBC_CLIENT_HEADER_BARKER;
+
+       /* If Image Address is not passed as argument to function,
+        * then Address and Size must be read from the Header.
+        */
+       if (*(img->img_addr_ptr) == 0) {
+       #ifdef CONFIG_ESBC_ADDR_64BIT
+               *(img->img_addr_ptr) = hdr->pimg64;
+       #else
+               *(img->img_addr_ptr) = hdr->pimg;
+       #endif
+       }
+
+       if (!hdr->img_size)
+               return ERROR_ESBC_CLIENT_HEADER_IMG_SIZE;
+
+       img->img_size = hdr->img_size;
+
+       /* Key checking*/
+#ifdef CONFIG_KEY_REVOCATION
+       if (check_srk(img)) {
+               ret = read_validate_srk_tbl(img);
+               if (ret != 0)
+                       return ret;
+               key_found = 1;
+       }
+#endif
+
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+       if (!key_found && check_ie(img)) {
+               ret = read_validate_ie_tbl(img);
+               if (ret != 0)
+                       return ret;
+               key_found = 1;
+       }
+#endif
+#ifndef CONFIG_ESBC_HDR_LS
+/* Single Key Feature not available in LS ESBC Header */
+       if (key_found == 0) {
+               ret = read_validate_single_key(img);
+               if (ret != 0)
+                       return ret;
+               key_found = 1;
+       }
+#endif
+       if (!key_found)
+               return ERROR_KEY_TABLE_NOT_FOUND;
+
+       /* check signaure */
+       if (get_key_len(img) == 2 * hdr->sign_len) {
+               /* check signature length */
+               if (!((hdr->sign_len == KEY_SIZE_BYTES / 4) ||
+                     (hdr->sign_len == KEY_SIZE_BYTES / 2) ||
+                     (hdr->sign_len == KEY_SIZE_BYTES)))
+                       return ERROR_ESBC_CLIENT_HEADER_SIG_LEN;
+       } else {
+               return ERROR_ESBC_CLIENT_HEADER_KEY_LEN_NOT_TWICE_SIG_LEN;
+       }
+
+       memcpy(&img->img_sign, esbc + hdr->psign, hdr->sign_len);
+/* No SG support in LS-CH3 */
+#ifndef CONFIG_ESBC_HDR_LS
+       /* No SG support */
+       if (hdr->sg_flag)
+               return ERROR_ESBC_CLIENT_HEADER_SG;
+#endif
+
+       /* modulus most significant bit should be set */
+       k = (u8 *)&img->img_key;
+
+       if ((k[0] & 0x80) == 0)
+               return ERROR_ESBC_CLIENT_HEADER_KEY_MOD_1;
+
+       /* modulus value should be odd */
+       if ((k[get_key_len(img) / 2 - 1] & 0x1) == 0)
+               return ERROR_ESBC_CLIENT_HEADER_KEY_MOD_2;
+
+       /* Check signature value < modulus value */
+       s = (u8 *)&img->img_sign;
+
+       if (!(memcmp(s, k, hdr->sign_len) < 0))
+               return ERROR_ESBC_CLIENT_HEADER_SIG_KEY_MOD;
+
+       return ESBC_VALID_HDR;
+}
+
+static inline int str2longbe(const char *p, ulong *num)
+{
+       char *endptr;
+       ulong tmp;
+
+       if (!p) {
+               return 0;
+       } else {
+               tmp = simple_strtoul(p, &endptr, 16);
+               if (sizeof(ulong) == 4)
+                       *num = cpu_to_be32(tmp);
+               else
+                       *num = cpu_to_be64(tmp);
+       }
+
+       return *p != '\0' && *endptr == '\0';
+}
+/* Function to calculate the ESBC Image Hash
+ * and hash from Digital signature.
+ * The Two hash's are compared to yield the
+ * result of signature validation.
+ */
+static int calculate_cmp_img_sig(struct fsl_secboot_img_priv *img)
+{
+       int ret;
+       uint32_t key_len;
+       struct key_prop prop;
+#if !defined(USE_HOSTCC)
+       struct udevice *mod_exp_dev;
+#endif
+       ret = calc_esbchdr_esbc_hash(img);
+       if (ret)
+               return ret;
+
+       /* Construct encoded hash EM' wrt PKCSv1.5 */
+       construct_img_encoded_hash_second(img);
+
+       /* Fill prop structure for public key */
+       memset(&prop, 0, sizeof(struct key_prop));
+       key_len = get_key_len(img) / 2;
+       prop.modulus = img->img_key;
+       prop.public_exponent = img->img_key + key_len;
+       prop.num_bits = key_len * 8;
+       prop.exp_len = key_len;
+
+       ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev);
+       if (ret) {
+               printf("RSA: Can't find Modular Exp implementation\n");
+               return -EINVAL;
+       }
+
+       ret = rsa_mod_exp(mod_exp_dev, img->img_sign, img->hdr.sign_len,
+                         &prop, img->img_encoded_hash);
+       if (ret)
+               return ret;
+
+       /*
+        * compare the encoded messages EM' and EM wrt RSA PKCSv1.5
+        * memcmp returns zero on success
+        * memcmp returns non-zero on failure
+        */
+       ret = memcmp(&img->img_encoded_hash_second, &img->img_encoded_hash,
+               img->hdr.sign_len);
+
+       if (ret)
+               return ERROR_ESBC_CLIENT_HASH_COMPARE_EM;
+
+       return 0;
+}
+/* Function to initialize img priv and global data structure
+ */
+static int secboot_init(struct fsl_secboot_img_priv **img_ptr)
+{
+       *img_ptr = malloc(sizeof(struct fsl_secboot_img_priv));
+
+       struct fsl_secboot_img_priv *img = *img_ptr;
+
+       if (!img)
+               return -ENOMEM;
+       memset(img, 0, sizeof(struct fsl_secboot_img_priv));
+
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+       if (glb.ie_addr)
+               img->ie_addr = glb.ie_addr;
+#endif
+       return 0;
+}
+
+
+/* haddr - Address of the header of image to be validated.
+ * arg_hash_str - Option hash string. If provided, this
+ * overrides the key hash in the SFP fuses.
+ * img_addr_ptr - Optional pointer to address of image to be validated.
+ * If non zero addr, this overrides the addr of image in header,
+ * otherwise updated to image addr in header.
+ * Acts as both input and output of function.
+ * This pointer shouldn't be NULL.
+ */
+int fsl_secboot_validate(uintptr_t haddr, char *arg_hash_str,
+                       uintptr_t *img_addr_ptr)
+{
+       struct ccsr_sfp_regs *sfp_regs = (void *)(CONFIG_SYS_SFP_ADDR);
+       ulong hash[SHA256_BYTES/sizeof(ulong)];
+       char hash_str[NUM_HEX_CHARS + 1];
+       struct fsl_secboot_img_priv *img;
+       struct fsl_secboot_img_hdr *hdr;
+       void *esbc;
+       int ret, i, hash_cmd = 0;
+       u32 srk_hash[8];
+
+       if (arg_hash_str != NULL) {
+               const char *cp = arg_hash_str;
+               int i = 0;
+
+               if (*cp == '0' && *(cp + 1) == 'x')
+                       cp += 2;
+
+               /* The input string expected is in hex, where
+                * each 4 bits would be represented by a hex
+                * sha256 hash is 256 bits long, which would mean
+                * num of characters = 256 / 4
+                */
+               if (strlen(cp) != SHA256_NIBBLES) {
+                       printf("%s is not a 256 bits hex string as expected\n",
+                              arg_hash_str);
+                       return -1;
+               }
+
+               for (i = 0; i < sizeof(hash)/sizeof(ulong); i++) {
+                       strncpy(hash_str, cp + (i * NUM_HEX_CHARS),
+                               NUM_HEX_CHARS);
+                       hash_str[NUM_HEX_CHARS] = '\0';
+                       if (!str2longbe(hash_str, &hash[i])) {
+                               printf("%s is not a 256 bits hex string ",
+                                      arg_hash_str);
+                               return -1;
+                       }
+               }
+
+               hash_cmd = 1;
+       }
+
+       ret = secboot_init(&img);
+       if (ret)
+               goto exit;
+
+       /* Update the information in Private Struct */
+       hdr = &img->hdr;
+       img->ehdrloc = haddr;
+       img->img_addr_ptr = img_addr_ptr;
+       esbc = (u8 *)img->ehdrloc;
+
+       memcpy(hdr, esbc, sizeof(struct fsl_secboot_img_hdr));
+
+       /* read and validate esbc header */
+       ret = read_validate_esbc_client_header(img);
+
+       if (ret != ESBC_VALID_HDR) {
+               fsl_secboot_handle_error(ret);
+               goto exit;
+       }
+
+       /* SRKH present in SFP */
+       for (i = 0; i < NUM_SRKH_REGS; i++)
+               srk_hash[i] = srk_in32(&sfp_regs->srk_hash[i]);
+
+       /*
+        * Calculate hash of key obtained via offset present in
+        * ESBC uboot client hdr
+        */
+       ret = calc_img_key_hash(img);
+       if (ret) {
+               fsl_secblk_handle_error(ret);
+               goto exit;
+       }
+
+       /* Compare hash obtained above with SRK hash present in SFP */
+       if (hash_cmd)
+               ret = memcmp(&hash, &img->img_key_hash, SHA256_BYTES);
+       else
+               ret = memcmp(srk_hash, img->img_key_hash, SHA256_BYTES);
+
+#if defined(CONFIG_FSL_ISBC_KEY_EXT)
+       if (!hash_cmd && check_ie(img))
+               ret = 0;
+#endif
+
+       if (ret != 0) {
+               fsl_secboot_handle_error(ERROR_ESBC_CLIENT_HASH_COMPARE_KEY);
+               goto exit;
+       }
+
+       ret = calculate_cmp_img_sig(img);
+       if (ret) {
+               fsl_secboot_handle_error(ret);
+               goto exit;
+       }
+
+exit:
+       /* Free Img as it was malloc'ed*/
+       free(img);
+       return ret;
+}
diff --git a/board/somdevices/common/ics307_clk.c b/board/somdevices/common/ics307_clk.c
new file mode 100644 (file)
index 0000000..f1e60cf
--- /dev/null
@@ -0,0 +1,145 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include "ics307_clk.h"
+
+#if defined(CONFIG_FSL_NGPIXIS)
+#include "ngpixis.h"
+#define fpga_reg pixis
+#elif defined(CONFIG_FSL_QIXIS)
+#include "qixis.h"
+#define fpga_reg ((struct qixis *)QIXIS_BASE)
+#else
+#include "pixis.h"
+#define fpga_reg pixis
+#endif
+
+/* define for SYS CLK or CLK1Frequency */
+#define TTL            1
+#define CLK2           0
+#define CRYSTAL                0
+#define MAX_VDW                (511 + 8)
+#define MAX_RDW                (127 + 2)
+#define MIN_VDW                (4 + 8)
+#define MIN_RDW                (1 + 2)
+#define NUM_OD_SETTING 8
+/*
+ * These defines cover the industrial temperature range part,
+ * for commercial, change below to 400000 and 55000, respectively
+ */
+#define MAX_VCO                360000
+#define MIN_VCO                60000
+
+/* decode S[0-2] to Output Divider (OD) */
+static u8 ics307_s_to_od[] = {
+       10, 2, 8, 4, 5, 7, 3, 6
+};
+
+/*
+ * Find one solution to generate required frequency for SYSCLK
+ * out_freq: KHz, required frequency to the SYSCLK
+ * the result will be retuned with component RDW, VDW, OD, TTL,
+ * CLK2 and crystal
+ */
+unsigned long ics307_sysclk_calculator(unsigned long out_freq)
+{
+       const unsigned long input_freq = CONFIG_ICS307_REFCLK_HZ;
+       unsigned long vdw, rdw, odp, s_vdw = 0, s_rdw = 0, s_odp = 0, od;
+       unsigned long tmp_out, diff, result = 0;
+       int found = 0;
+
+       for (odp = 0; odp < NUM_OD_SETTING; odp++) {
+               od = ics307_s_to_od[odp];
+               if (od * out_freq < MIN_VCO || od * out_freq > MAX_VCO)
+                       continue;
+               for (rdw = MIN_RDW; rdw <= MAX_RDW; rdw++) {
+                       /* Calculate the VDW */
+                       vdw = out_freq * 1000 * od * rdw / (input_freq * 2);
+                       if (vdw > MAX_VDW)
+                               vdw = MAX_VDW;
+                       if (vdw < MIN_VDW)
+                               continue;
+                       /* Calculate the temp out frequency */
+                       tmp_out = input_freq * 2 * vdw / (rdw * od * 1000);
+                       diff = max(out_freq, tmp_out) - min(out_freq, tmp_out);
+                       /*
+                        * calculate the percent, the precision is 1/1000
+                        * If greater than 1/1000, continue
+                        * otherwise, we think the solution is we required
+                        */
+                       if (diff * 1000 / out_freq > 1)
+                               continue;
+                       else {
+                               s_vdw = vdw;
+                               s_rdw = rdw;
+                               s_odp = odp;
+                               found = 1;
+                               break;
+                       }
+               }
+       }
+
+       if (found)
+               result = (s_rdw - 2) | (s_vdw - 8) << 7 | s_odp << 16 |
+                       CLK2 << 19 | TTL << 21 | CRYSTAL << 22;
+
+       debug("ICS307-02: RDW: %ld, VDW: %ld, OD: %d\n", s_rdw - 2, s_vdw - 8,
+                       ics307_s_to_od[s_odp]);
+       return result;
+}
+
+/*
+ * Calculate frequency being generated by ICS307-02 clock chip based upon
+ * the control bytes being programmed into it.
+ */
+static unsigned long ics307_clk_freq(u8 cw0, u8 cw1, u8 cw2)
+{
+       const unsigned long input_freq = CONFIG_ICS307_REFCLK_HZ;
+       unsigned long vdw = ((cw1 << 1) & 0x1FE) + ((cw2 >> 7) & 1);
+       unsigned long rdw = cw2 & 0x7F;
+       unsigned long od = ics307_s_to_od[cw0 & 0x7];
+       unsigned long freq;
+
+       /*
+        * CLK1 Freq = Input Frequency * 2 * (VDW + 8) / ((RDW + 2) * OD)
+        *
+        * cw0:  C1 C0 TTL F1 F0 S2 S1 S0
+        * cw1:  V8 V7 V6 V5 V4 V3 V2 V1
+        * cw2:  V0 R6 R5 R4 R3 R2 R1 R0
+        *
+        * R6:R0 = Reference Divider Word (RDW)
+        * V8:V0 = VCO Divider Word (VDW)
+        * S2:S0 = Output Divider Select (OD)
+        * F1:F0 = Function of CLK2 Output
+        * TTL = duty cycle
+        * C1:C0 = internal load capacitance for cyrstal
+        *
+        */
+
+       freq = input_freq * 2 * (vdw + 8) / ((rdw + 2) * od);
+
+       debug("ICS307: CW[0-2]: %02X %02X %02X => %lu Hz\n", cw0, cw1, cw2,
+                       freq);
+       return freq;
+}
+
+unsigned long get_board_sys_clk(void)
+{
+       return ics307_clk_freq(
+                       in_8(&fpga_reg->sclk[0]),
+                       in_8(&fpga_reg->sclk[1]),
+                       in_8(&fpga_reg->sclk[2]));
+}
+
+unsigned long get_board_ddr_clk(void)
+{
+       return ics307_clk_freq(
+                       in_8(&fpga_reg->dclk[0]),
+                       in_8(&fpga_reg->dclk[1]),
+                       in_8(&fpga_reg->dclk[2]));
+}
diff --git a/board/somdevices/common/ics307_clk.h b/board/somdevices/common/ics307_clk.h
new file mode 100644 (file)
index 0000000..81d1aa7
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2010-2011 Freescale Semiconductor, Inc.
+ */
+#ifndef __ICS_CLK_H_
+#define __ICS_CLK_H_   1
+
+#ifndef __ASSEMBLY__
+
+extern unsigned long get_board_sys_clk(void);
+extern unsigned long get_board_ddr_clk(void);
+extern unsigned long ics307_sysclk_calculator(unsigned long out_freq);
+#endif
+
+#endif /* __ICS_CLK_H_ */
diff --git a/board/somdevices/common/idt8t49n222a_serdes_clk.c b/board/somdevices/common/idt8t49n222a_serdes_clk.c
new file mode 100644 (file)
index 0000000..4f8e8b7
--- /dev/null
@@ -0,0 +1,206 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ * Author: Shaveta Leekha <shaveta@freescale.com>
+ */
+
+#include "idt8t49n222a_serdes_clk.h"
+
+#define DEVICE_ID_REG          0x00
+
+static int check_pll_status(u8 idt_addr)
+{
+       u8 val = 0;
+       int ret;
+
+       ret = i2c_read(idt_addr, 0x17, 1, &val, 1);
+       if (ret < 0) {
+               printf("IDT:0x%x could not read status register from device.\n",
+                       idt_addr);
+               return ret;
+       }
+
+       if (val & 0x04) {
+               debug("idt8t49n222a PLL is LOCKED: %x\n", val);
+       } else {
+               printf("idt8t49n222a PLL is not LOCKED: %x\n", val);
+               return -1;
+       }
+
+       return 0;
+}
+
+int set_serdes_refclk(u8 idt_addr, u8 serdes_num,
+                       enum serdes_refclk refclk1,
+                       enum serdes_refclk refclk2, u8 feedback)
+{
+       u8 dev_id = 0;
+       int i, ret;
+
+       debug("IDT:Configuring idt8t49n222a device at I2C address: 0x%2x\n",
+               idt_addr);
+
+       ret = i2c_read(idt_addr, DEVICE_ID_REG, 1, &dev_id, 1);
+       if (ret < 0) {
+               debug("IDT:0x%x could not read DEV_ID from device.\n",
+                       idt_addr);
+               return ret;
+       }
+
+       if ((dev_id != 0x00) && (dev_id != 0x24) && (dev_id != 0x2a)) {
+               debug("IDT: device at address 0x%x is not idt8t49n222a.\n",
+                       idt_addr);
+       }
+
+       if (serdes_num != 1 && serdes_num != 2) {
+               debug("serdes_num should be 1 for SerDes1 and"
+                       " 2 for SerDes2.\n");
+               return -1;
+       }
+
+       if ((refclk1 == SERDES_REFCLK_122_88 && refclk2 != SERDES_REFCLK_122_88)
+               || (refclk1 != SERDES_REFCLK_122_88
+                       && refclk2 == SERDES_REFCLK_122_88)) {
+               debug("Only one refclk at 122.88MHz is not supported."
+                       " Please set both refclk1 & refclk2 to 122.88MHz"
+                       " or both not to 122.88MHz.\n");
+               return -1;
+       }
+
+       if (refclk1 != SERDES_REFCLK_100 && refclk1 != SERDES_REFCLK_122_88
+                                       && refclk1 != SERDES_REFCLK_125
+                                       && refclk1 != SERDES_REFCLK_156_25) {
+               debug("refclk1 should be 100MHZ, 122.88MHz, 125MHz"
+                       " or 156.25MHz.\n");
+               return -1;
+       }
+
+       if (refclk2 != SERDES_REFCLK_100 && refclk2 != SERDES_REFCLK_122_88
+                                       && refclk2 != SERDES_REFCLK_125
+                                       && refclk2 != SERDES_REFCLK_156_25) {
+               debug("refclk2 should be 100MHZ, 122.88MHz, 125MHz"
+                       " or 156.25MHz.\n");
+               return -1;
+       }
+
+       if (feedback != 0 && feedback != 1) {
+               debug("valid values for feedback are 0(default) or 1.\n");
+               return -1;
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 122.88MHz  Refclk2 = 122.88MHz
+        */
+       if (refclk1 == SERDES_REFCLK_122_88 &&
+                       refclk2 == SERDES_REFCLK_122_88) {
+               printf("Setting refclk1:122.88 and refclk2:122.88\n");
+               for (i = 0; i < NUM_IDT_REGS; i++)
+                       i2c_reg_write(idt_addr, idt_conf_122_88[i][0],
+                                               idt_conf_122_88[i][1]);
+
+               if (feedback) {
+                       for (i = 0; i < NUM_IDT_REGS_FEEDBACK; i++)
+                               i2c_reg_write(idt_addr,
+                                       idt_conf_122_88_feedback[i][0],
+                                       idt_conf_122_88_feedback[i][1]);
+               }
+       }
+
+       if (refclk1 != SERDES_REFCLK_122_88 &&
+                       refclk2 != SERDES_REFCLK_122_88) {
+               for (i = 0; i < NUM_IDT_REGS; i++)
+                       i2c_reg_write(idt_addr, idt_conf_not_122_88[i][0],
+                                               idt_conf_not_122_88[i][1]);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 100MHz  Refclk2 = 125MHz
+        */
+       if (refclk1 == SERDES_REFCLK_100 && refclk2 == SERDES_REFCLK_125) {
+               printf("Setting refclk1:100 and refclk2:125\n");
+               i2c_reg_write(idt_addr, 0x11, 0x10);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 125MHz  Refclk2 = 125MHz
+        */
+       if (refclk1 == SERDES_REFCLK_125 && refclk2 == SERDES_REFCLK_125) {
+               printf("Setting refclk1:125 and refclk2:125\n");
+               i2c_reg_write(idt_addr, 0x10, 0x10);
+               i2c_reg_write(idt_addr, 0x11, 0x10);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 125MHz  Refclk2 = 100MHz
+        */
+       if (refclk1 == SERDES_REFCLK_125 && refclk2 == SERDES_REFCLK_100) {
+               printf("Setting refclk1:125 and refclk2:100\n");
+               i2c_reg_write(idt_addr, 0x10, 0x10);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 156.25MHz  Refclk2 = 156.25MHz
+        */
+       if (refclk1 == SERDES_REFCLK_156_25 &&
+                       refclk2 == SERDES_REFCLK_156_25) {
+               printf("Setting refclk1:156.25 and refclk2:156.25\n");
+               for (i = 0; i < NUM_IDT_REGS_156_25; i++)
+                       i2c_reg_write(idt_addr, idt_conf_156_25[i][0],
+                                               idt_conf_156_25[i][1]);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 100MHz  Refclk2 = 156.25MHz
+        */
+       if (refclk1 == SERDES_REFCLK_100 &&
+                       refclk2 == SERDES_REFCLK_156_25) {
+               printf("Setting refclk1:100 and refclk2:156.25\n");
+               for (i = 0; i < NUM_IDT_REGS_156_25; i++)
+                       i2c_reg_write(idt_addr, idt_conf_100_156_25[i][0],
+                                               idt_conf_100_156_25[i][1]);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 125MHz  Refclk2 = 156.25MHz
+        */
+       if (refclk1 == SERDES_REFCLK_125 &&
+                       refclk2 == SERDES_REFCLK_156_25) {
+               printf("Setting refclk1:125 and refclk2:156.25\n");
+               for (i = 0; i < NUM_IDT_REGS_156_25; i++)
+                       i2c_reg_write(idt_addr, idt_conf_125_156_25[i][0],
+                                               idt_conf_125_156_25[i][1]);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 156.25MHz  Refclk2 = 100MHz
+        */
+       if (refclk1 == SERDES_REFCLK_156_25 &&
+                       refclk2 == SERDES_REFCLK_100) {
+               printf("Setting refclk1:156.25 and refclk2:100\n");
+               for (i = 0; i < NUM_IDT_REGS_156_25; i++)
+                       i2c_reg_write(idt_addr, idt_conf_156_25_100[i][0],
+                                               idt_conf_156_25_100[i][1]);
+       }
+
+       /* Configuring IDT for output refclks as
+        * Refclk1 = 156.25MHz  Refclk2 = 125MHz
+        */
+       if (refclk1 == SERDES_REFCLK_156_25 &&
+                       refclk2 == SERDES_REFCLK_125) {
+               printf("Setting refclk1:156.25 and refclk2:125\n");
+               for (i = 0; i < NUM_IDT_REGS_156_25; i++)
+                       i2c_reg_write(idt_addr, idt_conf_156_25_125[i][0],
+                                               idt_conf_156_25_125[i][1]);
+       }
+
+       /* waiting for maximum of 1 second if PLL doesn'r get locked
+        * initially. then check the status again.
+        */
+       if (check_pll_status(idt_addr)) {
+               mdelay(1000);
+               if (check_pll_status(idt_addr))
+                       return -1;
+       }
+
+       return 0;
+}
diff --git a/board/somdevices/common/idt8t49n222a_serdes_clk.h b/board/somdevices/common/idt8t49n222a_serdes_clk.h
new file mode 100644 (file)
index 0000000..b1528e3
--- /dev/null
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ * Author: Shaveta Leekha <shaveta@freescale.com>
+ */
+
+#ifndef __IDT8T49N222A_SERDES_CLK_H_
+#define __IDT8T49N222A_SERDES_CLK_H_   1
+
+#include <common.h>
+#include <i2c.h>
+#include "qixis.h"
+#include "../b4860qds/b4860qds_qixis.h"
+#include <errno.h>
+
+#define NUM_IDT_REGS           23
+#define NUM_IDT_REGS_FEEDBACK  12
+#define NUM_IDT_REGS_156_25    11
+
+/* CLK */
+enum serdes_refclk {
+       SERDES_REFCLK_100,      /* refclk 100Mhz */
+       SERDES_REFCLK_122_88,   /* refclk 122.88Mhz */
+       SERDES_REFCLK_125,      /* refclk 125Mhz */
+       SERDES_REFCLK_156_25,   /* refclk 156.25Mhz */
+       SERDES_REFCLK_NONE = -1,
+};
+
+/* configuration values for IDT registers for Output Refclks:
+ * Refclk1 = 122.88MHz Refclk2 = 122.88MHz
+ */
+static const u8 idt_conf_122_88[23][2] = { {0x00, 0x3C}, {0x01, 0x00},
+               {0x02, 0x9F}, {0x03, 0x00}, {0x04, 0x0B}, {0x05, 0x00},
+               {0x06, 0x00}, {0x07, 0x00}, {0x08, 0x7D}, {0x09, 0x00},
+               {0x0A, 0x08}, {0x0B, 0x00}, {0x0C, 0xDC}, {0x0D, 0x00},
+               {0x0E, 0x00}, {0x0F, 0x00}, {0x10, 0x12}, {0x11, 0x12},
+               {0x12, 0xB9}, {0x13, 0xBC}, {0x14, 0x40}, {0x15, 0x08},
+               {0x16, 0xA0} };
+
+
+/* configuration values for IDT registers for Output Refclks:
+ * Refclk1 not equal to 122.88MHz Refclk2 not equal to 122.88MHz
+ */
+static const u8 idt_conf_not_122_88[23][2] = { {0x00, 0x00}, {0x01, 0x00},
+               {0x02, 0x00}, {0x03, 0x00}, {0x04, 0x0A}, {0x05, 0x00},
+               {0x06, 0x00}, {0x07, 0x00}, {0x08, 0x7D}, {0x09, 0x00},
+               {0x0A, 0x08}, {0x0B, 0x00}, {0x0C, 0xDC}, {0x0D, 0x00},
+               {0x0E, 0x00}, {0x0F, 0x00}, {0x10, 0x14}, {0x11, 0x14},
+               {0x12, 0x35}, {0x13, 0xBC}, {0x14, 0x40}, {0x15, 0x08},
+               {0x16, 0xA0} };
+
+/* Reconfiguration values for some of IDT registers for
+ * Output Refclks:
+ * Refclk1 = 122.88MHz Refclk2 = 122.88MHz
+ * and with feedback as 1
+ */
+static const u8 idt_conf_122_88_feedback[12][2] = { {0x00, 0x50}, {0x02, 0xD7},
+               {0x04, 0x89}, {0x06, 0xC3}, {0x08, 0xC0}, {0x0A, 0x07},
+               {0x0C, 0x80}, {0x10, 0x10}, {0x11, 0x10}, {0x12, 0x1B},
+               {0x14, 0x00}, {0x15, 0xE8} };
+
+/* configuration values for IDT registers for Output Refclks:
+ * Refclk1 : 156.25MHz Refclk2 : 156.25MHz
+ */
+static const u8 idt_conf_156_25[11][2] = { {0x04, 0x19}, {0x06, 0x03},
+               {0x08, 0xC0}, {0x0A, 0x07}, {0x0C, 0xA1}, {0x0E, 0x20},
+               {0x10, 0x10}, {0x11, 0x10}, {0x12, 0xB5}, {0x13, 0x3C},
+               {0x15, 0xE8} };
+
+/* configuration values for IDT registers for Output Refclks:
+ * Refclk1 : 100MHz Refclk2 : 156.25MHz
+ */
+static const u8 idt_conf_100_156_25[11][2] = { {0x04, 0x19}, {0x06, 0x03},
+               {0x08, 0xC0}, {0x0A, 0x07}, {0x0C, 0xA1}, {0x0E, 0x20},
+               {0x10, 0x19}, {0x11, 0x10}, {0x12, 0xB5}, {0x13, 0x3C},
+               {0x15, 0xE8} };
+
+/* configuration values for IDT registers for Output Refclks:
+ * Refclk1 : 125MHz Refclk2 : 156.25MHz
+ */
+static const u8 idt_conf_125_156_25[11][2] = { {0x04, 0x19}, {0x06, 0x03},
+               {0x08, 0xC0}, {0x0A, 0x07}, {0x0C, 0xA1}, {0x0E, 0x20},
+               {0x10, 0x14}, {0x11, 0x10}, {0x12, 0xB5}, {0x13, 0x3C},
+               {0x15, 0xE8} };
+
+/* configuration values for IDT registers for Output Refclks:
+ * Refclk1 : 156.25MHz Refclk2 : 100MHz
+ */
+static const u8 idt_conf_156_25_100[11][2] = { {0x04, 0x19}, {0x06, 0x03},
+               {0x08, 0xC0}, {0x0A, 0x07}, {0x0C, 0xA1}, {0x0E, 0x20},
+               {0x10, 0x10}, {0x11, 0x19}, {0x12, 0xB5}, {0x13, 0x3C},
+               {0x15, 0xE8} };
+
+/* configuration values for IDT registers for Output Refclks:
+ * Refclk1 : 156.25MHz Refclk2 : 125MHz
+ */
+static const u8 idt_conf_156_25_125[11][2] = { {0x04, 0x19}, {0x06, 0x03},
+               {0x08, 0xC0}, {0x0A, 0x07}, {0x0C, 0xA1}, {0x0E, 0x20},
+               {0x10, 0x10}, {0x11, 0x14}, {0x12, 0xB5}, {0x13, 0x3C},
+               {0x15, 0xE8} };
+
+int set_serdes_refclk(u8 idt_addr, u8 serdes_num,
+                       enum serdes_refclk refclk1,
+                       enum serdes_refclk refclk2, u8 feedback);
+
+#endif /*__IDT8T49N222A_SERDES_CLK_H_ */
diff --git a/board/somdevices/common/ls102xa_stream_id.c b/board/somdevices/common/ls102xa_stream_id.c
new file mode 100644 (file)
index 0000000..a6ee87d
--- /dev/null
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/ls102xa_stream_id.h>
+
+void ls102xa_config_smmu_stream_id(struct smmu_stream_id *id, uint32_t num)
+{
+       void *scfg = (void *)CONFIG_SYS_FSL_SCFG_ADDR;
+       int i;
+       u32 icid;
+
+       for (i = 0; i < num; i++) {
+               icid = (id[i].stream_id & 0xff) << 24;
+               out_be32((u32 *)(scfg + id[i].offset), icid);
+       }
+}
+
+void ls1021x_config_caam_stream_id(struct liodn_id_table *tbl, int size)
+{
+       int i;
+       u32 liodn;
+
+       for (i = 0; i < size; i++) {
+               if (tbl[i].num_ids == 2)
+                       liodn = (tbl[i].id[0] << 16) | tbl[i].id[1];
+               else
+                       liodn = tbl[i].id[0];
+
+               out_le32((u32 *)(tbl[i].reg_offset), liodn);
+       }
+}
diff --git a/board/somdevices/common/mc34vr500.c b/board/somdevices/common/mc34vr500.c
new file mode 100644 (file)
index 0000000..d4f0f0c
--- /dev/null
@@ -0,0 +1,94 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2016 Freescale Semiconductor, Inc.
+ * Hou Zhiqiang <Zhiqiang.Hou@freescale.com>
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <i2c.h>
+#include <power/pmic.h>
+#include <power/mc34vr500_pmic.h>
+
+static uint8_t swxvolt_addr[4] = { MC34VR500_SW1VOLT,
+                                  MC34VR500_SW2VOLT,
+                                  MC34VR500_SW3VOLT,
+                                  MC34VR500_SW4VOLT };
+
+static uint8_t swx_set_point_base[4] = { 13, 9, 9, 9 };
+
+int mc34vr500_get_sw_volt(uint8_t sw)
+{
+       struct pmic *p;
+       u32 swxvolt;
+       uint8_t spb;
+       int sw_volt;
+       int ret;
+
+       debug("%s: Get SW%u volt from swxvolt_addr = 0x%x\n",
+             __func__, sw + 1, swxvolt_addr[sw]);
+       if (sw > SW4) {
+               printf("%s: Unsupported SW(sw%d)\n", __func__, sw + 1);
+               return -EINVAL;
+       }
+
+       p = pmic_get("MC34VR500");
+       if (!p) {
+               printf("%s: Did NOT find PMIC MC34VR500\n", __func__);
+               return -ENODEV;
+       }
+
+       ret = pmic_probe(p);
+       if (ret)
+               return ret;
+
+       ret = pmic_reg_read(p, swxvolt_addr[sw], &swxvolt);
+       if (ret) {
+               printf("%s: Failed to get SW%u volt\n", __func__, sw + 1);
+               return ret;
+       }
+
+       debug("%s: SW%d step point swxvolt = %u\n", __func__, sw + 1, swxvolt);
+       spb = swx_set_point_base[sw];
+       /* The base of SW volt is 625mV and increase by step 25mV */
+       sw_volt = 625 + (swxvolt - spb) * 25;
+
+       debug("%s: SW%u volt = %dmV\n", __func__, sw + 1, sw_volt);
+       return sw_volt;
+}
+
+int mc34vr500_set_sw_volt(uint8_t sw, int sw_volt)
+{
+       struct pmic *p;
+       u32 swxvolt;
+       uint8_t spb;
+       int ret;
+
+       debug("%s: Set SW%u volt to %dmV\n", __func__, sw + 1, sw_volt);
+       /* The least SW volt is 625mV, and only 4 SW outputs */
+       if (sw > SW4 || sw_volt < 625)
+               return -EINVAL;
+
+       p = pmic_get("MC34VR500");
+       if (!p) {
+               printf("%s: Did NOT find PMIC MC34VR500\n", __func__);
+               return -ENODEV;
+       }
+
+       ret = pmic_probe(p);
+       if (ret)
+               return ret;
+
+       spb = swx_set_point_base[sw];
+       /* The base of SW volt is 625mV and increase by step 25mV */
+       swxvolt = (sw_volt - 625) / 25 + spb;
+       debug("%s: SW%d step point swxvolt = %u\n", __func__, sw + 1, swxvolt);
+       if (swxvolt > 63)
+               return -EINVAL;
+
+       ret = pmic_reg_write(p, swxvolt_addr[sw], swxvolt);
+       if (ret)
+               return ret;
+
+       return 0;
+}
diff --git a/board/somdevices/common/mmc.c b/board/somdevices/common/mmc.c
new file mode 100644 (file)
index 0000000..d886808
--- /dev/null
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2018 NXP
+ */
+#include <common.h>
+#include <asm/arch/sys_proto.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <stdbool.h>
+#include <mmc.h>
+
+static int check_mmc_autodetect(void)
+{
+       char *autodetect_str = env_get("mmcautodetect");
+
+       if ((autodetect_str != NULL) &&
+               (strcmp(autodetect_str, "yes") == 0)) {
+               return 1;
+       }
+
+       return 0;
+}
+
+/* This should be defined for each board */
+__weak int mmc_map_to_kernel_blk(int dev_no)
+{
+       return dev_no;
+}
+
+void board_late_mmc_env_init(void)
+{
+       char cmd[32];
+       char mmcblk[32];
+       u32 dev_no = mmc_get_env_dev();
+
+       if (!check_mmc_autodetect())
+               return;
+
+       env_set_ulong("mmcdev", dev_no);
+
+       /* Set mmcblk env */
+       sprintf(mmcblk, "/dev/mmcblk%dp2 rootwait rw",
+               mmc_map_to_kernel_blk(dev_no));
+       env_set("mmcroot", mmcblk);
+
+       sprintf(cmd, "mmc dev %d", dev_no);
+       run_command(cmd, 0);
+}
diff --git a/board/somdevices/common/mpc85xx_sleep.c b/board/somdevices/common/mpc85xx_sleep.c
new file mode 100644 (file)
index 0000000..739a416
--- /dev/null
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <asm/immap_85xx.h>
+#include "sleep.h"
+#ifdef CONFIG_U_QE
+#include <fsl_qe.h>
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void __weak board_mem_sleep_setup(void)
+{
+}
+
+void __weak board_sleep_prepare(void)
+{
+}
+
+bool is_warm_boot(void)
+{
+       struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_MPC85xx_GUTS_ADDR;
+
+       if (in_be32(&gur->scrtsr[0]) & DCFG_CCSR_CRSTSR_WDRFR)
+               return 1;
+
+       return 0;
+}
+
+void fsl_dp_disable_console(void)
+{
+       gd->flags |= GD_FLG_SILENT | GD_FLG_DISABLE_CONSOLE;
+}
+
+/*
+ * When wakeup from deep sleep, the first 128 bytes space
+ * will be used to do DDR training which corrupts the data
+ * in there. This function will restore them.
+ */
+static void dp_ddr_restore(void)
+{
+       u64 *src, *dst;
+       int i;
+       struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_MPC85xx_SCFG;
+
+       /* get the address of ddr date from SPARECR3 */
+       src = (u64 *)(in_be32(&scfg->sparecr[2]) + DDR_BUFF_LEN - 8);
+       dst = (u64 *)(CONFIG_SYS_SDRAM_BASE + DDR_BUFF_LEN - 8);
+
+       for (i = 0; i < DDR_BUFF_LEN / 8; i++)
+               *dst-- = *src--;
+
+       flush_dcache();
+}
+
+static void dp_resume_prepare(void)
+{
+       dp_ddr_restore();
+
+       board_sleep_prepare();
+
+       l2cache_init();
+#if defined(CONFIG_RAMBOOT_PBL)
+       disable_cpc_sram();
+#endif
+       enable_cpc();
+
+#ifdef CONFIG_U_QE
+       u_qe_resume();
+#endif
+
+}
+
+int fsl_dp_resume(void)
+{
+       u32 start_addr;
+       void (*kernel_resume)(void);
+       struct ccsr_scfg __iomem *scfg = (void *)CONFIG_SYS_MPC85xx_SCFG;
+
+       if (!is_warm_boot())
+               return 0;
+
+       dp_resume_prepare();
+
+       /* Get the entry address and jump to kernel */
+       start_addr = in_be32(&scfg->sparecr[1]);
+       debug("Entry address is 0x%08x\n", start_addr);
+       kernel_resume = (void (*)(void))start_addr;
+       kernel_resume();
+
+       return 0;
+}
diff --git a/board/somdevices/common/ngpixis.c b/board/somdevices/common/ngpixis.c
new file mode 100644 (file)
index 0000000..d725401
--- /dev/null
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * Copyright 2010-2011 Freescale Semiconductor
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * This file provides support for the ngPIXIS, a board-specific FPGA used on
+ * some Freescale reference boards.
+ *
+ * A "switch" is black rectangular block on the motherboard.  It contains
+ * eight "bits".  The ngPIXIS has a set of memory-mapped registers (SWx) that
+ * shadow the actual physical switches.  There is also another set of
+ * registers (ENx) that tell the ngPIXIS which bits of SWx should actually be
+ * used to override the values of the bits in the physical switches.
+ *
+ * The following macros need to be defined:
+ *
+ * PIXIS_BASE - The virtual address of the base of the PIXIS register map
+ *
+ * PIXIS_LBMAP_SWITCH - The switch number (i.e. the "x" in "SWx"). This value
+ *    is used in the PIXIS_SW() macro to determine which offset in
+ *    the PIXIS register map corresponds to the physical switch that controls
+ *    the boot bank.
+ *
+ * PIXIS_LBMAP_MASK - A bit mask the defines which bits in SWx to use.
+ *
+ * PIXIS_LBMAP_SHIFT - The shift value that corresponds to PIXIS_LBMAP_MASK.
+ *
+ * PIXIS_LBMAP_ALTBANK - The value to program into SWx to tell the ngPIXIS to
+ *    boot from the alternate bank.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+#include "ngpixis.h"
+
+static u8 __pixis_read(unsigned int reg)
+{
+       void *p = (void *)PIXIS_BASE;
+
+       return in_8(p + reg);
+}
+u8 pixis_read(unsigned int reg) __attribute__((weak, alias("__pixis_read")));
+
+static void __pixis_write(unsigned int reg, u8 value)
+{
+       void *p = (void *)PIXIS_BASE;
+
+       out_8(p + reg, value);
+}
+void pixis_write(unsigned int reg, u8 value)
+       __attribute__((weak, alias("__pixis_write")));
+
+/*
+ * Reset the board. This ignores the ENx registers.
+ */
+void __pixis_reset(void)
+{
+       PIXIS_WRITE(rst, 0);
+
+       while (1);
+}
+void pixis_reset(void) __attribute__((weak, alias("__pixis_reset")));
+
+/*
+ * Reset the board.  Like pixis_reset(), but it honors the ENx registers.
+ */
+void __pixis_bank_reset(void)
+{
+       PIXIS_WRITE(vctl, 0);
+       PIXIS_WRITE(vctl, 1);
+
+       while (1);
+}
+void pixis_bank_reset(void) __attribute__((weak, alias("__pixis_bank_reset")));
+
+/**
+ * Set the boot bank to the power-on default bank
+ */
+void __clear_altbank(void)
+{
+       u8 reg;
+
+       /* Tell the ngPIXIS to use this the bits in the physical switch for the
+        * boot bank value, instead of the SWx register.  We need to be careful
+        * only to set the bits in SWx that correspond to the boot bank.
+        */
+       reg = PIXIS_READ(s[PIXIS_LBMAP_SWITCH - 1].en);
+       reg &= ~PIXIS_LBMAP_MASK;
+       PIXIS_WRITE(s[PIXIS_LBMAP_SWITCH - 1].en, reg);
+}
+void clear_altbank(void) __attribute__((weak, alias("__clear_altbank")));
+
+/**
+ * Set the boot bank to the alternate bank
+ */
+void __set_altbank(void)
+{
+       u8 reg;
+
+       /* Program the alternate bank number into the SWx register.
+        */
+       reg = PIXIS_READ(s[PIXIS_LBMAP_SWITCH - 1].sw);
+       reg = (reg & ~PIXIS_LBMAP_MASK) | PIXIS_LBMAP_ALTBANK;
+       PIXIS_WRITE(s[PIXIS_LBMAP_SWITCH - 1].sw, reg);
+
+       /* Tell the ngPIXIS to use this the bits in the SWx register for the
+        * boot bank value, instead of the physical switch.  We need to be
+        * careful only to set the bits in SWx that correspond to the boot bank.
+        */
+       reg = PIXIS_READ(s[PIXIS_LBMAP_SWITCH - 1].en);
+       reg |= PIXIS_LBMAP_MASK;
+       PIXIS_WRITE(s[PIXIS_LBMAP_SWITCH - 1].en, reg);
+}
+void set_altbank(void) __attribute__((weak, alias("__set_altbank")));
+
+#ifdef DEBUG
+static void pixis_dump_regs(void)
+{
+       unsigned int i;
+
+       printf("id=%02x\n", PIXIS_READ(id));
+       printf("arch=%02x\n", PIXIS_READ(arch));
+       printf("scver=%02x\n", PIXIS_READ(scver));
+       printf("csr=%02x\n", PIXIS_READ(csr));
+       printf("rst=%02x\n", PIXIS_READ(rst));
+       printf("aux=%02x\n", PIXIS_READ(aux));
+       printf("spd=%02x\n", PIXIS_READ(spd));
+       printf("brdcfg0=%02x\n", PIXIS_READ(brdcfg0));
+       printf("brdcfg1=%02x\n", PIXIS_READ(brdcfg1));
+       printf("addr=%02x\n", PIXIS_READ(addr));
+       printf("data=%02x\n", PIXIS_READ(data));
+       printf("led=%02x\n", PIXIS_READ(led));
+       printf("vctl=%02x\n", PIXIS_READ(vctl));
+       printf("vstat=%02x\n", PIXIS_READ(vstat));
+       printf("vcfgen0=%02x\n", PIXIS_READ(vcfgen0));
+       printf("ocmcsr=%02x\n", PIXIS_READ(ocmcsr));
+       printf("ocmmsg=%02x\n", PIXIS_READ(ocmmsg));
+       printf("gmdbg=%02x\n", PIXIS_READ(gmdbg));
+       printf("sclk=%02x%02x%02x\n",
+              PIXIS_READ(sclk[0]), PIXIS_READ(sclk[1]), PIXIS_READ(sclk[2]));
+       printf("dclk=%02x%02x%02x\n",
+              PIXIS_READ(dclk[0]), PIXIS_READ(dclk[1]), PIXIS_READ(dclk[2]));
+       printf("watch=%02x\n", PIXIS_READ(watch));
+
+       for (i = 0; i < 8; i++) {
+               printf("SW%u=%02x/%02x ", i + 1,
+                       PIXIS_READ(s[i].sw), PIXIS_READ(s[i].en));
+       }
+       putc('\n');
+}
+#endif
+
+void pixis_sysclk_set(unsigned long sysclk)
+{
+       unsigned long freq_word;
+       u8 sclk0, sclk1, sclk2;
+
+       freq_word = ics307_sysclk_calculator(sysclk);
+       sclk2 = freq_word & 0xff;
+       sclk1 = (freq_word >> 8) & 0xff;
+       sclk0 = (freq_word >> 16) & 0xff;
+
+       /* set SYSCLK enable bit */
+       PIXIS_WRITE(vcfgen0, 0x01);
+
+       /* SYSCLK to required frequency */
+       PIXIS_WRITE(sclk[0], sclk0);
+       PIXIS_WRITE(sclk[1], sclk1);
+       PIXIS_WRITE(sclk[2], sclk2);
+}
+
+int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       unsigned int i;
+       unsigned long sysclk;
+       char *p_altbank = NULL;
+#ifdef DEBUG
+       char *p_dump = NULL;
+#endif
+       char *unknown_param = NULL;
+
+       /* No args is a simple reset request.
+        */
+       if (argc <= 1)
+               pixis_reset();
+
+       for (i = 1; i < argc; i++) {
+               if (strcmp(argv[i], "altbank") == 0) {
+                       p_altbank = argv[i];
+                       continue;
+               }
+
+#ifdef DEBUG
+               if (strcmp(argv[i], "dump") == 0) {
+                       p_dump = argv[i];
+                       continue;
+               }
+#endif
+               if (strcmp(argv[i], "sysclk") == 0) {
+                       sysclk = simple_strtoul(argv[i + 1], NULL, 0);
+                       i += 1;
+                       pixis_sysclk_set(sysclk);
+                       continue;
+               }
+
+               unknown_param = argv[i];
+       }
+
+       if (unknown_param) {
+               printf("Invalid option: %s\n", unknown_param);
+               return 1;
+       }
+
+#ifdef DEBUG
+       if (p_dump) {
+               pixis_dump_regs();
+
+               /* 'dump' ignores other commands */
+               return 0;
+       }
+#endif
+
+       if (p_altbank)
+               set_altbank();
+       else
+               clear_altbank();
+
+       pixis_bank_reset();
+
+       /* Shouldn't be reached. */
+       return 0;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char pixis_help_text[] =
+       "- hard reset to default bank\n"
+       "pixis_reset altbank - reset to alternate bank\n"
+#ifdef DEBUG
+       "pixis_reset dump - display the PIXIS registers\n"
+#endif
+       "pixis_reset sysclk <SYSCLK_freq> - reset with SYSCLK frequency(KHz)\n";
+#endif
+
+U_BOOT_CMD(
+       pixis_reset, CONFIG_SYS_MAXARGS, 1, pixis_reset_cmd,
+       "Reset the board using the FPGA sequencer", pixis_help_text
+       );
diff --git a/board/somdevices/common/ngpixis.h b/board/somdevices/common/ngpixis.h
new file mode 100644 (file)
index 0000000..7a20ee0
--- /dev/null
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/**
+ * Copyright 2010-2011 Freescale Semiconductor
+ * Author: Timur Tabi <timur@freescale.com>
+ *
+ * This file provides support for the ngPIXIS, a board-specific FPGA used on
+ * some Freescale reference boards.
+ */
+
+/* ngPIXIS register set. Hopefully, this won't change too much over time.
+ * Feel free to add board-specific #ifdefs where necessary.
+ */
+typedef struct ngpixis {
+       u8 id;
+       u8 arch;
+       u8 scver;
+       u8 csr;
+       u8 rst;
+       u8 serclk;
+       u8 aux;
+       u8 spd;
+       u8 brdcfg0;
+       u8 brdcfg1;     /* On some boards, this register is called 'dma' */
+       u8 addr;
+       u8 brdcfg2;
+       u8 gpiodir;
+       u8 data;
+       u8 led;
+       u8 tag;
+       u8 vctl;
+       u8 vstat;
+       u8 vcfgen0;
+       u8 res4;
+       u8 ocmcsr;
+       u8 ocmmsg;
+       u8 gmdbg;
+       u8 res5[2];
+       u8 sclk[3];
+       u8 dclk[3];
+       u8 watch;
+       struct {
+               u8 sw;
+               u8 en;
+       } s[9];         /* s[0]..s[7] is SW1..SW8, and s[8] is SW11 */
+} __attribute__ ((packed)) ngpixis_t;
+
+/* Pointer to the PIXIS register set */
+#define pixis ((ngpixis_t *)PIXIS_BASE)
+
+/* The PIXIS SW register that corresponds to board switch X, where x >= 1 */
+#define PIXIS_SW(x)            (pixis->s[(x) - 1].sw)
+
+/* The PIXIS EN register that corresponds to board switch X, where x >= 1 */
+#define PIXIS_EN(x)            (pixis->s[(x) - 1].en)
+
+u8 pixis_read(unsigned int reg);
+void pixis_write(unsigned int reg, u8 value);
+
+#define PIXIS_READ(reg) pixis_read(offsetof(ngpixis_t, reg))
+#define PIXIS_WRITE(reg, value) pixis_write(offsetof(ngpixis_t, reg), value)
diff --git a/board/somdevices/common/ns_access.c b/board/somdevices/common/ns_access.c
new file mode 100644 (file)
index 0000000..0e6f213
--- /dev/null
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <fsl_csu.h>
+#include <asm/arch/ns_access.h>
+#include <asm/arch/fsl_serdes.h>
+
+#ifdef CONFIG_ARCH_LS1021A
+static struct csu_ns_dev ns_dev[] = {
+       { CSU_CSLX_PCIE2_IO, CSU_ALL_RW },
+       { CSU_CSLX_PCIE1_IO, CSU_ALL_RW },
+       { CSU_CSLX_MG2TPR_IP, CSU_ALL_RW },
+       { CSU_CSLX_IFC_MEM, CSU_ALL_RW },
+       { CSU_CSLX_OCRAM, CSU_ALL_RW },
+       { CSU_CSLX_GIC, CSU_ALL_RW },
+       { CSU_CSLX_PCIE1, CSU_ALL_RW },
+       { CSU_CSLX_OCRAM2, CSU_ALL_RW },
+       { CSU_CSLX_QSPI_MEM, CSU_ALL_RW },
+       { CSU_CSLX_PCIE2, CSU_ALL_RW },
+       { CSU_CSLX_SATA, CSU_ALL_RW },
+       { CSU_CSLX_USB3, CSU_ALL_RW },
+       { CSU_CSLX_SERDES, CSU_ALL_RW },
+       { CSU_CSLX_QDMA, CSU_ALL_RW },
+       { CSU_CSLX_LPUART2, CSU_ALL_RW },
+       { CSU_CSLX_LPUART1, CSU_ALL_RW },
+       { CSU_CSLX_LPUART4, CSU_ALL_RW },
+       { CSU_CSLX_LPUART3, CSU_ALL_RW },
+       { CSU_CSLX_LPUART6, CSU_ALL_RW },
+       { CSU_CSLX_LPUART5, CSU_ALL_RW },
+       { CSU_CSLX_DSPI2, CSU_ALL_RW },
+       { CSU_CSLX_DSPI1, CSU_ALL_RW },
+       { CSU_CSLX_QSPI, CSU_ALL_RW },
+       { CSU_CSLX_ESDHC, CSU_ALL_RW },
+       { CSU_CSLX_2D_ACE, CSU_ALL_RW },
+       { CSU_CSLX_IFC, CSU_ALL_RW },
+       { CSU_CSLX_I2C1, CSU_ALL_RW },
+       { CSU_CSLX_USB2, CSU_ALL_RW },
+       { CSU_CSLX_I2C3, CSU_ALL_RW },
+       { CSU_CSLX_I2C2, CSU_ALL_RW },
+       { CSU_CSLX_DUART2, CSU_ALL_RW },
+       { CSU_CSLX_DUART1, CSU_ALL_RW },
+       { CSU_CSLX_WDT2, CSU_ALL_RW },
+       { CSU_CSLX_WDT1, CSU_ALL_RW },
+       { CSU_CSLX_EDMA, CSU_ALL_RW },
+       { CSU_CSLX_SYS_CNT, CSU_ALL_RW },
+       { CSU_CSLX_DMA_MUX2, CSU_ALL_RW },
+       { CSU_CSLX_DMA_MUX1, CSU_ALL_RW },
+       { CSU_CSLX_DDR, CSU_ALL_RW },
+       { CSU_CSLX_QUICC, CSU_ALL_RW },
+       { CSU_CSLX_DCFG_CCU_RCPM, CSU_ALL_RW },
+       { CSU_CSLX_SECURE_BOOTROM, CSU_ALL_RW },
+       { CSU_CSLX_SFP, CSU_ALL_RW },
+       { CSU_CSLX_TMU, CSU_ALL_RW },
+       { CSU_CSLX_SECURE_MONITOR, CSU_ALL_RW },
+       { CSU_CSLX_RESERVED0, CSU_ALL_RW },
+       { CSU_CSLX_ETSEC1, CSU_ALL_RW },
+       { CSU_CSLX_SEC5_5, CSU_ALL_RW },
+       { CSU_CSLX_ETSEC3, CSU_ALL_RW },
+       { CSU_CSLX_ETSEC2, CSU_ALL_RW },
+       { CSU_CSLX_GPIO2, CSU_ALL_RW },
+       { CSU_CSLX_GPIO1, CSU_ALL_RW },
+       { CSU_CSLX_GPIO4, CSU_ALL_RW },
+       { CSU_CSLX_GPIO3, CSU_ALL_RW },
+       { CSU_CSLX_PLATFORM_CONT, CSU_ALL_RW },
+       { CSU_CSLX_CSU, CSU_ALL_RW },
+       { CSU_CSLX_ASRC, CSU_ALL_RW },
+       { CSU_CSLX_SPDIF, CSU_ALL_RW },
+       { CSU_CSLX_FLEXCAN2, CSU_ALL_RW },
+       { CSU_CSLX_FLEXCAN1, CSU_ALL_RW },
+       { CSU_CSLX_FLEXCAN4, CSU_ALL_RW },
+       { CSU_CSLX_FLEXCAN3, CSU_ALL_RW },
+       { CSU_CSLX_SAI2, CSU_ALL_RW },
+       { CSU_CSLX_SAI1, CSU_ALL_RW },
+       { CSU_CSLX_SAI4, CSU_ALL_RW },
+       { CSU_CSLX_SAI3, CSU_ALL_RW },
+       { CSU_CSLX_FTM2, CSU_ALL_RW },
+       { CSU_CSLX_FTM1, CSU_ALL_RW },
+       { CSU_CSLX_FTM4, CSU_ALL_RW },
+       { CSU_CSLX_FTM3, CSU_ALL_RW },
+       { CSU_CSLX_FTM6, CSU_ALL_RW },
+       { CSU_CSLX_FTM5, CSU_ALL_RW },
+       { CSU_CSLX_FTM8, CSU_ALL_RW },
+       { CSU_CSLX_FTM7, CSU_ALL_RW },
+       { CSU_CSLX_COP_DCSR, CSU_ALL_RW },
+       { CSU_CSLX_EPU, CSU_ALL_RW },
+       { CSU_CSLX_GDI, CSU_ALL_RW },
+       { CSU_CSLX_DDI, CSU_ALL_RW },
+       { CSU_CSLX_RESERVED1, CSU_ALL_RW },
+       { CSU_CSLX_USB3_PHY, CSU_ALL_RW },
+       { CSU_CSLX_RESERVED2, CSU_ALL_RW },
+};
+
+#else
+static struct csu_ns_dev ns_dev[] = {
+        {CSU_CSLX_PCIE2_IO, CSU_ALL_RW},
+        {CSU_CSLX_PCIE1_IO, CSU_ALL_RW},
+        {CSU_CSLX_MG2TPR_IP, CSU_ALL_RW},
+        {CSU_CSLX_IFC_MEM, CSU_ALL_RW},
+        {CSU_CSLX_OCRAM, CSU_ALL_RW},
+        {CSU_CSLX_GIC, CSU_ALL_RW},
+        {CSU_CSLX_PCIE1, CSU_ALL_RW},
+        {CSU_CSLX_OCRAM2, CSU_ALL_RW},
+        {CSU_CSLX_QSPI_MEM, CSU_ALL_RW},
+        {CSU_CSLX_PCIE2, CSU_ALL_RW},
+        {CSU_CSLX_SATA, CSU_ALL_RW},
+        {CSU_CSLX_USB1, CSU_ALL_RW},
+        {CSU_CSLX_QM_BM_SWPORTAL, CSU_ALL_RW},
+        {CSU_CSLX_PCIE3, CSU_ALL_RW},
+        {CSU_CSLX_PCIE3_IO, CSU_ALL_RW},
+        {CSU_CSLX_USB3, CSU_ALL_RW},
+        {CSU_CSLX_USB2, CSU_ALL_RW},
+        {CSU_CSLX_PFE, CSU_ALL_RW},
+        {CSU_CSLX_SERDES, CSU_ALL_RW},
+        {CSU_CSLX_QDMA, CSU_ALL_RW},
+        {CSU_CSLX_LPUART2, CSU_ALL_RW},
+        {CSU_CSLX_LPUART1, CSU_ALL_RW},
+        {CSU_CSLX_LPUART4, CSU_ALL_RW},
+        {CSU_CSLX_LPUART3, CSU_ALL_RW},
+        {CSU_CSLX_LPUART6, CSU_ALL_RW},
+        {CSU_CSLX_LPUART5, CSU_ALL_RW},
+        {CSU_CSLX_DSPI1, CSU_ALL_RW},
+        {CSU_CSLX_QSPI, CSU_ALL_RW},
+        {CSU_CSLX_ESDHC, CSU_ALL_RW},
+        {CSU_CSLX_IFC, CSU_ALL_RW},
+        {CSU_CSLX_I2C1, CSU_ALL_RW},
+        {CSU_CSLX_I2C3, CSU_ALL_RW},
+        {CSU_CSLX_I2C2, CSU_ALL_RW},
+        {CSU_CSLX_DUART2, CSU_ALL_RW},
+        {CSU_CSLX_DUART1, CSU_ALL_RW},
+        {CSU_CSLX_WDT2, CSU_ALL_RW},
+        {CSU_CSLX_WDT1, CSU_ALL_RW},
+        {CSU_CSLX_EDMA, CSU_ALL_RW},
+        {CSU_CSLX_SYS_CNT, CSU_ALL_RW},
+        {CSU_CSLX_DMA_MUX2, CSU_ALL_RW},
+        {CSU_CSLX_DMA_MUX1, CSU_ALL_RW},
+        {CSU_CSLX_DDR, CSU_ALL_RW},
+        {CSU_CSLX_QUICC, CSU_ALL_RW},
+        {CSU_CSLX_DCFG_CCU_RCPM, CSU_ALL_RW},
+        {CSU_CSLX_SECURE_BOOTROM, CSU_ALL_RW},
+        {CSU_CSLX_SFP, CSU_ALL_RW},
+        {CSU_CSLX_TMU, CSU_ALL_RW},
+        {CSU_CSLX_SECURE_MONITOR, CSU_ALL_RW},
+        {CSU_CSLX_SCFG, CSU_ALL_RW},
+        {CSU_CSLX_FM, CSU_ALL_RW},
+        {CSU_CSLX_SEC5_5, CSU_ALL_RW},
+        {CSU_CSLX_BM, CSU_ALL_RW},
+        {CSU_CSLX_QM, CSU_ALL_RW},
+        {CSU_CSLX_GPIO2, CSU_ALL_RW},
+        {CSU_CSLX_GPIO1, CSU_ALL_RW},
+        {CSU_CSLX_GPIO4, CSU_ALL_RW},
+        {CSU_CSLX_GPIO3, CSU_ALL_RW},
+        {CSU_CSLX_PLATFORM_CONT, CSU_ALL_RW},
+        {CSU_CSLX_CSU, CSU_ALL_RW},
+        {CSU_CSLX_IIC4, CSU_ALL_RW},
+        {CSU_CSLX_WDT4, CSU_ALL_RW},
+        {CSU_CSLX_WDT3, CSU_ALL_RW},
+        {CSU_CSLX_ESDHC2, CSU_ALL_RW},
+        {CSU_CSLX_WDT5, CSU_ALL_RW},
+        {CSU_CSLX_SAI2, CSU_ALL_RW},
+        {CSU_CSLX_SAI1, CSU_ALL_RW},
+        {CSU_CSLX_SAI4, CSU_ALL_RW},
+        {CSU_CSLX_SAI3, CSU_ALL_RW},
+        {CSU_CSLX_FTM2, CSU_ALL_RW},
+        {CSU_CSLX_FTM1, CSU_ALL_RW},
+        {CSU_CSLX_FTM4, CSU_ALL_RW},
+        {CSU_CSLX_FTM3, CSU_ALL_RW},
+        {CSU_CSLX_FTM6, CSU_ALL_RW},
+        {CSU_CSLX_FTM5, CSU_ALL_RW},
+        {CSU_CSLX_FTM8, CSU_ALL_RW},
+        {CSU_CSLX_FTM7, CSU_ALL_RW},
+        {CSU_CSLX_DSCR, CSU_ALL_RW},
+};
+#endif
+
+void set_devices_ns_access(unsigned long index, u16 val)
+{
+       u32 *base = (u32 *)CONFIG_SYS_FSL_CSU_ADDR;
+       u32 *reg;
+       uint32_t tmp;
+
+       reg = base + index / 2;
+       tmp = in_be32(reg);
+       if (index % 2 == 0) {
+               tmp &= 0x0000ffff;
+               tmp |= val << 16;
+       } else {
+               tmp &= 0xffff0000;
+               tmp |= val;
+       }
+
+       out_be32(reg, tmp);
+}
+
+static void enable_devices_ns_access(struct csu_ns_dev *ns_dev, uint32_t num)
+{
+       int i;
+
+       for (i = 0; i < num; i++)
+               set_devices_ns_access(ns_dev[i].ind, ns_dev[i].val);
+}
+
+void enable_layerscape_ns_access(void)
+{
+#ifdef CONFIG_ARM64
+       if (current_el() == 3)
+#endif
+               enable_devices_ns_access(ns_dev, ARRAY_SIZE(ns_dev));
+}
+
+void set_pcie_ns_access(int pcie, u16 val)
+{
+       switch (pcie) {
+#ifdef CONFIG_PCIE1
+       case PCIE1:
+               set_devices_ns_access(CSU_CSLX_PCIE1, val);
+               set_devices_ns_access(CSU_CSLX_PCIE1_IO, val);
+               return;
+#endif
+#ifdef CONFIG_PCIE2
+       case PCIE2:
+               set_devices_ns_access(CSU_CSLX_PCIE2, val);
+               set_devices_ns_access(CSU_CSLX_PCIE2_IO, val);
+               return;
+#endif
+#ifdef CONFIG_PCIE3
+       case PCIE3:
+               set_devices_ns_access(CSU_CSLX_PCIE3, val);
+               set_devices_ns_access(CSU_CSLX_PCIE3_IO, val);
+               return;
+#endif
+       default:
+               debug("The PCIE%d doesn't exist!\n", pcie);
+               return;
+       }
+}
diff --git a/board/somdevices/common/p_corenet/Makefile b/board/somdevices/common/p_corenet/Makefile
new file mode 100644 (file)
index 0000000..29c9d54
--- /dev/null
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# (C) Copyright 2002-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+
+obj-y                  += law.o
+obj-$(CONFIG_PCI)      += pci.o
+obj-y                  += tlb.o
diff --git a/board/somdevices/common/p_corenet/law.c b/board/somdevices/common/p_corenet/law.c
new file mode 100644 (file)
index 0000000..603384a
--- /dev/null
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <asm/fsl_law.h>
+#include <asm/mmu.h>
+
+struct law_entry law_table[] = {
+       SET_LAW(CONFIG_SYS_FLASH_BASE_PHYS, LAW_SIZE_256M, LAW_TRGT_IF_LBC),
+#ifdef CONFIG_SYS_BMAN_MEM_PHYS
+       SET_LAW(CONFIG_SYS_BMAN_MEM_PHYS, LAW_SIZE_2M, LAW_TRGT_IF_BMAN),
+#endif
+#ifdef CONFIG_SYS_QMAN_MEM_PHYS
+       SET_LAW(CONFIG_SYS_QMAN_MEM_PHYS, LAW_SIZE_2M, LAW_TRGT_IF_QMAN),
+#endif
+#ifdef PIXIS_BASE_PHYS
+       SET_LAW(PIXIS_BASE_PHYS, LAW_SIZE_4K, LAW_TRGT_IF_LBC),
+#endif
+#ifdef CPLD_BASE_PHYS
+       SET_LAW(CPLD_BASE_PHYS, LAW_SIZE_4K, LAW_TRGT_IF_LBC),
+#endif
+#ifdef CONFIG_SYS_DCSRBAR_PHYS
+       /* Limit DCSR to 32M to access NPC Trace Buffer */
+       SET_LAW(CONFIG_SYS_DCSRBAR_PHYS, LAW_SIZE_32M, LAW_TRGT_IF_DCSR),
+#endif
+#ifdef CONFIG_SYS_NAND_BASE_PHYS
+       SET_LAW(CONFIG_SYS_NAND_BASE_PHYS, LAW_SIZE_1M, LAW_TRGT_IF_LBC),
+#endif
+};
+
+int num_law_entries = ARRAY_SIZE(law_table);
diff --git a/board/somdevices/common/p_corenet/pci.c b/board/somdevices/common/p_corenet/pci.c
new file mode 100644 (file)
index 0000000..a2df928
--- /dev/null
@@ -0,0 +1,22 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2007-2011 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <pci.h>
+#include <asm/fsl_pci.h>
+#include <linux/libfdt.h>
+#include <fdt_support.h>
+#include <asm/fsl_serdes.h>
+
+void pci_init_board(void)
+{
+       fsl_pcie_init_board(0);
+}
+
+void pci_of_setup(void *blob, bd_t *bd)
+{
+       FT_FSL_PCI_SETUP;
+}
diff --git a/board/somdevices/common/p_corenet/tlb.c b/board/somdevices/common/p_corenet/tlb.c
new file mode 100644 (file)
index 0000000..3d9459b
--- /dev/null
@@ -0,0 +1,160 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2008-2011 Freescale Semiconductor, Inc.
+ *
+ * (C) Copyright 2000
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ */
+
+#include <common.h>
+#include <asm/mmu.h>
+
+struct fsl_e_tlb_entry tlb_table[] = {
+       /* TLB 0 - for temp stack in cache */
+       SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR,
+                     CONFIG_SYS_INIT_RAM_ADDR_PHYS,
+                     MAS3_SW|MAS3_SR, 0,
+                     0, 0, BOOKE_PAGESZ_4K, 0),
+       SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 4 * 1024,
+                     CONFIG_SYS_INIT_RAM_ADDR_PHYS + 4 * 1024,
+                     MAS3_SW|MAS3_SR, 0,
+                     0, 0, BOOKE_PAGESZ_4K, 0),
+       SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 8 * 1024,
+                     CONFIG_SYS_INIT_RAM_ADDR_PHYS + 8 * 1024,
+                     MAS3_SW|MAS3_SR, 0,
+                     0, 0, BOOKE_PAGESZ_4K, 0),
+       SET_TLB_ENTRY(0, CONFIG_SYS_INIT_RAM_ADDR + 12 * 1024,
+                     CONFIG_SYS_INIT_RAM_ADDR_PHYS + 12 * 1024,
+                     MAS3_SW|MAS3_SR, 0,
+                     0, 0, BOOKE_PAGESZ_4K, 0),
+#ifdef CPLD_BASE
+       SET_TLB_ENTRY(0, CPLD_BASE, CPLD_BASE_PHYS,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 0, BOOKE_PAGESZ_4K, 0),
+#endif
+
+#ifdef PIXIS_BASE
+       SET_TLB_ENTRY(0, PIXIS_BASE, PIXIS_BASE_PHYS,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 0, BOOKE_PAGESZ_4K, 0),
+#endif
+
+       /* TLB 1 */
+       /* *I*** - Covers boot page */
+#if defined(CONFIG_SYS_RAMBOOT) && defined(CONFIG_SYS_INIT_L3_ADDR)
+
+#if !defined(CONFIG_SECURE_BOOT)
+       /*
+        * *I*G - L3SRAM. When L3 is used as 1M SRAM, the address of the
+        * SRAM is at 0xfff00000, it covered the 0xfffff000.
+        */
+       SET_TLB_ENTRY(1, CONFIG_SYS_INIT_L3_ADDR, CONFIG_SYS_INIT_L3_ADDR,
+                       MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                       0, 0, BOOKE_PAGESZ_1M, 1),
+#else
+       /*
+        * *I*G - L3SRAM. When L3 is used as 1M SRAM, in case of Secure Boot
+        * the physical address of the SRAM is at CONFIG_SYS_INIT_L3_ADDR,
+        * and virtual address is CONFIG_SYS_MONITOR_BASE
+        */
+
+       SET_TLB_ENTRY(1, CONFIG_SYS_MONITOR_BASE & 0xfff00000,
+                       CONFIG_SYS_INIT_L3_ADDR & 0xfff00000,
+                       MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                       0, 0, BOOKE_PAGESZ_1M, 1),
+#endif
+
+#elif defined(CONFIG_SRIO_PCIE_BOOT_SLAVE)
+       /*
+        * SRIO_PCIE_BOOT-SLAVE. When slave boot, the address of the
+        * space is at 0xfff00000, it covered the 0xfffff000.
+        */
+       SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR,
+                       CONFIG_SYS_SRIO_PCIE_BOOT_SLAVE_ADDR_PHYS,
+                       MAS3_SX|MAS3_SW|MAS3_SR, MAS2_W|MAS2_G,
+                       0, 0, BOOKE_PAGESZ_1M, 1),
+#else
+       SET_TLB_ENTRY(1, 0xfffff000, 0xfffff000,
+                     MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 0, BOOKE_PAGESZ_4K, 1),
+#endif
+
+       /* *I*G* - CCSRBAR */
+       SET_TLB_ENTRY(1, CONFIG_SYS_CCSRBAR, CONFIG_SYS_CCSRBAR_PHYS,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 1, BOOKE_PAGESZ_16M, 1),
+
+       /* *I*G* - Flash, localbus */
+       /* This will be changed to *I*G* after relocation to RAM. */
+       SET_TLB_ENTRY(1, CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH_BASE_PHYS,
+                     MAS3_SX|MAS3_SR, MAS2_W|MAS2_G,
+                     0, 2, BOOKE_PAGESZ_256M, 1),
+
+       /* *I*G* - PCI */
+       SET_TLB_ENTRY(1, CONFIG_SYS_PCIE1_MEM_VIRT, CONFIG_SYS_PCIE1_MEM_PHYS,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 3, BOOKE_PAGESZ_1G, 1),
+
+       /* *I*G* - PCI */
+       SET_TLB_ENTRY(1, CONFIG_SYS_PCIE1_MEM_VIRT + 0x40000000,
+                     CONFIG_SYS_PCIE1_MEM_PHYS + 0x40000000,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 4, BOOKE_PAGESZ_256M, 1),
+
+       SET_TLB_ENTRY(1, CONFIG_SYS_PCIE1_MEM_VIRT + 0x50000000,
+                     CONFIG_SYS_PCIE1_MEM_PHYS + 0x50000000,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 5, BOOKE_PAGESZ_256M, 1),
+
+       /* *I*G* - PCI I/O */
+       SET_TLB_ENTRY(1, CONFIG_SYS_PCIE1_IO_VIRT, CONFIG_SYS_PCIE1_IO_PHYS,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 6, BOOKE_PAGESZ_256K, 1),
+
+       /* Bman/Qman */
+#ifdef CONFIG_SYS_BMAN_MEM_PHYS
+       SET_TLB_ENTRY(1, CONFIG_SYS_BMAN_MEM_BASE, CONFIG_SYS_BMAN_MEM_PHYS,
+                     MAS3_SW|MAS3_SR, 0,
+                     0, 9, BOOKE_PAGESZ_1M, 1),
+       SET_TLB_ENTRY(1, CONFIG_SYS_BMAN_MEM_BASE + 0x00100000,
+                     CONFIG_SYS_BMAN_MEM_PHYS + 0x00100000,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 10, BOOKE_PAGESZ_1M, 1),
+#endif
+#ifdef CONFIG_SYS_QMAN_MEM_PHYS
+       SET_TLB_ENTRY(1, CONFIG_SYS_QMAN_MEM_BASE, CONFIG_SYS_QMAN_MEM_PHYS,
+                     MAS3_SW|MAS3_SR, 0,
+                     0, 11, BOOKE_PAGESZ_1M, 1),
+       SET_TLB_ENTRY(1, CONFIG_SYS_QMAN_MEM_BASE + 0x00100000,
+                     CONFIG_SYS_QMAN_MEM_PHYS + 0x00100000,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 12, BOOKE_PAGESZ_1M, 1),
+#endif
+#ifdef CONFIG_SYS_DCSRBAR_PHYS
+       SET_TLB_ENTRY(1, CONFIG_SYS_DCSRBAR, CONFIG_SYS_DCSRBAR_PHYS,
+                     MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                     0, 13, BOOKE_PAGESZ_4M, 1),
+#endif
+#ifdef CONFIG_SYS_NAND_BASE
+       /*
+        * *I*G - NAND
+        * entry 14 and 15 has been used hard coded, they will be disabled
+        * in cpu_init_f, so we use entry 16 for nand.
+        */
+       SET_TLB_ENTRY(1, CONFIG_SYS_NAND_BASE, CONFIG_SYS_NAND_BASE_PHYS,
+                       MAS3_SX|MAS3_SW|MAS3_SR, MAS2_I|MAS2_G,
+                       0, 16, BOOKE_PAGESZ_1M, 1),
+#endif
+#ifdef CONFIG_SRIO_PCIE_BOOT_SLAVE
+       /*
+        * SRIO_PCIE_BOOT-SLAVE. 1M space from 0xffe00000 for
+        * fetching ucode and ENV from master
+        */
+       SET_TLB_ENTRY(1, CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR,
+               CONFIG_SYS_SRIO_PCIE_BOOT_UCODE_ENV_ADDR_PHYS,
+               MAS3_SX|MAS3_SW|MAS3_SR, MAS2_G,
+               0, 17, BOOKE_PAGESZ_1M, 1),
+#endif
+};
+
+int num_tlb_entries = ARRAY_SIZE(tlb_table);
diff --git a/board/somdevices/common/pfuze.c b/board/somdevices/common/pfuze.c
new file mode 100644 (file)
index 0000000..03ebe4e
--- /dev/null
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <power/pmic.h>
+#include <power/pfuze100_pmic.h>
+
+#ifndef CONFIG_DM_PMIC_PFUZE100
+int pfuze_mode_init(struct pmic *p, u32 mode)
+{
+       unsigned char offset, i, switch_num;
+       u32 id;
+       int ret;
+
+       pmic_reg_read(p, PFUZE100_DEVICEID, &id);
+       id = id & 0xf;
+
+       if (id == 0) {
+               switch_num = 6;
+               offset = PFUZE100_SW1CMODE;
+       } else if (id == 1) {
+               switch_num = 4;
+               offset = PFUZE100_SW2MODE;
+       } else {
+               printf("Not supported, id=%d\n", id);
+               return -EINVAL;
+       }
+
+       ret = pmic_reg_write(p, PFUZE100_SW1ABMODE, mode);
+       if (ret < 0) {
+               printf("Set SW1AB mode error!\n");
+               return ret;
+       }
+
+       for (i = 0; i < switch_num - 1; i++) {
+               ret = pmic_reg_write(p, offset + i * SWITCH_SIZE, mode);
+               if (ret < 0) {
+                       printf("Set switch 0x%x mode error!\n",
+                              offset + i * SWITCH_SIZE);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+struct pmic *pfuze_common_init(unsigned char i2cbus)
+{
+       struct pmic *p;
+       int ret;
+       unsigned int reg;
+
+       ret = power_pfuze100_init(i2cbus);
+       if (ret)
+               return NULL;
+
+       p = pmic_get("PFUZE100");
+       ret = pmic_probe(p);
+       if (ret)
+               return NULL;
+
+       pmic_reg_read(p, PFUZE100_DEVICEID, &reg);
+       printf("PMIC:  PFUZE100 ID=0x%02x\n", reg);
+
+       /* Set SW1AB stanby volage to 0.975V */
+       pmic_reg_read(p, PFUZE100_SW1ABSTBY, &reg);
+       reg &= ~SW1x_STBY_MASK;
+       reg |= SW1x_0_975V;
+       pmic_reg_write(p, PFUZE100_SW1ABSTBY, reg);
+
+       /* Set SW1AB/VDDARM step ramp up time from 16us to 4us/25mV */
+       pmic_reg_read(p, PFUZE100_SW1ABCONF, &reg);
+       reg &= ~SW1xCONF_DVSSPEED_MASK;
+       reg |= SW1xCONF_DVSSPEED_4US;
+       pmic_reg_write(p, PFUZE100_SW1ABCONF, reg);
+
+       /* Set SW1C standby voltage to 0.975V */
+       pmic_reg_read(p, PFUZE100_SW1CSTBY, &reg);
+       reg &= ~SW1x_STBY_MASK;
+       reg |= SW1x_0_975V;
+       pmic_reg_write(p, PFUZE100_SW1CSTBY, reg);
+
+       /* Set SW1C/VDDSOC step ramp up time from 16us to 4us/25mV */
+       pmic_reg_read(p, PFUZE100_SW1CCONF, &reg);
+       reg &= ~SW1xCONF_DVSSPEED_MASK;
+       reg |= SW1xCONF_DVSSPEED_4US;
+       pmic_reg_write(p, PFUZE100_SW1CCONF, reg);
+
+       return p;
+}
+#else
+int pfuze_mode_init(struct udevice *dev, u32 mode)
+{
+       unsigned char offset, i, switch_num;
+       u32 id;
+       int ret;
+
+       id = pmic_reg_read(dev, PFUZE100_DEVICEID);
+       id = id & 0xf;
+
+       if (id == 0) {
+               switch_num = 6;
+               offset = PFUZE100_SW1CMODE;
+       } else if (id == 1) {
+               switch_num = 4;
+               offset = PFUZE100_SW2MODE;
+       } else {
+               printf("Not supported, id=%d\n", id);
+               return -EINVAL;
+       }
+
+       ret = pmic_reg_write(dev, PFUZE100_SW1ABMODE, mode);
+       if (ret < 0) {
+               printf("Set SW1AB mode error!\n");
+               return ret;
+       }
+
+       for (i = 0; i < switch_num - 1; i++) {
+               ret = pmic_reg_write(dev, offset + i * SWITCH_SIZE, mode);
+               if (ret < 0) {
+                       printf("Set switch 0x%x mode error!\n",
+                              offset + i * SWITCH_SIZE);
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+struct udevice *pfuze_common_init(void)
+{
+       struct udevice *dev;
+       int ret;
+       unsigned int reg, dev_id, rev_id;
+
+       ret = pmic_get("pfuze100", &dev);
+       if (ret == -ENODEV)
+               return NULL;
+
+       dev_id = pmic_reg_read(dev, PFUZE100_DEVICEID);
+       rev_id = pmic_reg_read(dev, PFUZE100_REVID);
+       printf("PMIC: PFUZE100! DEV_ID=0x%x REV_ID=0x%x\n", dev_id, rev_id);
+
+       /* Set SW1AB stanby volage to 0.975V */
+       reg = pmic_reg_read(dev, PFUZE100_SW1ABSTBY);
+       reg &= ~SW1x_STBY_MASK;
+       reg |= SW1x_0_975V;
+       pmic_reg_write(dev, PFUZE100_SW1ABSTBY, reg);
+
+       /* Set SW1AB/VDDARM step ramp up time from 16us to 4us/25mV */
+       reg = pmic_reg_read(dev, PFUZE100_SW1ABCONF);
+       reg &= ~SW1xCONF_DVSSPEED_MASK;
+       reg |= SW1xCONF_DVSSPEED_4US;
+       pmic_reg_write(dev, PFUZE100_SW1ABCONF, reg);
+
+       /* Set SW1C standby voltage to 0.975V */
+       reg = pmic_reg_read(dev, PFUZE100_SW1CSTBY);
+       reg &= ~SW1x_STBY_MASK;
+       reg |= SW1x_0_975V;
+       pmic_reg_write(dev, PFUZE100_SW1CSTBY, reg);
+
+       /* Set SW1C/VDDSOC step ramp up time from 16us to 4us/25mV */
+       reg = pmic_reg_read(dev, PFUZE100_SW1CCONF);
+       reg &= ~SW1xCONF_DVSSPEED_MASK;
+       reg |= SW1xCONF_DVSSPEED_4US;
+       pmic_reg_write(dev, PFUZE100_SW1CCONF, reg);
+
+       return dev;
+}
+#endif
diff --git a/board/somdevices/common/pfuze.h b/board/somdevices/common/pfuze.h
new file mode 100644 (file)
index 0000000..45b49af
--- /dev/null
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __PFUZE_BOARD_HELPER__
+#define __PFUZE_BOARD_HELPER__
+
+#ifdef CONFIG_DM_PMIC_PFUZE100
+struct udevice *pfuze_common_init(void);
+int pfuze_mode_init(struct udevice *dev, u32 mode);
+#else
+struct pmic *pfuze_common_init(unsigned char i2cbus);
+int pfuze_mode_init(struct pmic *p, u32 mode);
+#endif
+
+#endif
diff --git a/board/somdevices/common/pixis.c b/board/somdevices/common/pixis.c
new file mode 100644 (file)
index 0000000..e9b7127
--- /dev/null
@@ -0,0 +1,541 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2006,2010 Freescale Semiconductor
+ * Jeff Brown
+ * Srikanth Srinivasan (srikanth.srinivasan@freescale.com)
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+#define pixis_base (u8 *)PIXIS_BASE
+
+/*
+ * Simple board reset.
+ */
+void pixis_reset(void)
+{
+       out_8(pixis_base + PIXIS_RST, 0);
+
+       while (1);
+}
+
+/*
+ * Per table 27, page 58 of MPC8641HPCN spec.
+ */
+static int set_px_sysclk(unsigned long sysclk)
+{
+       u8 sysclk_s, sysclk_r, sysclk_v, vclkh, vclkl, sysclk_aux;
+
+       switch (sysclk) {
+       case 33:
+               sysclk_s = 0x04;
+               sysclk_r = 0x04;
+               sysclk_v = 0x07;
+               sysclk_aux = 0x00;
+               break;
+       case 40:
+               sysclk_s = 0x01;
+               sysclk_r = 0x1F;
+               sysclk_v = 0x20;
+               sysclk_aux = 0x01;
+               break;
+       case 50:
+               sysclk_s = 0x01;
+               sysclk_r = 0x1F;
+               sysclk_v = 0x2A;
+               sysclk_aux = 0x02;
+               break;
+       case 66:
+               sysclk_s = 0x01;
+               sysclk_r = 0x04;
+               sysclk_v = 0x04;
+               sysclk_aux = 0x03;
+               break;
+       case 83:
+               sysclk_s = 0x01;
+               sysclk_r = 0x1F;
+               sysclk_v = 0x4B;
+               sysclk_aux = 0x04;
+               break;
+       case 100:
+               sysclk_s = 0x01;
+               sysclk_r = 0x1F;
+               sysclk_v = 0x5C;
+               sysclk_aux = 0x05;
+               break;
+       case 134:
+               sysclk_s = 0x06;
+               sysclk_r = 0x1F;
+               sysclk_v = 0x3B;
+               sysclk_aux = 0x06;
+               break;
+       case 166:
+               sysclk_s = 0x06;
+               sysclk_r = 0x1F;
+               sysclk_v = 0x4B;
+               sysclk_aux = 0x07;
+               break;
+       default:
+               printf("Unsupported SYSCLK frequency.\n");
+               return 0;
+       }
+
+       vclkh = (sysclk_s << 5) | sysclk_r;
+       vclkl = sysclk_v;
+
+       out_8(pixis_base + PIXIS_VCLKH, vclkh);
+       out_8(pixis_base + PIXIS_VCLKL, vclkl);
+
+       out_8(pixis_base + PIXIS_AUX, sysclk_aux);
+
+       return 1;
+}
+
+/* Set the CFG_SYSPLL bits
+ *
+ * This only has effect if PX_VCFGEN0[SYSPLL]=1, which is true if
+ * read_from_px_regs() is called.
+ */
+static int set_px_mpxpll(unsigned long mpxpll)
+{
+       switch (mpxpll) {
+       case 2:
+       case 4:
+       case 6:
+       case 8:
+       case 10:
+       case 12:
+       case 14:
+       case 16:
+               clrsetbits_8(pixis_base + PIXIS_VSPEED1, 0x1F, mpxpll);
+               return 1;
+       }
+
+       printf("Unsupported MPXPLL ratio.\n");
+       return 0;
+}
+
+static int set_px_corepll(unsigned long corepll)
+{
+       u8 val;
+
+       switch (corepll) {
+       case 20:
+               val = 0x08;
+               break;
+       case 25:
+               val = 0x0C;
+               break;
+       case 30:
+               val = 0x10;
+               break;
+       case 35:
+               val = 0x1C;
+               break;
+       case 40:
+               val = 0x14;
+               break;
+       case 45:
+               val = 0x0E;
+               break;
+       default:
+               printf("Unsupported COREPLL ratio.\n");
+               return 0;
+       }
+
+       clrsetbits_8(pixis_base + PIXIS_VSPEED0, 0x1F, val);
+       return 1;
+}
+
+#ifndef CONFIG_SYS_PIXIS_VCFGEN0_ENABLE
+#define CONFIG_SYS_PIXIS_VCFGEN0_ENABLE                0x1C
+#endif
+
+/* Tell the PIXIS where to find the COREPLL, MPXPLL, SYSCLK values
+ *
+ * The PIXIS can be programmed to look at either the on-board dip switches
+ * or various other PIXIS registers to determine the values for COREPLL,
+ * MPXPLL, and SYSCLK.
+ *
+ * CONFIG_SYS_PIXIS_VCFGEN0_ENABLE is the value to write to the PIXIS_VCFGEN0
+ * register that tells the pixis to use the various PIXIS register.
+ */
+static void read_from_px_regs(int set)
+{
+       u8 tmp = in_8(pixis_base + PIXIS_VCFGEN0);
+
+       if (set)
+               tmp = tmp | CONFIG_SYS_PIXIS_VCFGEN0_ENABLE;
+       else
+               tmp = tmp & ~CONFIG_SYS_PIXIS_VCFGEN0_ENABLE;
+
+       out_8(pixis_base + PIXIS_VCFGEN0, tmp);
+}
+
+/* CONFIG_SYS_PIXIS_VBOOT_ENABLE is the value to write to the PX_VCFGEN1
+ * register that tells the pixis to use the PX_VBOOT[LBMAP] register.
+ */
+#ifndef CONFIG_SYS_PIXIS_VBOOT_ENABLE
+#define CONFIG_SYS_PIXIS_VBOOT_ENABLE  0x04
+#endif
+
+/* Configure the source of the boot location
+ *
+ * The PIXIS can be programmed to look at either the on-board dip switches
+ * or the PX_VBOOT[LBMAP] register to determine where we should boot.
+ *
+ * If we want to boot from the alternate boot bank, we need to tell the PIXIS
+ * to ignore the on-board dip switches and use the PX_VBOOT[LBMAP] instead.
+ */
+static void read_from_px_regs_altbank(int set)
+{
+       u8 tmp = in_8(pixis_base + PIXIS_VCFGEN1);
+
+       if (set)
+               tmp = tmp | CONFIG_SYS_PIXIS_VBOOT_ENABLE;
+       else
+               tmp = tmp & ~CONFIG_SYS_PIXIS_VBOOT_ENABLE;
+
+       out_8(pixis_base + PIXIS_VCFGEN1, tmp);
+}
+
+/* CONFIG_SYS_PIXIS_VBOOT_MASK contains the bits to set in VBOOT register that
+ * tells the PIXIS what the alternate flash bank is.
+ *
+ * Note that it's not really a mask.  It contains the actual LBMAP bits that
+ * must be set to select the alternate bank.  This code assumes that the
+ * primary bank has these bits set to 0, and the alternate bank has these
+ * bits set to 1.
+ */
+#ifndef CONFIG_SYS_PIXIS_VBOOT_MASK
+#define CONFIG_SYS_PIXIS_VBOOT_MASK    (0x40)
+#endif
+
+/* Tell the PIXIS to boot from the default flash bank
+ *
+ * Program the default flash bank into the VBOOT register.  This register is
+ * used only if PX_VCFGEN1[FLASH]=1.
+ */
+static void clear_altbank(void)
+{
+       clrbits_8(pixis_base + PIXIS_VBOOT, CONFIG_SYS_PIXIS_VBOOT_MASK);
+}
+
+/* Tell the PIXIS to boot from the alternate flash bank
+ *
+ * Program the alternate flash bank into the VBOOT register.  This register is
+ * used only if PX_VCFGEN1[FLASH]=1.
+ */
+static void set_altbank(void)
+{
+       setbits_8(pixis_base + PIXIS_VBOOT, CONFIG_SYS_PIXIS_VBOOT_MASK);
+}
+
+/* Reset the board with watchdog disabled.
+ *
+ * This respects the altbank setting.
+ */
+static void set_px_go(void)
+{
+       /* Disable the VELA sequencer and watchdog */
+       clrbits_8(pixis_base + PIXIS_VCTL, 9);
+
+       /* Reboot by starting the VELA sequencer */
+       setbits_8(pixis_base + PIXIS_VCTL, 0x1);
+
+       while (1);
+}
+
+/* Reset the board with watchdog enabled.
+ *
+ * This respects the altbank setting.
+ */
+static void set_px_go_with_watchdog(void)
+{
+       /* Disable the VELA sequencer */
+       clrbits_8(pixis_base + PIXIS_VCTL, 1);
+
+       /* Enable the watchdog and reboot by starting the VELA sequencer */
+       setbits_8(pixis_base + PIXIS_VCTL, 0x9);
+
+       while (1);
+}
+
+/* Disable the watchdog
+ *
+ */
+static int pixis_disable_watchdog_cmd(cmd_tbl_t *cmdtp, int flag, int argc,
+                                     char * const argv[])
+{
+       /* Disable the VELA sequencer and the watchdog */
+       clrbits_8(pixis_base + PIXIS_VCTL, 9);
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       diswd, 1, 0, pixis_disable_watchdog_cmd,
+       "Disable watchdog timer",
+       ""
+);
+
+#ifdef CONFIG_PIXIS_SGMII_CMD
+
+/* Enable or disable SGMII mode for a TSEC
+ */
+static int pixis_set_sgmii(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int which_tsec = -1;
+       unsigned char mask;
+       unsigned char switch_mask;
+
+       if ((argc > 2) && (strcmp(argv[1], "all") != 0))
+               which_tsec = simple_strtoul(argv[1], NULL, 0);
+
+       switch (which_tsec) {
+#ifdef CONFIG_TSEC1
+       case 1:
+               mask = PIXIS_VSPEED2_TSEC1SER;
+               switch_mask = PIXIS_VCFGEN1_TSEC1SER;
+               break;
+#endif
+#ifdef CONFIG_TSEC2
+       case 2:
+               mask = PIXIS_VSPEED2_TSEC2SER;
+               switch_mask = PIXIS_VCFGEN1_TSEC2SER;
+               break;
+#endif
+#ifdef CONFIG_TSEC3
+       case 3:
+               mask = PIXIS_VSPEED2_TSEC3SER;
+               switch_mask = PIXIS_VCFGEN1_TSEC3SER;
+               break;
+#endif
+#ifdef CONFIG_TSEC4
+       case 4:
+               mask = PIXIS_VSPEED2_TSEC4SER;
+               switch_mask = PIXIS_VCFGEN1_TSEC4SER;
+               break;
+#endif
+       default:
+               mask = PIXIS_VSPEED2_MASK;
+               switch_mask = PIXIS_VCFGEN1_MASK;
+               break;
+       }
+
+       /* Toggle whether the switches or FPGA control the settings */
+       if (!strcmp(argv[argc - 1], "switch"))
+               clrbits_8(pixis_base + PIXIS_VCFGEN1, switch_mask);
+       else
+               setbits_8(pixis_base + PIXIS_VCFGEN1, switch_mask);
+
+       /* If it's not the switches, enable or disable SGMII, as specified */
+       if (!strcmp(argv[argc - 1], "on"))
+               clrbits_8(pixis_base + PIXIS_VSPEED2, mask);
+       else if (!strcmp(argv[argc - 1], "off"))
+               setbits_8(pixis_base + PIXIS_VSPEED2, mask);
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       pixis_set_sgmii, CONFIG_SYS_MAXARGS, 1, pixis_set_sgmii,
+       "pixis_set_sgmii"
+       " - Enable or disable SGMII mode for a given TSEC \n",
+       "\npixis_set_sgmii [TSEC num] <on|off|switch>\n"
+       "    TSEC num: 1,2,3,4 or 'all'.  'all' is default.\n"
+       "    on - enables SGMII\n"
+       "    off - disables SGMII\n"
+       "    switch - use switch settings"
+);
+
+#endif
+
+/*
+ * This function takes the non-integral cpu:mpx pll ratio
+ * and converts it to an integer that can be used to assign
+ * FPGA register values.
+ * input: strptr i.e. argv[2]
+ */
+static unsigned long strfractoint(char *strptr)
+{
+       int i, j;
+       int mulconst;
+       int no_dec = 0;
+       unsigned long intval = 0, decval = 0;
+       char intarr[3], decarr[3];
+
+       /* Assign the integer part to intarr[]
+        * If there is no decimal point i.e.
+        * if the ratio is an integral value
+        * simply create the intarr.
+        */
+       i = 0;
+       while (strptr[i] != '.') {
+               if (strptr[i] == 0) {
+                       no_dec = 1;
+                       break;
+               }
+               intarr[i] = strptr[i];
+               i++;
+       }
+
+       intarr[i] = '\0';
+
+       if (no_dec) {
+               /* Currently needed only for single digit corepll ratios */
+               mulconst = 10;
+               decval = 0;
+       } else {
+               j = 0;
+               i++;            /* Skipping the decimal point */
+               while ((strptr[i] >= '0') && (strptr[i] <= '9')) {
+                       decarr[j] = strptr[i];
+                       i++;
+                       j++;
+               }
+
+               decarr[j] = '\0';
+
+               mulconst = 1;
+               for (i = 0; i < j; i++)
+                       mulconst *= 10;
+               decval = simple_strtoul(decarr, NULL, 10);
+       }
+
+       intval = simple_strtoul(intarr, NULL, 10);
+       intval = intval * mulconst;
+
+       return intval + decval;
+}
+
+static int pixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       unsigned int i;
+       char *p_cf = NULL;
+       char *p_cf_sysclk = NULL;
+       char *p_cf_corepll = NULL;
+       char *p_cf_mpxpll = NULL;
+       char *p_altbank = NULL;
+       char *p_wd = NULL;
+       int unknown_param = 0;
+
+       /*
+        * No args is a simple reset request.
+        */
+       if (argc <= 1) {
+               pixis_reset();
+               /* not reached */
+       }
+
+       for (i = 1; i < argc; i++) {
+               if (strcmp(argv[i], "cf") == 0) {
+                       p_cf = argv[i];
+                       if (i + 3 >= argc) {
+                               break;
+                       }
+                       p_cf_sysclk = argv[i+1];
+                       p_cf_corepll = argv[i+2];
+                       p_cf_mpxpll = argv[i+3];
+                       i += 3;
+                       continue;
+               }
+
+               if (strcmp(argv[i], "altbank") == 0) {
+                       p_altbank = argv[i];
+                       continue;
+               }
+
+               if (strcmp(argv[i], "wd") == 0) {
+                       p_wd = argv[i];
+                       continue;
+               }
+
+               unknown_param = 1;
+       }
+
+       /*
+        * Check that cf has all required parms
+        */
+       if ((p_cf && !(p_cf_sysclk && p_cf_corepll && p_cf_mpxpll))
+           ||  unknown_param) {
+#ifdef CONFIG_SYS_LONGHELP
+               puts(cmdtp->help);
+               putc('\n');
+#endif
+               return 1;
+       }
+
+       /*
+        * PIXIS seems to be sensitive to the ordering of
+        * the registers that are touched.
+        */
+       read_from_px_regs(0);
+
+       if (p_altbank)
+               read_from_px_regs_altbank(0);
+
+       clear_altbank();
+
+       /*
+        * Clock configuration specified.
+        */
+       if (p_cf) {
+               unsigned long sysclk;
+               unsigned long corepll;
+               unsigned long mpxpll;
+
+               sysclk = simple_strtoul(p_cf_sysclk, NULL, 10);
+               corepll = strfractoint(p_cf_corepll);
+               mpxpll = simple_strtoul(p_cf_mpxpll, NULL, 10);
+
+               if (!(set_px_sysclk(sysclk)
+                     && set_px_corepll(corepll)
+                     && set_px_mpxpll(mpxpll))) {
+#ifdef CONFIG_SYS_LONGHELP
+                       puts(cmdtp->help);
+                       putc('\n');
+#endif
+                       return 1;
+               }
+               read_from_px_regs(1);
+       }
+
+       /*
+        * Altbank specified
+        *
+        * NOTE CHANGE IN BEHAVIOR: previous code would default
+        * to enabling watchdog if altbank is specified.
+        * Now the watchdog must be enabled explicitly using 'wd'.
+        */
+       if (p_altbank) {
+               set_altbank();
+               read_from_px_regs_altbank(1);
+       }
+
+       /*
+        * Reset with watchdog specified.
+        */
+       if (p_wd)
+               set_px_go_with_watchdog();
+       else
+               set_px_go();
+
+       /*
+        * Shouldn't be reached.
+        */
+       return 0;
+}
+
+
+U_BOOT_CMD(
+       pixis_reset, CONFIG_SYS_MAXARGS, 1, pixis_reset_cmd,
+       "Reset the board using the FPGA sequencer",
+       "    pixis_reset\n"
+       "    pixis_reset [altbank]\n"
+       "    pixis_reset altbank wd\n"
+       "    pixis_reset altbank cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>\n"
+       "    pixis_reset cf <SYSCLK freq> <COREPLL ratio> <MPXPLL ratio>"
+);
diff --git a/board/somdevices/common/pixis.h b/board/somdevices/common/pixis.h
new file mode 100644 (file)
index 0000000..40053c4
--- /dev/null
@@ -0,0 +1,165 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2010 Freescale Semiconductor, Inc.
+ */
+#ifndef __PIXIS_H_
+#define __PIXIS_H_     1
+
+/* PIXIS register set. */
+#if defined(CONFIG_TARGET_MPC8536DS)
+typedef struct pixis {
+       u8 id;
+       u8 ver;
+       u8 pver;
+       u8 csr;
+       u8 rst;
+       u8 rst2;
+       u8 aux1;
+       u8 spd;
+       u8 aux2;
+       u8 csr2;
+       u8 watch;
+       u8 led;
+       u8 pwr;
+       u8 res[3];
+       u8 vctl;
+       u8 vstat;
+       u8 vcfgen0;
+       u8 vcfgen1;
+       u8 vcore0;
+       u8 res1;
+       u8 vboot;
+       u8 vspeed[3];
+       u8 sclk[3];
+       u8 dclk[3];
+       u8 i2cdacr;
+       u8 vcoreacc[4];
+       u8 vcorecnt[3];
+       u8 vcoremax[2];
+       u8 vplatacc[4];
+       u8 vplatcnt[3];
+       u8 vplatmax[2];
+       u8 vtempacc[4];
+       u8 vtempcnt[3];
+       u8 vtempmax[2];
+       u8 res2[4];
+} __attribute__ ((packed)) pixis_t;
+
+#elif defined(CONFIG_TARGET_MPC8544DS)
+typedef struct pixis {
+       u8 id;
+       u8 ver;
+       u8 pver;
+       u8 csr;
+       u8 rst;
+       u8 pwr;
+       u8 aux1;
+       u8 spd;
+       u8 res[8];
+       u8 vctl;
+       u8 vstat;
+       u8 vcfgen0;
+       u8 vcfgen1;
+       u8 vcore0;
+       u8 res1;
+       u8 vboot;
+       u8 vspeed[2];
+       u8 vclkh;
+       u8 vclkl;
+       u8 watch;
+       u8 led;
+       u8 vspeed2;
+       u8 res2[34];
+} __attribute__ ((packed)) pixis_t;
+
+#elif defined(CONFIG_TARGET_MPC8572DS)
+typedef struct pixis {
+       u8 id;
+       u8 ver;
+       u8 pver;
+       u8 csr;
+       u8 rst;
+       u8 pwr1;
+       u8 aux1;
+       u8 spd;
+       u8 aux2;
+       u8 res[7];
+       u8 vctl;
+       u8 vstat;
+       u8 vcfgen0;
+       u8 vcfgen1;
+       u8 vcore0;
+       u8 res1;
+       u8 vboot;
+       u8 vspeed[3];
+       u8 res2[2];
+       u8 sclk[3];
+       u8 dclk[3];
+       u8 res3[2];
+       u8 watch;
+       u8 led;
+       u8 res4[25];
+} __attribute__ ((packed)) pixis_t;
+
+#elif defined(CONFIG_TARGET_MPC8610HPCD)
+typedef struct pixis {
+       u8 id;
+       u8 ver; /* also called arch */
+       u8 pver;
+       u8 csr;
+       u8 rst;
+       u8 pwr;
+       u8 aux;
+       u8 spd;
+       u8 brdcfg0;
+       u8 brdcfg1;
+       u8 res[4];
+       u8 led;
+       u8 serno;
+       u8 vctl;
+       u8 vstat;
+       u8 vcfgen0;
+       u8 vcfgen1;
+       u8 vcore0;
+       u8 res1;
+       u8 vboot;
+       u8 vspeed[2];
+       u8 res2;
+       u8 sclk[3];
+       u8 res3;
+       u8 watch;
+       u8 res4[33];
+} __attribute__ ((packed)) pixis_t;
+
+#elif defined(CONFIG_TARGET_MPC8641HPCN)
+typedef struct pixis {
+       u8 id;
+       u8 ver;
+       u8 pver;
+       u8 csr;
+       u8 rst;
+       u8 pwr;
+       u8 aux;
+       u8 spd;
+       u8 res[8];
+       u8 vctl;
+       u8 vstat;
+       u8 vcfgen0;
+       u8 vcfgen1;
+       u8 vcore0;
+       u8 res1;
+       u8 vboot;
+       u8 vspeed[2];
+       u8 vclkh;
+       u8 vclkl;
+       u8 watch;
+       u8 res3[36];
+} __attribute__ ((packed)) pixis_t;
+#else
+#error Need to define pixis_t for this board
+#endif
+
+/* Pointer to the PIXIS register set */
+#define pixis ((pixis_t *)PIXIS_BASE)
+
+#endif /* __PIXIS_H_ */
diff --git a/board/somdevices/common/pq-mds-pib.c b/board/somdevices/common/pq-mds-pib.c
new file mode 100644 (file)
index 0000000..d152a78
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc.
+ *
+ * Tony Li <tony.li@freescale.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ */
+
+#include <common.h>
+#include <i2c.h>
+#include <asm/io.h>
+
+#include "pq-mds-pib.h"
+
+int pib_init(void)
+{
+       u8 val8;
+       u8 orig_i2c_bus;
+
+       /* Switch temporarily to I2C bus #2 */
+       orig_i2c_bus = i2c_get_bus_num();
+       i2c_set_bus_num(1);
+
+       val8 = 0;
+#if defined(CONFIG_PCI) && !defined(CONFIG_PCISLAVE)
+       /* Assign PIB PMC slot to desired PCI bus */
+       i2c_write(0x23, 0x6, 1, &val8, 1);
+       i2c_write(0x23, 0x7, 1, &val8, 1);
+       val8 = 0xff;
+       i2c_write(0x23, 0x2, 1, &val8, 1);
+       i2c_write(0x23, 0x3, 1, &val8, 1);
+
+       val8 = 0;
+       i2c_write(0x26, 0x6, 1, &val8, 1);
+       val8 = 0x34;
+       i2c_write(0x26, 0x7, 1, &val8, 1);
+#if defined(CONFIG_MPC832XEMDS)
+       val8 = 0xf9;            /* PMC2, PMC3 slot to PCI bus */
+#else
+       val8 = 0xf3;            /* PMC1, PMC2, PMC3 slot to PCI bus */
+#endif
+       i2c_write(0x26, 0x2, 1, &val8, 1);
+       val8 = 0xff;
+       i2c_write(0x26, 0x3, 1, &val8, 1);
+
+       val8 = 0;
+       i2c_write(0x27, 0x6, 1, &val8, 1);
+       i2c_write(0x27, 0x7, 1, &val8, 1);
+       val8 = 0xff;
+       i2c_write(0x27, 0x2, 1, &val8, 1);
+       val8 = 0xef;
+       i2c_write(0x27, 0x3, 1, &val8, 1);
+
+       eieio();
+
+#if defined(CONFIG_MPC832XEMDS)
+       printf("PCI 32bit bus on PMC2 &PMC3\n");
+#else
+       printf("PCI 32bit bus on PMC1 & PMC2 &PMC3\n");
+#endif
+#endif
+
+#if defined(CONFIG_PQ_MDS_PIB_ATM)
+#if defined(CONFIG_TARGET_MPC8569MDS)
+       val8 = 0;
+       i2c_write(0x20, 0x6, 1, &val8, 1);
+       i2c_write(0x20, 0x7, 1, &val8, 1);
+
+       val8 = 0xdf;
+       i2c_write(0x20, 0x2, 1, &val8, 1);
+       val8 = 0xf7;
+       i2c_write(0x20, 0x3, 1, &val8, 1);
+
+       eieio();
+
+       printf("QOC3 ATM card on PMC0\n");
+#elif defined(CONFIG_MPC832XEMDS)
+       val8 = 0;
+       i2c_write(0x26, 0x7, 1, &val8, 1);
+       val8 = 0xf7;
+       i2c_write(0x26, 0x3, 1, &val8, 1);
+
+       val8 = 0;
+       i2c_write(0x21, 0x6, 1, &val8, 1);
+       i2c_write(0x21, 0x7, 1, &val8, 1);
+
+       val8 = 0xdf;
+       i2c_write(0x21, 0x2, 1, &val8, 1);
+       val8 = 0xef;
+       i2c_write(0x21, 0x3, 1, &val8, 1);
+
+       eieio();
+
+       printf("QOC3 ATM card on PMC1\n");
+#endif
+#endif
+       /* Reset to original I2C bus */
+       i2c_set_bus_num(orig_i2c_bus);
+       return 0;
+}
diff --git a/board/somdevices/common/pq-mds-pib.h b/board/somdevices/common/pq-mds-pib.h
new file mode 100644 (file)
index 0000000..67066fd
--- /dev/null
@@ -0,0 +1,9 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation;
+ */
+
+extern int pib_init(void);
diff --git a/board/somdevices/common/qixis.c b/board/somdevices/common/qixis.c
new file mode 100644 (file)
index 0000000..f1b98bc
--- /dev/null
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2011 Freescale Semiconductor
+ * Author: Shengzhou Liu <Shengzhou.Liu@freescale.com>
+ *
+ * This file provides support for the QIXIS of some Freescale reference boards.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <linux/compiler.h>
+#include <linux/time.h>
+#include <i2c.h>
+#include "qixis.h"
+
+#ifndef QIXIS_LBMAP_BRDCFG_REG
+/*
+ * For consistency with existing platforms
+ */
+#define QIXIS_LBMAP_BRDCFG_REG 0x00
+#endif
+
+#ifdef CONFIG_SYS_I2C_FPGA_ADDR
+u8 qixis_read_i2c(unsigned int reg)
+{
+       return i2c_reg_read(CONFIG_SYS_I2C_FPGA_ADDR, reg);
+}
+
+void qixis_write_i2c(unsigned int reg, u8 value)
+{
+       u8 val = value;
+       i2c_reg_write(CONFIG_SYS_I2C_FPGA_ADDR, reg, val);
+}
+#endif
+
+#ifdef QIXIS_BASE
+u8 qixis_read(unsigned int reg)
+{
+       void *p = (void *)QIXIS_BASE;
+
+       return in_8(p + reg);
+}
+
+void qixis_write(unsigned int reg, u8 value)
+{
+       void *p = (void *)QIXIS_BASE;
+
+       out_8(p + reg, value);
+}
+#endif
+
+u16 qixis_read_minor(void)
+{
+       u16 minor;
+
+       /* this data is in little endian */
+       QIXIS_WRITE(tagdata, 5);
+       minor = QIXIS_READ(tagdata);
+       QIXIS_WRITE(tagdata, 6);
+       minor += QIXIS_READ(tagdata) << 8;
+
+       return minor;
+}
+
+char *qixis_read_time(char *result)
+{
+       time_t time = 0;
+       int i;
+
+       /* timestamp is in 32-bit big endian */
+       for (i = 8; i <= 11; i++) {
+               QIXIS_WRITE(tagdata, i);
+               time =  (time << 8) + QIXIS_READ(tagdata);
+       }
+
+       return ctime_r(&time, result);
+}
+
+char *qixis_read_tag(char *buf)
+{
+       int i;
+       char tag, *ptr = buf;
+
+       for (i = 16; i <= 63; i++) {
+               QIXIS_WRITE(tagdata, i);
+               tag = QIXIS_READ(tagdata);
+               *(ptr++) = tag;
+               if (!tag)
+                       break;
+       }
+       if (i > 63)
+               *ptr = '\0';
+
+       return buf;
+}
+
+/*
+ * return the string of binary of u8 in the format of
+ * 1010 10_0. The masked bit is filled as underscore.
+ */
+const char *byte_to_binary_mask(u8 val, u8 mask, char *buf)
+{
+       char *ptr;
+       int i;
+
+       ptr = buf;
+       for (i = 0x80; i > 0x08 ; i >>= 1, ptr++)
+               *ptr = (val & i) ? '1' : ((mask & i) ? '_' : '0');
+       *(ptr++) = ' ';
+       for (i = 0x08; i > 0 ; i >>= 1, ptr++)
+               *ptr = (val & i) ? '1' : ((mask & i) ? '_' : '0');
+
+       *ptr = '\0';
+
+       return buf;
+}
+
+#ifdef QIXIS_RST_FORCE_MEM
+void board_assert_mem_reset(void)
+{
+       u8 rst;
+
+       rst = QIXIS_READ(rst_frc[0]);
+       if (!(rst & QIXIS_RST_FORCE_MEM))
+               QIXIS_WRITE(rst_frc[0], rst | QIXIS_RST_FORCE_MEM);
+}
+
+void board_deassert_mem_reset(void)
+{
+       u8 rst;
+
+       rst = QIXIS_READ(rst_frc[0]);
+       if (rst & QIXIS_RST_FORCE_MEM)
+               QIXIS_WRITE(rst_frc[0], rst & ~QIXIS_RST_FORCE_MEM);
+}
+#endif
+
+#ifndef CONFIG_SPL_BUILD
+static void qixis_reset(void)
+{
+       QIXIS_WRITE(rst_ctl, QIXIS_RST_CTL_RESET);
+}
+
+static void qixis_bank_reset(void)
+{
+       QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_IDLE);
+       QIXIS_WRITE(rcfg_ctl, QIXIS_RCFG_CTL_RECONFIG_START);
+}
+
+static void __maybe_unused set_lbmap(int lbmap)
+{
+       u8 reg;
+
+       reg = QIXIS_READ(brdcfg[QIXIS_LBMAP_BRDCFG_REG]);
+       reg = (reg & ~QIXIS_LBMAP_MASK) | lbmap;
+       QIXIS_WRITE(brdcfg[QIXIS_LBMAP_BRDCFG_REG], reg);
+}
+
+static void __maybe_unused set_rcw_src(int rcw_src)
+{
+       u8 reg;
+
+       reg = QIXIS_READ(dutcfg[1]);
+       reg = (reg & ~1) | (rcw_src & 1);
+       QIXIS_WRITE(dutcfg[1], reg);
+       QIXIS_WRITE(dutcfg[0], (rcw_src >> 1) & 0xff);
+}
+
+static void qixis_dump_regs(void)
+{
+       int i;
+
+       printf("id      = %02x\n", QIXIS_READ(id));
+       printf("arch    = %02x\n", QIXIS_READ(arch));
+       printf("scver   = %02x\n", QIXIS_READ(scver));
+       printf("model   = %02x\n", QIXIS_READ(model));
+       printf("rst_ctl = %02x\n", QIXIS_READ(rst_ctl));
+       printf("aux     = %02x\n", QIXIS_READ(aux));
+       for (i = 0; i < 16; i++)
+               printf("brdcfg%02d = %02x\n", i, QIXIS_READ(brdcfg[i]));
+       for (i = 0; i < 16; i++)
+               printf("dutcfg%02d = %02x\n", i, QIXIS_READ(dutcfg[i]));
+       printf("sclk    = %02x%02x%02x\n", QIXIS_READ(sclk[0]),
+               QIXIS_READ(sclk[1]), QIXIS_READ(sclk[2]));
+       printf("dclk    = %02x%02x%02x\n", QIXIS_READ(dclk[0]),
+               QIXIS_READ(dclk[1]), QIXIS_READ(dclk[2]));
+       printf("aux     = %02x\n", QIXIS_READ(aux));
+       printf("watch   = %02x\n", QIXIS_READ(watch));
+       printf("ctl_sys = %02x\n", QIXIS_READ(ctl_sys));
+       printf("rcw_ctl = %02x\n", QIXIS_READ(rcw_ctl));
+       printf("present = %02x\n", QIXIS_READ(present));
+       printf("present2 = %02x\n", QIXIS_READ(present2));
+       printf("clk_spd = %02x\n", QIXIS_READ(clk_spd));
+       printf("stat_dut = %02x\n", QIXIS_READ(stat_dut));
+       printf("stat_sys = %02x\n", QIXIS_READ(stat_sys));
+       printf("stat_alrm = %02x\n", QIXIS_READ(stat_alrm));
+}
+
+void __weak qixis_dump_switch(void)
+{
+       puts("Reverse engineering switch is not implemented for this board\n");
+}
+
+static int qixis_reset_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       int i;
+
+       if (argc <= 1) {
+               set_lbmap(QIXIS_LBMAP_DFLTBANK);
+               qixis_reset();
+       } else if (strcmp(argv[1], "altbank") == 0) {
+               set_lbmap(QIXIS_LBMAP_ALTBANK);
+               qixis_bank_reset();
+       } else if (strcmp(argv[1], "nand") == 0) {
+#ifdef QIXIS_LBMAP_NAND
+               QIXIS_WRITE(rst_ctl, 0x30);
+               QIXIS_WRITE(rcfg_ctl, 0);
+               set_lbmap(QIXIS_LBMAP_NAND);
+               set_rcw_src(QIXIS_RCW_SRC_NAND);
+               QIXIS_WRITE(rcfg_ctl, 0x20);
+               QIXIS_WRITE(rcfg_ctl, 0x21);
+#else
+               printf("Not implemented\n");
+#endif
+       } else if (strcmp(argv[1], "sd") == 0) {
+#ifdef QIXIS_LBMAP_SD
+               QIXIS_WRITE(rst_ctl, 0x30);
+               QIXIS_WRITE(rcfg_ctl, 0);
+#ifdef NON_EXTENDED_DUTCFG
+               QIXIS_WRITE(dutcfg[0], QIXIS_RCW_SRC_SD);
+#else
+               set_lbmap(QIXIS_LBMAP_SD);
+               set_rcw_src(QIXIS_RCW_SRC_SD);
+#endif
+               QIXIS_WRITE(rcfg_ctl, 0x20);
+               QIXIS_WRITE(rcfg_ctl, 0x21);
+#else
+               printf("Not implemented\n");
+#endif
+       } else if (strcmp(argv[1], "ifc") == 0) {
+#ifdef QIXIS_LBMAP_IFC
+               QIXIS_WRITE(rst_ctl, 0x30);
+               QIXIS_WRITE(rcfg_ctl, 0);
+               set_lbmap(QIXIS_LBMAP_IFC);
+               set_rcw_src(QIXIS_RCW_SRC_IFC);
+               QIXIS_WRITE(rcfg_ctl, 0x20);
+               QIXIS_WRITE(rcfg_ctl, 0x21);
+#else
+               printf("Not implemented\n");
+#endif
+       } else if (strcmp(argv[1], "emmc") == 0) {
+#ifdef QIXIS_LBMAP_EMMC
+               QIXIS_WRITE(rst_ctl, 0x30);
+               QIXIS_WRITE(rcfg_ctl, 0);
+               set_lbmap(QIXIS_LBMAP_EMMC);
+               set_rcw_src(QIXIS_RCW_SRC_EMMC);
+               QIXIS_WRITE(rcfg_ctl, 0x20);
+               QIXIS_WRITE(rcfg_ctl, 0x21);
+#else
+               printf("Not implemented\n");
+#endif
+       } else if (strcmp(argv[1], "sd_qspi") == 0) {
+#ifdef QIXIS_LBMAP_SD_QSPI
+               QIXIS_WRITE(rst_ctl, 0x30);
+               QIXIS_WRITE(rcfg_ctl, 0);
+               set_lbmap(QIXIS_LBMAP_SD_QSPI);
+               set_rcw_src(QIXIS_RCW_SRC_SD);
+               qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x20);
+               qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x21);
+#else
+               printf("Not implemented\n");
+#endif
+       } else if (strcmp(argv[1], "qspi") == 0) {
+#ifdef QIXIS_LBMAP_QSPI
+               QIXIS_WRITE(rst_ctl, 0x30);
+               QIXIS_WRITE(rcfg_ctl, 0);
+               set_lbmap(QIXIS_LBMAP_QSPI);
+               set_rcw_src(QIXIS_RCW_SRC_QSPI);
+               qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x20);
+               qixis_write_i2c(offsetof(struct qixis, rcfg_ctl), 0x21);
+#else
+               printf("Not implemented\n");
+#endif
+       } else if (strcmp(argv[1], "watchdog") == 0) {
+               static char *period[9] = {"2s", "4s", "8s", "16s", "32s",
+                                         "1min", "2min", "4min", "8min"};
+               u8 rcfg = QIXIS_READ(rcfg_ctl);
+
+               if (argv[2] == NULL) {
+                       printf("qixis watchdog <watchdog_period>\n");
+                       return 0;
+               }
+               for (i = 0; i < ARRAY_SIZE(period); i++) {
+                       if (strcmp(argv[2], period[i]) == 0) {
+                               /* disable watchdog */
+                               QIXIS_WRITE(rcfg_ctl,
+                                       rcfg & ~QIXIS_RCFG_CTL_WATCHDOG_ENBLE);
+                               QIXIS_WRITE(watch, ((i<<2) - 1));
+                               QIXIS_WRITE(rcfg_ctl, rcfg);
+                               return 0;
+                       }
+               }
+       } else if (strcmp(argv[1], "dump") == 0) {
+               qixis_dump_regs();
+               return 0;
+       } else if (strcmp(argv[1], "switch") == 0) {
+               qixis_dump_switch();
+               return 0;
+       } else {
+               printf("Invalid option: %s\n", argv[1]);
+               return 1;
+       }
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       qixis_reset, CONFIG_SYS_MAXARGS, 1, qixis_reset_cmd,
+       "Reset the board using the FPGA sequencer",
+       "- hard reset to default bank\n"
+       "qixis_reset altbank - reset to alternate bank\n"
+       "qixis_reset nand - reset to nand\n"
+       "qixis_reset sd - reset to sd\n"
+       "qixis_reset sd_qspi - reset to sd with qspi support\n"
+       "qixis_reset qspi - reset to qspi\n"
+       "qixis watchdog <watchdog_period> - set the watchdog period\n"
+       "       period: 1s 2s 4s 8s 16s 32s 1min 2min 4min 8min\n"
+       "qixis_reset dump - display the QIXIS registers\n"
+       "qixis_reset switch - display switch\n"
+       );
+#endif
diff --git a/board/somdevices/common/qixis.h b/board/somdevices/common/qixis.h
new file mode 100644 (file)
index 0000000..c11062e
--- /dev/null
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2011 Freescale Semiconductor
+ * Author: Shengzhou Liu <Shengzhou.Liu@freescale.com>
+ *
+ * This file provides support for the QIXIS of some Freescale reference boards.
+ */
+
+#ifndef __QIXIS_H_
+#define __QIXIS_H_
+
+struct qixis {
+       u8 id;      /* ID value uniquely identifying each QDS board type */
+       u8 arch;    /* Board version information */
+       u8 scver;   /* QIXIS Version Register */
+       u8 model;   /* Information of software programming model version */
+       u8 tagdata;
+       u8 ctl_sys;
+       u8 aux;         /* Auxiliary Register,0x06 */
+       u8 clk_spd;
+       u8 stat_dut;
+       u8 stat_sys;
+       u8 stat_alrm;
+       u8 present;
+       u8 present2;    /* Presence Status Register 2,0x0c */
+       u8 rcw_ctl;
+       u8 ctl_led;
+       u8 i2cblk;
+       u8 rcfg_ctl;    /* Reconfig Control Register,0x10 */
+       u8 rcfg_st;
+       u8 dcm_ad;
+       u8 dcm_da;
+       u8 dcmd;
+       u8 dmsg;
+       u8 gdc;
+       u8 gdd;         /* DCM Debug Data Register,0x17 */
+       u8 dmack;
+       u8 res1[6];
+       u8 watch;       /* Watchdog Register,0x1F */
+       u8 pwr_ctl[2];  /* Power Control Register,0x20 */
+       u8 res2[2];
+       u8 pwr_stat[4]; /* Power Status Register,0x24 */
+       u8 res3[8];
+       u8 clk_spd2[2];  /* SYSCLK clock Speed Register,0x30 */
+       u8 res4[2];
+       u8 sclk[3];  /* Clock Configuration Registers,0x34 */
+       u8 res5;
+       u8 dclk[3];
+       u8 res6;
+       u8 clk_dspd[3];
+       u8 res7;
+       u8 rst_ctl;     /* Reset Control Register,0x40 */
+       u8 rst_stat;    /* Reset Status Register */
+       u8 rst_rsn;     /* Reset Reason Register */
+       u8 rst_frc[2];  /* Reset Force Registers,0x43 */
+       u8 res8[11];
+       u8 brdcfg[16];  /* Board Configuration Register,0x50 */
+       u8 dutcfg[16];
+       u8 rcw_ad[2];   /* RCW SRAM Address Registers,0x70 */
+       u8 rcw_data;
+       u8 res9[5];
+       u8 post_ctl;
+       u8 post_stat;
+       u8 post_dat[2];
+       u8 pi_d[4];
+       u8 gpio_io[4];
+       u8 gpio_dir[4];
+       u8 res10[20];
+       u8 rjtag_ctl;
+       u8 rjtag_dat;
+       u8 res11[2];
+       u8 trig_src[4];
+       u8 trig_dst[4];
+       u8 trig_stat;
+       u8 res12[3];
+       u8 trig_ctr[4];
+       u8 res13[16];
+       u8 clk_freq[6]; /* Clock Measurement Registers */
+       u8 res_c6[8];
+       u8 clk_base[2]; /* Clock Frequency Base Reg */
+       u8 res_d0[8];
+       u8 cms[2];      /* Core Management Space Address Register, 0xD8 */
+       u8 res_c0[6];
+       u8 aux2[4];     /* Auxiliary Registers,0xE0 */
+       u8 res14[10];
+       u8 aux_ad;
+       u8 aux_da;
+       u8 res15[16];
+};
+
+u8 qixis_read(unsigned int reg);
+void qixis_write(unsigned int reg, u8 value);
+u16 qixis_read_minor(void);
+char *qixis_read_time(char *result);
+char *qixis_read_tag(char *buf);
+const char *byte_to_binary_mask(u8 val, u8 mask, char *buf);
+#ifdef CONFIG_SYS_I2C_FPGA_ADDR
+u8 qixis_read_i2c(unsigned int reg);
+void qixis_write_i2c(unsigned int reg, u8 value);
+#endif
+
+#if defined(CONFIG_QIXIS_I2C_ACCESS) && defined(CONFIG_SYS_I2C_FPGA_ADDR)
+#define QIXIS_READ(reg) qixis_read_i2c(offsetof(struct qixis, reg))
+#define QIXIS_WRITE(reg, value) \
+       qixis_write_i2c(offsetof(struct qixis, reg), value)
+#else
+#define QIXIS_READ(reg) qixis_read(offsetof(struct qixis, reg))
+#define QIXIS_WRITE(reg, value) qixis_write(offsetof(struct qixis, reg), value)
+#endif
+
+#ifdef CONFIG_SYS_I2C_FPGA_ADDR
+#define QIXIS_READ_I2C(reg) qixis_read_i2c(offsetof(struct qixis, reg))
+#define QIXIS_WRITE_I2C(reg, value) \
+                       qixis_write_i2c(offsetof(struct qixis, reg), value)
+#endif
+
+/* Use for SDHC adapter card type identification and operation */
+#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
+#define QIXIS_SDID_MASK                         0x07
+#define QIXIS_ESDHC_ADAPTER_TYPE_EMMC45         0x1    /* eMMC Card Rev4.5 */
+#define QIXIS_ESDHC_ADAPTER_TYPE_SDMMC_LEGACY   0x2    /* SD/MMC Legacy Card */
+#define QIXIS_ESDHC_ADAPTER_TYPE_EMMC44         0x3    /* eMMC Card Rev4.4 */
+#define QIXIS_ESDHC_ADAPTER_TYPE_RSV            0x4    /* Reserved */
+#define QIXIS_ESDHC_ADAPTER_TYPE_MMC            0x5    /* MMC Card */
+#define QIXIS_ESDHC_ADAPTER_TYPE_SD             0x6    /* SD Card Rev2.0 3.0 */
+#define QIXIS_ESDHC_NO_ADAPTER                  0x7    /* No Card is Present*/
+
+#define QIXIS_SDCLKIN          0x08
+#define QIXIS_SDCLKOUT         0x02
+#define QIXIS_DAT5_6_7         0X02
+#define QIXIS_DAT4             0X01
+
+#define QIXIS_EVDD_BY_SDHC_VS  0x0c
+#endif
+
+#endif
diff --git a/board/somdevices/common/qspi_header b/board/somdevices/common/qspi_header
new file mode 100644 (file)
index 0000000..d4f3c12
--- /dev/null
@@ -0,0 +1,128 @@
+0                      /*dqs_loopback=0 or 1*/
+0                      /*hold_delay=0 to 3*/
+0                      /*hsphs=0 (Half Speed Phase sampling at non-inverted clock) or 1 (sampling at inverted clock)*/
+0                      /*hsdly=0 (Half Speed Delay one clk delay) or 1 (two clk cycle delay)*/
+0                      /*device_quad_mode_en=1 to enable sending command to SPI device*/
+0                      /*device_cmd=command to device for enableing Quad I/O mode*/
+0                      /*write_cmd_ipcr=hex value to be written to IPCR register for write cmd of device*/
+2000000                        /*write_enable_ipcr=hex value to be written to IPCR register for write enable of device*/
+3                      /*cs_hold_time=0 to 0xF*/
+3                      /*cs_setup_time=0 to 0xF*/
+8000000                /*sflash_A1_size=size in byte(hex)*/
+0              /*sflash_A2_size=size in byte(hex)*/
+8000000                /*sflash_B1_size=size in byte(hex)*/
+0              /*sflash_B2_size=size in byte(hex)*/
+0                      /*sclk_freq=0 to 6*/
+0                      /*busy_bit_offset=bit position of device BUSY in device status register*/
+1                      /*sflash_type=1 (Single), 2 (Dual), 4 (Quad mode of operation)*/
+0                      /*sflash_port=0 or 1 (Port B used)*/
+0                      /*ddr_mode_enable=0 or 1*/
+0                      /*dqs_enable=0 or 1*/
+0                      /*parallel_mode_enable=0 or 1*/
+0                      /*portA_cs1=0 or 1*/
+0                      /*portB_cs1=0 or 1*/
+0                      /*fsphs=0 (Full Speed Phase sampling at non-inverted clock) or 1 (sampling at inverted clock)*/
+0                      /*fsdly=0 (Full Speed Delay One clk delay) or 1 (two clk cycle delay)*/
+0                      /*ddrsmp=0 to 7 (sampling point for incoming data in DDR mode)*/
+08180403               /*lut[0] command sequence*/
+24001c00               /*lut[1] command sequence*/
+0                      /*lut[2] command sequence*/
+0                      /*lut[3] command sequence*/
+0                      /*lut[4] command sequence*/
+0                      /*lut[5] command sequence*/
+0                      /*lut[6] command sequence*/
+0                      /*lut[7] command sequence*/
+0                      /*lut[8] command sequence*/
+0                      /*lut[9] command sequence*/
+0                      /*lut[10] command sequence*/
+0                      /*lut[11] command sequence*/
+0                      /*lut[12] command sequence*/
+0                      /*lut[13] command sequence*/
+0                      /*lut[14] command sequence*/
+0                      /*lut[15] command sequence*/
+0                      /*lut[16] command sequence*/
+0                      /*lut[17] command sequence*/
+0                      /*lut[18] command sequence*/
+0                      /*lut[19] command sequence*/
+0                      /*lut[20] command sequence*/
+0                      /*lut[21] command sequence*/
+0                      /*lut[22] command sequence*/
+0                      /*lut[23] command sequence*/
+0                      /*lut[24] command sequence*/
+0                      /*lut[25] command sequence*/
+0                      /*lut[26] command sequence*/
+0                      /*lut[27] command sequence*/
+0                      /*lut[28] command sequence*/
+0                      /*lut[29] command sequence*/
+0                      /*lut[30] command sequence*/
+0                      /*lut[31] command sequence*/
+0                      /*lut[32] command sequence*/
+0                      /*lut[33] command sequence*/
+0                      /*lut[34] command sequence*/
+0                      /*lut[35] command sequence*/
+0                      /*lut[36] command sequence*/
+0                      /*lut[37] command sequence*/
+0                      /*lut[38] command sequence*/
+0                      /*lut[39] command sequence*/
+0                      /*lut[40] command sequence*/
+0                      /*lut[41] command sequence*/
+0                      /*lut[42] command sequence*/
+0                      /*lut[43] command sequence*/
+0                      /*lut[44] command sequence*/
+0                      /*lut[45] command sequence*/
+0                      /*lut[46] command sequence*/
+0                      /*lut[47] command sequence*/
+0                      /*lut[48] command sequence*/
+0                      /*lut[49] command sequence*/
+0                      /*lut[50] command sequence*/
+0                      /*lut[51] command sequence*/
+0                      /*lut[52] command sequence*/
+0                      /*lut[53] command sequence*/
+0                      /*lut[54] command sequence*/
+0                      /*lut[55] command sequence*/
+0                      /*lut[56] command sequence*/
+0                      /*lut[57] command sequence*/
+0                      /*lut[58] command sequence*/
+0                      /*lut[59] command sequence*/
+0                      /*lut[60] command sequence*/
+0                      /*lut[61] command sequence*/
+0                      /*lut[62] command sequence*/
+0                      /*lut[63] command sequence*/
+1000001                        /*read_status_ipcr=hex value to be written to IPCR register for reading status reg of device*/
+0                      /*enable_dqs_phase=0 or 1*/
+0                      /*config_cmds_en, enable config command*/
+0                      /*config_cmds[0]*/
+0                      /*config_cmds[1]*/
+0                      /*config_cmds[2]*/
+0                      /*config_cmds[3]*/
+0                      /*config_cmds_args[0]*/
+0                      /*config_cmds_args[1]*/
+0                      /*config_cmds_args[2]*/
+0                      /*config_cmds_args[3]*/
+0                      /*io_pad_override_setting QSPI pins override setting*/
+0                      /*reserve[0], 25 byte reserved area*/
+0                      /*reserve[1], 25 byte reserved area*/
+0                      /*reserve[2], 25 byte reserved area*/
+0                      /*reserve[3], 25 byte reserved area*/
+0                      /*reserve[4], 25 byte reserved area*/
+0                      /*reserve[5], 25 byte reserved area*/
+0                      /*reserve[6], 25 byte reserved area*/
+0                      /*reserve[7], 25 byte reserved area*/
+0                      /*reserve[8], 25 byte reserved area*/
+0                      /*reserve[9], 25 byte reserved area*/
+0                      /*reserve[10], 25 byte reserved area*/
+0                      /*reserve[11], 25 byte reserved area*/
+0                      /*reserve[12], 25 byte reserved area*/
+0                      /*reserve[13], 25 byte reserved area*/
+0                      /*reserve[14], 25 byte reserved area*/
+0                      /*reserve[15], 25 byte reserved area*/
+0                      /*reserve[16], 25 byte reserved area*/
+0                      /*reserve[17], 25 byte reserved area*/
+0                      /*reserve[18], 25 byte reserved area*/
+0                      /*reserve[19], 25 byte reserved area*/
+0                      /*reserve[20], 25 byte reserved area*/
+0                      /*reserve[21], 25 byte reserved area*/
+0                      /*reserve[22], 25 byte reserved area*/
+0                      /*reserve[23], 25 byte reserved area*/
+0                      /*reserve[24], 25 byte reserved area*/
+c0ffee01       /*tag, QSPI configuration tag, should be 0xc0ffee01*/
diff --git a/board/somdevices/common/recovery_keypad.c b/board/somdevices/common/recovery_keypad.c
new file mode 100644 (file)
index 0000000..2f5a58a
--- /dev/null
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier:    GPL-2.0+
+/*
+ * Copyright (C) 2010-2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
+ *
+ */
+#include <common.h>
+#include <malloc.h>
+#include <recovery.h>
+#ifdef CONFIG_MXC_KPD
+#include <mxc_keyb.h>
+#endif
+#include <asm/mach-imx/boot_mode.h>
+
+#ifdef CONFIG_MXC_KPD
+#define PRESSED_VOL_DOWN       0x01
+#define PRESSED_POWER      0x02
+#define RECOVERY_KEY_MASK (PRESSED_VOL_DOWN | PRESSED_POWER)
+
+inline int test_key(int value, struct kpp_key_info *ki)
+{
+       return (ki->val == value) && (ki->evt == KDepress);
+}
+
+int is_recovery_keypad_pressing(void)
+{
+       struct kpp_key_info *key_info = NULL;
+       int state = 0, keys, i;
+
+       int ret = 0;
+
+       mxc_kpp_init();
+       /* due to glitch suppression circuit,
+          wait sometime to let all keys scanned. */
+       udelay(1000);
+       keys = mxc_kpp_getc(&key_info);
+
+       printf("Detecting VOL_DOWN+POWER key for recovery(%d:%d) ...\n",
+               keys, keys ? key_info->val : 0);
+       if (keys > 1) {
+               for (i = 0; i < keys; i++) {
+                       if (test_key(CONFIG_POWER_KEY, &key_info[i]))
+                               state |= PRESSED_POWER;
+                       else if (test_key(CONFIG_VOL_DOWN_KEY, &key_info[i]))
+                               state |= PRESSED_VOL_DOWN;
+               }
+       }
+       if ((state & RECOVERY_KEY_MASK) == RECOVERY_KEY_MASK)
+               ret = 1;
+       if (key_info)
+               free(key_info);
+       return ret;
+}
+#else
+/* If not using mxc keypad, currently we will detect power key on board */
+int is_recovery_keypad_pressing(void)
+{
+       return 0;
+}
+#endif
diff --git a/board/somdevices/common/recovery_keypad.h b/board/somdevices/common/recovery_keypad.h
new file mode 100644 (file)
index 0000000..9adf224
--- /dev/null
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier:    GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2017 NXP
+ *
+ */
+
+#ifndef __RECOVERY_KEYPAD_H_
+#define __RECOVERY_KEYPAD_H_
+
+int is_recovery_keypad_pressing(void);
+
+#endif
diff --git a/board/somdevices/common/sdhc_boot.c b/board/somdevices/common/sdhc_boot.c
new file mode 100644 (file)
index 0000000..357aba9
--- /dev/null
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2011 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <mmc.h>
+#include <malloc.h>
+
+/*
+ * The environment variables are written to just after the u-boot image
+ * on SDCard, so we must read the MBR to get the start address and code
+ * length of the u-boot image, then calculate the address of the env.
+ */
+#define ESDHC_BOOT_IMAGE_SIZE  0x48
+#define ESDHC_BOOT_IMAGE_ADDR  0x50
+
+#define ESDHC_DEFAULT_ENVADDR  0x400
+
+int mmc_get_env_addr(struct mmc *mmc, int copy, u32 *env_addr)
+{
+       u8 *tmp_buf;
+       u32 blklen, code_offset, code_len, n;
+
+       blklen = mmc->read_bl_len;
+       tmp_buf = malloc(blklen);
+       if (!tmp_buf)
+               return 1;
+
+       /* read out the first block, get the config data information */
+       n = mmc->block_dev.block_read(&mmc->block_dev, 0, 1, tmp_buf);
+       if (!n) {
+               free(tmp_buf);
+               return 1;
+       }
+
+       /* Get the Source Address, from offset 0x50 */
+       code_offset = *(u32 *)(tmp_buf + ESDHC_BOOT_IMAGE_ADDR);
+
+       /* Get the code size from offset 0x48 */
+       code_len = *(u32 *)(tmp_buf + ESDHC_BOOT_IMAGE_SIZE);
+
+#ifdef CONFIG_ESDHC_HC_BLK_ADDR
+       /*
+        * On soc BSC9131, BSC9132:
+        * In High Capacity SD Cards (> 2 GBytes), the 32-bit source address and
+        * code length of these soc specify the memory address in block address
+        * format. Block length is fixed to 512 bytes as per the SD High
+        * Capacity specification.
+        */
+       u64 tmp;
+
+       if (mmc->high_capacity) {
+               tmp = (u64)code_offset * blklen;
+               tmp += code_len * blklen;
+       } else
+               tmp = code_offset + code_len;
+
+       if ((tmp + CONFIG_ENV_SIZE > mmc->capacity) ||
+                       (tmp > 0xFFFFFFFFU))
+               *env_addr = ESDHC_DEFAULT_ENVADDR;
+       else
+               *env_addr = tmp;
+
+       free(tmp_buf);
+
+       return 0;
+#endif
+
+       *env_addr = code_offset + code_len;
+
+       free(tmp_buf);
+
+       return 0;
+}
diff --git a/board/somdevices/common/sgmii_riser.c b/board/somdevices/common/sgmii_riser.c
new file mode 100644 (file)
index 0000000..f3e0fb2
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Freescale SGMII Riser Card
+ *
+ * This driver supports the SGMII Riser card found on the
+ * "DS" style of development board from Freescale.
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+#include <net.h>
+#include <linux/libfdt.h>
+#include <tsec.h>
+#include <fdt_support.h>
+
+void fsl_sgmii_riser_init(struct tsec_info_struct *tsec_info, int num)
+{
+       int i;
+
+       for (i = 0; i < num; i++)
+               if (tsec_info[i].flags & TSEC_SGMII)
+                       tsec_info[i].phyaddr += SGMII_RISER_PHY_OFFSET;
+}
+
+void fsl_sgmii_riser_fdt_fixup(void *fdt)
+{
+       struct eth_device *dev;
+       int node;
+       int mdio_node;
+       int i = -1;
+       int etsec_num = 0;
+
+       node = fdt_path_offset(fdt, "/aliases");
+       if (node < 0)
+               return;
+
+       while ((dev = eth_get_dev_by_index(++i)) != NULL) {
+               struct tsec_private *priv;
+               int phy_node;
+               int enet_node;
+               uint32_t ph;
+               char sgmii_phy[16];
+               char enet[16];
+               const u32 *phyh;
+               const char *model;
+               const char *path;
+
+               if (!strstr(dev->name, "eTSEC"))
+                       continue;
+
+               priv = dev->priv;
+               if (!(priv->flags & TSEC_SGMII)) {
+                       etsec_num++;
+                       continue;
+               }
+
+               mdio_node = fdt_node_offset_by_compatible(fdt, -1,
+                               "fsl,gianfar-mdio");
+               if (mdio_node < 0)
+                       return;
+
+               sprintf(sgmii_phy, "sgmii-phy@%d", etsec_num);
+               phy_node = fdt_subnode_offset(fdt, mdio_node, sgmii_phy);
+               if (phy_node > 0) {
+                       fdt_increase_size(fdt, 32);
+                       ph = fdt_create_phandle(fdt, phy_node);
+                       if (!ph)
+                               continue;
+               }
+
+               sprintf(enet, "ethernet%d", etsec_num++);
+               path = fdt_getprop(fdt, node, enet, NULL);
+               if (!path) {
+                       debug("No alias for %s\n", enet);
+                       continue;
+               }
+
+               enet_node = fdt_path_offset(fdt, path);
+               if (enet_node < 0)
+                       continue;
+
+               model = fdt_getprop(fdt, enet_node, "model", NULL);
+
+               /*
+                * We only want to do this to eTSECs.  On some platforms
+                * there are more than one type of gianfar-style ethernet
+                * controller, and as we are creating an implicit connection
+                * between ethernet nodes and eTSEC devices, it is best to
+                * make the connection use as much explicit information
+                * as exists.
+                */
+               if (!strstr(model, "TSEC"))
+                       continue;
+
+               if (phy_node < 0) {
+                       /*
+                        * This part is only for old device tree without
+                        * sgmii_phy nodes. It's kept just for compatible
+                        * reason. Soon to be deprecated if all device tree
+                        * get updated.
+                        */
+                       phyh = fdt_getprop(fdt, enet_node, "phy-handle", NULL);
+                       if (!phyh)
+                               continue;
+
+                       phy_node = fdt_node_offset_by_phandle(fdt,
+                                       fdt32_to_cpu(*phyh));
+
+                       priv = dev->priv;
+
+                       if (priv->flags & TSEC_SGMII)
+                               fdt_setprop_cell(fdt, phy_node, "reg",
+                                               priv->phyaddr);
+               } else {
+                       fdt_setprop(fdt, enet_node, "phy-handle", &ph,
+                                       sizeof(ph));
+                       fdt_setprop_string(fdt, enet_node,
+                                       "phy-connection-type",
+                                       phy_string_for_interface(
+                                               PHY_INTERFACE_MODE_SGMII));
+               }
+       }
+}
diff --git a/board/somdevices/common/sgmii_riser.h b/board/somdevices/common/sgmii_riser.h
new file mode 100644 (file)
index 0000000..e1fcc85
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Freescale SGMII Riser Card
+ *
+ * This driver supports the SGMII Riser card found on the
+ * "DS" style of development board from Freescale.
+ *
+ * This software may be used and distributed according to the
+ * terms of the GNU Public License, Version 2, incorporated
+ * herein by reference.
+ *
+ * Copyright 2008 Freescale Semiconductor, Inc.
+ *
+ */
+
+void fsl_sgmii_riser_init(struct tsec_info_struct *tsec_info, int num);
+void fsl_sgmii_riser_fdt_fixup(void *fdt);
diff --git a/board/somdevices/common/sleep.h b/board/somdevices/common/sleep.h
new file mode 100644 (file)
index 0000000..1450baa
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __SLEEP_H
+#define __SLEEP_H
+
+#define DCFG_CCSR_CRSTSR_WDRFR (1 << 3)
+#define DDR_BUFF_LEN                   128
+
+/* determine if it is a wakeup from deep sleep */
+bool is_warm_boot(void);
+
+/* disable console output */
+void fsl_dp_disable_console(void);
+
+/* clean up everything and jump to kernel */
+int fsl_dp_resume(void);
+#endif
diff --git a/board/somdevices/common/spl.h b/board/somdevices/common/spl.h
new file mode 100644 (file)
index 0000000..d4689d3
--- /dev/null
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2016 Google, Inc
+ */
+
+#ifndef __FREESCALE_BOARD_SPL_H
+#define __FREESCALE_BOARD_SPL_H
+
+void fsl_spi_spl_load_image(uint32_t offs, unsigned int size, void *vdst);
+void fsl_spi_boot(void) __noreturn;
+
+#endif
diff --git a/board/somdevices/common/sys_eeprom.c b/board/somdevices/common/sys_eeprom.c
new file mode 100644 (file)
index 0000000..ab0fe0b
--- /dev/null
@@ -0,0 +1,542 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2006, 2008-2009, 2011 Freescale Semiconductor
+ * York Sun (yorksun@freescale.com)
+ * Haiying Wang (haiying.wang@freescale.com)
+ * Timur Tabi (timur@freescale.com)
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <linux/ctype.h>
+
+#ifdef CONFIG_SYS_I2C_EEPROM_CCID
+#include "../common/eeprom.h"
+#define MAX_NUM_PORTS  8
+#endif
+
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+/* some boards with non-256-bytes EEPROM have special define */
+/* for MAX_NUM_PORTS in board-specific file */
+#ifndef MAX_NUM_PORTS
+#define MAX_NUM_PORTS  16
+#endif
+#define NXID_VERSION   1
+#endif
+
+/**
+ * static eeprom: EEPROM layout for CCID or NXID formats
+ *
+ * See application note AN3638 for details.
+ */
+static struct __attribute__ ((__packed__)) eeprom {
+#ifdef CONFIG_SYS_I2C_EEPROM_CCID
+       u8 id[4];         /* 0x00 - 0x03 EEPROM Tag 'CCID' */
+       u8 major;         /* 0x04        Board revision, major */
+       u8 minor;         /* 0x05        Board revision, minor */
+       u8 sn[10];        /* 0x06 - 0x0F Serial Number*/
+       u8 errata[2];     /* 0x10 - 0x11 Errata Level */
+       u8 date[6];       /* 0x12 - 0x17 Build Date */
+       u8 res_0[40];     /* 0x18 - 0x3f Reserved */
+       u8 mac_count;     /* 0x40        Number of MAC addresses */
+       u8 mac_flag;      /* 0x41        MAC table flags */
+       u8 mac[MAX_NUM_PORTS][6];     /* 0x42 - 0x71 MAC addresses */
+       u32 crc;          /* 0x72        CRC32 checksum */
+#endif
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       u8 id[4];         /* 0x00 - 0x03 EEPROM Tag 'NXID' */
+       u8 sn[12];        /* 0x04 - 0x0F Serial Number */
+       u8 errata[5];     /* 0x10 - 0x14 Errata Level */
+       u8 date[6];       /* 0x15 - 0x1a Build Date */
+       u8 res_0;         /* 0x1b        Reserved */
+       u32 version;      /* 0x1c - 0x1f NXID Version */
+       u8 tempcal[8];    /* 0x20 - 0x27 Temperature Calibration Factors */
+       u8 tempcalsys[2]; /* 0x28 - 0x29 System Temperature Calibration Factors */
+       u8 tempcalflags;  /* 0x2a        Temperature Calibration Flags */
+       u8 res_1[21];     /* 0x2b - 0x3f Reserved */
+       u8 mac_count;     /* 0x40        Number of MAC addresses */
+       u8 mac_flag;      /* 0x41        MAC table flags */
+       u8 mac[MAX_NUM_PORTS][6];     /* 0x42 - 0xa1 MAC addresses */
+       u8 res_2[90];     /* 0xa2 - 0xfb Reserved */    
+       u32 crc;          /* 0xfc - 0xff CRC32 checksum */
+#endif
+} e;
+
+/* Set to 1 if we've read EEPROM into memory */
+static int has_been_read = 0;
+
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+/* Is this a valid NXID EEPROM? */
+#define is_valid ((e.id[0] == 'N') || (e.id[1] == 'X') || \
+                 (e.id[2] == 'I') || (e.id[3] == 'D'))
+#endif
+
+#ifdef CONFIG_SYS_I2C_EEPROM_CCID
+/* Is this a valid CCID EEPROM? */
+#define is_valid ((e.id[0] == 'C') || (e.id[1] == 'C') || \
+                 (e.id[2] == 'I') || (e.id[3] == 'D'))
+#endif
+
+/**
+ * show_eeprom - display the contents of the EEPROM
+ */
+static void show_eeprom(void)
+{
+       int i;
+       unsigned int crc;
+
+       /* EEPROM tag ID, either CCID or NXID */
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       printf("ID: %c%c%c%c v%u\n", e.id[0], e.id[1], e.id[2], e.id[3],
+              be32_to_cpu(e.version));
+#else
+       printf("ID: %c%c%c%c\n", e.id[0], e.id[1], e.id[2], e.id[3]);
+#endif
+
+       /* Serial number */
+       printf("SN: %s\n", e.sn);
+
+       /* Errata level. */
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       printf("Errata: %s\n", e.errata);
+#else
+       printf("Errata: %c%c\n",
+               e.errata[0] ? e.errata[0] : '.',
+               e.errata[1] ? e.errata[1] : '.');
+#endif
+
+       /* Build date, BCD date values, as YYMMDDhhmmss */
+       printf("Build date: 20%02x/%02x/%02x %02x:%02x:%02x %s\n",
+               e.date[0], e.date[1], e.date[2],
+               e.date[3] & 0x7F, e.date[4], e.date[5],
+               e.date[3] & 0x80 ? "PM" : "");
+
+       /* Show MAC addresses  */
+       for (i = 0; i < min(e.mac_count, (u8)MAX_NUM_PORTS); i++) {
+
+               u8 *p = e.mac[i];
+
+               printf("Eth%u: %02x:%02x:%02x:%02x:%02x:%02x\n", i,
+                       p[0], p[1], p[2], p[3], p[4], p[5]);
+       }
+
+       crc = crc32(0, (void *)&e, sizeof(e) - 4);
+
+       if (crc == be32_to_cpu(e.crc))
+               printf("CRC: %08x\n", be32_to_cpu(e.crc));
+       else
+               printf("CRC: %08x (should be %08x)\n",
+                       be32_to_cpu(e.crc), crc);
+
+#ifdef DEBUG
+       printf("EEPROM dump: (0x%x bytes)\n", sizeof(e));
+       for (i = 0; i < sizeof(e); i++) {
+               if ((i % 16) == 0)
+                       printf("%02X: ", i);
+               printf("%02X ", ((u8 *)&e)[i]);
+               if (((i % 16) == 15) || (i == sizeof(e) - 1))
+                       printf("\n");
+       }
+#endif
+}
+
+/**
+ * read_eeprom - read the EEPROM into memory
+ */
+static int read_eeprom(void)
+{
+       int ret;
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+       unsigned int bus;
+#endif
+
+       if (has_been_read)
+               return 0;
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+       bus = i2c_get_bus_num();
+       i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
+#endif
+
+       ret = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0, CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
+               (void *)&e, sizeof(e));
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+       i2c_set_bus_num(bus);
+#endif
+
+#ifdef DEBUG
+       show_eeprom();
+#endif
+
+       has_been_read = (ret == 0) ? 1 : 0;
+
+       return ret;
+}
+
+/**
+ *  update_crc - update the CRC
+ *
+ *  This function should be called after each update to the EEPROM structure,
+ *  to make sure the CRC is always correct.
+ */
+static void update_crc(void)
+{
+       u32 crc;
+
+       crc = crc32(0, (void *)&e, sizeof(e) - 4);
+       e.crc = cpu_to_be32(crc);
+}
+
+/**
+ * prog_eeprom - write the EEPROM from memory
+ */
+static int prog_eeprom(void)
+{
+       int ret = 0;
+       int i;
+       void *p;
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+       unsigned int bus;
+#endif
+
+       /* Set the reserved values to 0xFF   */
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       e.res_0 = 0xFF;
+       memset(e.res_1, 0xFF, sizeof(e.res_1));
+#else
+       memset(e.res_0, 0xFF, sizeof(e.res_0));
+#endif
+       update_crc();
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+       bus = i2c_get_bus_num();
+       i2c_set_bus_num(CONFIG_SYS_EEPROM_BUS_NUM);
+#endif
+
+       /*
+        * The AT24C02 datasheet says that data can only be written in page
+        * mode, which means 8 bytes at a time, and it takes up to 5ms to
+        * complete a given write.
+        */
+       for (i = 0, p = &e; i < sizeof(e); i += 8, p += 8) {
+               ret = i2c_write(CONFIG_SYS_I2C_EEPROM_ADDR, i, CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
+                               p, min((int)(sizeof(e) - i), 8));
+               if (ret)
+                       break;
+               udelay(5000);   /* 5ms write cycle timing */
+       }
+
+       if (!ret) {
+               /* Verify the write by reading back the EEPROM and comparing */
+               struct eeprom e2;
+
+               ret = i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0,
+                       CONFIG_SYS_I2C_EEPROM_ADDR_LEN, (void *)&e2, sizeof(e2));
+               if (!ret && memcmp(&e, &e2, sizeof(e)))
+                       ret = -1;
+       }
+
+#ifdef CONFIG_SYS_EEPROM_BUS_NUM
+       i2c_set_bus_num(bus);
+#endif
+
+       if (ret) {
+               printf("Programming failed.\n");
+               has_been_read = 0;
+               return -1;
+       }
+
+       printf("Programming passed.\n");
+       return 0;
+}
+
+/**
+ * h2i - converts hex character into a number
+ *
+ * This function takes a hexadecimal character (e.g. '7' or 'C') and returns
+ * the integer equivalent.
+ */
+static inline u8 h2i(char p)
+{
+       if ((p >= '0') && (p <= '9'))
+               return p - '0';
+
+       if ((p >= 'A') && (p <= 'F'))
+               return (p - 'A') + 10;
+
+       if ((p >= 'a') && (p <= 'f'))
+               return (p - 'a') + 10;
+
+       return 0;
+}
+
+/**
+ * set_date - stores the build date into the EEPROM
+ *
+ * This function takes a pointer to a string in the format "YYMMDDhhmmss"
+ * (2-digit year, 2-digit month, etc), converts it to a 6-byte BCD string,
+ * and stores it in the build date field of the EEPROM local copy.
+ */
+static void set_date(const char *string)
+{
+       unsigned int i;
+
+       if (strlen(string) != 12) {
+               printf("Usage: mac date YYMMDDhhmmss\n");
+               return;
+       }
+
+       for (i = 0; i < 6; i++)
+               e.date[i] = h2i(string[2 * i]) << 4 | h2i(string[2 * i + 1]);
+
+       update_crc();
+}
+
+/**
+ * set_mac_address - stores a MAC address into the EEPROM
+ *
+ * This function takes a pointer to MAC address string
+ * (i.e."XX:XX:XX:XX:XX:XX", where "XX" is a two-digit hex number) and
+ * stores it in one of the MAC address fields of the EEPROM local copy.
+ */
+static void set_mac_address(unsigned int index, const char *string)
+{
+       char *p = (char *) string;
+       unsigned int i;
+
+       if ((index >= MAX_NUM_PORTS) || !string) {
+               printf("Usage: mac <n> XX:XX:XX:XX:XX:XX\n");
+               return;
+       }
+
+       for (i = 0; *p && (i < 6); i++) {
+               e.mac[index][i] = simple_strtoul(p, &p, 16);
+               if (*p == ':')
+                       p++;
+       }
+
+       update_crc();
+}
+
+int do_mac(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+       char cmd;
+
+       if (argc == 1) {
+               show_eeprom();
+               return 0;
+       }
+
+       cmd = argv[1][0];
+
+       if (cmd == 'r') {
+               read_eeprom();
+               return 0;
+       }
+
+       if (cmd == 'i') {
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+               memcpy(e.id, "NXID", sizeof(e.id));
+               e.version = cpu_to_be32(NXID_VERSION);
+#else
+               memcpy(e.id, "CCID", sizeof(e.id));
+#endif
+               update_crc();
+               return 0;
+       }
+
+       if (!is_valid) {
+               printf("Please read the EEPROM ('r') and/or set the ID ('i') first.\n");
+               return 0;
+       }
+
+       if (argc == 2) {
+               switch (cmd) {
+               case 's':       /* save */
+                       prog_eeprom();
+                       break;
+               default:
+                       return cmd_usage(cmdtp);
+               }
+
+               return 0;
+       }
+
+       /* We know we have at least one parameter  */
+
+       switch (cmd) {
+       case 'n':       /* serial number */
+               memset(e.sn, 0, sizeof(e.sn));
+               strncpy((char *)e.sn, argv[2], sizeof(e.sn) - 1);
+               update_crc();
+               break;
+       case 'e':       /* errata */
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+               memset(e.errata, 0, 5);
+               strncpy((char *)e.errata, argv[2], 4);
+#else
+               e.errata[0] = argv[2][0];
+               e.errata[1] = argv[2][1];
+#endif
+               update_crc();
+               break;
+       case 'd':       /* date BCD format YYMMDDhhmmss */
+               set_date(argv[2]);
+               break;
+       case 'p':       /* MAC table size */
+               e.mac_count = simple_strtoul(argv[2], NULL, 16);
+               update_crc();
+               break;
+       case '0' ... '9':       /* "mac 0" through "mac 22" */
+               set_mac_address(simple_strtoul(argv[1], NULL, 10), argv[2]);
+               break;
+       case 'h':       /* help */
+       default:
+               return cmd_usage(cmdtp);
+       }
+
+       return 0;
+}
+
+/**
+ * mac_read_from_eeprom - read the MAC addresses from EEPROM
+ *
+ * This function reads the MAC addresses from EEPROM and sets the
+ * appropriate environment variables for each one read.
+ *
+ * The environment variables are only set if they haven't been set already.
+ * This ensures that any user-saved variables are never overwritten.
+ *
+ * This function must be called after relocation.
+ *
+ * For NXID v1 EEPROMs, we support loading and up-converting the older NXID v0
+ * format.  In a v0 EEPROM, there are only eight MAC addresses and the CRC is
+ * located at a different offset.
+ */
+int mac_read_from_eeprom(void)
+{
+       unsigned int i;
+       u32 crc, crc_offset = offsetof(struct eeprom, crc);
+       u32 *crcp; /* Pointer to the CRC in the data read from the EEPROM */
+
+       puts("EEPROM: ");
+
+       if (read_eeprom()) {
+               printf("Read failed.\n");
+               return 0;
+       }
+
+       if (!is_valid) {
+               printf("Invalid ID (%02x %02x %02x %02x)\n",
+                      e.id[0], e.id[1], e.id[2], e.id[3]);
+               return 0;
+       }
+
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       /*
+        * If we've read an NXID v0 EEPROM, then we need to set the CRC offset
+        * to where it is in v0.
+        */
+       if (e.version == 0)
+               crc_offset = 0x72;
+#endif
+
+       crc = crc32(0, (void *)&e, crc_offset);
+       crcp = (void *)&e + crc_offset;
+       if (crc != be32_to_cpu(*crcp)) {
+               printf("CRC mismatch (%08x != %08x)\n", crc, be32_to_cpu(e.crc));
+               return 0;
+       }
+
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       /*
+        * MAC address #9 in v1 occupies the same position as the CRC in v0.
+        * Erase it so that it's not mistaken for a MAC address.  We'll
+        * update the CRC later.
+        */
+       if (e.version == 0)
+               memset(e.mac[8], 0xff, 6);
+#endif
+
+       for (i = 0; i < min(e.mac_count, (u8)MAX_NUM_PORTS); i++) {
+               if (memcmp(&e.mac[i], "\0\0\0\0\0\0", 6) &&
+                   memcmp(&e.mac[i], "\xFF\xFF\xFF\xFF\xFF\xFF", 6)) {
+                       char ethaddr[18];
+                       char enetvar[9];
+
+                       sprintf(ethaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
+                               e.mac[i][0],
+                               e.mac[i][1],
+                               e.mac[i][2],
+                               e.mac[i][3],
+                               e.mac[i][4],
+                               e.mac[i][5]);
+                       sprintf(enetvar, i ? "eth%daddr" : "ethaddr", i);
+                       /* Only initialize environment variables that are blank
+                        * (i.e. have not yet been set)
+                        */
+                       if (!env_get(enetvar))
+                               env_set(enetvar, ethaddr);
+               }
+       }
+
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       printf("%c%c%c%c v%u\n", e.id[0], e.id[1], e.id[2], e.id[3],
+              be32_to_cpu(e.version));
+#else
+       printf("%c%c%c%c\n", e.id[0], e.id[1], e.id[2], e.id[3]);
+#endif
+
+#ifdef CONFIG_SYS_I2C_EEPROM_NXID
+       /*
+        * Now we need to upconvert the data into v1 format.  We do this last so
+        * that at boot time, U-Boot will still say "NXID v0".
+        */
+       if (e.version == 0) {
+               e.version = cpu_to_be32(NXID_VERSION);
+               update_crc();
+       }
+#endif
+
+       return 0;
+}
+
+#ifdef CONFIG_SYS_I2C_EEPROM_CCID
+
+/**
+ * get_cpu_board_revision - get the CPU board revision on 85xx boards
+ *
+ * Read the EEPROM to determine the board revision.
+ *
+ * This function is called before relocation, so we need to read a private
+ * copy of the EEPROM into a local variable on the stack.
+ *
+ * Also, we assume that CONFIG_SYS_EEPROM_BUS_NUM == CONFIG_SYS_SPD_BUS_NUM.  The global
+ * variable i2c_bus_num must be compile-time initialized to CONFIG_SYS_SPD_BUS_NUM,
+ * so that the SPD code will work.  This means that all pre-relocation I2C
+ * operations can only occur on the CONFIG_SYS_SPD_BUS_NUM bus.  So if
+ * CONFIG_SYS_EEPROM_BUS_NUM != CONFIG_SYS_SPD_BUS_NUM, then we can't read the EEPROM when
+ * this function is called.  Oh well.
+ */
+unsigned int get_cpu_board_revision(void)
+{
+       struct board_eeprom {
+               u32 id;           /* 0x00 - 0x03 EEPROM Tag 'CCID' */
+               u8 major;         /* 0x04        Board revision, major */
+               u8 minor;         /* 0x05        Board revision, minor */
+       } be;
+
+       i2c_read(CONFIG_SYS_I2C_EEPROM_ADDR, 0, CONFIG_SYS_I2C_EEPROM_ADDR_LEN,
+               (void *)&be, sizeof(be));
+
+       if (be.id != (('C' << 24) | ('C' << 16) | ('I' << 8) | 'D'))
+               return MPC85XX_CPU_BOARD_REV(0, 0);
+
+       if ((be.major == 0xff) && (be.minor == 0xff))
+               return MPC85XX_CPU_BOARD_REV(0, 0);
+
+       return MPC85XX_CPU_BOARD_REV(be.major, be.minor);
+}
+#endif
diff --git a/board/somdevices/common/tcpc.c b/board/somdevices/common/tcpc.c
new file mode 100644 (file)
index 0000000..bf3e371
--- /dev/null
@@ -0,0 +1,1012 @@
+/*
+ * Copyright 2017,2019 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+#include <common.h>
+#include <i2c.h>
+#include <time.h>
+#include "tcpc.h"
+
+#ifdef DEBUG
+#define tcpc_debug_log(port, fmt, args...) tcpc_log(port, fmt, ##args)
+#else
+#define tcpc_debug_log(port, fmt, args...)
+#endif
+
+static int tcpc_log(struct tcpc_port *port, const char *fmt, ...)
+{
+       va_list args;
+       int i;
+
+       va_start(args, fmt);
+       i = vscnprintf(port->log_p, port->log_size, fmt, args);
+       va_end(args);
+
+       port->log_size -= i;
+       port->log_p += i;
+
+       return i;
+}
+
+int tcpc_set_cc_to_source(struct tcpc_port *port)
+{
+       uint8_t valb;
+       int err;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       valb = (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC1_SHIFT) |
+                       (TCPC_ROLE_CTRL_CC_RP << TCPC_ROLE_CTRL_CC2_SHIFT) |
+                       (TCPC_ROLE_CTRL_RP_VAL_DEF <<
+                        TCPC_ROLE_CTRL_RP_VAL_SHIFT) | TCPC_ROLE_CTRL_DRP;
+
+       err = dm_i2c_write(port->i2c_dev, TCPC_ROLE_CTRL, &valb, 1);
+       if (err)
+               tcpc_log(port, "%s dm_i2c_write failed, err %d\n", __func__, err);
+       return err;
+}
+
+int tcpc_set_cc_to_sink(struct tcpc_port *port)
+{
+       uint8_t valb;
+       int err;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       valb = (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC1_SHIFT) |
+                       (TCPC_ROLE_CTRL_CC_RD << TCPC_ROLE_CTRL_CC2_SHIFT) | TCPC_ROLE_CTRL_DRP;
+
+       err = dm_i2c_write(port->i2c_dev, TCPC_ROLE_CTRL, &valb, 1);
+       if (err)
+               tcpc_log(port, "%s dm_i2c_write failed, err %d\n", __func__, err);
+       return err;
+}
+
+
+int tcpc_set_plug_orientation(struct tcpc_port *port, enum typec_cc_polarity polarity)
+{
+       uint8_t valb;
+       int err;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       err = dm_i2c_read(port->i2c_dev, TCPC_TCPC_CTRL, &valb, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       if (polarity == TYPEC_POLARITY_CC2)
+               valb |= TCPC_TCPC_CTRL_ORIENTATION;
+       else
+               valb &= ~TCPC_TCPC_CTRL_ORIENTATION;
+
+       err = dm_i2c_write(port->i2c_dev, TCPC_TCPC_CTRL, &valb, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_write failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int tcpc_get_cc_status(struct tcpc_port *port, enum typec_cc_polarity *polarity, enum typec_cc_state *state)
+{
+
+       uint8_t valb_cc, cc2, cc1;
+       int err;
+
+       if (port == NULL || polarity == NULL || state == NULL)
+               return -EINVAL;
+
+       err = dm_i2c_read(port->i2c_dev, TCPC_CC_STATUS, (uint8_t *)&valb_cc, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       tcpc_debug_log(port, "cc status 0x%x\n", valb_cc);
+
+       cc2 = (valb_cc >> TCPC_CC_STATUS_CC2_SHIFT) & TCPC_CC_STATUS_CC2_MASK;
+       cc1 = (valb_cc >> TCPC_CC_STATUS_CC1_SHIFT) & TCPC_CC_STATUS_CC1_MASK;
+
+       if (valb_cc & TCPC_CC_STATUS_LOOK4CONN)
+               return -EFAULT;
+
+       *state = TYPEC_STATE_OPEN;
+
+       if (valb_cc & TCPC_CC_STATUS_TERM) {
+               if (cc2) {
+                       *polarity = TYPEC_POLARITY_CC2;
+
+                       switch (cc2) {
+                       case 0x1:
+                               *state = TYPEC_STATE_SNK_DEFAULT;
+                               tcpc_log(port, "SNK.Default on CC2\n");
+                               break;
+                       case 0x2:
+                               *state = TYPEC_STATE_SNK_POWER15;
+                               tcpc_log(port, "SNK.Power1.5 on CC2\n");
+                               break;
+                       case 0x3:
+                               *state = TYPEC_STATE_SNK_POWER30;
+                               tcpc_log(port, "SNK.Power3.0 on CC2\n");
+                               break;
+                       }
+               } else if (cc1) {
+                       *polarity = TYPEC_POLARITY_CC1;
+
+                       switch (cc1) {
+                       case 0x1:
+                               *state = TYPEC_STATE_SNK_DEFAULT;
+                               tcpc_log(port, "SNK.Default on CC1\n");
+                               break;
+                       case 0x2:
+                               *state = TYPEC_STATE_SNK_POWER15;
+                               tcpc_log(port, "SNK.Power1.5 on CC1\n");
+                               break;
+                       case 0x3:
+                               *state = TYPEC_STATE_SNK_POWER30;
+                               tcpc_log(port, "SNK.Power3.0 on CC1\n");
+                               break;
+                       }
+               } else {
+                       *state = TYPEC_STATE_OPEN;
+                       return -EPERM;
+               }
+
+       } else {
+               if (cc2) {
+                       *polarity = TYPEC_POLARITY_CC2;
+
+                       switch (cc2) {
+                       case 0x1:
+                               if (cc1 == 0x1) {
+                                       *state = TYPEC_STATE_SRC_BOTH_RA;
+                                       tcpc_log(port, "SRC.Ra on both CC1 and CC2\n");
+                               } else if (cc1 == 0x2) {
+                                       *state = TYPEC_STATE_SRC_RD_RA;
+                                       tcpc_log(port, "SRC.Ra on CC2, SRC.Rd on CC1\n");
+                               } else if (cc1 == 0x0) {
+                                       tcpc_log(port, "SRC.Ra only on CC2\n");
+                                       return -EFAULT;
+                               } else
+                                       return -EFAULT;
+                               break;
+                       case 0x2:
+                               if (cc1 == 0x1) {
+                                       *state = TYPEC_STATE_SRC_RD_RA;
+                                       tcpc_log(port, "SRC.Ra on CC1, SRC.Rd on CC2\n");
+                               } else if (cc1 == 0x0) {
+                                       *state = TYPEC_STATE_SRC_RD;
+                                       tcpc_log(port, "SRC.Rd on CC2\n");
+                               } else
+                                       return -EFAULT;
+                               break;
+                       case 0x3:
+                               *state = TYPEC_STATE_SRC_RESERVED;
+                               return -EFAULT;
+                       }
+               } else if (cc1) {
+                       *polarity = TYPEC_POLARITY_CC1;
+
+                       switch (cc1) {
+                       case 0x1:
+                               tcpc_log(port, "SRC.Ra only on CC1\n");
+                               return -EFAULT;
+                       case 0x2:
+                               *state = TYPEC_STATE_SRC_RD;
+                               tcpc_log(port, "SRC.Rd on CC1\n");
+                               break;
+                       case 0x3:
+                               *state = TYPEC_STATE_SRC_RESERVED;
+                               return -EFAULT;
+                       }
+               } else {
+                       *state = TYPEC_STATE_OPEN;
+                       return -EPERM;
+               }
+       }
+
+       return 0;
+}
+
+int tcpc_clear_alert(struct tcpc_port *port, uint16_t clear_mask)
+{
+       int err;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       err = dm_i2c_write(port->i2c_dev, TCPC_ALERT, (const uint8_t *)&clear_mask, 2);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_write failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int tcpc_send_command(struct tcpc_port *port, uint8_t command)
+{
+       int err;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       err = dm_i2c_write(port->i2c_dev, TCPC_COMMAND, (const uint8_t *)&command, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_write failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int tcpc_polling_reg(struct tcpc_port *port, uint8_t reg,
+       uint8_t reg_width, uint16_t mask, uint16_t value, ulong timeout_ms)
+{
+       uint16_t val = 0;
+       int err;
+       ulong start;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       tcpc_debug_log(port, "%s reg 0x%x, mask 0x%x, value 0x%x\n", __func__, reg, mask, value);
+
+       /* TCPC registers is 8 bits or 16 bits */
+       if (reg_width != 1 && reg_width != 2)
+               return -EINVAL;
+
+       start = get_timer(0);   /* Get current timestamp */
+       do {
+               err = dm_i2c_read(port->i2c_dev, reg, (uint8_t *)&val, reg_width);
+               if (err)
+                       return -EIO;
+
+               if ((val & mask) == value)
+                       return 0;
+       } while (get_timer(0) < (start + timeout_ms));
+
+       return -ETIME;
+}
+
+void tcpc_print_log(struct tcpc_port *port)
+{
+       if (port == NULL)
+               return;
+
+       if (port->log_print == port->log_p) /*nothing to output*/
+               return;
+
+       printf("%s", port->log_print);
+
+       port->log_print = port->log_p;
+}
+
+int tcpc_setup_dfp_mode(struct tcpc_port *port)
+{
+       enum typec_cc_polarity pol;
+       enum typec_cc_state state;
+       int ret;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       if (tcpc_pd_sink_check_charging(port)) {
+               tcpc_log(port, "%s: Can't apply DFP mode when PD is charging\n",
+                       __func__);
+               return -EPERM;
+       }
+
+       tcpc_set_cc_to_source(port);
+
+       ret = tcpc_send_command(port, TCPC_CMD_LOOK4CONNECTION);
+       if (ret)
+               return ret;
+
+       /* At least wait tCcStatusDelay + tTCPCFilter + tCcTCPCSampleRate (max) = 200us + 500us + ?ms
+        * PTN5110 datasheet does not contain the sample rate value, according other productions,
+        * the sample rate is at ms level, about 2 ms -10ms. So wait 100ms should be enough.
+        */
+       mdelay(100);
+
+       ret = tcpc_polling_reg(port, TCPC_ALERT, 2, TCPC_ALERT_CC_STATUS, TCPC_ALERT_CC_STATUS, 100);
+       if (ret) {
+               tcpc_log(port, "%s: Polling ALERT register, TCPC_ALERT_CC_STATUS bit failed, ret = %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       ret = tcpc_get_cc_status(port, &pol, &state);
+       tcpc_clear_alert(port, TCPC_ALERT_CC_STATUS);
+
+       if (!ret) {
+               /* If presenting as Rd/audio mode/open, return */
+               if (state != TYPEC_STATE_SRC_RD_RA && state != TYPEC_STATE_SRC_RD)
+                       return -EPERM;
+
+               if (pol == TYPEC_POLARITY_CC1)
+                       tcpc_debug_log(port, "polarity cc1\n");
+               else
+                       tcpc_debug_log(port, "polarity cc2\n");
+
+               if (port->ss_sel_func)
+                       port->ss_sel_func(pol);
+
+               ret = tcpc_set_plug_orientation(port, pol);
+               if (ret)
+                       return ret;
+
+               /* Enable source vbus default voltage */
+               ret = tcpc_send_command(port, TCPC_CMD_SRC_VBUS_DEFAULT);
+               if (ret)
+                       return ret;
+
+               /* The max vbus on time is 200ms, we add margin 100ms */
+               mdelay(300);
+
+       }
+
+       return 0;
+}
+
+int tcpc_setup_ufp_mode(struct tcpc_port *port)
+{
+       enum typec_cc_polarity pol;
+       enum typec_cc_state state;
+       int ret;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       /* Check if the PD charge is working. If not, need to configure CC role for UFP */
+       if (!tcpc_pd_sink_check_charging(port)) {
+
+               /* Disable the source vbus once it is enabled by DFP mode */
+               tcpc_disable_src_vbus(port);
+
+               tcpc_set_cc_to_sink(port);
+
+               ret = tcpc_send_command(port, TCPC_CMD_LOOK4CONNECTION);
+               if (ret)
+                       return ret;
+
+               /* At least wait tCcStatusDelay + tTCPCFilter + tCcTCPCSampleRate (max) = 200us + 500us + ?ms
+                * PTN5110 datasheet does not contain the sample rate value, according other productions,
+                * the sample rate is at ms level, about 2 ms -10ms. So wait 100ms should be enough.
+                */
+               mdelay(100);
+
+               ret = tcpc_polling_reg(port, TCPC_ALERT, 2, TCPC_ALERT_CC_STATUS, TCPC_ALERT_CC_STATUS, 100);
+               if (ret) {
+                       tcpc_log(port, "%s: Polling ALERT register, TCPC_ALERT_CC_STATUS bit failed, ret = %d\n",
+                               __func__, ret);
+                       return ret;
+               }
+
+               ret = tcpc_get_cc_status(port, &pol, &state);
+               tcpc_clear_alert(port, TCPC_ALERT_CC_STATUS);
+
+       } else {
+               ret = tcpc_get_cc_status(port, &pol, &state);
+       }
+
+       if (!ret) {
+               /* If presenting not as sink, then return */
+               if (state != TYPEC_STATE_SNK_DEFAULT && state != TYPEC_STATE_SNK_POWER15 &&
+                       state != TYPEC_STATE_SNK_POWER30)
+                       return -EPERM;
+
+               if (pol == TYPEC_POLARITY_CC1)
+                       tcpc_debug_log(port, "polarity cc1\n");
+               else
+                       tcpc_debug_log(port, "polarity cc2\n");
+
+               if (port->ss_sel_func)
+                       port->ss_sel_func(pol);
+
+               ret = tcpc_set_plug_orientation(port, pol);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int tcpc_disable_src_vbus(struct tcpc_port *port)
+{
+       int ret;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       /* Disable VBUS*/
+       ret = tcpc_send_command(port, TCPC_CMD_DISABLE_SRC_VBUS);
+       if (ret)
+               return ret;
+
+       /* The max vbus off time is 0.5ms, we add margin 0.5 ms */
+       mdelay(1);
+
+       return 0;
+}
+
+int tcpc_disable_sink_vbus(struct tcpc_port *port)
+{
+       int ret;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       /* Disable SINK VBUS*/
+       ret = tcpc_send_command(port, TCPC_CMD_DISABLE_SINK_VBUS);
+       if (ret)
+               return ret;
+
+       /* The max vbus off time is 0.5ms, we add margin 0.5 ms */
+       mdelay(1);
+
+       return 0;
+}
+
+
+static int tcpc_pd_receive_message(struct tcpc_port *port, struct pd_message *msg)
+{
+       int ret;
+       uint8_t cnt;
+       uint16_t val;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       /* Generally the max tSenderResponse is 30ms, max tTypeCSendSourceCap is 200ms, we set the timeout to 500ms */
+       ret = tcpc_polling_reg(port, TCPC_ALERT, 2, TCPC_ALERT_RX_STATUS, TCPC_ALERT_RX_STATUS, 500);
+       if (ret) {
+               tcpc_log(port, "%s: Polling ALERT register, TCPC_ALERT_RX_STATUS bit failed, ret = %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       cnt = 0;
+       ret = dm_i2c_read(port->i2c_dev, TCPC_RX_BYTE_CNT, (uint8_t *)&cnt, 1);
+       if (ret)
+               return -EIO;
+
+       if (cnt > 0) {
+               ret = dm_i2c_read(port->i2c_dev, TCPC_RX_BUF_FRAME_TYPE, (uint8_t *)msg, cnt);
+               if (ret)
+                       return -EIO;
+
+               /* Clear RX status alert bit */
+               val = TCPC_ALERT_RX_STATUS;
+               ret = dm_i2c_write(port->i2c_dev, TCPC_ALERT, (const uint8_t *)&val, 2);
+               if (ret)
+                       return -EIO;
+       }
+
+       return cnt;
+}
+
+static int tcpc_pd_transmit_message(struct tcpc_port *port, struct pd_message *msg_p, uint8_t bytes)
+{
+       int ret;
+       uint8_t valb;
+       uint16_t val;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       if (msg_p == NULL || bytes <= 0)
+               return -EINVAL;
+
+       ret = dm_i2c_write(port->i2c_dev, TCPC_TX_BYTE_CNT, (const uint8_t *)&bytes, 1);
+       if (ret)
+               return -EIO;
+
+       ret = dm_i2c_write(port->i2c_dev, TCPC_TX_HDR, (const uint8_t *)&(msg_p->header), bytes);
+       if (ret)
+               return -EIO;
+
+       valb = (3 << TCPC_TRANSMIT_RETRY_SHIFT) | (TCPC_TX_SOP << TCPC_TRANSMIT_TYPE_SHIFT);
+       ret = dm_i2c_write(port->i2c_dev, TCPC_TRANSMIT, (const uint8_t *)&valb, 1);
+       if (ret)
+               return -EIO;
+
+       /* Max tReceive is 1.1ms, we set to 5ms timeout */
+       ret = tcpc_polling_reg(port, TCPC_ALERT, 2, TCPC_ALERT_TX_SUCCESS, TCPC_ALERT_TX_SUCCESS, 5);
+       if (ret) {
+               if (ret == -ETIME) {
+                       ret = dm_i2c_read(port->i2c_dev, TCPC_ALERT, (uint8_t *)&val, 2);
+                       if (ret)
+                               return -EIO;
+
+                       if (val & TCPC_ALERT_TX_FAILED)
+                               tcpc_log(port, "%s: PD TX FAILED, ALERT = 0x%x\n", __func__, val);
+
+                       if (val & TCPC_ALERT_TX_DISCARDED)
+                               tcpc_log(port, "%s: PD TX DISCARDED, ALERT = 0x%x\n", __func__, val);
+
+               } else {
+                       tcpc_log(port, "%s: Polling ALERT register, TCPC_ALERT_TX_SUCCESS bit failed, ret = %d\n",
+                               __func__, ret);
+               }
+       } else {
+               port->tx_msg_id = (port->tx_msg_id + 1) & PD_HEADER_ID_MASK;
+       }
+
+       /* Clear ALERT status */
+       val &= (TCPC_ALERT_TX_FAILED | TCPC_ALERT_TX_DISCARDED | TCPC_ALERT_TX_SUCCESS);
+       ret = dm_i2c_write(port->i2c_dev, TCPC_ALERT, (const uint8_t *)&val, 2);
+       if (ret)
+               return -EIO;
+
+       return ret;
+}
+
+static void tcpc_log_source_caps(struct tcpc_port *port, uint32_t *caps, unsigned int capcount)
+{
+       int i;
+
+       for (i = 0; i < capcount; i++) {
+               u32 pdo = caps[i];
+               enum pd_pdo_type type = pdo_type(pdo);
+
+               tcpc_log(port, "PDO %d: type %d, ",
+                        i, type);
+
+               switch (type) {
+               case PDO_TYPE_FIXED:
+                       tcpc_log(port, "%u mV, %u mA [%s%s%s%s%s%s]\n",
+                                 pdo_fixed_voltage(pdo),
+                                 pdo_max_current(pdo),
+                                 (pdo & PDO_FIXED_DUAL_ROLE) ?
+                                                       "R" : "",
+                                 (pdo & PDO_FIXED_SUSPEND) ?
+                                                       "S" : "",
+                                 (pdo & PDO_FIXED_HIGHER_CAP) ?
+                                                       "H" : "",
+                                 (pdo & PDO_FIXED_USB_COMM) ?
+                                                       "U" : "",
+                                 (pdo & PDO_FIXED_DATA_SWAP) ?
+                                                       "D" : "",
+                                 (pdo & PDO_FIXED_EXTPOWER) ?
+                                                       "E" : "");
+                       break;
+               case PDO_TYPE_VAR:
+                       tcpc_log(port, "%u-%u mV, %u mA\n",
+                                 pdo_min_voltage(pdo),
+                                 pdo_max_voltage(pdo),
+                                 pdo_max_current(pdo));
+                       break;
+               case PDO_TYPE_BATT:
+                       tcpc_log(port, "%u-%u mV, %u mW\n",
+                                 pdo_min_voltage(pdo),
+                                 pdo_max_voltage(pdo),
+                                 pdo_max_power(pdo));
+                       break;
+               default:
+                       tcpc_log(port, "undefined\n");
+                       break;
+               }
+       }
+}
+
+static int tcpc_pd_select_pdo(uint32_t *caps, uint32_t capcount, uint32_t max_snk_mv, uint32_t max_snk_ma)
+{
+       unsigned int i, max_mw = 0, max_mv = 0;
+       int ret = -EINVAL;
+
+       /*
+        * Select the source PDO providing the most power while staying within
+        * the board's voltage limits. Prefer PDO providing exp
+        */
+       for (i = 0; i < capcount; i++) {
+               u32 pdo = caps[i];
+               enum pd_pdo_type type = pdo_type(pdo);
+               unsigned int mv, ma, mw;
+
+               if (type == PDO_TYPE_FIXED)
+                       mv = pdo_fixed_voltage(pdo);
+               else
+                       mv = pdo_min_voltage(pdo);
+
+               if (type == PDO_TYPE_BATT) {
+                       mw = pdo_max_power(pdo);
+               } else {
+                       ma = min(pdo_max_current(pdo),
+                                max_snk_ma);
+                       mw = ma * mv / 1000;
+               }
+
+               /* Perfer higher voltages if available */
+               if ((mw > max_mw || (mw == max_mw && mv > max_mv)) &&
+                   mv <= max_snk_mv) {
+                       ret = i;
+                       max_mw = mw;
+                       max_mv = mv;
+               }
+       }
+
+       return ret;
+}
+
+static int tcpc_pd_build_request(struct tcpc_port *port,
+                                                                               uint32_t *caps,
+                                                                               uint32_t capcount,
+                                                                               uint32_t max_snk_mv,
+                                                                               uint32_t max_snk_ma,
+                                                                               uint32_t max_snk_mw,
+                                                                               uint32_t operating_snk_mw,
+                                                                               uint32_t *rdo)
+{
+       unsigned int mv, ma, mw, flags;
+       unsigned int max_ma, max_mw;
+       enum pd_pdo_type type;
+       int index;
+       u32 pdo;
+
+       index = tcpc_pd_select_pdo(caps, capcount, max_snk_mv, max_snk_ma);
+       if (index < 0)
+               return -EINVAL;
+
+       pdo = caps[index];
+       type = pdo_type(pdo);
+
+       if (type == PDO_TYPE_FIXED)
+               mv = pdo_fixed_voltage(pdo);
+       else
+               mv = pdo_min_voltage(pdo);
+
+       /* Select maximum available current within the board's power limit */
+       if (type == PDO_TYPE_BATT) {
+               mw = pdo_max_power(pdo);
+               ma = 1000 * min(mw, max_snk_mw) / mv;
+       } else {
+               ma = min(pdo_max_current(pdo),
+                        1000 * max_snk_mw / mv);
+       }
+       ma = min(ma, max_snk_ma);
+
+       /* XXX: Any other flags need to be set? */
+       flags = 0;
+
+       /* Set mismatch bit if offered power is less than operating power */
+       mw = ma * mv / 1000;
+       max_ma = ma;
+       max_mw = mw;
+       if (mw < operating_snk_mw) {
+               flags |= RDO_CAP_MISMATCH;
+               max_mw = operating_snk_mw;
+               max_ma = max_mw * 1000 / mv;
+       }
+
+       if (type == PDO_TYPE_BATT) {
+               *rdo = RDO_BATT(index + 1, mw, max_mw, flags);
+
+               tcpc_log(port, "Requesting PDO %d: %u mV, %u mW%s\n",
+                        index, mv, mw,
+                        flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
+       } else {
+               *rdo = RDO_FIXED(index + 1, ma, max_ma, flags);
+
+               tcpc_log(port, "Requesting PDO %d: %u mV, %u mA%s\n",
+                        index, mv, ma,
+                        flags & RDO_CAP_MISMATCH ? " [mismatch]" : "");
+       }
+
+       return 0;
+}
+
+static void tcpc_pd_sink_process(struct tcpc_port *port)
+{
+       int ret;
+       uint8_t msgtype;
+       uint32_t objcnt;
+       struct pd_message msg;
+       enum pd_sink_state pd_state = WAIT_SOURCE_CAP;
+
+       while (tcpc_pd_receive_message(port, &msg) > 0) {
+
+               msgtype = pd_header_type(msg.header);
+               objcnt = pd_header_cnt_le(msg.header);
+
+               tcpc_debug_log(port, "get msg, type %d, cnt %d\n", msgtype, objcnt);
+
+               switch (pd_state) {
+               case WAIT_SOURCE_CAP:
+               case SINK_READY:
+                       if (msgtype != PD_DATA_SOURCE_CAP)
+                               continue;
+
+                       uint32_t *caps = (uint32_t *)&msg.payload;
+                       uint32_t rdo = 0;
+
+                       tcpc_log_source_caps(port, caps, objcnt);
+
+                       tcpc_pd_build_request(port, caps, objcnt,
+                               port->cfg.max_snk_mv, port->cfg.max_snk_ma,
+                               port->cfg.max_snk_mw, port->cfg.op_snk_mv,
+                               &rdo);
+
+                       memset(&msg, 0, sizeof(msg));
+                       msg.header = PD_HEADER(PD_DATA_REQUEST, 0, 0, port->tx_msg_id, 1);  /* power sink, data device, id 0, len 1 */
+                       msg.payload[0] = rdo;
+
+                       ret = tcpc_pd_transmit_message(port, &msg, 6);
+                       if (ret)
+                               tcpc_log(port, "send request failed\n");
+                       else
+                               pd_state = WAIT_SOURCE_ACCEPT;
+
+                       break;
+               case WAIT_SOURCE_ACCEPT:
+                       if (objcnt > 0) /* Should be ctrl message */
+                               continue;
+
+                       if (msgtype == PD_CTRL_ACCEPT) {
+                               pd_state = WAIT_SOURCE_READY;
+                               tcpc_log(port, "Source accept request\n");
+                       } else if (msgtype == PD_CTRL_REJECT) {
+                               tcpc_log(port, "Source reject request\n");
+                               return;
+                       }
+
+                       break;
+               case WAIT_SOURCE_READY:
+                       if (objcnt > 0) /* Should be ctrl message */
+                               continue;
+
+                       if (msgtype == PD_CTRL_PS_RDY) {
+                               tcpc_log(port, "PD source ready!\n");
+                               pd_state = SINK_READY;
+                       }
+
+                       break;
+               default:
+                       tcpc_log(port, "unexpect status: %u\n", pd_state);
+                       break;
+               }
+       }
+}
+
+bool tcpc_pd_sink_check_charging(struct tcpc_port *port)
+{
+       uint8_t valb;
+       int err;
+       enum typec_cc_polarity pol;
+       enum typec_cc_state state;
+
+       if (port == NULL)
+               return false;
+
+       /* Check the CC status, must be sink */
+       err = tcpc_get_cc_status(port, &pol, &state);
+       if (err || (state != TYPEC_STATE_SNK_POWER15
+               && state != TYPEC_STATE_SNK_POWER30
+               && state != TYPEC_STATE_SNK_DEFAULT)) {
+               tcpc_debug_log(port, "TCPC wrong state for PD charging, err = %d, CC = 0x%x\n",
+                       err, state);
+               return false;
+       }
+
+       /* Check the VBUS PRES and SINK VBUS for dead battery */
+       err = dm_i2c_read(port->i2c_dev, TCPC_POWER_STATUS, &valb, 1);
+       if (err) {
+               tcpc_debug_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return false;
+       }
+
+       if (!(valb & TCPC_POWER_STATUS_VBUS_PRES)) {
+               tcpc_debug_log(port, "VBUS NOT PRES \n");
+               return false;
+       }
+
+       if (!(valb & TCPC_POWER_STATUS_SINKING_VBUS)) {
+               tcpc_debug_log(port, "SINK VBUS is not enabled for dead battery\n");
+               return false;
+       }
+
+       return true;
+}
+
+static int tcpc_pd_sink_disable(struct tcpc_port *port)
+{
+       uint8_t valb;
+       int err;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       port->pd_state = UNATTACH;
+
+       /* Check the VBUS PRES and SINK VBUS for dead battery */
+       err = dm_i2c_read(port->i2c_dev, TCPC_POWER_STATUS, &valb, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       if ((valb & TCPC_POWER_STATUS_VBUS_PRES) && (valb & TCPC_POWER_STATUS_SINKING_VBUS)) {
+               dm_i2c_read(port->i2c_dev, TCPC_POWER_CTRL, (uint8_t *)&valb, 1);
+               valb &= ~TCPC_POWER_CTRL_AUTO_DISCH_DISCO; /* disable AutoDischargeDisconnect */
+               dm_i2c_write(port->i2c_dev, TCPC_POWER_CTRL, (const uint8_t *)&valb, 1);
+
+               tcpc_disable_sink_vbus(port);
+       }
+
+       if (port->cfg.switch_setup_func)
+               port->cfg.switch_setup_func(port);
+
+       return 0;
+}
+
+static int tcpc_pd_sink_init(struct tcpc_port *port)
+{
+       uint8_t valb;
+       uint16_t val;
+       int err;
+       enum typec_cc_polarity pol;
+       enum typec_cc_state state;
+
+       if (port == NULL)
+               return -EINVAL;
+
+       port->pd_state = UNATTACH;
+
+       /* Check the VBUS PRES and SINK VBUS for dead battery */
+       err = dm_i2c_read(port->i2c_dev, TCPC_POWER_STATUS, &valb, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       if (!(valb & TCPC_POWER_STATUS_VBUS_PRES)) {
+               tcpc_debug_log(port, "VBUS NOT PRES \n");
+               return -EPERM;
+       }
+
+       if (!(valb & TCPC_POWER_STATUS_SINKING_VBUS)) {
+               tcpc_debug_log(port, "SINK VBUS is not enabled for dead battery\n");
+               return -EPERM;
+       }
+
+       err = dm_i2c_read(port->i2c_dev, TCPC_ALERT, (uint8_t *)&val, 2);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       if (!(val & TCPC_ALERT_CC_STATUS)) {
+               tcpc_debug_log(port, "CC STATUS not detected for dead battery\n");
+               return -EPERM;
+       }
+
+       err = tcpc_get_cc_status(port, &pol, &state);
+       if (err || (state != TYPEC_STATE_SNK_POWER15
+               && state != TYPEC_STATE_SNK_POWER30
+               && state != TYPEC_STATE_SNK_DEFAULT)) {
+               tcpc_log(port, "TCPC wrong state for dead battery, err = %d, CC = 0x%x\n",
+                       err, state);
+               return -EPERM;
+       } else
+               port->pd_state = ATTACHED;
+
+       dm_i2c_read(port->i2c_dev, TCPC_POWER_CTRL, (uint8_t *)&valb, 1);
+       valb &= ~TCPC_POWER_CTRL_AUTO_DISCH_DISCO; /* disable AutoDischargeDisconnect */
+       dm_i2c_write(port->i2c_dev, TCPC_POWER_CTRL, (const uint8_t *)&valb, 1);
+
+       if (port->cfg.switch_setup_func)
+               port->cfg.switch_setup_func(port);
+
+       /* As sink role */
+       valb = 0x00;
+       err = dm_i2c_write(port->i2c_dev, TCPC_MSG_HDR_INFO, (const uint8_t *)&valb, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       /* Enable rx */
+       valb = TCPC_RX_DETECT_SOP | TCPC_RX_DETECT_HARD_RESET;
+       err = dm_i2c_write(port->i2c_dev, TCPC_RX_DETECT, (const uint8_t *)&valb, 1);
+       if (err) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, err);
+               return -EIO;
+       }
+
+       tcpc_pd_sink_process(port);
+
+       return 0;
+}
+
+int tcpc_init(struct tcpc_port *port, struct tcpc_port_config config, ss_mux_sel ss_sel_func)
+{
+       int ret;
+       uint8_t valb;
+       uint16_t vid, pid;
+       struct udevice *bus;
+       struct udevice *i2c_dev = NULL;
+
+       memset(port, 0, sizeof(struct tcpc_port));
+
+       if (port == NULL)
+               return -EINVAL;
+
+       port->cfg = config;
+       port->tx_msg_id = 0;
+       port->ss_sel_func = ss_sel_func;
+       port->log_p = (char *)&(port->logbuffer);
+       port->log_size = TCPC_LOG_BUFFER_SIZE;
+       port->log_print = port->log_p;
+       memset(&(port->logbuffer), 0, TCPC_LOG_BUFFER_SIZE);
+
+       ret = uclass_get_device_by_seq(UCLASS_I2C, port->cfg.i2c_bus, &bus);
+       if (ret) {
+               printf("%s: Can't find bus\n", __func__);
+               return -EINVAL;
+       }
+
+       ret = dm_i2c_probe(bus, port->cfg.addr, 0, &i2c_dev);
+       if (ret) {
+               printf("%s: Can't find device id=0x%x\n",
+                       __func__, config.addr);
+               return -ENODEV;
+       }
+
+       port->i2c_dev = i2c_dev;
+
+       /* Check the Initialization Status bit in 1s */
+       ret = tcpc_polling_reg(port, TCPC_POWER_STATUS, 1, TCPC_POWER_STATUS_UNINIT, 0, 1000);
+       if (ret) {
+               tcpc_log(port, "%s: Polling TCPC POWER STATUS Initialization Status bit failed, ret = %d\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       dm_i2c_read(port->i2c_dev, TCPC_POWER_STATUS, &valb, 1);
+       tcpc_debug_log(port, "POWER STATUS: 0x%x\n", valb);
+
+       /* Clear AllRegistersResetToDefault */
+       valb = 0x80;
+       ret = dm_i2c_write(port->i2c_dev, TCPC_FAULT_STATUS, (const uint8_t *)&valb, 1);
+       if (ret) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, ret);
+               return -EIO;
+       }
+
+       /* Read Vendor ID and Product ID */
+       ret = dm_i2c_read(port->i2c_dev, TCPC_VENDOR_ID, (uint8_t *)&vid, 2);
+       if (ret) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, ret);
+               return -EIO;
+       }
+
+       ret = dm_i2c_read(port->i2c_dev, TCPC_PRODUCT_ID, (uint8_t *)&pid, 2);
+       if (ret) {
+               tcpc_log(port, "%s dm_i2c_read failed, err %d\n", __func__, ret);
+               return -EIO;
+       }
+
+       tcpc_log(port, "TCPC:  Vendor ID [0x%x], Product ID [0x%x], Addr [I2C%u 0x%x]\n",
+               vid, pid, port->cfg.i2c_bus, port->cfg.addr);
+
+       if (!port->cfg.disable_pd) {
+               if  (port->cfg.port_type == TYPEC_PORT_UFP
+                       || port->cfg.port_type == TYPEC_PORT_DRP)
+                       tcpc_pd_sink_init(port);
+       } else {
+               tcpc_pd_sink_disable(port);
+       }
+
+       tcpc_clear_alert(port, 0xffff);
+
+       tcpc_print_log(port);
+
+       return 0;
+}
diff --git a/board/somdevices/common/tcpc.h b/board/somdevices/common/tcpc.h
new file mode 100644 (file)
index 0000000..ff74951
--- /dev/null
@@ -0,0 +1,469 @@
+/*
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __TCPCI_H
+#define __TCPCI_H
+
+#include <dm.h>
+
+#define TCPC_VENDOR_ID                 0x0
+#define TCPC_PRODUCT_ID                        0x2
+
+#define TCPC_ALERT                                     0x10
+#define TCPC_ALERT_VBUS_DISCNCT                BIT(11)
+#define TCPC_ALERT_RX_BUF_OVF          BIT(10)
+#define TCPC_ALERT_FAULT                       BIT(9)
+#define TCPC_ALERT_V_ALARM_LO          BIT(8)
+#define TCPC_ALERT_V_ALARM_HI          BIT(7)
+#define TCPC_ALERT_TX_SUCCESS          BIT(6)
+#define TCPC_ALERT_TX_DISCARDED                BIT(5)
+#define TCPC_ALERT_TX_FAILED           BIT(4)
+#define TCPC_ALERT_RX_HARD_RST         BIT(3)
+#define TCPC_ALERT_RX_STATUS           BIT(2)
+#define TCPC_ALERT_POWER_STATUS                BIT(1)
+#define TCPC_ALERT_CC_STATUS           BIT(0)
+
+#define TCPC_TCPC_CTRL                         0x19
+#define TCPC_TCPC_CTRL_BIST_MODE       BIT(1)
+#define TCPC_TCPC_CTRL_ORIENTATION     BIT(0)
+
+#define TCPC_ROLE_CTRL                         0x1a
+#define TCPC_ROLE_CTRL_DRP                     BIT(6)
+#define TCPC_ROLE_CTRL_RP_VAL_SHIFT    4
+#define TCPC_ROLE_CTRL_RP_VAL_MASK     0x3
+#define TCPC_ROLE_CTRL_RP_VAL_DEF      0x0
+#define TCPC_ROLE_CTRL_RP_VAL_1_5      0x1
+#define TCPC_ROLE_CTRL_RP_VAL_3_0      0x2
+#define TCPC_ROLE_CTRL_CC2_SHIFT       2
+#define TCPC_ROLE_CTRL_CC2_MASK                0x3
+#define TCPC_ROLE_CTRL_CC1_SHIFT       0
+#define TCPC_ROLE_CTRL_CC1_MASK                0x3
+#define TCPC_ROLE_CTRL_CC_RA           0x0
+#define TCPC_ROLE_CTRL_CC_RP           0x1
+#define TCPC_ROLE_CTRL_CC_RD           0x2
+#define TCPC_ROLE_CTRL_CC_OPEN         0x3
+
+#define TCPC_POWER_CTRL                                                0x1c
+#define TCPC_POWER_CTRL_EN_VCONN                       BIT(0)
+#define TCPC_POWER_CTRL_VCONN_POWER                    BIT(1)
+#define TCPC_POWER_CTRL_FORCE_DISCH                    BIT(2)
+#define TCPC_POWER_CTRL_EN_BLEED_CH                    BIT(3)
+#define TCPC_POWER_CTRL_AUTO_DISCH_DISCO       BIT(4)
+#define TCPC_POWER_CTRL_DIS_V_ALARMS           BIT(5)
+#define TCPC_POWER_CTRL_VBUS_V_MONITOR         BIT(6)
+
+#define TCPC_CC_STATUS                                 0x1d
+#define TCPC_CC_STATUS_LOOK4CONN               BIT(5)
+#define TCPC_CC_STATUS_TERM                            BIT(4)
+#define TCPC_CC_STATUS_CC2_SHIFT               2
+#define TCPC_CC_STATUS_CC2_MASK                        0x3
+#define TCPC_CC_STATUS_CC1_SHIFT               0
+#define TCPC_CC_STATUS_CC1_MASK                        0x3
+
+#define TCPC_POWER_STATUS                              0x1e
+#define TCPC_POWER_STATUS_UNINIT               BIT(6)
+#define TCPC_POWER_STATUS_VBUS_DET             BIT(3)
+#define TCPC_POWER_STATUS_VBUS_PRES            BIT(2)
+#define TCPC_POWER_STATUS_SINKING_VBUS BIT(0)
+
+#define TCPC_FAULT_STATUS               0x1f
+
+#define TCPC_COMMAND                                   0x23
+#define TCPC_CMD_WAKE_I2C                              0x11
+#define TCPC_CMD_DISABLE_VBUS_DETECT   0x22
+#define TCPC_CMD_ENABLE_VBUS_DETECT            0x33
+#define TCPC_CMD_DISABLE_SINK_VBUS             0x44
+#define TCPC_CMD_SINK_VBUS                             0x55
+#define TCPC_CMD_DISABLE_SRC_VBUS              0x66
+#define TCPC_CMD_SRC_VBUS_DEFAULT              0x77
+#define TCPC_CMD_SRC_VBUS_HIGH                 0x88
+#define TCPC_CMD_LOOK4CONNECTION               0x99
+#define TCPC_CMD_RXONEMORE                             0xAA
+#define TCPC_CMD_I2C_IDLE                              0xFF
+
+#define TCPC_DEV_CAP_1                                 0x24
+#define TCPC_DEV_CAP_2                                 0x26
+#define TCPC_STD_INPUT_CAP                             0x28
+#define TCPC_STD_OUTPUT_CAP                            0x29
+
+#define TCPC_MSG_HDR_INFO                              0x2e
+#define TCPC_MSG_HDR_INFO_DATA_ROLE            BIT(3)
+#define TCPC_MSG_HDR_INFO_PWR_ROLE             BIT(0)
+#define TCPC_MSG_HDR_INFO_REV_SHIFT            1
+#define TCPC_MSG_HDR_INFO_REV_MASK             0x3
+
+#define TCPC_RX_DETECT                                 0x2f
+#define TCPC_RX_DETECT_HARD_RESET              BIT(5)
+#define TCPC_RX_DETECT_SOP                             BIT(0)
+
+#define TCPC_RX_BYTE_CNT                               0x30
+#define TCPC_RX_BUF_FRAME_TYPE                 0x31
+#define TCPC_RX_HDR                                            0x32
+#define TCPC_RX_DATA                                   0x34 /* through 0x4f */
+
+#define TCPC_TRANSMIT                                  0x50
+#define TCPC_TRANSMIT_RETRY_SHIFT              4
+#define TCPC_TRANSMIT_RETRY_MASK               0x3
+#define TCPC_TRANSMIT_TYPE_SHIFT               0
+#define TCPC_TRANSMIT_TYPE_MASK                        0x7
+
+#define TCPC_TX_BYTE_CNT                               0x51
+#define TCPC_TX_HDR                                            0x52
+#define TCPC_TX_DATA                                   0x54 /* through 0x6f */
+
+#define TCPC_VBUS_VOLTAGE                                      0x70
+#define TCPC_VBUS_VOL_MASK                                     0x3ff
+#define TCPC_VBUS_VOL_SCALE_FACTOR_MASK                0xc00
+#define TCPC_VBUS_VOL_SCALE_FACTOR_SHIFT       10
+#define TCPC_VBUS_VOL_MV_UNIT                          25
+
+#define TCPC_VBUS_SINK_DISCONNECT_THRESH       0x72
+#define TCPC_VBUS_STOP_DISCHARGE_THRESH                0x74
+#define TCPC_VBUS_VOLTAGE_ALARM_HI_CFG         0x76
+#define TCPC_VBUS_VOLTAGE_ALARM_LO_CFG         0x78
+
+enum typec_role {
+       TYPEC_SINK,
+       TYPEC_SOURCE,
+       TYPEC_ROLE_UNKNOWN,
+};
+
+enum typec_data_role {
+       TYPEC_DEVICE,
+       TYPEC_HOST,
+};
+
+enum typec_cc_polarity {
+       TYPEC_POLARITY_CC1,
+       TYPEC_POLARITY_CC2,
+};
+
+enum typec_cc_state {
+       TYPEC_STATE_OPEN,
+       TYPEC_STATE_SRC_BOTH_RA,
+       TYPEC_STATE_SRC_RD_RA,
+       TYPEC_STATE_SRC_RD,
+       TYPEC_STATE_SRC_RESERVED,
+       TYPEC_STATE_SNK_DEFAULT,
+       TYPEC_STATE_SNK_POWER15,
+       TYPEC_STATE_SNK_POWER30,
+};
+
+
+/* USB PD Messages */
+enum pd_ctrl_msg_type {
+       /* 0 Reserved */
+       PD_CTRL_GOOD_CRC = 1,
+       PD_CTRL_GOTO_MIN = 2,
+       PD_CTRL_ACCEPT = 3,
+       PD_CTRL_REJECT = 4,
+       PD_CTRL_PING = 5,
+       PD_CTRL_PS_RDY = 6,
+       PD_CTRL_GET_SOURCE_CAP = 7,
+       PD_CTRL_GET_SINK_CAP = 8,
+       PD_CTRL_DR_SWAP = 9,
+       PD_CTRL_PR_SWAP = 10,
+       PD_CTRL_VCONN_SWAP = 11,
+       PD_CTRL_WAIT = 12,
+       PD_CTRL_SOFT_RESET = 13,
+       /* 14-15 Reserved */
+};
+
+enum pd_data_msg_type {
+       /* 0 Reserved */
+       PD_DATA_SOURCE_CAP = 1,
+       PD_DATA_REQUEST = 2,
+       PD_DATA_BIST = 3,
+       PD_DATA_SINK_CAP = 4,
+       /* 5-14 Reserved */
+       PD_DATA_VENDOR_DEF = 15,
+};
+
+enum tcpc_transmit_type {
+       TCPC_TX_SOP = 0,
+       TCPC_TX_SOP_PRIME = 1,
+       TCPC_TX_SOP_PRIME_PRIME = 2,
+       TCPC_TX_SOP_DEBUG_PRIME = 3,
+       TCPC_TX_SOP_DEBUG_PRIME_PRIME = 4,
+       TCPC_TX_HARD_RESET = 5,
+       TCPC_TX_CABLE_RESET = 6,
+       TCPC_TX_BIST_MODE_2 = 7
+};
+
+enum pd_sink_state{
+       UNATTACH = 0,
+       ATTACHED,
+       WAIT_SOURCE_CAP,
+       WAIT_SOURCE_ACCEPT,
+       WAIT_SOURCE_READY,
+       SINK_READY,
+};
+
+
+#define PD_REV10        0x0
+#define PD_REV20        0x1
+
+#define PD_HEADER_CNT_SHIFT     12
+#define PD_HEADER_CNT_MASK      0x7
+#define PD_HEADER_ID_SHIFT      9
+#define PD_HEADER_ID_MASK       0x7
+#define PD_HEADER_PWR_ROLE      BIT(8)
+#define PD_HEADER_REV_SHIFT     6
+#define PD_HEADER_REV_MASK      0x3
+#define PD_HEADER_DATA_ROLE     BIT(5)
+#define PD_HEADER_TYPE_SHIFT    0
+#define PD_HEADER_TYPE_MASK     0xf
+
+#define PD_HEADER(type, pwr, data, id, cnt)                             \
+       ((((type) & PD_HEADER_TYPE_MASK) << PD_HEADER_TYPE_SHIFT) |     \
+        ((pwr) == TYPEC_SOURCE ? PD_HEADER_PWR_ROLE : 0) |             \
+        ((data) == TYPEC_HOST ? PD_HEADER_DATA_ROLE : 0) |             \
+        (PD_REV20 << PD_HEADER_REV_SHIFT) |                            \
+        (((id) & PD_HEADER_ID_MASK) << PD_HEADER_ID_SHIFT) |           \
+        (((cnt) & PD_HEADER_CNT_MASK) << PD_HEADER_CNT_SHIFT))
+
+
+static inline unsigned int pd_header_cnt(uint16_t header)
+{
+       return (header >> PD_HEADER_CNT_SHIFT) & PD_HEADER_CNT_MASK;
+}
+
+static inline unsigned int pd_header_cnt_le(__le16 header)
+{
+       return pd_header_cnt(le16_to_cpu(header));
+}
+
+static inline unsigned int pd_header_type(uint16_t header)
+{
+       return (header >> PD_HEADER_TYPE_SHIFT) & PD_HEADER_TYPE_MASK;
+}
+
+static inline unsigned int pd_header_type_le(__le16 header)
+{
+       return pd_header_type(le16_to_cpu(header));
+}
+
+#define PD_MAX_PAYLOAD          7
+
+struct pd_message {
+       uint8_t   frametype;
+       uint16_t  header;
+       uint32_t  payload[PD_MAX_PAYLOAD];
+} __packed;
+
+enum pd_pdo_type {
+       PDO_TYPE_FIXED = 0,
+       PDO_TYPE_BATT = 1,
+       PDO_TYPE_VAR = 2,
+};
+
+
+#define PDO_TYPE_SHIFT          30
+#define PDO_TYPE_MASK           0x3
+
+#define PDO_TYPE(t)     ((t) << PDO_TYPE_SHIFT)
+
+#define PDO_VOLT_MASK           0x3ff
+#define PDO_CURR_MASK           0x3ff
+#define PDO_PWR_MASK            0x3ff
+
+#define PDO_FIXED_DUAL_ROLE     BIT(29) /* Power role swap supported */
+#define PDO_FIXED_SUSPEND       BIT(28) /* USB Suspend supported (Source) */
+#define PDO_FIXED_HIGHER_CAP    BIT(28) /* Requires more than vSafe5V (Sink) */
+#define PDO_FIXED_EXTPOWER      BIT(27) /* Externally powered */
+#define PDO_FIXED_USB_COMM      BIT(26) /* USB communications capable */
+#define PDO_FIXED_DATA_SWAP     BIT(25) /* Data role swap supported */
+#define PDO_FIXED_VOLT_SHIFT    10      /* 50mV units */
+#define PDO_FIXED_CURR_SHIFT    0       /* 10mA units */
+
+#define PDO_FIXED_VOLT(mv)      ((((mv) / 50) & PDO_VOLT_MASK) << PDO_FIXED_VOLT_SHIFT)
+#define PDO_FIXED_CURR(ma)      ((((ma) / 10) & PDO_CURR_MASK) << PDO_FIXED_CURR_SHIFT)
+
+#define PDO_FIXED(mv, ma, flags)                        \
+       (PDO_TYPE(PDO_TYPE_FIXED) | (flags) |           \
+        PDO_FIXED_VOLT(mv) | PDO_FIXED_CURR(ma))
+
+#define PDO_BATT_MAX_VOLT_SHIFT 20      /* 50mV units */
+#define PDO_BATT_MIN_VOLT_SHIFT 10      /* 50mV units */
+#define PDO_BATT_MAX_PWR_SHIFT  0       /* 250mW units */
+
+#define PDO_BATT_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MIN_VOLT_SHIFT)
+#define PDO_BATT_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_BATT_MAX_VOLT_SHIFT)
+#define PDO_BATT_MAX_POWER(mw) ((((mw) / 250) & PDO_PWR_MASK) << PDO_BATT_MAX_PWR_SHIFT)
+
+#define PDO_BATT(min_mv, max_mv, max_mw)                        \
+       (PDO_TYPE(PDO_TYPE_BATT) | PDO_BATT_MIN_VOLT(min_mv) |  \
+        PDO_BATT_MAX_VOLT(max_mv) | PDO_BATT_MAX_POWER(max_mw))
+
+#define PDO_VAR_MAX_VOLT_SHIFT  20      /* 50mV units */
+#define PDO_VAR_MIN_VOLT_SHIFT  10      /* 50mV units */
+#define PDO_VAR_MAX_CURR_SHIFT  0       /* 10mA units */
+
+#define PDO_VAR_MIN_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MIN_VOLT_SHIFT)
+#define PDO_VAR_MAX_VOLT(mv) ((((mv) / 50) & PDO_VOLT_MASK) << PDO_VAR_MAX_VOLT_SHIFT)
+#define PDO_VAR_MAX_CURR(ma) ((((ma) / 10) & PDO_CURR_MASK) << PDO_VAR_MAX_CURR_SHIFT)
+
+#define PDO_VAR(min_mv, max_mv, max_ma)                         \
+       (PDO_TYPE(PDO_TYPE_VAR) | PDO_VAR_MIN_VOLT(min_mv) |    \
+        PDO_VAR_MAX_VOLT(max_mv) | PDO_VAR_MAX_CURR(max_ma))
+
+static inline enum pd_pdo_type pdo_type(uint32_t pdo)
+{
+       return (pdo >> PDO_TYPE_SHIFT) & PDO_TYPE_MASK;
+}
+
+static inline unsigned int pdo_fixed_voltage(uint32_t pdo)
+{
+       return ((pdo >> PDO_FIXED_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
+}
+
+static inline unsigned int pdo_min_voltage(uint32_t pdo)
+{
+       return ((pdo >> PDO_VAR_MIN_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
+}
+
+static inline unsigned int pdo_max_voltage(uint32_t pdo)
+{
+       return ((pdo >> PDO_VAR_MAX_VOLT_SHIFT) & PDO_VOLT_MASK) * 50;
+}
+
+static inline unsigned int pdo_max_current(uint32_t pdo)
+{
+       return ((pdo >> PDO_VAR_MAX_CURR_SHIFT) & PDO_CURR_MASK) * 10;
+}
+
+static inline unsigned int pdo_max_power(uint32_t pdo)
+{
+       return ((pdo >> PDO_BATT_MAX_PWR_SHIFT) & PDO_PWR_MASK) * 250;
+}
+
+/* RDO: Request Data Object */
+#define RDO_OBJ_POS_SHIFT       28
+#define RDO_OBJ_POS_MASK        0x7
+#define RDO_GIVE_BACK           BIT(27) /* Supports reduced operating current */
+#define RDO_CAP_MISMATCH        BIT(26) /* Not satisfied by source caps */
+#define RDO_USB_COMM            BIT(25) /* USB communications capable */
+#define RDO_NO_SUSPEND          BIT(24) /* USB Suspend not supported */
+
+#define RDO_PWR_MASK                    0x3ff
+#define RDO_CURR_MASK                   0x3ff
+
+#define RDO_FIXED_OP_CURR_SHIFT         10
+#define RDO_FIXED_MAX_CURR_SHIFT        0
+
+#define RDO_OBJ(idx) (((idx) & RDO_OBJ_POS_MASK) << RDO_OBJ_POS_SHIFT)
+
+#define PDO_FIXED_OP_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_OP_CURR_SHIFT)
+#define PDO_FIXED_MAX_CURR(ma) ((((ma) / 10) & RDO_CURR_MASK) << RDO_FIXED_MAX_CURR_SHIFT)
+
+#define RDO_FIXED(idx, op_ma, max_ma, flags)                    \
+       (RDO_OBJ(idx) | (flags) |                               \
+        PDO_FIXED_OP_CURR(op_ma) | PDO_FIXED_MAX_CURR(max_ma))
+
+#define RDO_BATT_OP_PWR_SHIFT           10      /* 250mW units */
+#define RDO_BATT_MAX_PWR_SHIFT          0       /* 250mW units */
+
+#define RDO_BATT_OP_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_OP_PWR_SHIFT)
+#define RDO_BATT_MAX_PWR(mw) ((((mw) / 250) & RDO_PWR_MASK) << RDO_BATT_MAX_PWR_SHIFT)
+
+#define RDO_BATT(idx, op_mw, max_mw, flags)                     \
+       (RDO_OBJ(idx) | (flags) |                               \
+        RDO_BATT_OP_PWR(op_mw) | RDO_BATT_MAX_PWR(max_mw))
+
+static inline unsigned int rdo_index(u32 rdo)
+{
+       return (rdo >> RDO_OBJ_POS_SHIFT) & RDO_OBJ_POS_MASK;
+}
+
+static inline unsigned int rdo_op_current(u32 rdo)
+{
+       return ((rdo >> RDO_FIXED_OP_CURR_SHIFT) & RDO_CURR_MASK) * 10;
+}
+
+static inline unsigned int rdo_max_current(u32 rdo)
+{
+       return ((rdo >> RDO_FIXED_MAX_CURR_SHIFT) &
+                       RDO_CURR_MASK) * 10;
+}
+
+static inline unsigned int rdo_op_power(u32 rdo)
+{
+       return ((rdo >> RDO_BATT_OP_PWR_SHIFT) & RDO_PWR_MASK) * 250;
+}
+
+static inline unsigned int rdo_max_power(u32 rdo)
+{
+       return ((rdo >> RDO_BATT_MAX_PWR_SHIFT) & RDO_PWR_MASK) * 250;
+}
+
+#define TCPC_LOG_BUFFER_SIZE 1024
+
+struct tcpc_port;
+
+typedef void (*ss_mux_sel)(enum typec_cc_polarity pol);
+typedef int (*ext_pd_switch_setup)(struct tcpc_port *port_p);
+
+enum tcpc_port_type {
+       TYPEC_PORT_DFP,
+       TYPEC_PORT_UFP,
+       TYPEC_PORT_DRP,
+};
+
+struct tcpc_port_config {
+       uint8_t i2c_bus;
+       uint8_t addr;
+       enum tcpc_port_type port_type;
+       uint32_t max_snk_mv;
+       uint32_t max_snk_ma;
+       uint32_t max_snk_mw;
+       uint32_t op_snk_mv;
+       bool disable_pd;
+       ext_pd_switch_setup switch_setup_func;
+};
+
+struct tcpc_port {
+       struct tcpc_port_config cfg;
+       struct udevice *i2c_dev;
+       ss_mux_sel ss_sel_func;
+       enum pd_sink_state pd_state;
+       uint32_t tx_msg_id;
+       uint32_t log_size;
+       char logbuffer[TCPC_LOG_BUFFER_SIZE];
+       char *log_p;
+       char *log_print;
+};
+
+int tcpc_set_cc_to_source(struct tcpc_port *port);
+int tcpc_set_cc_to_sink(struct tcpc_port *port);
+int tcpc_set_plug_orientation(struct tcpc_port *port, enum typec_cc_polarity polarity);
+int tcpc_get_cc_status(struct tcpc_port *port, enum typec_cc_polarity *polarity, enum typec_cc_state *state);
+int tcpc_clear_alert(struct tcpc_port *port, uint16_t clear_mask);
+int tcpc_send_command(struct tcpc_port *port, uint8_t command);
+int tcpc_polling_reg(struct tcpc_port *port, uint8_t reg,
+       uint8_t reg_width, uint16_t mask, uint16_t value, ulong timeout_ms);
+int tcpc_setup_dfp_mode(struct tcpc_port *port);
+int tcpc_setup_ufp_mode(struct tcpc_port *port);
+int tcpc_disable_src_vbus(struct tcpc_port *port);
+int tcpc_init(struct tcpc_port *port, struct tcpc_port_config config, ss_mux_sel ss_sel_func);
+bool tcpc_pd_sink_check_charging(struct tcpc_port *port);
+void tcpc_print_log(struct tcpc_port *port);
+
+#ifdef CONFIG_SPL_BUILD
+int tcpc_setup_ufp_mode(struct tcpc_port *port)
+{
+       return 0;
+}
+int tcpc_setup_dfp_mode(struct tcpc_port *port)
+{
+       return 0;
+}
+
+int tcpc_disable_src_vbus(struct tcpc_port *port)
+{
+       return 0;
+}
+#endif
+#endif /* __TCPCI_H */
diff --git a/board/somdevices/common/via.h b/board/somdevices/common/via.h
new file mode 100644 (file)
index 0000000..77cfacc
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef _MPC85xx_VIA_H
+void mpc85xx_config_via(struct pci_controller* hose, pci_dev_t dev, struct pci_config_table *tab);
+
+/* Function 1, IDE */
+void mpc85xx_config_via_usbide(struct pci_controller* hose, pci_dev_t dev, struct pci_config_table *tab);
+
+/* Function 2, USB ports 0-1 */
+void mpc85xx_config_via_usb(struct pci_controller* hose, pci_dev_t dev, struct pci_config_table *tab);
+
+/* Function 3, USB ports 2-3 */
+void mpc85xx_config_via_usb2(struct pci_controller* hose, pci_dev_t dev, struct pci_config_table *tab);
+
+/* Function 5, Power Management */
+void mpc85xx_config_via_power(struct pci_controller* hose, pci_dev_t dev, struct pci_config_table *tab);
+
+/* Function 6, AC97 Interface */
+void mpc85xx_config_via_ac97(struct pci_controller* hose, pci_dev_t dev, struct pci_config_table *tab);
+#endif /* _MPC85xx_VIA_H */
diff --git a/board/somdevices/common/vid.c b/board/somdevices/common/vid.c
new file mode 100644 (file)
index 0000000..0ca389c
--- /dev/null
@@ -0,0 +1,879 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <i2c.h>
+#include <asm/io.h>
+#ifdef CONFIG_FSL_LSCH2
+#include <asm/arch/immap_lsch2.h>
+#elif defined(CONFIG_FSL_LSCH3)
+#include <asm/arch/immap_lsch3.h>
+#else
+#include <asm/immap_85xx.h>
+#endif
+#include "vid.h"
+
+int __weak i2c_multiplexer_select_vid_channel(u8 channel)
+{
+       return 0;
+}
+
+/*
+ * Compensate for a board specific voltage drop between regulator and SoC
+ * return a value in mV
+ */
+int __weak board_vdd_drop_compensation(void)
+{
+       return 0;
+}
+
+/*
+ * Board specific settings for specific voltage value
+ */
+int __weak board_adjust_vdd(int vdd)
+{
+       return 0;
+}
+
+#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
+       defined(CONFIG_VOL_MONITOR_IR36021_READ)
+/*
+ * Get the i2c address configuration for the IR regulator chip
+ *
+ * There are some variance in the RDB HW regarding the I2C address configuration
+ * for the IR regulator chip, which is likely a problem of external resistor
+ * accuracy. So we just check each address in a hopefully non-intrusive mode
+ * and use the first one that seems to work
+ *
+ * The IR chip can show up under the following addresses:
+ * 0x08 (Verified on T1040RDB-PA,T4240RDB-PB,X-T4240RDB-16GPA)
+ * 0x09 (Verified on T1040RDB-PA)
+ * 0x38 (Verified on T2080QDS, T2081QDS, T4240RDB)
+ */
+static int find_ir_chip_on_i2c(void)
+{
+       int i2caddress;
+       int ret;
+       u8 byte;
+       int i;
+       const int ir_i2c_addr[] = {0x38, 0x08, 0x09};
+
+       /* Check all the address */
+       for (i = 0; i < (sizeof(ir_i2c_addr)/sizeof(ir_i2c_addr[0])); i++) {
+               i2caddress = ir_i2c_addr[i];
+               ret = i2c_read(i2caddress,
+                              IR36021_MFR_ID_OFFSET, 1, (void *)&byte,
+                              sizeof(byte));
+               if ((ret >= 0) && (byte == IR36021_MFR_ID))
+                       return i2caddress;
+       }
+       return -1;
+}
+#endif
+
+/* Maximum loop count waiting for new voltage to take effect */
+#define MAX_LOOP_WAIT_NEW_VOL          100
+/* Maximum loop count waiting for the voltage to be stable */
+#define MAX_LOOP_WAIT_VOL_STABLE       100
+/*
+ * read_voltage from sensor on I2C bus
+ * We use average of 4 readings, waiting for WAIT_FOR_ADC before
+ * another reading
+ */
+#define NUM_READINGS    4       /* prefer to be power of 2 for efficiency */
+
+/* If an INA220 chip is available, we can use it to read back the voltage
+ * as it may have a higher accuracy than the IR chip for the same purpose
+ */
+#ifdef CONFIG_VOL_MONITOR_INA220
+#define WAIT_FOR_ADC   532     /* wait for 532 microseconds for ADC */
+#define ADC_MIN_ACCURACY       4
+#else
+#define WAIT_FOR_ADC   138     /* wait for 138 microseconds for ADC */
+#define ADC_MIN_ACCURACY       4
+#endif
+
+#ifdef CONFIG_VOL_MONITOR_INA220
+static int read_voltage_from_INA220(int i2caddress)
+{
+       int i, ret, voltage_read = 0;
+       u16 vol_mon;
+       u8 buf[2];
+
+       for (i = 0; i < NUM_READINGS; i++) {
+               ret = i2c_read(I2C_VOL_MONITOR_ADDR,
+                              I2C_VOL_MONITOR_BUS_V_OFFSET, 1,
+                              (void *)&buf, 2);
+               if (ret) {
+                       printf("VID: failed to read core voltage\n");
+                       return ret;
+               }
+               vol_mon = (buf[0] << 8) | buf[1];
+               if (vol_mon & I2C_VOL_MONITOR_BUS_V_OVF) {
+                       printf("VID: Core voltage sensor error\n");
+                       return -1;
+               }
+               debug("VID: bus voltage reads 0x%04x\n", vol_mon);
+               /* LSB = 4mv */
+               voltage_read += (vol_mon >> I2C_VOL_MONITOR_BUS_V_SHIFT) * 4;
+               udelay(WAIT_FOR_ADC);
+       }
+       /* calculate the average */
+       voltage_read /= NUM_READINGS;
+
+       return voltage_read;
+}
+#endif
+
+/* read voltage from IR */
+#ifdef CONFIG_VOL_MONITOR_IR36021_READ
+static int read_voltage_from_IR(int i2caddress)
+{
+       int i, ret, voltage_read = 0;
+       u16 vol_mon;
+       u8 buf;
+
+       for (i = 0; i < NUM_READINGS; i++) {
+               ret = i2c_read(i2caddress,
+                              IR36021_LOOP1_VOUT_OFFSET,
+                              1, (void *)&buf, 1);
+               if (ret) {
+                       printf("VID: failed to read vcpu\n");
+                       return ret;
+               }
+               vol_mon = buf;
+               if (!vol_mon) {
+                       printf("VID: Core voltage sensor error\n");
+                       return -1;
+               }
+               debug("VID: bus voltage reads 0x%02x\n", vol_mon);
+               /* Resolution is 1/128V. We scale up here to get 1/128mV
+                * and divide at the end
+                */
+               voltage_read += vol_mon * 1000;
+               udelay(WAIT_FOR_ADC);
+       }
+       /* Scale down to the real mV as IR resolution is 1/128V, rounding up */
+       voltage_read = DIV_ROUND_UP(voltage_read, 128);
+
+       /* calculate the average */
+       voltage_read /= NUM_READINGS;
+
+       /* Compensate for a board specific voltage drop between regulator and
+        * SoC before converting into an IR VID value
+        */
+       voltage_read -= board_vdd_drop_compensation();
+
+       return voltage_read;
+}
+#endif
+
+#ifdef CONFIG_VOL_MONITOR_LTC3882_READ
+/* read the current value of the LTC Regulator Voltage */
+static int read_voltage_from_LTC(int i2caddress)
+{
+       int  ret, vcode = 0;
+       u8 chan = PWM_CHANNEL0;
+
+       /* select the PAGE 0 using PMBus commands PAGE for VDD*/
+       ret = i2c_write(I2C_VOL_MONITOR_ADDR,
+                       PMBUS_CMD_PAGE, 1, &chan, 1);
+       if (ret) {
+               printf("VID: failed to select VDD Page 0\n");
+               return ret;
+       }
+
+       /*read the output voltage using PMBus command READ_VOUT*/
+       ret = i2c_read(I2C_VOL_MONITOR_ADDR,
+                      PMBUS_CMD_READ_VOUT, 1, (void *)&vcode, 2);
+       if (ret) {
+               printf("VID: failed to read the volatge\n");
+               return ret;
+       }
+
+       /* Scale down to the real mV as LTC resolution is 1/4096V,rounding up */
+       vcode = DIV_ROUND_UP(vcode * 1000, 4096);
+
+       return vcode;
+}
+#endif
+
+static int read_voltage(int i2caddress)
+{
+       int voltage_read;
+#ifdef CONFIG_VOL_MONITOR_INA220
+       voltage_read = read_voltage_from_INA220(i2caddress);
+#elif defined CONFIG_VOL_MONITOR_IR36021_READ
+       voltage_read = read_voltage_from_IR(i2caddress);
+#elif defined CONFIG_VOL_MONITOR_LTC3882_READ
+       voltage_read = read_voltage_from_LTC(i2caddress);
+#else
+       return -1;
+#endif
+       return voltage_read;
+}
+
+#ifdef CONFIG_VOL_MONITOR_IR36021_SET
+/*
+ * We need to calculate how long before the voltage stops to drop
+ * or increase. It returns with the loop count. Each loop takes
+ * several readings (WAIT_FOR_ADC)
+ */
+static int wait_for_new_voltage(int vdd, int i2caddress)
+{
+       int timeout, vdd_current;
+
+       vdd_current = read_voltage(i2caddress);
+       /* wait until voltage starts to reach the target. Voltage slew
+        * rates by typical regulators will always lead to stable readings
+        * within each fairly long ADC interval in comparison to the
+        * intended voltage delta change until the target voltage is
+        * reached. The fairly small voltage delta change to any target
+        * VID voltage also means that this function will always complete
+        * within few iterations. If the timeout was ever reached, it would
+        * point to a serious failure in the regulator system.
+        */
+       for (timeout = 0;
+            abs(vdd - vdd_current) > (IR_VDD_STEP_UP + IR_VDD_STEP_DOWN) &&
+            timeout < MAX_LOOP_WAIT_NEW_VOL; timeout++) {
+               vdd_current = read_voltage(i2caddress);
+       }
+       if (timeout >= MAX_LOOP_WAIT_NEW_VOL) {
+               printf("VID: Voltage adjustment timeout\n");
+               return -1;
+       }
+       return timeout;
+}
+
+/*
+ * this function keeps reading the voltage until it is stable or until the
+ * timeout expires
+ */
+static int wait_for_voltage_stable(int i2caddress)
+{
+       int timeout, vdd_current, vdd;
+
+       vdd = read_voltage(i2caddress);
+       udelay(NUM_READINGS * WAIT_FOR_ADC);
+
+       /* wait until voltage is stable */
+       vdd_current = read_voltage(i2caddress);
+       /* The maximum timeout is
+        * MAX_LOOP_WAIT_VOL_STABLE * NUM_READINGS * WAIT_FOR_ADC
+        */
+       for (timeout = MAX_LOOP_WAIT_VOL_STABLE;
+            abs(vdd - vdd_current) > ADC_MIN_ACCURACY &&
+            timeout > 0; timeout--) {
+               vdd = vdd_current;
+               udelay(NUM_READINGS * WAIT_FOR_ADC);
+               vdd_current = read_voltage(i2caddress);
+       }
+       if (timeout == 0)
+               return -1;
+       return vdd_current;
+}
+
+/* Set the voltage to the IR chip */
+static int set_voltage_to_IR(int i2caddress, int vdd)
+{
+       int wait, vdd_last;
+       int ret;
+       u8 vid;
+
+       /* Compensate for a board specific voltage drop between regulator and
+        * SoC before converting into an IR VID value
+        */
+       vdd += board_vdd_drop_compensation();
+#ifdef CONFIG_FSL_LSCH2
+       vid = DIV_ROUND_UP(vdd - 265, 5);
+#else
+       vid = DIV_ROUND_UP(vdd - 245, 5);
+#endif
+
+       ret = i2c_write(i2caddress, IR36021_LOOP1_MANUAL_ID_OFFSET,
+                       1, (void *)&vid, sizeof(vid));
+       if (ret) {
+               printf("VID: failed to write VID\n");
+               return -1;
+       }
+       wait = wait_for_new_voltage(vdd, i2caddress);
+       if (wait < 0)
+               return -1;
+       debug("VID: Waited %d us\n", wait * NUM_READINGS * WAIT_FOR_ADC);
+
+       vdd_last = wait_for_voltage_stable(i2caddress);
+       if (vdd_last < 0)
+               return -1;
+       debug("VID: Current voltage is %d mV\n", vdd_last);
+       return vdd_last;
+}
+
+#endif
+
+#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
+/* this function sets the VDD and returns the value set */
+static int set_voltage_to_LTC(int i2caddress, int vdd)
+{
+       int ret, vdd_last, vdd_target = vdd;
+       int count = 100, temp = 0;
+
+       /* Scale up to the LTC resolution is 1/4096V */
+       vdd = (vdd * 4096) / 1000;
+
+       /* 5-byte buffer which needs to be sent following the
+        * PMBus command PAGE_PLUS_WRITE.
+        */
+       u8 buff[5] = {0x04, PWM_CHANNEL0, PMBUS_CMD_VOUT_COMMAND,
+                       vdd & 0xFF, (vdd & 0xFF00) >> 8};
+
+       /* Write the desired voltage code to the regulator */
+       ret = i2c_write(I2C_VOL_MONITOR_ADDR,
+                       PMBUS_CMD_PAGE_PLUS_WRITE, 1, (void *)&buff, 5);
+       if (ret) {
+               printf("VID: I2C failed to write to the volatge regulator\n");
+               return -1;
+       }
+
+       /* Wait for the volatge to get to the desired value */
+       do {
+               vdd_last = read_voltage_from_LTC(i2caddress);
+               if (vdd_last < 0) {
+                       printf("VID: Couldn't read sensor abort VID adjust\n");
+                       return -1;
+               }
+               count--;
+               temp = vdd_last - vdd_target;
+       } while ((abs(temp) > 2)  && (count > 0));
+
+       return vdd_last;
+}
+#endif
+
+static int set_voltage(int i2caddress, int vdd)
+{
+       int vdd_last = -1;
+
+#ifdef CONFIG_VOL_MONITOR_IR36021_SET
+       vdd_last = set_voltage_to_IR(i2caddress, vdd);
+#elif defined CONFIG_VOL_MONITOR_LTC3882_SET
+       vdd_last = set_voltage_to_LTC(i2caddress, vdd);
+#else
+       #error Specific voltage monitor must be defined
+#endif
+       return vdd_last;
+}
+
+#ifdef CONFIG_FSL_LSCH3
+int adjust_vdd(ulong vdd_override)
+{
+       int re_enable = disable_interrupts();
+       struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+       u32 fusesr;
+#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
+       defined(CONFIG_VOL_MONITOR_IR36021_READ)
+       u8 vid, buf;
+#else
+       u8 vid;
+#endif
+       int vdd_target, vdd_current, vdd_last;
+       int ret, i2caddress;
+       unsigned long vdd_string_override;
+       char *vdd_string;
+#ifdef CONFIG_ARCH_LX2160A
+       static const u16 vdd[32] = {
+               8250,
+               7875,
+               7750,
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               8000,
+               8125,
+               8250,
+               0,      /* reserved */
+               8500,
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+       };
+#else
+#ifdef CONFIG_ARCH_LS1088A
+       static const uint16_t vdd[32] = {
+               10250,
+               9875,
+               9750,
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               9000,
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               10000,  /* 1.0000V */
+               10125,
+               10250,
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+       };
+
+#else
+       static const uint16_t vdd[32] = {
+               10500,
+               0,      /* reserved */
+               9750,
+               0,      /* reserved */
+               9500,
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               9000,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               10000,  /* 1.0000V */
+               0,      /* reserved */
+               10250,
+               0,      /* reserved */
+               10500,
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+               0,      /* reserved */
+       };
+#endif
+#endif
+       struct vdd_drive {
+               u8 vid;
+               unsigned voltage;
+       };
+
+       ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
+       if (ret) {
+               debug("VID: I2C failed to switch channel\n");
+               ret = -1;
+               goto exit;
+       }
+#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
+       defined(CONFIG_VOL_MONITOR_IR36021_READ)
+       ret = find_ir_chip_on_i2c();
+       if (ret < 0) {
+               printf("VID: Could not find voltage regulator on I2C.\n");
+               ret = -1;
+               goto exit;
+       } else {
+               i2caddress = ret;
+               debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
+       }
+
+       /* check IR chip work on Intel mode*/
+       ret = i2c_read(i2caddress,
+                      IR36021_INTEL_MODE_OOFSET,
+                      1, (void *)&buf, 1);
+       if (ret) {
+               printf("VID: failed to read IR chip mode.\n");
+               ret = -1;
+               goto exit;
+       }
+       if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
+               printf("VID: IR Chip is not used in Intel mode.\n");
+               ret = -1;
+               goto exit;
+       }
+#endif
+
+       /* get the voltage ID from fuse status register */
+       fusesr = in_le32(&gur->dcfg_fusesr);
+       vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_ALTVID_SHIFT) &
+               FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK;
+       if ((vid == 0) || (vid == FSL_CHASSIS3_DCFG_FUSESR_ALTVID_MASK)) {
+               vid = (fusesr >> FSL_CHASSIS3_DCFG_FUSESR_VID_SHIFT) &
+                       FSL_CHASSIS3_DCFG_FUSESR_VID_MASK;
+       }
+       vdd_target = vdd[vid];
+
+       /* check override variable for overriding VDD */
+       vdd_string = env_get(CONFIG_VID_FLS_ENV);
+       if (vdd_override == 0 && vdd_string &&
+           !strict_strtoul(vdd_string, 10, &vdd_string_override))
+               vdd_override = vdd_string_override;
+
+       if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
+               vdd_target = vdd_override * 10; /* convert to 1/10 mV */
+               debug("VDD override is %lu\n", vdd_override);
+       } else if (vdd_override != 0) {
+               printf("Invalid value.\n");
+       }
+
+       /* divide and round up by 10 to get a value in mV */
+       vdd_target = DIV_ROUND_UP(vdd_target, 10);
+       if (vdd_target == 0) {
+               debug("VID: VID not used\n");
+               ret = 0;
+               goto exit;
+       } else if (vdd_target < VDD_MV_MIN || vdd_target > VDD_MV_MAX) {
+               /* Check vdd_target is in valid range */
+               printf("VID: Target VID %d mV is not in range.\n",
+                      vdd_target);
+               ret = -1;
+               goto exit;
+       } else {
+               debug("VID: vid = %d mV\n", vdd_target);
+       }
+
+       /*
+        * Read voltage monitor to check real voltage.
+        */
+       vdd_last = read_voltage(i2caddress);
+       if (vdd_last < 0) {
+               printf("VID: Couldn't read sensor abort VID adjustment\n");
+               ret = -1;
+               goto exit;
+       }
+       vdd_current = vdd_last;
+       debug("VID: Core voltage is currently at %d mV\n", vdd_last);
+
+#ifdef CONFIG_VOL_MONITOR_LTC3882_SET
+       /* Set the target voltage */
+       vdd_last = vdd_current = set_voltage(i2caddress, vdd_target);
+#else
+       /*
+         * Adjust voltage to at or one step above target.
+         * As measurements are less precise than setting the values
+         * we may run through dummy steps that cancel each other
+         * when stepping up and then down.
+         */
+       while (vdd_last > 0 &&
+              vdd_last < vdd_target) {
+               vdd_current += IR_VDD_STEP_UP;
+               vdd_last = set_voltage(i2caddress, vdd_current);
+       }
+       while (vdd_last > 0 &&
+              vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
+               vdd_current -= IR_VDD_STEP_DOWN;
+               vdd_last = set_voltage(i2caddress, vdd_current);
+       }
+
+#endif
+       if (board_adjust_vdd(vdd_target) < 0) {
+               ret = -1;
+               goto exit;
+       }
+
+       if (vdd_last > 0)
+               printf("VID: Core voltage after adjustment is at %d mV\n",
+                      vdd_last);
+       else
+               ret = -1;
+exit:
+       if (re_enable)
+               enable_interrupts();
+       i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
+       return ret;
+}
+#else /* !CONFIG_FSL_LSCH3 */
+int adjust_vdd(ulong vdd_override)
+{
+       int re_enable = disable_interrupts();
+#if defined(CONFIG_FSL_LSCH2)
+       struct ccsr_gur *gur = (void *)(CONFIG_SYS_FSL_GUTS_ADDR);
+#else
+       ccsr_gur_t __iomem *gur =
+               (void __iomem *)(CONFIG_SYS_MPC85xx_GUTS_ADDR);
+#endif
+       u32 fusesr;
+       u8 vid, buf;
+       int vdd_target, vdd_current, vdd_last;
+       int ret, i2caddress;
+       unsigned long vdd_string_override;
+       char *vdd_string;
+       static const uint16_t vdd[32] = {
+               0,      /* unused */
+               9875,   /* 0.9875V */
+               9750,
+               9625,
+               9500,
+               9375,
+               9250,
+               9125,
+               9000,
+               8875,
+               8750,
+               8625,
+               8500,
+               8375,
+               8250,
+               8125,
+               10000,  /* 1.0000V */
+               10125,
+               10250,
+               10375,
+               10500,
+               10625,
+               10750,
+               10875,
+               11000,
+               0,      /* reserved */
+       };
+       struct vdd_drive {
+               u8 vid;
+               unsigned voltage;
+       };
+
+       ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
+       if (ret) {
+               debug("VID: I2C failed to switch channel\n");
+               ret = -1;
+               goto exit;
+       }
+#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
+       defined(CONFIG_VOL_MONITOR_IR36021_READ)
+       ret = find_ir_chip_on_i2c();
+       if (ret < 0) {
+               printf("VID: Could not find voltage regulator on I2C.\n");
+               ret = -1;
+               goto exit;
+       } else {
+               i2caddress = ret;
+               debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
+       }
+
+       /* check IR chip work on Intel mode*/
+       ret = i2c_read(i2caddress,
+                      IR36021_INTEL_MODE_OOFSET,
+                      1, (void *)&buf, 1);
+       if (ret) {
+               printf("VID: failed to read IR chip mode.\n");
+               ret = -1;
+               goto exit;
+       }
+       if ((buf & IR36021_MODE_MASK) != IR36021_INTEL_MODE) {
+               printf("VID: IR Chip is not used in Intel mode.\n");
+               ret = -1;
+               goto exit;
+       }
+#endif
+
+       /* get the voltage ID from fuse status register */
+       fusesr = in_be32(&gur->dcfg_fusesr);
+       /*
+        * VID is used according to the table below
+        *                ---------------------------------------
+        *                |                DA_V                 |
+        *                |-------------------------------------|
+        *                | 5b00000 | 5b00001-5b11110 | 5b11111 |
+        * ---------------+---------+-----------------+---------|
+        * | D | 5b00000  | NO VID  | VID = DA_V      | NO VID  |
+        * | A |----------+---------+-----------------+---------|
+        * | _ | 5b00001  |VID =    | VID =           |VID =    |
+        * | V |   ~      | DA_V_ALT|   DA_V_ALT      | DA_A_VLT|
+        * | _ | 5b11110  |         |                 |         |
+        * | A |----------+---------+-----------------+---------|
+        * | L | 5b11111  | No VID  | VID = DA_V      | NO VID  |
+        * | T |          |         |                 |         |
+        * ------------------------------------------------------
+        */
+#ifdef CONFIG_FSL_LSCH2
+       vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_ALTVID_SHIFT) &
+               FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK;
+       if ((vid == 0) || (vid == FSL_CHASSIS2_DCFG_FUSESR_ALTVID_MASK)) {
+               vid = (fusesr >> FSL_CHASSIS2_DCFG_FUSESR_VID_SHIFT) &
+                       FSL_CHASSIS2_DCFG_FUSESR_VID_MASK;
+       }
+#else
+       vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_ALTVID_SHIFT) &
+               FSL_CORENET_DCFG_FUSESR_ALTVID_MASK;
+       if ((vid == 0) || (vid == FSL_CORENET_DCFG_FUSESR_ALTVID_MASK)) {
+               vid = (fusesr >> FSL_CORENET_DCFG_FUSESR_VID_SHIFT) &
+                       FSL_CORENET_DCFG_FUSESR_VID_MASK;
+       }
+#endif
+       vdd_target = vdd[vid];
+
+       /* check override variable for overriding VDD */
+       vdd_string = env_get(CONFIG_VID_FLS_ENV);
+       if (vdd_override == 0 && vdd_string &&
+           !strict_strtoul(vdd_string, 10, &vdd_string_override))
+               vdd_override = vdd_string_override;
+       if (vdd_override >= VDD_MV_MIN && vdd_override <= VDD_MV_MAX) {
+               vdd_target = vdd_override * 10; /* convert to 1/10 mV */
+               debug("VDD override is %lu\n", vdd_override);
+       } else if (vdd_override != 0) {
+               printf("Invalid value.\n");
+       }
+       if (vdd_target == 0) {
+               debug("VID: VID not used\n");
+               ret = 0;
+               goto exit;
+       } else {
+               /* divide and round up by 10 to get a value in mV */
+               vdd_target = DIV_ROUND_UP(vdd_target, 10);
+               debug("VID: vid = %d mV\n", vdd_target);
+       }
+
+       /*
+        * Read voltage monitor to check real voltage.
+        */
+       vdd_last = read_voltage(i2caddress);
+       if (vdd_last < 0) {
+               printf("VID: Couldn't read sensor abort VID adjustment\n");
+               ret = -1;
+               goto exit;
+       }
+       vdd_current = vdd_last;
+       debug("VID: Core voltage is currently at %d mV\n", vdd_last);
+       /*
+         * Adjust voltage to at or one step above target.
+         * As measurements are less precise than setting the values
+         * we may run through dummy steps that cancel each other
+         * when stepping up and then down.
+         */
+       while (vdd_last > 0 &&
+              vdd_last < vdd_target) {
+               vdd_current += IR_VDD_STEP_UP;
+               vdd_last = set_voltage(i2caddress, vdd_current);
+       }
+       while (vdd_last > 0 &&
+              vdd_last > vdd_target + (IR_VDD_STEP_DOWN - 1)) {
+               vdd_current -= IR_VDD_STEP_DOWN;
+               vdd_last = set_voltage(i2caddress, vdd_current);
+       }
+
+       if (vdd_last > 0)
+               printf("VID: Core voltage after adjustment is at %d mV\n",
+                      vdd_last);
+       else
+               ret = -1;
+exit:
+       if (re_enable)
+               enable_interrupts();
+
+       i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
+
+       return ret;
+}
+#endif
+
+static int print_vdd(void)
+{
+       int vdd_last, ret, i2caddress;
+
+       ret = i2c_multiplexer_select_vid_channel(I2C_MUX_CH_VOL_MONITOR);
+       if (ret) {
+               debug("VID : I2c failed to switch channel\n");
+               return -1;
+       }
+#if defined(CONFIG_VOL_MONITOR_IR36021_SET) || \
+       defined(CONFIG_VOL_MONITOR_IR36021_READ)
+       ret = find_ir_chip_on_i2c();
+       if (ret < 0) {
+               printf("VID: Could not find voltage regulator on I2C.\n");
+               goto exit;
+       } else {
+               i2caddress = ret;
+               debug("VID: IR Chip found on I2C address 0x%02x\n", i2caddress);
+       }
+#endif
+
+       /*
+        * Read voltage monitor to check real voltage.
+        */
+       vdd_last = read_voltage(i2caddress);
+       if (vdd_last < 0) {
+               printf("VID: Couldn't read sensor abort VID adjustment\n");
+               goto exit;
+       }
+       printf("VID: Core voltage is at %d mV\n", vdd_last);
+exit:
+       i2c_multiplexer_select_vid_channel(I2C_MUX_CH_DEFAULT);
+
+       return ret < 0 ? -1 : 0;
+
+}
+
+static int do_vdd_override(cmd_tbl_t *cmdtp,
+                          int flag, int argc,
+                          char * const argv[])
+{
+       ulong override;
+
+       if (argc < 2)
+               return CMD_RET_USAGE;
+
+       if (!strict_strtoul(argv[1], 10, &override))
+               adjust_vdd(override);   /* the value is checked by callee */
+       else
+               return CMD_RET_USAGE;
+       return 0;
+}
+
+static int do_vdd_read(cmd_tbl_t *cmdtp,
+                        int flag, int argc,
+                        char * const argv[])
+{
+       if (argc < 1)
+               return CMD_RET_USAGE;
+       print_vdd();
+
+       return 0;
+}
+
+U_BOOT_CMD(
+       vdd_override, 2, 0, do_vdd_override,
+       "override VDD",
+       " - override with the voltage specified in mV, eg. 1050"
+);
+
+U_BOOT_CMD(
+       vdd_read, 1, 0, do_vdd_read,
+       "read VDD",
+       " - Read the voltage specified in mV"
+)
diff --git a/board/somdevices/common/vid.h b/board/somdevices/common/vid.h
new file mode 100644 (file)
index 0000000..99778e9
--- /dev/null
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __VID_H_
+#define __VID_H_
+
+#define IR36021_LOOP1_MANUAL_ID_OFFSET 0x6A
+#define IR36021_LOOP1_VOUT_OFFSET      0x9A
+#define IR36021_MFR_ID_OFFSET          0x92
+#define IR36021_MFR_ID                 0x43
+#define IR36021_INTEL_MODE_OOFSET      0x14
+#define IR36021_MODE_MASK              0x20
+#define IR36021_INTEL_MODE             0x00
+#define IR36021_AMD_MODE               0x20
+
+/* step the IR regulator in 5mV increments */
+#define IR_VDD_STEP_DOWN               5
+#define IR_VDD_STEP_UP                 5
+int adjust_vdd(ulong vdd_override);
+
+#endif  /* __VID_H_ */
diff --git a/board/somdevices/common/vsc3316_3308.c b/board/somdevices/common/vsc3316_3308.c
new file mode 100644 (file)
index 0000000..033fae0
--- /dev/null
@@ -0,0 +1,275 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ */
+
+#include "vsc3316_3308.h"
+
+#define REVISION_ID_REG                0x7E
+#define INTERFACE_MODE_REG             0x79
+#define CURRENT_PAGE_REGISTER          0x7F
+#define CONNECTION_CONFIG_PAGE         0x00
+#define INPUT_STATE_REG                0x13
+#define GLOBAL_INPUT_ISE1              0x51
+#define GLOBAL_INPUT_ISE2              0x52
+#define GLOBAL_INPUT_GAIN              0x53
+#define GLOBAL_INPUT_LOS               0x55
+#define GLOBAL_OUTPUT_PE1              0x56
+#define GLOBAL_OUTPUT_PE2              0x57
+#define GLOBAL_OUTPUT_LEVEL            0x58
+#define GLOBAL_OUTPUT_TERMINATION      0x5A
+#define GLOBAL_CORE_CNTRL              0x5D
+#define OUTPUT_MODE_PAGE               0x23
+#define CORE_CONTROL_PAGE              0x25
+#define CORE_CONFIG_REG                0x75
+
+int vsc_if_enable(unsigned int vsc_addr)
+{
+       u8 data;
+
+       debug("VSC:Configuring VSC at I2C address 0x%2x"
+                       " for 2-wire interface\n", vsc_addr);
+
+       /* enable 2-wire Serial InterFace (I2C) */
+       data = 0x02;
+       return i2c_write(vsc_addr, INTERFACE_MODE_REG, 1, &data, 1);
+}
+
+int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
+               unsigned int num_con)
+{
+       unsigned int i;
+       u8 rev_id = 0;
+       int ret;
+
+       debug("VSC:Initializing VSC3316 at I2C address 0x%2x"
+               " for Tx\n", vsc_addr);
+
+       ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
+       if (ret < 0) {
+               printf("VSC:0x%x could not read REV_ID from device.\n",
+                       vsc_addr);
+               return ret;
+       }
+
+       if (rev_id != 0xab) {
+               printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
+                       vsc_addr);
+               return -ENODEV;
+       }
+
+       ret = vsc_if_enable(vsc_addr);
+       if (ret) {
+               printf("VSC:0x%x could not configured for 2-wire I/F.\n",
+                       vsc_addr);
+               return ret;
+       }
+
+       /* config connections - page 0x00 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
+
+       /* Making crosspoint connections, by connecting required
+        * input to output */
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
+
+       /* input state - page 0x13 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
+       /* Configuring the required input of the switch */
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr, con_arr[i][0], 0x80);
+
+       /* Setting Global Input LOS threshold value */
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
+
+       /* config output mode - page 0x23 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
+       /* Turn ON the Output driver correspond to required output*/
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr,  con_arr[i][1], 0);
+
+       /* configure global core control register, Turn on Global core power */
+       i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
+
+       vsc_wp_config(vsc_addr);
+
+       return 0;
+}
+
+#ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
+int vsc3308_config_adjust(unsigned int vsc_addr, const int8_t con_arr[][2],
+               unsigned int num_con)
+{
+       unsigned int i;
+       u8 rev_id = 0;
+       int ret;
+
+       debug("VSC:Initializing VSC3308 at I2C address 0x%x for Tx\n",
+             vsc_addr);
+
+       ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
+       if (ret < 0) {
+               printf("VSC:0x%x could not read REV_ID from device.\n",
+                      vsc_addr);
+               return ret;
+       }
+
+       if (rev_id != 0xab) {
+               printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
+                      vsc_addr);
+               return -ENODEV;
+       }
+
+       ret = vsc_if_enable(vsc_addr);
+       if (ret) {
+               printf("VSC:0x%x could not configured for 2-wire I/F.\n",
+                      vsc_addr);
+               return ret;
+       }
+
+       /* config connections - page 0x00 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
+
+       /* Configure Global Input ISE */
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0);
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0);
+
+       /* Configure Tx/Rx Global Output PE1 */
+       i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE1, 0);
+
+       /* Configure Tx/Rx Global Output PE2 */
+       i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_PE2, 0);
+
+       /* Configure Tx/Rx Global Input GAIN */
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_GAIN, 0x3F);
+
+       /* Setting Global Input LOS threshold value */
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0xE0);
+
+       /* Setting Global output termination */
+       i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_TERMINATION, 0);
+
+       /* Configure Tx/Rx Global Output level */
+       if (vsc_addr == VSC3308_TX_ADDRESS)
+               i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 4);
+       else
+               i2c_reg_write(vsc_addr, GLOBAL_OUTPUT_LEVEL, 2);
+
+       /* Making crosspoint connections, by connecting required
+        * input to output */
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
+
+       /* input state - page 0x13 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
+       /* Turning off all the required input of the switch */
+       for (i = 0; i < num_con; i++)
+               i2c_reg_write(vsc_addr, con_arr[i][0], 1);
+
+       /* only turn on specific Tx/Rx requested by the XFI erratum */
+       if (vsc_addr == VSC3308_TX_ADDRESS) {
+               i2c_reg_write(vsc_addr, 2, 0);
+               i2c_reg_write(vsc_addr, 3, 0);
+       } else {
+               i2c_reg_write(vsc_addr, 0, 0);
+               i2c_reg_write(vsc_addr, 1, 0);
+       }
+
+       /* config output mode - page 0x23 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
+       /* Turn off the Output driver correspond to required output*/
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr,  con_arr[i][1], 1);
+
+       /* only turn on specific Tx/Rx requested by the XFI erratum */
+       if (vsc_addr == VSC3308_TX_ADDRESS) {
+               i2c_reg_write(vsc_addr, 0, 0);
+               i2c_reg_write(vsc_addr, 1, 0);
+       } else {
+               i2c_reg_write(vsc_addr, 3, 0);
+               i2c_reg_write(vsc_addr, 4, 0);
+       }
+
+       /* configure global core control register, Turn on Global core power */
+       i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
+
+       vsc_wp_config(vsc_addr);
+
+       return 0;
+}
+#endif
+
+int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
+               unsigned int num_con)
+{
+       unsigned int i;
+       u8 rev_id = 0;
+       int ret;
+
+       debug("VSC:Initializing VSC3308 at I2C address 0x%x"
+               " for Tx\n", vsc_addr);
+
+       ret = i2c_read(vsc_addr, REVISION_ID_REG, 1, &rev_id, 1);
+       if (ret < 0) {
+               printf("VSC:0x%x could not read REV_ID from device.\n",
+                       vsc_addr);
+               return ret;
+       }
+
+       if (rev_id != 0xab) {
+               printf("VSC: device at address 0x%x is not VSC3316/3308.\n",
+                       vsc_addr);
+               return -ENODEV;
+       }
+
+       ret = vsc_if_enable(vsc_addr);
+       if (ret) {
+               printf("VSC:0x%x could not configured for 2-wire I/F.\n",
+                       vsc_addr);
+               return ret;
+       }
+
+       /* config connections - page 0x00 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, CONNECTION_CONFIG_PAGE);
+
+       /* Making crosspoint connections, by connecting required
+        * input to output */
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr, con_arr[i][1], con_arr[i][0]);
+
+       /*Configure Global Input ISE and gain */
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE1, 0x12);
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_ISE2, 0x12);
+
+       /* input state - page 0x13 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, INPUT_STATE_REG);
+       /* Turning ON the required input of the switch */
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr, con_arr[i][0], 0);
+
+       /* Setting Global Input LOS threshold value */
+       i2c_reg_write(vsc_addr, GLOBAL_INPUT_LOS, 0x60);
+
+       /* config output mode - page 0x23 */
+       i2c_reg_write(vsc_addr, CURRENT_PAGE_REGISTER, OUTPUT_MODE_PAGE);
+       /* Turn ON the Output driver correspond to required output*/
+       for (i = 0; i < num_con ; i++)
+               i2c_reg_write(vsc_addr,  con_arr[i][1], 0);
+
+       /* configure global core control register, Turn on Global core power */
+       i2c_reg_write(vsc_addr, GLOBAL_CORE_CNTRL, 0);
+
+       vsc_wp_config(vsc_addr);
+
+       return 0;
+}
+
+void vsc_wp_config(unsigned int vsc_addr)
+{
+       debug("VSC:Configuring VSC at address:0x%x for WP\n", vsc_addr);
+
+       /* For new crosspoint configuration to occur, WP bit of
+        * CORE_CONFIG_REG should be set 1 and then reset to 0 */
+       i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x01);
+       i2c_reg_write(vsc_addr, CORE_CONFIG_REG, 0x0);
+}
diff --git a/board/somdevices/common/vsc3316_3308.h b/board/somdevices/common/vsc3316_3308.h
new file mode 100644 (file)
index 0000000..49a684f
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2012 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __VSC_CROSSBAR_H_
+#define __VSC_CROSSBAR_H       1_
+
+#include <common.h>
+#include <i2c.h>
+#include <errno.h>
+
+int vsc_if_enable(unsigned int vsc_addr);
+int vsc3316_config(unsigned int vsc_addr, int8_t con_arr[][2],
+               unsigned int num_con);
+#ifdef CONFIG_SYS_FSL_B4860QDS_XFI_ERR
+int vsc3308_config_adjust(unsigned int vsc_addr, const int8_t con_arr[][2],
+               unsigned int num_con);
+#endif
+int vsc3308_config(unsigned int vsc_addr, const int8_t con_arr[][2],
+               unsigned int num_con);
+void vsc_wp_config(unsigned int vsc_addr);
+
+#endif /* __VSC_CROSSBAR_H_ */
diff --git a/board/somdevices/common/zm7300.c b/board/somdevices/common/zm7300.c
new file mode 100644 (file)
index 0000000..acd5343
--- /dev/null
@@ -0,0 +1,232 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ */
+
+/* Power-One ZM7300 DPM */
+#include "zm7300.h"
+
+#define DPM_WP 0x96
+#define WRP_OPCODE 0x01
+#define WRM_OPCODE 0x02
+#define RRP_OPCODE 0x11
+
+#define DPM_SUCCESS 0x01
+#define DPM_EXEC_FAIL 0x00
+
+static const uint16_t hex_to_1_10mv[] = {
+       5000,
+       5125,
+       5250,
+       5375,
+       5500,
+       5625,
+       5750,
+       5875,
+       6000,
+       6125,
+       6250,
+       6375,
+       6500,
+       6625,
+       6750,
+       6875,
+       7000,
+       7125,
+       7250,
+       7375,
+       7500,
+       7625,
+       7750,
+       7875,
+       8000,
+       8125,
+       8250,
+       8375,
+       8500,
+       8625,
+       8750,
+       8875,
+       9000,
+       9125,
+       9250,
+       9375,
+       9500,  /* 0.95mV */
+       9625,
+       9750,
+       9875,
+       10000,  /* 1.0V */
+       10125,
+       10250,
+       10375,
+       10500,
+       10625,
+       10750,
+       10875,
+       11000,
+       11125,
+       11250,
+       11375,
+       11500,
+       11625,
+       11750,
+       11875,
+       12000,
+       12125,
+       12250,
+       12375,
+       0,      /* reserved */
+};
+
+
+/* Read Data d from Register r of POL p */
+u8 dpm_rrp(uchar r)
+{
+       u8 ret[5];
+
+       ret[0] = RRP_OPCODE;
+       /* POL is 0 */
+       ret[1] = 0;
+       ret[2] = r;
+       i2c_read(I2C_DPM_ADDR, 0, -3, ret, 2);
+       if (ret[1] == DPM_SUCCESS) { /* the DPM returned success as status */
+               debug("RRP_OPCODE returned success data is %x\n", ret[0]);
+               return ret[0];
+       } else {
+               return -1;
+       }
+}
+
+/* Write Data d into DPM register r (RAM) */
+int dpm_wrm(u8 r, u8 d)
+{
+       u8 ret[5];
+
+       ret[0] = WRM_OPCODE;
+       ret[1] = r;
+       ret[2] = d;
+       i2c_read(I2C_DPM_ADDR, 0, -3, ret, 1);
+       if (ret[0] == DPM_SUCCESS) { /* the DPM returned success as status */
+               debug("WRM_OPCODE returned success data is %x\n", ret[0]);
+               return ret[0];
+       } else {
+               return -1;
+       }
+}
+
+/* Write Data d into Register r of POL(s) a */
+int dpm_wrp(u8 r, u8 d)
+{
+       u8 ret[7];
+
+       ret[0] = WRP_OPCODE;
+       /* only POL0 is present */
+       ret[1] = 0x01;
+       ret[2] = 0x00;
+       ret[3] = 0x00;
+       ret[4] = 0x00;
+       ret[5] = r;
+       ret[6] = d;
+       i2c_read(I2C_DPM_ADDR, 0, -7, ret, 1);
+       if (ret[0] == DPM_SUCCESS) { /* the DPM returned success as status */
+               debug("WRP_OPCODE returned success data is %x\n", ret[0]);
+               return 0;
+       } else {
+               return -1;
+       }
+}
+
+/* Uses the DPM command RRP */
+u8 zm_read(uchar reg)
+{
+       return dpm_rrp(reg);
+}
+
+/* ZM_write --
+       Steps:
+       a. Write data to the register
+       b. Read data from register and compare to written value
+       c. Return return_code & voltage_read
+*/
+u8 zm_write(u8 reg, u8 data)
+{
+       u8 d;
+
+       /* write data to register */
+       dpm_wrp(reg, data);
+
+       /* read register and compare to written value */
+       d = dpm_rrp(reg);
+       if (d != data) {
+               printf("zm_write : Comparison register data failed\n");
+               return -1;
+       }
+
+       return d;
+}
+
+/* zm_write_out_voltage
+ * voltage in 1/10 mV
+ */
+int zm_write_voltage(int voltage)
+{
+       u8 reg = 0x7, vid;
+       uint16_t voltage_read;
+       u8 ret;
+
+       vid =  (voltage - 5000) / ZM_STEP;
+
+       ret = zm_write(reg, vid);
+       if (ret != -1) {
+               voltage_read = hex_to_1_10mv[ret];
+               debug("voltage set to %dmV\n", voltage_read/10);
+               return voltage_read;
+       }
+       return -1;
+}
+
+/* zm_read_out_voltage
+ * voltage in 1/10 mV
+ */
+int zm_read_voltage(void)
+{
+       u8 reg = 0x7;
+       u8 ret;
+       int voltage;
+
+       ret = zm_read(reg);
+       if (ret != -1) {
+               voltage =  hex_to_1_10mv[ret];
+               debug("Voltage read is %dmV\n", voltage/10);
+               return voltage;
+       } else {
+               return -1;
+       }
+}
+
+int zm_disable_wp()
+{
+       u8 new_wp_value;
+
+       /* Disable using Write-Protect register 0x96 */
+       new_wp_value = 0x8;
+       if ((dpm_wrm(DPM_WP, new_wp_value)) < 0) {
+               printf("Disable Write-Protect register failed\n");
+               return -1;
+       }
+       return 0;
+}
+
+int zm_enable_wp()
+{
+       u8 orig_wp_value;
+       orig_wp_value = 0x0;
+
+       /* Enable using Write-Protect register 0x96 */
+       if ((dpm_wrm(DPM_WP, orig_wp_value)) < 0) {
+               printf("Enable Write-Protect register failed\n");
+               return -1;
+       }
+       return 0;
+}
+
diff --git a/board/somdevices/common/zm7300.h b/board/somdevices/common/zm7300.h
new file mode 100644 (file)
index 0000000..9ce24af
--- /dev/null
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ */
+
+#ifndef __ZM7300_H_
+#define __ZM7300_H     1_
+
+#include <common.h>
+#include <i2c.h>
+#include <errno.h>
+#include <asm/io.h>
+
+#define ZM_STEP 125
+int zm7300_set_voltage(int voltage_1_10mv);
+int zm_write_voltage(int voltage);
+int zm_read_voltage(void);
+int zm_disable_wp(void);
+int zm_enable_wp(void);
+
+#endif /* __ZM7300_H_ */
diff --git a/board/somdevices/imx6ull_somdevices/Kconfig b/board/somdevices/imx6ull_somdevices/Kconfig
new file mode 100644 (file)
index 0000000..985763c
--- /dev/null
@@ -0,0 +1,14 @@
+if TARGET_MX6ULL_14X14_EVK || TARGET_MX6ULL_9X9_EVK
+
+config SYS_BOARD
+       default "mx6ullevk"
+
+config SYS_VENDOR
+       default "freescale"
+
+config SYS_CONFIG_NAME
+       default "mx6ullevk"
+
+config SYS_TEXT_BASE
+       default 0x87800000
+endif
diff --git a/board/somdevices/imx6ull_somdevices/MAINTAINERS b/board/somdevices/imx6ull_somdevices/MAINTAINERS
new file mode 100644 (file)
index 0000000..73031cd
--- /dev/null
@@ -0,0 +1,7 @@
+MX6ULLEVK BOARD
+M:     Peng Fan <peng.fan@nxp.com>
+S:     Maintained
+F:     board/freescale/mx6ullevk/
+F:     include/configs/mx6ullevk.h
+F:     configs/mx6ull_14x14_evk_defconfig
+F:     configs/mx6ull_14x14_evk_plugin_defconfig
diff --git a/board/somdevices/imx6ull_somdevices/Makefile b/board/somdevices/imx6ull_somdevices/Makefile
new file mode 100644 (file)
index 0000000..1ff03b5
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0+
+# (C) Copyright 2016 Freescale Semiconductor, Inc.
+
+obj-y  := mx6ullevk.o
diff --git a/board/somdevices/imx6ull_somdevices/README b/board/somdevices/imx6ull_somdevices/README
new file mode 100644 (file)
index 0000000..d5c8770
--- /dev/null
@@ -0,0 +1,36 @@
+How to use U-Boot on Freescale MX6ULL 14x14 EVK
+----------------------------------------------
+
+- First make sure you have installed the dtc package (device tree compiler):
+
+$ sudo apt-get install device-tree-compiler
+
+- Build U-Boot for MX6ULL 14x14 EVK:
+
+$ make mrproper
+$ make mx6ull_14x14_evk_defconfig
+$ make
+
+This generates the u-boot-dtb.imx image in the current directory.
+
+- Flash the u-boot-dtb.imx image into the micro SD card:
+
+$ sudo dd if=u-boot-dtb.imx of=/dev/sdb bs=1K seek=1 && sync
+
+- Jumper settings:
+
+SW601: 0 0 1 0
+Sw602: 1 0
+
+Where 0 means bottom position and 1 means top position (from the switch label
+numbers reference).
+
+Connect the USB cable between the EVK and the PC for the console.
+(The USB console connector is the one close the push buttons)
+
+Insert the micro SD card in the board, power it up and U-Boot messages should
+come up.
+
+The link for the board: http://www.nxp.com/products/microcontrollers-and- \
+processors/arm-processors/i.mx-applications-processors/i.mx-6-processors/ \
+i.mx6qp/evaluation-kit-for-the-i.mx-6ull-applications-processor:MCIMX6ULL-EVK
diff --git a/board/somdevices/imx6ull_somdevices/imximage.cfg b/board/somdevices/imx6ull_somdevices/imximage.cfg
new file mode 100644 (file)
index 0000000..33e7fcd
--- /dev/null
@@ -0,0 +1,121 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * 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
+ */
+
+#define __ASSEMBLY__
+#include <config.h>
+
+/* image version */
+
+IMAGE_VERSION 2
+
+/*
+ * Boot Device : one of
+ * spi/sd/nand/onenand, qspi/nor
+ */
+
+#ifdef CONFIG_QSPI_BOOT
+BOOT_FROM      qspi
+#elif defined(CONFIG_NOR_BOOT)
+BOOT_FROM      nor
+#else
+BOOT_FROM      sd
+#endif
+
+#ifdef CONFIG_USE_IMXIMG_PLUGIN
+/*PLUGIN    plugin-binary-file    IRAM_FREE_START_ADDR*/
+PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
+#else
+
+#ifdef CONFIG_SECURE_BOOT
+CSF CONFIG_CSF_SIZE
+#endif
+
+/*
+ * 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
+ */
+
+/* Enable all clocks */
+DATA 4 0x020c4068 0xffffffff
+DATA 4 0x020c406c 0xffffffff
+DATA 4 0x020c4070 0xffffffff
+DATA 4 0x020c4074 0xffffffff
+DATA 4 0x020c4078 0xffffffff
+DATA 4 0x020c407c 0xffffffff
+DATA 4 0x020c4080 0xffffffff
+
+#ifdef CONFIG_IMX_OPTEE
+DATA 4 0x20e4024 0x00000001
+CHECK_BITS_SET 4 0x20e4024 0x1
+#endif
+
+DATA 4 0x020E04B4 0x000C0000
+DATA 4 0x020E04AC 0x00000000
+DATA 4 0x020E027C 0x00000030
+DATA 4 0x020E0250 0x00000030
+DATA 4 0x020E024C 0x00000030
+DATA 4 0x020E0490 0x00000030
+DATA 4 0x020E0288 0x000C0030
+DATA 4 0x020E0270 0x00000000
+DATA 4 0x020E0260 0x00000030
+DATA 4 0x020E0264 0x00000030
+DATA 4 0x020E04A0 0x00000030
+DATA 4 0x020E0494 0x00020000
+DATA 4 0x020E0280 0x00000030
+DATA 4 0x020E0284 0x00000030
+DATA 4 0x020E04B0 0x00020000
+DATA 4 0x020E0498 0x00000030
+DATA 4 0x020E04A4 0x00000030
+DATA 4 0x020E0244 0x00000030
+DATA 4 0x020E0248 0x00000030
+DATA 4 0x021B001C 0x00008000
+DATA 4 0x021B0800 0xA1390003
+DATA 4 0x021B080C 0x00000004
+DATA 4 0x021B083C 0x41640158
+DATA 4 0x021B0848 0x40403237
+DATA 4 0x021B0850 0x40403C33
+DATA 4 0x021B081C 0x33333333
+DATA 4 0x021B0820 0x33333333
+DATA 4 0x021B082C 0xf3333333
+DATA 4 0x021B0830 0xf3333333
+DATA 4 0x021B08C0 0x00944009
+DATA 4 0x021B08b8 0x00000800
+DATA 4 0x021B0004 0x0002002D
+DATA 4 0x021B0008 0x1B333030
+DATA 4 0x021B000C 0x676B52F3
+DATA 4 0x021B0010 0xB66D0B63
+DATA 4 0x021B0014 0x01FF00DB
+DATA 4 0x021B0018 0x00201740
+DATA 4 0x021B001C 0x00008000
+DATA 4 0x021B002C 0x000026D2
+DATA 4 0x021B0030 0x006B1023
+DATA 4 0x021B0040 0x0000004F
+DATA 4 0x021B0000 0x84180000
+DATA 4 0x021B0890 0x00400000
+DATA 4 0x021B001C 0x02008032
+DATA 4 0x021B001C 0x00008033
+DATA 4 0x021B001C 0x00048031
+DATA 4 0x021B001C 0x15208030
+DATA 4 0x021B001C 0x04008040
+DATA 4 0x021B0020 0x00000800
+DATA 4 0x021B0818 0x00000227
+DATA 4 0x021B0004 0x0002552D
+DATA 4 0x021B0404 0x00011006
+DATA 4 0x021B001C 0x00000000
+
+#endif
diff --git a/board/somdevices/imx6ull_somdevices/imximage_lpddr2.cfg b/board/somdevices/imx6ull_somdevices/imximage_lpddr2.cfg
new file mode 100644 (file)
index 0000000..3e3ad26
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ *
+ * Refer docs/README.imxmage for more details about how-to configure
+ * and create imximage boot image
+ *
+ * The syntax is taken as close as possible with the kwbimage
+ */
+
+#define __ASSEMBLY__
+#include <config.h>
+
+/* image version */
+
+IMAGE_VERSION 2
+
+/*
+ * Boot Device : one of
+ * spi/sd/nand/onenand, qspi/nor
+ */
+
+#ifdef CONFIG_QSPI_BOOT
+BOOT_FROM      qspi
+#elif defined(CONFIG_NOR_BOOT)
+BOOT_FROM      nor
+#else
+BOOT_FROM      sd
+#endif
+
+#ifdef CONFIG_USE_IMXIMG_PLUGIN
+/*PLUGIN    plugin-binary-file    IRAM_FREE_START_ADDR*/
+PLUGIN board/freescale/mx6ullevk/plugin.bin 0x00907000
+#else
+
+#ifdef CONFIG_SECURE_BOOT
+CSF CONFIG_CSF_SIZE
+#endif
+
+/*
+ * 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
+ */
+
+DATA 4 0x020c4068 0xffffffff
+DATA 4 0x020c406c 0xffffffff
+DATA 4 0x020c4070 0xffffffff
+DATA 4 0x020c4074 0xffffffff
+DATA 4 0x020c4078 0xffffffff
+DATA 4 0x020c407c 0xffffffff
+DATA 4 0x020c4080 0xffffffff
+
+#ifdef CONFIG_IMX_OPTEE
+DATA 4 0x20e4024 0x00000001
+CHECK_BITS_SET 4 0x20e4024 0x1
+#endif
+
+DATA 4 0x020E04B4 0x00080000
+DATA 4 0x020E04AC 0x00000000
+DATA 4 0x020E027C 0x00000030
+DATA 4 0x020E0250 0x00000030
+DATA 4 0x020E024C 0x00000030
+DATA 4 0x020E0490 0x00000030
+DATA 4 0x020E0288 0x00000030
+DATA 4 0x020E0270 0x00000000
+DATA 4 0x020E0260 0x00000000
+DATA 4 0x020E0264 0x00000000
+DATA 4 0x020E04A0 0x00000030
+DATA 4 0x020E0494 0x00020000
+DATA 4 0x020E0280 0x00003030
+DATA 4 0x020E0284 0x00003030
+DATA 4 0x020E04B0 0x00020000
+DATA 4 0x020E0498 0x00000030
+DATA 4 0x020E04A4 0x00000030
+DATA 4 0x020E0244 0x00000030
+DATA 4 0x020E0248 0x00000030
+
+DATA 4 0x021B001C 0x00008000
+DATA 4 0x021B085C 0x1b4700c7
+DATA 4 0x021B0800 0xA1390003
+DATA 4 0x021B0890 0x23400A38
+DATA 4 0x021B08b8 0x00000800
+
+DATA 4 0x021B081C 0x33333333
+DATA 4 0x021B0820 0x33333333
+DATA 4 0x021B082C 0xf3333333
+DATA 4 0x021B0830 0xf3333333
+DATA 4 0x021B083C 0x20000000
+DATA 4 0x021B0848 0x40403439
+DATA 4 0x021B0850 0x4040342D
+DATA 4 0x021B08C0 0x00921012
+DATA 4 0x021B08b8 0x00000800
+
+DATA 4 0x021B0004 0x00020052
+DATA 4 0x021B0008 0x00000000
+DATA 4 0x021B000C 0x33374133
+DATA 4 0x021B0010 0x00100A82
+DATA 4 0x021B0038 0x00170557
+DATA 4 0x021B0014 0x00000093
+DATA 4 0x021B0018 0x00201748
+DATA 4 0x021B002C 0x0F9F26D2
+DATA 4 0x021B0030 0x009F0010
+DATA 4 0x021B0040 0x00000047
+DATA 4 0x021B0000 0x83100000
+DATA 4 0x021B001C 0x00008010
+DATA 4 0x021B001C 0x003F8030
+DATA 4 0x021B001C 0xFF0A8030
+DATA 4 0x021B001C 0x82018030
+DATA 4 0x021B001C 0x04028030
+DATA 4 0x021B001C 0x01038030
+DATA 4 0x021B0020 0x00001800
+DATA 4 0x021B0818 0x00000000
+DATA 4 0x021B0800 0xA1310003
+DATA 4 0x021B0004 0x00025552
+DATA 4 0x021B0404 0x00011006
+DATA 4 0x021B001C 0x00000000
+#endif
diff --git a/board/somdevices/imx6ull_somdevices/mx6ullevk.c b/board/somdevices/imx6ull_somdevices/mx6ullevk.c
new file mode 100644 (file)
index 0000000..3b0a8ad
--- /dev/null
@@ -0,0 +1,414 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+#include <asm/arch/clock.h>
+#include <asm/arch/iomux.h>
+#include <asm/arch/imx-regs.h>
+#include <asm/arch/crm_regs.h>
+#include <asm/arch/mx6-pins.h>
+#include <asm/arch/sys_proto.h>
+#include <asm/gpio.h>
+#include <asm/mach-imx/iomux-v3.h>
+#include <asm/mach-imx/boot_mode.h>
+#include <asm/mach-imx/mxc_i2c.h>
+#include <asm/io.h>
+#include <common.h>
+#include <i2c.h>
+#include <miiphy.h>
+#include <fsl_esdhc.h>
+#include <linux/sizes.h>
+#include <mmc.h>
+#include <mxsfb.h>
+#include <asm/mach-imx/video.h>
+#include <power/pmic.h>
+#include <power/pfuze3000_pmic.h>
+#include "../common/pfuze.h"
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define UART_PAD_CTRL  (PAD_CTL_PKE | PAD_CTL_PUE |            \
+       PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED |               \
+       PAD_CTL_DSE_40ohm   | PAD_CTL_SRE_FAST  | PAD_CTL_HYS)
+
+#define I2C_PAD_CTRL    (PAD_CTL_PKE | PAD_CTL_PUE |            \
+       PAD_CTL_PUS_100K_UP | PAD_CTL_SPEED_MED |               \
+       PAD_CTL_DSE_40ohm | PAD_CTL_HYS |                       \
+       PAD_CTL_ODE)
+
+#define LCD_PAD_CTRL    (PAD_CTL_HYS | PAD_CTL_PUS_100K_UP | PAD_CTL_PUE | \
+       PAD_CTL_PKE | PAD_CTL_SPEED_MED | PAD_CTL_DSE_40ohm)
+
+#define GPMI_PAD_CTRL0 (PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_100K_UP)
+#define GPMI_PAD_CTRL1 (PAD_CTL_DSE_40ohm | PAD_CTL_SPEED_MED | \
+                       PAD_CTL_SRE_FAST)
+#define GPMI_PAD_CTRL2 (GPMI_PAD_CTRL0 | GPMI_PAD_CTRL1)
+
+
+#ifdef CONFIG_DM_PMIC
+int power_init_board(void)
+{
+       struct udevice *dev;
+       int ret, dev_id, rev_id;
+       unsigned int reg;
+
+       ret = pmic_get("pfuze3000", &dev);
+       if (ret == -ENODEV)
+               return 0;
+       if (ret != 0)
+               return ret;
+
+       dev_id = pmic_reg_read(dev, PFUZE3000_DEVICEID);
+       rev_id = pmic_reg_read(dev, PFUZE3000_REVID);
+       printf("PMIC: PFUZE3000 DEV_ID=0x%x REV_ID=0x%x\n", dev_id, rev_id);
+
+       /* disable Low Power Mode during standby mode */
+       reg = pmic_reg_read(dev, PFUZE3000_LDOGCTL);
+       reg |= 0x1;
+       pmic_reg_write(dev, PFUZE3000_LDOGCTL, reg);
+
+       /* SW1B step ramp up time from 2us to 4us/25mV */
+       pmic_reg_write(dev, PFUZE3000_SW1BCONF, 0x40);
+
+       /* SW1B mode to APS/PFM */
+       pmic_reg_write(dev, PFUZE3000_SW1BMODE, 0xc);
+
+       /* SW1B standby voltage set to 0.975V */
+       pmic_reg_write(dev, PFUZE3000_SW1BSTBY, 0xb);
+
+       return 0;
+}
+
+#ifdef CONFIG_LDO_BYPASS_CHECK
+void ldo_mode_set(int ldo_bypass)
+{
+       unsigned int value;
+       u32 vddarm;
+       struct udevice *dev;
+       int ret;
+
+       ret = pmic_get("pfuze3000", &dev);
+       if (ret == -ENODEV) {
+               printf("No PMIC found!\n");
+               return;
+       }
+
+       /* switch to ldo_bypass mode */
+       if (ldo_bypass) {
+               prep_anatop_bypass();
+               /* decrease VDDARM to 1.275V */
+               value = pmic_reg_read(dev, PFUZE3000_SW1BVOLT);
+               value &= ~0x1f;
+               value |= PFUZE3000_SW1AB_SETP(12750);
+               pmic_reg_write(dev, PFUZE3000_SW1BVOLT, value);
+
+               set_anatop_bypass(1);
+               vddarm = PFUZE3000_SW1AB_SETP(11750);
+
+               value = pmic_reg_read(dev, PFUZE3000_SW1BVOLT);
+               value &= ~0x1f;
+               value |= vddarm;
+               pmic_reg_write(dev, PFUZE3000_SW1BVOLT, value);
+
+               finish_anatop_bypass();
+
+               printf("switch to ldo_bypass mode!\n");
+       }
+}
+#endif
+#endif
+
+int dram_init(void)
+{
+       gd->ram_size = imx_ddr_size();
+
+       return 0;
+}
+
+static iomux_v3_cfg_t const uart1_pads[] = {
+       MX6_PAD_UART1_TX_DATA__UART1_DCE_TX | MUX_PAD_CTRL(UART_PAD_CTRL),
+       MX6_PAD_UART1_RX_DATA__UART1_DCE_RX | MUX_PAD_CTRL(UART_PAD_CTRL),
+};
+
+static void setup_iomux_uart(void)
+{
+       imx_iomux_v3_setup_multiple_pads(uart1_pads, ARRAY_SIZE(uart1_pads));
+}
+
+#ifdef CONFIG_FSL_QSPI
+
+#ifndef CONFIG_DM_SPI
+#define QSPI_PAD_CTRL1 \
+       (PAD_CTL_SRE_FAST | PAD_CTL_SPEED_MED | \
+        PAD_CTL_PKE | PAD_CTL_PUE | PAD_CTL_PUS_47K_UP | PAD_CTL_DSE_120ohm)
+
+static iomux_v3_cfg_t const quadspi_pads[] = {
+       MX6_PAD_NAND_WP_B__QSPI_A_SCLK | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+       MX6_PAD_NAND_READY_B__QSPI_A_DATA00 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+       MX6_PAD_NAND_CE0_B__QSPI_A_DATA01 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+       MX6_PAD_NAND_CE1_B__QSPI_A_DATA02 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+       MX6_PAD_NAND_CLE__QSPI_A_DATA03 | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+       MX6_PAD_NAND_DQS__QSPI_A_SS0_B | MUX_PAD_CTRL(QSPI_PAD_CTRL1),
+};
+#endif
+
+static int board_qspi_init(void)
+{
+#ifndef CONFIG_DM_SPI
+       /* Set the iomux */
+       imx_iomux_v3_setup_multiple_pads(quadspi_pads,
+                                        ARRAY_SIZE(quadspi_pads));
+#endif
+       /* Set the clock */
+       enable_qspi_clk(0);
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_NAND_MXS
+static iomux_v3_cfg_t const nand_pads[] = {
+       MX6_PAD_NAND_DATA00__RAWNAND_DATA00 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DATA01__RAWNAND_DATA01 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DATA02__RAWNAND_DATA02 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DATA03__RAWNAND_DATA03 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DATA04__RAWNAND_DATA04 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DATA05__RAWNAND_DATA05 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DATA06__RAWNAND_DATA06 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DATA07__RAWNAND_DATA07 | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_CLE__RAWNAND_CLE | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_ALE__RAWNAND_ALE | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_CE0_B__RAWNAND_CE0_B | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_CE1_B__RAWNAND_CE1_B | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_RE_B__RAWNAND_RE_B | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_WE_B__RAWNAND_WE_B | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_WP_B__RAWNAND_WP_B | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_READY_B__RAWNAND_READY_B | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+       MX6_PAD_NAND_DQS__RAWNAND_DQS | MUX_PAD_CTRL(GPMI_PAD_CTRL2),
+};
+
+static void setup_gpmi_nand(void)
+{
+       struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
+
+       /* config gpmi nand iomux */
+       imx_iomux_v3_setup_multiple_pads(nand_pads, ARRAY_SIZE(nand_pads));
+
+       setup_gpmi_io_clk((3 << MXC_CCM_CSCDR1_BCH_PODF_OFFSET) |
+                         (3 << MXC_CCM_CSCDR1_GPMI_PODF_OFFSET));
+
+       /* enable apbh clock gating */
+       setbits_le32(&mxc_ccm->CCGR0, MXC_CCM_CCGR0_APBHDMA_MASK);
+}
+#endif
+
+#ifdef CONFIG_FEC_MXC
+static int setup_fec(int fec_id)
+{
+       struct iomuxc *const iomuxc_regs = (struct iomuxc *)IOMUXC_BASE_ADDR;
+       int ret;
+
+       if (fec_id == 0) {
+               if (check_module_fused(MX6_MODULE_ENET1))
+                       return -1;
+
+               /*
+                * Use 50M anatop loopback REF_CLK1 for ENET1,
+                * clear gpr1[13], set gpr1[17].
+                */
+               clrsetbits_le32(&iomuxc_regs->gpr[1], IOMUX_GPR1_FEC1_MASK,
+                               IOMUX_GPR1_FEC1_CLOCK_MUX1_SEL_MASK);
+       } else {
+               if (check_module_fused(MX6_MODULE_ENET2))
+                       return -1;
+
+               /*
+                * Use 50M anatop loopback REF_CLK2 for ENET2,
+                * clear gpr1[14], set gpr1[18].
+                */
+               clrsetbits_le32(&iomuxc_regs->gpr[1], IOMUX_GPR1_FEC2_MASK,
+                               IOMUX_GPR1_FEC2_CLOCK_MUX1_SEL_MASK);
+       }
+
+       ret = enable_fec_anatop_clock(fec_id, ENET_50MHZ);
+       if (ret)
+               return ret;
+
+       enable_enet_clk(1);
+
+       return 0;
+}
+
+int board_phy_config(struct phy_device *phydev)
+{
+       phy_write(phydev, MDIO_DEVAD_NONE, 0x1f, 0x8190);
+
+       if (phydev->drv->config)
+               phydev->drv->config(phydev);
+
+       return 0;
+}
+#endif
+
+#ifdef CONFIG_VIDEO_MXS
+static iomux_v3_cfg_t const lcd_pads[] = {
+       MX6_PAD_LCD_CLK__LCDIF_CLK | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_ENABLE__LCDIF_ENABLE | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_HSYNC__LCDIF_HSYNC | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_VSYNC__LCDIF_VSYNC | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA00__LCDIF_DATA00 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA01__LCDIF_DATA01 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA02__LCDIF_DATA02 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA03__LCDIF_DATA03 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA04__LCDIF_DATA04 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA05__LCDIF_DATA05 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA06__LCDIF_DATA06 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA07__LCDIF_DATA07 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA08__LCDIF_DATA08 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA09__LCDIF_DATA09 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA10__LCDIF_DATA10 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA11__LCDIF_DATA11 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA12__LCDIF_DATA12 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA13__LCDIF_DATA13 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA14__LCDIF_DATA14 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA15__LCDIF_DATA15 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA16__LCDIF_DATA16 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA17__LCDIF_DATA17 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA18__LCDIF_DATA18 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA19__LCDIF_DATA19 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA20__LCDIF_DATA20 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA21__LCDIF_DATA21 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA22__LCDIF_DATA22 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+       MX6_PAD_LCD_DATA23__LCDIF_DATA23 | MUX_PAD_CTRL(LCD_PAD_CTRL),
+
+       /* LCD_RST */
+       MX6_PAD_SNVS_TAMPER9__GPIO5_IO09 | MUX_PAD_CTRL(NO_PAD_CTRL),
+
+       /* Use GPIO for Brightness adjustment, duty cycle = period. */
+       MX6_PAD_GPIO1_IO08__GPIO1_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
+};
+
+void do_enable_parallel_lcd(struct display_info_t const *dev)
+{
+       enable_lcdif_clock(dev->bus, 1);
+
+       imx_iomux_v3_setup_multiple_pads(lcd_pads, ARRAY_SIZE(lcd_pads));
+
+       /* Reset the LCD */
+       gpio_request(IMX_GPIO_NR(5, 9), "lcd reset");
+       gpio_direction_output(IMX_GPIO_NR(5, 9) , 0);
+       udelay(500);
+       gpio_direction_output(IMX_GPIO_NR(5, 9) , 1);
+
+       /* Set Brightness to high */
+       gpio_request(IMX_GPIO_NR(1, 8), "backlight");
+       gpio_direction_output(IMX_GPIO_NR(1, 8) , 1);
+}
+
+struct display_info_t const displays[] = {{
+       .bus = MX6UL_LCDIF1_BASE_ADDR,
+       .addr = 0,
+       .pixfmt = 24,
+       .detect = NULL,
+       .enable = do_enable_parallel_lcd,
+       .mode   = {
+               .name                   = "TFT43AB",
+               .xres           = 480,
+               .yres           = 272,
+               .pixclock       = 108695,
+               .left_margin    = 8,
+               .right_margin   = 4,
+               .upper_margin   = 2,
+               .lower_margin   = 4,
+               .hsync_len      = 41,
+               .vsync_len      = 10,
+               .sync           = 0,
+               .vmode          = FB_VMODE_NONINTERLACED
+} } };
+size_t display_count = ARRAY_SIZE(displays);
+#endif
+
+int board_early_init_f(void)
+{
+       setup_iomux_uart();
+
+       return 0;
+}
+
+int board_init(void)
+{
+       /* Address of boot parameters */
+       gd->bd->bi_boot_params = PHYS_SDRAM + 0x100;
+
+#ifdef CONFIG_FEC_MXC
+       setup_fec(CONFIG_FEC_ENET_DEV);
+#endif
+
+#ifdef CONFIG_FSL_QSPI
+       board_qspi_init();
+#endif
+
+#ifdef CONFIG_NAND_MXS
+       setup_gpmi_nand();
+#endif
+
+       return 0;
+}
+
+#ifdef CONFIG_CMD_BMODE
+static const struct boot_mode board_boot_modes[] = {
+       /* 4 bit bus width */
+       {"sd1", MAKE_CFGVAL(0x42, 0x20, 0x00, 0x00)},
+       {"sd2", MAKE_CFGVAL(0x40, 0x28, 0x00, 0x00)},
+       {"qspi1", MAKE_CFGVAL(0x10, 0x00, 0x00, 0x00)},
+       {NULL,   0},
+};
+#endif
+
+int board_late_init(void)
+{
+#ifdef CONFIG_CMD_BMODE
+       add_board_boot_modes(board_boot_modes);
+#endif
+
+       env_set("tee", "no");
+#ifdef CONFIG_IMX_OPTEE
+       env_set("tee", "yes");
+#endif
+
+#ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
+       env_set("board_name", "EVK");
+
+       if (is_mx6ull_9x9_evk())
+               env_set("board_rev", "9X9");
+       else
+               env_set("board_rev", "14X14");
+
+       if (is_cpu_type(MXC_CPU_MX6ULZ)) {
+               env_set("board_name", "ULZ-EVK");
+               env_set("usb_net_cmd", "usb start");
+    }
+#endif
+
+#ifdef CONFIG_ENV_IS_IN_MMC
+       board_late_mmc_env_init();
+#endif
+
+       set_wdog_reset((struct wdog_regs *)WDOG1_BASE_ADDR);
+
+       return 0;
+}
+
+int checkboard(void)
+{
+       if (is_mx6ull_9x9_evk())
+               puts("Board: MX6ULL 9x9 EVK\n");
+       else if (is_cpu_type(MXC_CPU_MX6ULZ))
+               puts("Board: MX6ULZ 14x14 EVK\n");
+       else
+               puts("Board: MX6ULL 14x14 EVK\n");
+
+       return 0;
+}
diff --git a/board/somdevices/imx6ull_somdevices/plugin.S b/board/somdevices/imx6ull_somdevices/plugin.S
new file mode 100644 (file)
index 0000000..812088d
--- /dev/null
@@ -0,0 +1,263 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Freescale Semiconductor, Inc.
+ * Copyright 2017 NXP
+ */
+
+#include <config.h>
+
+/* DDR script */
+.macro imx6ull_ddr3_evk_setting
+       ldr r0, =IOMUXC_BASE_ADDR
+       ldr r1, =0x000C0000
+       str r1, [r0, #0x4B4]
+       ldr r1, =0x00000000
+       str r1, [r0, #0x4AC]
+       ldr r1, =0x00000030
+       str r1, [r0, #0x27C]
+       ldr r1, =0x00000030
+       str r1, [r0, #0x250]
+       str r1, [r0, #0x24C]
+       str r1, [r0, #0x490]
+       ldr r1, =0x000C0030
+       str r1, [r0, #0x288]
+
+       ldr r1, =0x00000000
+       str r1, [r0, #0x270]
+
+       ldr r1, =0x00000030
+       str r1, [r0, #0x260]
+       str r1, [r0, #0x264]
+       str r1, [r0, #0x4A0]
+
+       ldr r1, =0x00020000
+       str r1, [r0, #0x494]
+
+       ldr r1, =0x00000030
+       str r1, [r0, #0x280]
+       ldr r1, =0x00000030
+       str r1, [r0, #0x284]
+
+       ldr r1, =0x00020000
+       str r1, [r0, #0x4B0]
+
+       ldr r1, =0x00000030
+       str r1, [r0, #0x498]
+       str r1, [r0, #0x4A4]
+       str r1, [r0, #0x244]
+       str r1, [r0, #0x248]
+
+       ldr r0, =MMDC_P0_BASE_ADDR
+       ldr r1, =0x00008000
+       str r1, [r0, #0x1C]
+       ldr r1, =0xA1390003
+       str r1, [r0, #0x800]
+       ldr r1, =0x00000004
+       str r1, [r0, #0x80C]
+       ldr r1, =0x41640158
+       str r1, [r0, #0x83C]
+       ldr r1, =0x40403237
+       str r1, [r0, #0x848]
+       ldr r1, =0x40403C33
+       str r1, [r0, #0x850]
+       ldr r1, =0x33333333
+       str r1, [r0, #0x81C]
+       str r1, [r0, #0x820]
+       ldr r1, =0xF3333333
+       str r1, [r0, #0x82C]
+       str r1, [r0, #0x830]
+       ldr r1, =0x00944009
+       str r1, [r0, #0x8C0]
+       ldr r1, =0x00000800
+       str r1, [r0, #0x8B8]
+       ldr r1, =0x0002002D
+       str r1, [r0, #0x004]
+       ldr r1, =0x1B333030
+       str r1, [r0, #0x008]
+       ldr r1, =0x676B52F3
+       str r1, [r0, #0x00C]
+       ldr r1, =0xB66D0B63
+       str r1, [r0, #0x010]
+       ldr r1, =0x01FF00DB
+       str r1, [r0, #0x014]
+       ldr r1, =0x00201740
+       str r1, [r0, #0x018]
+       ldr r1, =0x00008000
+       str r1, [r0, #0x01C]
+       ldr r1, =0x000026D2
+       str r1, [r0, #0x02C]
+       ldr r1, =0x006B1023
+       str r1, [r0, #0x030]
+       ldr r1, =0x0000004F
+       str r1, [r0, #0x040]
+       ldr r1, =0x84180000
+       str r1, [r0, #0x000]
+       ldr r1, =0x00400000
+       str r1, [r0, #0x890]
+       ldr r1, =0x02008032
+       str r1, [r0, #0x01C]
+       ldr r1, =0x00008033
+       str r1, [r0, #0x01C]
+       ldr r1, =0x00048031
+       str r1, [r0, #0x01C]
+       ldr r1, =0x15208030
+       str r1, [r0, #0x01C]
+       ldr r1, =0x04008040
+       str r1, [r0, #0x01C]
+       ldr r1, =0x00000800
+       str r1, [r0, #0x020]
+       ldr r1, =0x00000227
+       str r1, [r0, #0x818]
+       ldr r1, =0x0002552D
+       str r1, [r0, #0x004]
+       ldr r1, =0x00011006
+       str r1, [r0, #0x404]
+       ldr r1, =0x00000000
+       str r1, [r0, #0x01C]
+.endm
+
+.macro imx6ull_lpddr2_evk_setting
+       ldr r0, =IOMUXC_BASE_ADDR
+       ldr r1, =0x00080000
+       str r1, [r0, #0x4B4]
+       ldr r1, =0x00000000
+       str r1, [r0, #0x4AC]
+       ldr r1, =0x00000030
+       str r1, [r0, #0x27C]
+       str r1, [r0, #0x250]
+       str r1, [r0, #0x24C]
+       str r1, [r0, #0x490]
+       str r1, [r0, #0x288]
+
+       ldr r1, =0x00000000
+       str r1, [r0, #0x270]
+       str r1, [r0, #0x260]
+       str r1, [r0, #0x264]
+
+       ldr r1, =0x00000030
+       str r1, [r0, #0x4A0]
+
+       ldr r1, =0x00020000
+       str r1, [r0, #0x494]
+
+       ldr r1, =0x00003030
+       str r1, [r0, #0x280]
+       ldr r1, =0x00003030
+       str r1, [r0, #0x284]
+
+       ldr r1, =0x00020000
+       str r1, [r0, #0x4B0]
+
+       ldr r1, =0x00000030
+       str r1, [r0, #0x498]
+       str r1, [r0, #0x4A4]
+       str r1, [r0, #0x244]
+       str r1, [r0, #0x248]
+
+       ldr r0, =MMDC_P0_BASE_ADDR
+       ldr r1, =0x00008000
+       str r1, [r0, #0x1C]
+       ldr r1, =0x1b4700c7
+       str r1, [r0, #0x85c]
+       ldr r1, =0xA1390003
+       str r1, [r0, #0x800]
+       ldr r1, =0x23400A38
+       str r1, [r0, #0x890]
+       ldr r1, =0x00000800
+       str r1, [r0, #0x8b8]
+       ldr r1, =0x33333333
+       str r1, [r0, #0x81C]
+       str r1, [r0, #0x820]
+       ldr r1, =0xF3333333
+       str r1, [r0, #0x82C]
+       str r1, [r0, #0x830]
+       ldr r1, =0x20000000
+       str r1, [r0, #0x83C]
+       ldr r1, =0x40403439
+       str r1, [r0, #0x848]
+       ldr r1, =0x4040342D
+       str r1, [r0, #0x850]
+       ldr r1, =0x00921012
+       str r1, [r0, #0x8C0]
+       ldr r1, =0x00000800
+       str r1, [r0, #0x8B8]
+
+       ldr r1, =0x00020052
+       str r1, [r0, #0x004]
+       ldr r1, =0x00000000
+       str r1, [r0, #0x008]
+       ldr r1, =0x33374133
+       str r1, [r0, #0x00C]
+       ldr r1, =0x00100A82
+       str r1, [r0, #0x010]
+       ldr r1, =0x00170557
+       str r1, [r0, #0x038]
+       ldr r1, =0x00000093
+       str r1, [r0, #0x014]
+       ldr r1, =0x00201748
+       str r1, [r0, #0x018]
+       ldr r1, =0x0F9F26D2
+       str r1, [r0, #0x02C]
+       ldr r1, =0x009F0010
+       str r1, [r0, #0x030]
+       ldr r1, =0x00000047
+       str r1, [r0, #0x040]
+       ldr r1, =0x83100000
+       str r1, [r0, #0x000]
+       ldr r1, =0x00008010
+       str r1, [r0, #0x01C]
+       ldr r1, =0x003F8030
+       str r1, [r0, #0x01C]
+       ldr r1, =0xFF0A8030
+       str r1, [r0, #0x01C]
+       ldr r1, =0x82018030
+       str r1, [r0, #0x01C]
+       ldr r1, =0x04028030
+       str r1, [r0, #0x01C]
+       ldr r1, =0x01038030
+       str r1, [r0, #0x01C]
+       ldr r1, =0x00001800
+       str r1, [r0, #0x020]
+       ldr r1, =0x00000000
+       str r1, [r0, #0x818]
+       ldr r1, =0xA1310003
+       str r1, [r0, #0x800]
+       ldr r1, =0x00025552
+       str r1, [r0, #0x004]
+       ldr r1, =0x00011006
+       str r1, [r0, #0x404]
+       ldr r1, =0x00000000
+       str r1, [r0, #0x01C]
+.endm
+
+.macro imx6_clock_gating
+       ldr r0, =CCM_BASE_ADDR
+       ldr r1, =0xFFFFFFFF
+       str r1, [r0, #0x68]
+       str r1, [r0, #0x6C]
+       str r1, [r0, #0x70]
+       str r1, [r0, #0x74]
+       str r1, [r0, #0x78]
+       str r1, [r0, #0x7C]
+       str r1, [r0, #0x80]
+
+#ifdef CONFIG_IMX_OPTEE
+       ldr r0, =0x20e4024
+       ldr r1, =0x1
+       str r1, [r0]
+#endif
+.endm
+
+.macro imx6_qos_setting
+.endm
+
+.macro imx6_ddr_setting
+#if defined (CONFIG_TARGET_MX6ULL_9X9_EVK)
+       imx6ull_lpddr2_evk_setting
+#else
+       imx6ull_ddr3_evk_setting
+#endif
+.endm
+
+/* include the common plugin code here */
+#include <asm/arch/mx6_plugin.S>