cs5536: Make NAND code optional and implement timing setting

The reset value for NAND timings is the slowest possible for Flash interface.
Implement optionally setting it to a different value inside the NAND device.
Set it to appropriate values for Artec Group DBE61 and DBE62.
This results in a roughly two times quicker read time as measured by hdparm
for these boards.

Because we can not cast to southbridge_amd_cs5536_nand_config if the board dts
does not have an entry for the NAND device, this change proposes a method for
reasonably clean way to only optionally compile in support for certain devices:
If a board wants to support an optional device, its Kconfig entry can select
that configuration. If it's optional even across the same board, it can expose
a subconfig option of the board, that describes it and if chosen selects the
device config. The source code for that device is conditionally compiled only
if the Kconfig option gets enabled by the configuration for the board.
A requirement is that if the board configuration can enable a device, it is
contained in the boards dts file as well.

A perhaps better long-term alternative for this could be making dtc generate
preprocessor definitions for each device_configuration struct that it creates.
Then the source code file is always enabled, but that file can be wrapped
around a simple #ifdef check in its entirety.

Conversion to the alternative approach from the short-term Kconfig approach
proposed here should be relatively easy, as to not block inclusion of the
Kconfig approach in the short term.

Signed-off-by: Mart Raudsepp <mart.raudsepp@artecdesign.ee>
---
 Kconfig                         |    5 ++
 mainboard/artecgroup/Kconfig    |    2 +
 mainboard/artecgroup/dbe61/dts  |    5 ++-
 mainboard/artecgroup/dbe62/dts  |    5 ++-
 southbridge/amd/cs5536/Makefile |    4 ++
 southbridge/amd/cs5536/cs5536.c |   53 +----------------------
 southbridge/amd/cs5536/cs5536.h |    1 +
 southbridge/amd/cs5536/nand     |    4 ++
 southbridge/amd/cs5536/nand.c   |   93 +++++++++++++++++++++++++++++++++++++++
 9 files changed, 118 insertions(+), 54 deletions(-)
 create mode 100644 southbridge/amd/cs5536/nand.c

diff --git a/Kconfig b/Kconfig
index 82e2c44..8adc045 100644
--- a/Kconfig
+++ b/Kconfig
@@ -163,6 +163,11 @@ config SUPERIO_ITE_IT8712F
 config SUPERIO_VIA_VT1211
 	boolean
 
+# Other devices that may be optional for a board:
+config DEVICE_AMD_CS5536_NAND
+	select SOUTHBRIDGE_AMD_CS5536
+	boolean
+
 menu "Payload"
 
 config PAYLOAD_ELF_LOADER
diff --git a/mainboard/artecgroup/Kconfig b/mainboard/artecgroup/Kconfig
index fe7acea..afa4d25 100644
--- a/mainboard/artecgroup/Kconfig
+++ b/mainboard/artecgroup/Kconfig
@@ -29,6 +29,7 @@ config BOARD_ARTECGROUP_DBE61
 	select CPU_AMD_GEODELX
 	select NORTHBRIDGE_AMD_GEODELX
 	select SOUTHBRIDGE_AMD_CS5536
+	select DEVICE_AMD_CS5536_NAND
 	select PIRQ_TABLE
 	help
 	  Artec Group DBE61 ThinCan, also known as Linutop 1.
@@ -39,6 +40,7 @@ config BOARD_ARTECGROUP_DBE62
 	select CPU_AMD_GEODELX
 	select NORTHBRIDGE_AMD_GEODELX
 	select SOUTHBRIDGE_AMD_CS5536
+	select DEVICE_AMD_CS5536_NAND
 	select PIRQ_TABLE
 	help
 	  Artec Group DBE62 ThinCan.
diff --git a/mainboard/artecgroup/dbe61/dts b/mainboard/artecgroup/dbe61/dts
index a6995ce..cb46292 100644
--- a/mainboard/artecgroup/dbe61/dts
+++ b/mainboard/artecgroup/dbe61/dts
@@ -109,8 +109,11 @@ end
 			/* USB Port Power Handling setting. */
 			pph = "0xf5";
 		};
-		pci@f,1 {
+		pci@f,1 { /* NAND Flash */
 			/config/("southbridge/amd/cs5536/nand");
+			/* Timings */
+			nandf_data = "0x01200120";
+			nandf_ctl = "0x00000120";
 		};
 	};
 };
diff --git a/mainboard/artecgroup/dbe62/dts b/mainboard/artecgroup/dbe62/dts
index 8089e79..73dc5a7 100644
--- a/mainboard/artecgroup/dbe62/dts
+++ b/mainboard/artecgroup/dbe62/dts
@@ -63,8 +63,11 @@
 			/* USB Port Power Handling setting. */
 			pph = "0xf5";
 		};
-		pci@f,1 {
+		pci@f,1 { /* NAND Flash */
 			/config/("southbridge/amd/cs5536/nand");
+			/* Timings */
+			nandf_data = "0x01200120";
+			nandf_ctl = "0x00000120";
 		};
 	};
 };
diff --git a/southbridge/amd/cs5536/Makefile b/southbridge/amd/cs5536/Makefile
index ed21896..811991c 100644
--- a/southbridge/amd/cs5536/Makefile
+++ b/southbridge/amd/cs5536/Makefile
@@ -23,6 +23,10 @@ ifeq ($(CONFIG_SOUTHBRIDGE_AMD_CS5536),y)
 
 STAGE2_CHIPSET_SRC += $(src)/southbridge/amd/cs5536/cs5536.c
 
+ifeq ($(CONFIG_DEVICE_AMD_CS5536_NAND),y)
+STAGE2_CHIPSET_SRC += $(src)/southbridge/amd/cs5536/nand.c
+endif
+
 ifeq ($(CONFIG_PIRQ_TABLE),y)
 STAGE2_CHIPSET_SRC += $(src)/southbridge/amd/cs5536/irq_tables.c
 endif
diff --git a/southbridge/amd/cs5536/cs5536.c b/southbridge/amd/cs5536/cs5536.c
index 5e4af9d..0113a0a 100644
--- a/southbridge/amd/cs5536/cs5536.c
+++ b/southbridge/amd/cs5536/cs5536.c
@@ -88,7 +88,7 @@ static const u32 FlashPort[] = {
  * bits 24 -> 30 reserved and set to zero
  * bit  31       triggers the config cycle
  */
-static void hide_vpci(u32 vpci_devid)
+void hide_vpci(u32 vpci_devid)
 {
 	printk(BIOS_DEBUG, "Hiding VPCI device: 0x%08X (%02x:%02x.%01x)\n",
 		vpci_devid, (vpci_devid >> 16) & 0xff,
@@ -98,43 +98,6 @@ static void hide_vpci(u32 vpci_devid)
 }
 
 /**
- * Enables the FLASH PCI header when NAND device existing in mainboard device
- * tree. Used when the mainboard has a FLASH part instead of an IDE drive and
- * that fact is expressed in the mainboard device tree.
- * Must be called after VSA init but before PCI scans to enable the flash
- * PCI device header early enough - that is .phase2_fixup of the device.
- *
- * @param dev The device.
- */
-static void nand_phase2(struct device *dev)
-{
-	if (dev->enabled) {
-		/* Tell VSA to use FLASH PCI header. Not IDE header. */
-		hide_vpci(0x800079C4);
-	}
-}
-
-static void nand_read_resources(struct device *dev)
-{
-	pci_dev_read_resources(dev);
-
-	/* All memory accesses in the range of 0xF0000000 - 0xFFFFFFFF routed to
-	 * Diverse Integration Logic (DIVIL) get always sent to the device inside
-	 * DIVIL as set in DIVIL_BALL_OPTS PRI_BOOT_LOC and SEC_BOOT_LOC bits
-	 * (see CS5536 data book chapter 6.6.2.10 DIVIL_BALL_OPTS PRI_BOOT_LOC
-	 * description).
-	 * The virtual PCI address limit test gives us a false upper limit of
-	 * 0xFFFFFFFF for this device, but we do not want NAND Flash to be using
-	 * memory addresses 0xF0000000 and above as those accesses would end up
-	 * somewhere else instead. Therefore if VSA2 gave us a MMIO resource for
-	 * NAND Flash, patch this (fixed) resources higher bound to 0xEFFFFFFF.
-	 */
-	if ((dev->resources >= 1) && (dev->resource[0].flags & IORESOURCE_MEM) &&
-		(dev->resource[0].limit > 0xefffffff))
-		dev->resource[0].limit = 0xefffffff;
-}
-
-/**
  * Power button setup.
  *
  * Setup GPIO24, it is the external signal for CS5536 vsb_work_aux which
@@ -749,17 +712,3 @@ struct device_operations cs5536_ide = {
 	.phase6_init		 = ide_init,
 	.ops_pci		 = &pci_dev_ops_pci,
 };
-
-struct device_operations cs5536_nand = {
-	.id = {.type = DEVICE_ID_PCI,
-		{.pci = {.vendor = PCI_VENDOR_ID_AMD,
-			 .device = PCI_DEVICE_ID_AMD_CS5536_FLASH}}},
-	.constructor		 = default_device_constructor,
-	.phase2_fixup		 = nand_phase2,
-	.phase3_scan		 = 0,
-	.phase4_read_resources	 = nand_read_resources,
-	.phase4_set_resources	 = pci_set_resources,
-	.phase5_enable_resources = pci_dev_enable_resources,
-	.phase6_init		 = 0, /* No Option ROMs */
-	.ops_pci		 = &pci_dev_ops_pci,
-};
diff --git a/southbridge/amd/cs5536/cs5536.h b/southbridge/amd/cs5536/cs5536.h
index 54a3c05..1f099c5 100644
--- a/southbridge/amd/cs5536/cs5536.h
+++ b/southbridge/amd/cs5536/cs5536.h
@@ -445,5 +445,6 @@
 void cs5536_disable_internal_uart(void);
 void cs5536_setup_onchipuart(int uart);
 void cs5536_stage1(void);
+void hide_vpci(u32 vpci_devid);
 
 #endif /* SOUTHBRIDGE_AMD_CS5536_CS5536_H */
diff --git a/southbridge/amd/cs5536/nand b/southbridge/amd/cs5536/nand
index 69f4fa4..62c28b0 100644
--- a/southbridge/amd/cs5536/nand
+++ b/southbridge/amd/cs5536/nand
@@ -20,4 +20,8 @@
 
 {
 	device_operations = "cs5536_nand";
+
+	/* NAND timings per data book and NAND chip on board. 0x0 leaves to reset value. */
+	nandf_data = "0x0";
+	nandf_ctl = "0x0";
 };
diff --git a/southbridge/amd/cs5536/nand.c b/southbridge/amd/cs5536/nand.c
new file mode 100644
index 0000000..7d176c2
--- /dev/null
+++ b/southbridge/amd/cs5536/nand.c
@@ -0,0 +1,93 @@
+/*
+ * This file is part of the coreboot project.
+ *
+ * Copyright (C) 2009 Artec Design LLC.
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
+ */
+
+#include <console.h>
+#include <device/pci.h>
+#include <msr.h>
+#include <statictree.h>
+#include "cs5536.h"
+
+/**
+ * Enables the FLASH PCI header when NAND device existing in mainboard device
+ * tree. Used when the mainboard has a FLASH part instead of an IDE drive and
+ * that fact is expressed in the mainboard device tree.
+ * Must be called after VSA init but before PCI scans to enable the flash
+ * PCI device header early enough - that is .phase2_fixup of the device.
+ *
+ * @param dev The device.
+ */
+static void nand_phase2(struct device *dev)
+{
+	if (dev->enabled) {
+		struct southbridge_amd_cs5536_nand_config *nand;
+		struct msr msr;
+
+		/* Set up timings */
+		nand = (struct southbridge_amd_cs5536_nand_config *)dev->device_configuration;
+		msr.hi = 0x0;
+
+		if (nand->nandf_data) {
+			msr.lo = nand->nandf_data;
+			wrmsr(MDD_NANDF_DATA, msr);
+			printk(BIOS_DEBUG, "NANDF_DATA set to 0x%08x\n", msr.lo);
+		}
+		if (nand->nandf_ctl) {
+			msr.lo = nand->nandf_ctl;
+			wrmsr(MDD_NANDF_CTL, msr);
+			printk(BIOS_DEBUG, "NANDF_CTL set to 0x%08x\n", msr.lo);
+		}
+
+		/* Tell VSA to use FLASH PCI header. Not IDE header. */
+		hide_vpci(0x800079C4);
+	}
+}
+
+static void nand_read_resources(struct device *dev)
+{
+	pci_dev_read_resources(dev);
+
+	/* All memory accesses in the range of 0xF0000000 - 0xFFFFFFFF routed to
+	 * Diverse Integration Logic (DIVIL) get always sent to the device inside
+	 * DIVIL as set in DIVIL_BALL_OPTS PRI_BOOT_LOC and SEC_BOOT_LOC bits
+	 * (see CS5536 data book chapter 6.6.2.10 DIVIL_BALL_OPTS PRI_BOOT_LOC
+	 * description).
+	 * The virtual PCI address limit test gives us a false upper limit of
+	 * 0xFFFFFFFF for this device, but we do not want NAND Flash to be using
+	 * memory addresses 0xF0000000 and above as those accesses would end up
+	 * somewhere else instead. Therefore if VSA2 gave us a MMIO resource for
+	 * NAND Flash, patch this (fixed) resources higher bound to 0xEFFFFFFF.
+	 */
+	if ((dev->resources >= 1) && (dev->resource[0].flags & IORESOURCE_MEM) &&
+		(dev->resource[0].limit > 0xefffffff))
+		dev->resource[0].limit = 0xefffffff;
+}
+
+struct device_operations cs5536_nand = {
+	.id = {.type = DEVICE_ID_PCI,
+		{.pci = {.vendor = PCI_VENDOR_ID_AMD,
+			 .device = PCI_DEVICE_ID_AMD_CS5536_FLASH}}},
+	.constructor		 = default_device_constructor,
+	.phase2_fixup		 = nand_phase2,
+	.phase3_scan		 = 0,
+	.phase4_read_resources	 = nand_read_resources,
+	.phase4_set_resources	 = pci_set_resources,
+	.phase5_enable_resources = pci_dev_enable_resources,
+	.phase6_init		 = 0, /* No Option ROMs */
+	.ops_pci		 = &pci_dev_ops_pci,
+};
-- 
1.6.1.3

