arm/ls102xa:add hwconfig setting to support disable unused devices

DEVDISRn registers provides a mechanism for gating clocks of IP blocks
that are not used. Here we implement hwconfig option to allow users
to disable unused peripherals on the board.

For ex. If eSDHC/qDMA/eDMA are unused and with disabled status in dts,
User can enable CONFIG_FSL_DEVICE_DISABLE and set "devdis:esdhc,qdma,edma"
in hwconfig, thus ESDHC controller & eDMA/qDMA will be clock gated to
save more power.

Signed-off-by: Zhuoyu Zhang <Zhuoyu.Zhang@freescale.com>
Reviewed-by: York Sun <yorksun@freescale.com>
diff --git a/arch/arm/include/asm/arch-ls102xa/ls102xa_devdis.h b/arch/arm/include/asm/arch-ls102xa/ls102xa_devdis.h
new file mode 100644
index 0000000..3e9e9ea
--- /dev/null
+++ b/arch/arm/include/asm/arch-ls102xa/ls102xa_devdis.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __FSL_LS102XA_DEVDIS_H_
+#define __FSL_LS102XA_DEVDIS_H_
+
+#include <fsl_devdis.h>
+
+const struct devdis_table devdis_tbl[] = {
+	{ "pbl", 0x0, 0x80000000 },	/* PBL	*/
+	{ "esdhc", 0x0, 0x20000000 },	/* eSDHC	*/
+	{ "qdma", 0x0, 0x800000 },	/* qDMA		*/
+	{ "edma", 0x0, 0x400000 },	/* eDMA		*/
+	{ "usb3", 0x0, 0x84000 },	/* USB3.0 controller and PHY*/
+	{ "usb2", 0x0, 0x40000 },	/* USB2.0 controller	*/
+	{ "sata", 0x0, 0x8000 },	/* SATA		*/
+	{ "sec", 0x0, 0x200 },		/* SEC		*/
+	{ "dcu", 0x0, 0x2 },		/* Display controller Unit	*/
+	{ "qe", 0x0, 0x1 },		/* QUICC Engine	*/
+	{ "etsec1", 0x1, 0x80000000 },	/* eTSEC1 controller	*/
+	{ "etesc2", 0x1, 0x40000000 },	/* eTSEC2 controller	*/
+	{ "etsec3", 0x1, 0x20000000 },	/* eTSEC3 controller	*/
+	{ "pex1", 0x2, 0x80000000 },	/* PCIE controller 1	*/
+	{ "pex2", 0x2, 0x40000000 },	/* PCIE controller 2	*/
+	{ "duart1", 0x3, 0x20000000 },	/* DUART1	*/
+	{ "duart2", 0x3, 0x10000000 },	/* DUART2	*/
+	{ "qspi", 0x3, 0x8000000 },	/* QSPI		*/
+	{ "ddr", 0x4, 0x80000000 },	/* DDR		*/
+	{ "ocram1", 0x4, 0x8000000 },	/* OCRAM1	*/
+	{ "ifc", 0x4, 0x800000 },	/* IFC		*/
+	{ "gpio", 0x4, 0x400000 },	/* GPIO		*/
+	{ "dbg", 0x4, 0x200000 },	/* DBG		*/
+	{ "can1", 0x4, 0x80000 },	/* FlexCAN1	*/
+	{ "can2_4", 0x4, 0x40000 },	/* FlexCAN2_3_4	*/
+	{ "ftm2_8", 0x4, 0x20000 },	/* FlexTimer2_3_4_5_6_7_8	*/
+	{ "secmon", 0x4, 0x4000 },	/* Security Monitor	*/
+	{ "wdog1_2", 0x4, 0x400 },	/* WatchDog1_2	*/
+	{ "i2c2_3", 0x4, 0x200 },	/* I2C2_3	*/
+	{ "sai1_4", 0x4, 0x100 },	/* SAI1_2_3_4	*/
+	{ "lpuart2_6", 0x4, 0x80 },	/* LPUART2_3_4_5_6	*/
+	{ "dspi1_2", 0x4, 0x40 },	/* DSPI1_2	*/
+	{ "asrc", 0x4, 0x20 },		/* ASRC		*/
+	{ "spdif", 0x4, 0x10 },		/* SPDIF	*/
+	{ "i2c1", 0x4, 0x4 },		/* I2C1		*/
+	{ "lpuart1", 0x4, 0x2 },	/* LPUART1	*/
+	{ "ftm1", 0x4, 0x1 },		/* FlexTimer1	*/
+};
+
+#endif
diff --git a/board/freescale/ls1021aqds/ls1021aqds.c b/board/freescale/ls1021aqds/ls1021aqds.c
index e585380..655fc64 100644
--- a/board/freescale/ls1021aqds/ls1021aqds.c
+++ b/board/freescale/ls1021aqds/ls1021aqds.c
@@ -12,12 +12,14 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/fsl_serdes.h>
 #include <asm/arch/ls102xa_stream_id.h>
+#include <asm/arch/ls102xa_devdis.h>
 #include <hwconfig.h>
 #include <mmc.h>
 #include <fsl_esdhc.h>
 #include <fsl_ifc.h>
 #include <fsl_sec.h>
 #include <spl.h>
+#include <fsl_devdis.h>
 
 #include "../common/sleep.h"
 #include "../common/qixis.h"
@@ -531,6 +533,9 @@
 	else if (hwconfig("sdhc"))
 		config_board_mux(MUX_TYPE_SDHC);
 
+#ifdef CONFIG_FSL_DEVICE_DISABLE
+	device_disable(devdis_tbl, ARRAY_SIZE(devdis_tbl));
+#endif
 #ifdef CONFIG_FSL_CAAM
 	return sec_init();
 #endif
diff --git a/board/freescale/ls1021atwr/ls1021atwr.c b/board/freescale/ls1021atwr/ls1021atwr.c
index 006700f..228dbf8 100644
--- a/board/freescale/ls1021atwr/ls1021atwr.c
+++ b/board/freescale/ls1021atwr/ls1021atwr.c
@@ -12,6 +12,7 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/fsl_serdes.h>
 #include <asm/arch/ls102xa_stream_id.h>
+#include <asm/arch/ls102xa_devdis.h>
 #include <hwconfig.h>
 #include <mmc.h>
 #include <fsl_esdhc.h>
@@ -21,6 +22,7 @@
 #include <fsl_mdio.h>
 #include <tsec.h>
 #include <fsl_sec.h>
+#include <fsl_devdis.h>
 #include <spl.h>
 #include "../common/sleep.h"
 #ifdef CONFIG_U_QE
@@ -652,6 +654,9 @@
 #if defined(CONFIG_MISC_INIT_R)
 int misc_init_r(void)
 {
+#ifdef CONFIG_FSL_DEVICE_DISABLE
+	device_disable(devdis_tbl, ARRAY_SIZE(devdis_tbl));
+#endif
 #ifndef CONFIG_QSPI_BOOT
 	config_board_mux();
 #endif
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 5218b91..8d0fc3c 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -35,3 +35,4 @@
 obj-$(CONFIG_FSL_SEC_MON) += fsl_sec_mon.o
 obj-$(CONFIG_PCA9551_LED) += pca9551_led.o
 obj-$(CONFIG_RESET) += reset-uclass.o
+obj-$(CONFIG_FSL_DEVICE_DISABLE) += fsl_devdis.o
diff --git a/drivers/misc/fsl_devdis.c b/drivers/misc/fsl_devdis.c
new file mode 100644
index 0000000..996f45c
--- /dev/null
+++ b/drivers/misc/fsl_devdis.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ * Author: Zhuoyu Zhang <Zhuoyu.Zhang@freescale.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch-ls102xa/immap_ls102xa.h>
+#include <asm/arch-ls102xa/config.h>
+#include <linux/compiler.h>
+#include <hwconfig.h>
+#include <fsl_devdis.h>
+
+void device_disable(const struct devdis_table *tbl, uint32_t num)
+{
+	int i;
+	struct ccsr_gur __iomem *gur = (void *)CONFIG_SYS_FSL_GUTS_ADDR;
+
+	/*
+	 * Extract hwconfig from environment and disable unused device.
+	 */
+	for (i = 0; i < num; i++) {
+		if (hwconfig_sub("devdis", tbl[i].name))
+			setbits_be32(&gur->devdisr + tbl[i].offset,
+				tbl[i].mask);
+	}
+}
+
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index dfaffa1..b44f326 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -566,7 +566,9 @@
 #define CONFIG_TIMER_CLK_FREQ		12500000
 
 #define CONFIG_HWCONFIG
-#define HWCONFIG_BUFFER_SIZE		128
+#define HWCONFIG_BUFFER_SIZE		256
+
+#define CONFIG_FSL_DEVICE_DISABLE
 
 #define CONFIG_BOOTDELAY		3
 
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h
index 3299a9f..7dcb719 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -414,7 +414,9 @@
 #define CONFIG_TIMER_CLK_FREQ		12500000
 
 #define CONFIG_HWCONFIG
-#define HWCONFIG_BUFFER_SIZE		128
+#define HWCONFIG_BUFFER_SIZE		256
+
+#define CONFIG_FSL_DEVICE_DISABLE
 
 #define CONFIG_BOOTDELAY		3
 
diff --git a/include/fsl_devdis.h b/include/fsl_devdis.h
new file mode 100644
index 0000000..02415fe
--- /dev/null
+++ b/include/fsl_devdis.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2015 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __FSL_DEVDIS_H_
+#define __FSL_DEVDIS_H_
+
+struct devdis_table {
+	char name[32];
+	u32 offset;
+	u32 mask;
+};
+
+void device_disable(const struct devdis_table *tbl, uint32_t num);
+
+#endif