linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 00/11] Update support for MPC512x
@ 2010-02-05 13:42 Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 01/11] powerpc/mpc5121: avoid using arch_initcall for clock init Anatolij Gustschin
                   ` (11 more replies)
  0 siblings, 12 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: wd, dzu, linux-usb, linux-mtd, rtc-linux, Dan Williams,
	Anatolij Gustschin

The patches are based on v2.6.33-rc6 and cover the following
items:

- platform, DTS
- DMA
- DIU
- UART (without h/w flow control)
- I2C
- NAND
- RTC

The code has been tested on the Freescale/STX "MPC5121ADS" board
(board rev. 4) with a MPC5121e Rev. 2. No attempt was made to provide
backward compatibility to older silicon revisions or older revisions
of the board.

Changes since v2:
 - New cleanup patch added to avoid usage of platform specific
   clock init on non-5121 platforms
 - Comments to v2 patches addressed, detailed changelog is added
   to related patches. As a result there are 11 patches now as
   NAND and USB patches were split.

Changes since v1:
 - MPC5121 FEC support patches are removed from this patch series
   as these were not accepted
 - I2C support path is also removed, the I2C support is addressed
   by another patch series from Wolfgang Grandegger:
       i2c-mpc: add support for the Freescale MPC512x and other fixes
   Appropriate fixes for MPC5121ADS DTS are addressed by DTS patch in
   this patch series
 - Detailed changelog is added to each patch of the series


Anatolij Gustschin (10):
  powerpc/mpc5121: avoid using arch_initcall for clock init
  powerpc/mpc5121: Add machine restart support
  rtc: Add MPC5121 Real time clock driver
  mtd: Add MPC5121 NAND Flash Controller driver
  powerpc/mpc5121: create and register NFC device
  powerpc/fsl_soc.c: prepare for addition of mpc5121 USB code
  powerpc/mpc5121: add USB host support
  powerpc/mpc5121: shared DIU framebuffer support
  powerpc/mpc5121: update mpc5121ads DTS
  powerpc/mpc5121: Add default config for MPC5121

Piotr Ziecik (1):
  dma: Add MPC512x DMA driver

 Documentation/powerpc/dts-bindings/fsl/usb.txt |   22 +
 arch/powerpc/boot/dts/mpc5121ads.dts           |   55 +-
 arch/powerpc/configs/mpc512x_defconfig         | 1694 ++++++++++++++++++++++++
 arch/powerpc/include/asm/mpc5xxx.h             |   14 +-
 arch/powerpc/platforms/512x/Kconfig            |    3 +
 arch/powerpc/platforms/512x/Makefile           |    2 +-
 arch/powerpc/platforms/512x/clock.c            |    5 +-
 arch/powerpc/platforms/512x/mpc5121_ads.c      |   10 +-
 arch/powerpc/platforms/512x/mpc5121_generic.c  |   15 +-
 arch/powerpc/platforms/512x/mpc5121_usb.c      |  138 ++
 arch/powerpc/platforms/512x/mpc512x.h          |    7 +
 arch/powerpc/platforms/512x/mpc512x_shared.c   |  331 +++++
 arch/powerpc/sysdev/fsl_soc.c                  |  230 ++--
 arch/powerpc/sysdev/fsl_soc.h                  |   10 +
 drivers/dma/Kconfig                            |    7 +
 drivers/dma/Makefile                           |    1 +
 drivers/dma/mpc512x_dma.c                      |  800 +++++++++++
 drivers/mtd/nand/Kconfig                       |    7 +
 drivers/mtd/nand/Makefile                      |    1 +
 drivers/mtd/nand/mpc5121_nfc.c                 |  916 +++++++++++++
 drivers/rtc/Kconfig                            |   10 +
 drivers/rtc/Makefile                           |    1 +
 drivers/rtc/rtc-mpc5121.c                      |  387 ++++++
 drivers/usb/host/ehci-fsl.c                    |  111 ++-
 drivers/usb/host/ehci-fsl.h                    |   19 +-
 drivers/usb/host/ehci-mem.c                    |    2 +-
 drivers/video/fsl-diu-fb.c                     |   40 +-
 {drivers/video => include/linux}/fsl-diu-fb.h  |    0
 include/linux/fsl_devices.h                    |   10 +
 29 files changed, 4661 insertions(+), 187 deletions(-)
 create mode 100644 arch/powerpc/configs/mpc512x_defconfig
 create mode 100644 arch/powerpc/platforms/512x/mpc5121_usb.c
 create mode 100644 drivers/dma/mpc512x_dma.c
 create mode 100644 drivers/mtd/nand/mpc5121_nfc.c
 create mode 100644 drivers/rtc/rtc-mpc5121.c
 rename {drivers/video => include/linux}/fsl-diu-fb.h (100%)

Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: <rtc-linux@googlegroups.com>
Cc: <linux-mtd@lists.infradead.org>
Cc: <linux-usb@vger.kernel.org>

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v3 01/11] powerpc/mpc5121: avoid using arch_initcall for clock init
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support Anatolij Gustschin
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anatolij Gustschin, wd, dzu

Move mpc5121_clk_init() call to platform init code so it won't
get called on non-5121 platforms on a multiplatform kernel.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
Note to avoid confusion: this patch is new and was not
in previous v2 patch series. It was generated as a cleanup
patch before adding following patches.

 arch/powerpc/platforms/512x/clock.c           |    5 +----
 arch/powerpc/platforms/512x/mpc5121_ads.c     |    2 +-
 arch/powerpc/platforms/512x/mpc5121_generic.c |    2 +-
 arch/powerpc/platforms/512x/mpc512x.h         |    2 ++
 arch/powerpc/platforms/512x/mpc512x_shared.c  |    5 +++++
 5 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
index 84544d0..8733143 100644
--- a/arch/powerpc/platforms/512x/clock.c
+++ b/arch/powerpc/platforms/512x/clock.c
@@ -698,7 +698,7 @@ static struct clk_interface mpc5121_clk_functions = {
 	.clk_get_parent		= NULL,
 };
 
-static int
+int __init
 mpc5121_clk_init(void)
 {
 	struct device_node *np;
@@ -724,6 +724,3 @@ mpc5121_clk_init(void)
 	clk_functions = mpc5121_clk_functions;
 	return 0;
 }
-
-
-arch_initcall(mpc5121_clk_init);
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index 441abc4..0f8f2e9 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -64,7 +64,7 @@ define_machine(mpc5121_ads) {
 	.name			= "MPC5121 ADS",
 	.probe			= mpc5121_ads_probe,
 	.setup_arch		= mpc5121_ads_setup_arch,
-	.init			= mpc512x_declare_of_platform_devices,
+	.init			= mpc512x_init,
 	.init_IRQ		= mpc5121_ads_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
index 2479de9..9b8c9b0 100644
--- a/arch/powerpc/platforms/512x/mpc5121_generic.c
+++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
@@ -51,7 +51,7 @@ static int __init mpc5121_generic_probe(void)
 define_machine(mpc5121_generic) {
 	.name			= "MPC5121 generic",
 	.probe			= mpc5121_generic_probe,
-	.init			= mpc512x_declare_of_platform_devices,
+	.init			= mpc512x_init,
 	.init_IRQ		= mpc512x_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index 22a5352..ac3da1a 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -12,5 +12,7 @@
 #ifndef __MPC512X_H__
 #define __MPC512X_H__
 extern void __init mpc512x_init_IRQ(void);
+extern void __init mpc512x_init(void);
+extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 434d683..b683165 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -58,3 +58,8 @@ void __init mpc512x_declare_of_platform_devices(void)
 			"Error while probing of_platform bus\n");
 }
 
+void __init mpc512x_init(void)
+{
+	mpc512x_declare_of_platform_devices();
+	mpc5121_clk_init();
+}
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 01/11] powerpc/mpc5121: avoid using arch_initcall for clock init Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-09 23:24   ` Wolfram Sang
  2010-02-10  2:32   ` Grant Likely
  2010-02-05 13:42 ` [PATCH v3 03/11] rtc: Add MPC5121 Real time clock driver Anatolij Gustschin
                   ` (9 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, Anatolij Gustschin, Piotr Ziecik

Add reset module registers representation and
machine restart callback for mpc5121 platform.

Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
Changes since v2:
 - call mpc512x_restart_init() explicitely from platform
   init code

Changes since v1:
 - use 'struct mpc512x_reset_module *' type for 'reset_module_base'
 - remove empty line
 - remove leftover colon and use pr_err() instead of printk.

 arch/powerpc/include/asm/mpc5xxx.h            |   14 +++++++++-
 arch/powerpc/platforms/512x/mpc5121_ads.c     |    1 +
 arch/powerpc/platforms/512x/mpc5121_generic.c |    1 +
 arch/powerpc/platforms/512x/mpc512x.h         |    1 +
 arch/powerpc/platforms/512x/mpc512x_shared.c  |   34 +++++++++++++++++++++++++
 5 files changed, 50 insertions(+), 1 deletions(-)

diff --git a/arch/powerpc/include/asm/mpc5xxx.h b/arch/powerpc/include/asm/mpc5xxx.h
index 5ce9c5f..0004986 100644
--- a/arch/powerpc/include/asm/mpc5xxx.h
+++ b/arch/powerpc/include/asm/mpc5xxx.h
@@ -18,5 +18,17 @@
 
 extern unsigned long mpc5xxx_get_bus_frequency(struct device_node *node);
 
-#endif /* __ASM_POWERPC_MPC5xxx_H__ */
+/* MPC512x Reset module registers */
+struct mpc512x_reset_module {
+	u32	rcwlr;	/* Reset Configuration Word Low Register */
+	u32	rcwhr;	/* Reset Configuration Word High Register */
+	u32	reserved1;
+	u32	reserved2;
+	u32	rsr;	/* Reset Status Register */
+	u32	rmr;	/* Reset Mode Register */
+	u32	rpr;	/* Reset Protection Register */
+	u32	rcr;	/* Reset Control Register */
+	u32	rcer;	/* Reset Control Enable Register */
+};
 
+#endif /* __ASM_POWERPC_MPC5xxx_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index 0f8f2e9..ee6ae12 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -68,4 +68,5 @@ define_machine(mpc5121_ads) {
 	.init_IRQ		= mpc5121_ads_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
+	.restart		= mpc512x_restart,
 };
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
index 9b8c9b0..a6c0e3a 100644
--- a/arch/powerpc/platforms/512x/mpc5121_generic.c
+++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
@@ -55,4 +55,5 @@ define_machine(mpc5121_generic) {
 	.init_IRQ		= mpc512x_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
+	.restart		= mpc512x_restart,
 };
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index ac3da1a..b2daca0 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -15,4 +15,5 @@ extern void __init mpc512x_init_IRQ(void);
 extern void __init mpc512x_init(void);
 extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
+extern void mpc512x_restart(char *cmd);
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index b683165..ac0400e 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -21,9 +21,42 @@
 #include <asm/ipic.h>
 #include <asm/prom.h>
 #include <asm/time.h>
+#include <asm/mpc5xxx.h>
 
 #include "mpc512x.h"
 
+static struct mpc512x_reset_module __iomem *reset_module_base;
+
+static int __init mpc512x_restart_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+	if (!np)
+		return -1;
+
+	reset_module_base = of_iomap(np, 0);
+	of_node_put(np);
+
+	return 0;
+}
+
+void mpc512x_restart(char *cmd)
+{
+	struct mpc512x_reset_module *rm = reset_module_base;
+
+	if (rm) {
+		/* Enable software reset "RSTE" */
+		out_be32(&rm->rpr, 0x52535445);
+		/* Set software hard reset */
+		out_be32(&rm->rcr, 0x2);
+	} else {
+		pr_err("Restart module not mapped.\n");
+	}
+	for (;;)
+		;
+}
+
 void __init mpc512x_init_IRQ(void)
 {
 	struct device_node *np;
@@ -62,4 +95,5 @@ void __init mpc512x_init(void)
 {
 	mpc512x_declare_of_platform_devices();
 	mpc5121_clk_init();
+	mpc512x_restart_init();
 }
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 03/11] rtc: Add MPC5121 Real time clock driver
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 01/11] powerpc/mpc5121: avoid using arch_initcall for clock init Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-10  2:39   ` Grant Likely
  2010-02-05 13:42 ` [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver Anatolij Gustschin
                   ` (8 subsequent siblings)
  11 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, rtc-linux, Anatolij Gustschin, Piotr Ziecik

Add support for MPC5121 real time clock module.

Signed-off-by: John Rigby <jcrigby@gmail.com>
Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: <rtc-linux@googlegroups.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---

Changes since v2:
 - change commit message to describe what the patch is
 - use __devinit/__devexit/__devexit_p for the probe/remove hooks
   and __devinitdata for the match table
 - register device after it is completely set up

Changes since v1 (as requested by Alessandro Zummo):
 - Remove history from the driver file, the same history is in
   commit message
 - implement alarm/irq interface using ->ops structure, don't
   use ops->ioctl() any more
 - Clean up probe()
 - replace printk() by dev_*()
 - add arch dependency in Kconfig
 - add requested include linux/init.h
 - move MODULE_XXX to the end
 - use rtc_valid_tm() when returning 'tm'
 - use __init/__exit/__exit_p as this is not a hotpluggable device

 drivers/rtc/Kconfig       |   10 ++
 drivers/rtc/Makefile      |    1 +
 drivers/rtc/rtc-mpc5121.c |  387 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 398 insertions(+), 0 deletions(-)
 create mode 100644 drivers/rtc/rtc-mpc5121.c

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 8167e9e..2bb8a8b 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -868,4 +868,14 @@ config RTC_DRV_MC13783
 	help
 	  This enables support for the Freescale MC13783 PMIC RTC
 
+config RTC_DRV_MPC5121
+	tristate "Freescale MPC5121 built-in RTC"
+	depends on PPC_MPC512x && RTC_CLASS
+	help
+	  If you say yes here you will get support for the
+	  built-in RTC MPC5121.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-mpc5121.
+
 endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index e5160fd..b7148af 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_MC13783)	+= rtc-mc13783.o
 obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o
+obj-$(CONFIG_RTC_DRV_MPC5121)	+= rtc-mpc5121.o
 obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o
 obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o
 obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
new file mode 100644
index 0000000..4313ca0
--- /dev/null
+++ b/drivers/rtc/rtc-mpc5121.c
@@ -0,0 +1,387 @@
+/*
+ * Real-time clock driver for MPC5121
+ *
+ * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
+ * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * 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 <linux/init.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+
+struct mpc5121_rtc_regs {
+	u8 set_time;		/* RTC + 0x00 */
+	u8 hour_set;		/* RTC + 0x01 */
+	u8 minute_set;		/* RTC + 0x02 */
+	u8 second_set;		/* RTC + 0x03 */
+
+	u8 set_date;		/* RTC + 0x04 */
+	u8 month_set;		/* RTC + 0x05 */
+	u8 weekday_set;		/* RTC + 0x06 */
+	u8 date_set;		/* RTC + 0x07 */
+
+	u8 write_sw;		/* RTC + 0x08 */
+	u8 sw_set;		/* RTC + 0x09 */
+	u16 year_set;		/* RTC + 0x0a */
+
+	u8 alm_enable;		/* RTC + 0x0c */
+	u8 alm_hour_set;	/* RTC + 0x0d */
+	u8 alm_min_set;		/* RTC + 0x0e */
+	u8 int_enable;		/* RTC + 0x0f */
+
+	u8 reserved1;
+	u8 hour;		/* RTC + 0x11 */
+	u8 minute;		/* RTC + 0x12 */
+	u8 second;		/* RTC + 0x13 */
+
+	u8 month;		/* RTC + 0x14 */
+	u8 wday_mday;		/* RTC + 0x15 */
+	u16 year;		/* RTC + 0x16 */
+
+	u8 int_alm;		/* RTC + 0x18 */
+	u8 int_sw;		/* RTC + 0x19 */
+	u8 alm_status;		/* RTC + 0x1a */
+	u8 sw_minute;		/* RTC + 0x1b */
+
+	u8 bus_error_1;		/* RTC + 0x1c */
+	u8 int_day;		/* RTC + 0x1d */
+	u8 int_min;		/* RTC + 0x1e */
+	u8 int_sec;		/* RTC + 0x1f */
+
+	/*
+	 * target_time:
+	 *	intended to be used for hibernation but hibernation
+	 *	does not work on silicon rev 1.5 so use it for non-volatile
+	 *	storage of offset between the actual_time register and linux
+	 *	time
+	 */
+	u32 target_time;	/* RTC + 0x20 */
+	/*
+	 * actual_time:
+	 * 	readonly time since VBAT_RTC was last connected
+	 */
+	u32 actual_time;	/* RTC + 0x24 */
+	u32 keep_alive;		/* RTC + 0x28 */
+};
+
+struct mpc5121_rtc_data {
+	unsigned irq;
+	unsigned irq_periodic;
+	struct mpc5121_rtc_regs __iomem *regs;
+	struct rtc_device *rtc;
+	struct rtc_wkalrm wkalarm;
+};
+
+/*
+ * Update second/minute/hour registers.
+ *
+ * This is just so alarm will work.
+ */
+static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs,
+				   struct rtc_time *tm)
+{
+	out_8(&regs->second_set, tm->tm_sec);
+	out_8(&regs->minute_set, tm->tm_min);
+	out_8(&regs->hour_set, tm->tm_hour);
+
+	/* set time sequence */
+	out_8(&regs->set_time, 0x1);
+	out_8(&regs->set_time, 0x3);
+	out_8(&regs->set_time, 0x1);
+	out_8(&regs->set_time, 0x0);
+}
+
+static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+	unsigned long now;
+
+	/*
+	 * linux time is actual_time plus the offset saved in target_time
+	 */
+	now = in_be32(&regs->actual_time) + in_be32(&regs->target_time);
+
+	rtc_time_to_tm(now, tm);
+
+	/*
+	 * update second minute hour registers
+	 * so alarms will work
+	 */
+	mpc5121_rtc_update_smh(regs, tm);
+
+	return rtc_valid_tm(tm);
+}
+
+static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+	int ret;
+	unsigned long now;
+
+	/*
+	 * The actual_time register is read only so we write the offset
+	 * between it and linux time to the target_time register.
+	 */
+	ret = rtc_tm_to_time(tm, &now);
+	if (ret == 0)
+		out_be32(&regs->target_time, now - in_be32(&regs->actual_time));
+
+	/*
+	 * update second minute hour registers
+	 * so alarms will work
+	 */
+	mpc5121_rtc_update_smh(regs, tm);
+
+	return 0;
+}
+
+static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+	*alarm = rtc->wkalarm;
+
+	alarm->pending = in_8(&regs->alm_status);
+
+	return 0;
+}
+
+static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+	/*
+	 * the alarm has no seconds so deal with it
+	 */
+	if (alarm->time.tm_sec) {
+		alarm->time.tm_sec = 0;
+		alarm->time.tm_min++;
+		if (alarm->time.tm_min >= 60) {
+			alarm->time.tm_min = 0;
+			alarm->time.tm_hour++;
+			if (alarm->time.tm_hour >= 24)
+				alarm->time.tm_hour = 0;
+		}
+	}
+
+	alarm->time.tm_mday = -1;
+	alarm->time.tm_mon = -1;
+	alarm->time.tm_year = -1;
+
+	out_8(&regs->alm_min_set, alarm->time.tm_min);
+	out_8(&regs->alm_hour_set, alarm->time.tm_hour);
+
+	out_8(&regs->alm_enable, alarm->enabled);
+
+	rtc->wkalarm = *alarm;
+	return 0;
+}
+
+static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+	if (in_8(&regs->int_alm)) {
+		/* acknowledge and clear status */
+		out_8(&regs->int_alm, 1);
+		out_8(&regs->alm_status, 1);
+
+		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata((struct device *)dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+	if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)) {
+		/* acknowledge */
+		out_8(&regs->int_sec, 1);
+
+		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_UF);
+		return IRQ_HANDLED;
+	}
+
+	return IRQ_NONE;
+}
+
+static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
+					unsigned int enabled)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+	int val;
+
+	if (enabled)
+		val = 1;
+	else
+		val = 0;
+
+	out_8(&regs->alm_enable, val);
+	rtc->wkalarm.enabled = val;
+
+	return 0;
+}
+
+static int mpc5121_rtc_update_irq_enable(struct device *dev,
+					 unsigned int enabled)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata(dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+	int val;
+
+	val = in_8(&regs->int_enable);
+
+	if (enabled)
+		val = (val & ~0x8) | 0x1;
+	else
+		val &= ~0x1;
+
+	out_8(&regs->int_enable, val);
+
+	return 0;
+}
+
+static const struct rtc_class_ops mpc5121_rtc_ops = {
+	.read_time = mpc5121_rtc_read_time,
+	.set_time = mpc5121_rtc_set_time,
+	.read_alarm = mpc5121_rtc_read_alarm,
+	.set_alarm = mpc5121_rtc_set_alarm,
+	.alarm_irq_enable = mpc5121_rtc_alarm_irq_enable,
+	.update_irq_enable = mpc5121_rtc_update_irq_enable,
+};
+
+static int __devinit mpc5121_rtc_probe(struct of_device *op,
+					const struct of_device_id *match)
+{
+	struct mpc5121_rtc_data *rtc;
+	int err = 0;
+	u32 ka;
+
+	rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+	if (!rtc)
+		return -ENOMEM;
+
+	rtc->regs = of_iomap(op->node, 0);
+	if (!rtc->regs) {
+		dev_err(&op->dev, "%s: couldn't map io space\n", __func__);
+		err = -ENOSYS;
+		goto out_free;
+	}
+
+	device_init_wakeup(&op->dev, 1);
+
+	dev_set_drvdata(&op->dev, rtc);
+
+	rtc->irq = irq_of_parse_and_map(op->node, 1);
+	err = request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DISABLED,
+						"mpc5121-rtc", &op->dev);
+	if (err) {
+		dev_err(&op->dev, "%s: could not request irq: %i\n",
+							__func__, rtc->irq);
+		goto out_dispose;
+	}
+
+	rtc->irq_periodic = irq_of_parse_and_map(op->node, 0);
+	err = request_irq(rtc->irq_periodic, mpc5121_rtc_handler_upd,
+				IRQF_DISABLED, "mpc5121-rtc_upd", &op->dev);
+	if (err) {
+		dev_err(&op->dev, "%s: could not request irq: %i\n",
+						__func__, rtc->irq_periodic);
+		goto out_dispose2;
+	}
+
+	ka = in_be32(&rtc->regs->keep_alive);
+	if (ka & 0x02) {
+		dev_warn(&op->dev,
+			"mpc5121-rtc: Battery or oscillator failure!\n");
+		out_be32(&rtc->regs->keep_alive, ka);
+	}
+
+	rtc->rtc = rtc_device_register("mpc5121-rtc", &op->dev,
+					&mpc5121_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc->rtc)) {
+		err = PTR_ERR(rtc->rtc);
+		goto out_free_irq;
+	}
+
+	return 0;
+
+out_free_irq:
+	free_irq(rtc->irq_periodic, &op->dev);
+out_dispose2:
+	irq_dispose_mapping(rtc->irq_periodic);
+	free_irq(rtc->irq, &op->dev);
+out_dispose:
+	irq_dispose_mapping(rtc->irq);
+	iounmap(rtc->regs);
+out_free:
+	kfree(rtc);
+
+	return err;
+}
+
+static int __devexit mpc5121_rtc_remove(struct of_device *op)
+{
+	struct mpc5121_rtc_data *rtc = dev_get_drvdata(&op->dev);
+	struct mpc5121_rtc_regs __iomem *regs = rtc->regs;
+
+	/* disable interrupt, so there are no nasty surprises */
+	out_8(&regs->alm_enable, 0);
+	out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
+
+	rtc_device_unregister(rtc->rtc);
+	iounmap(rtc->regs);
+	free_irq(rtc->irq, &op->dev);
+	free_irq(rtc->irq_periodic, &op->dev);
+	irq_dispose_mapping(rtc->irq);
+	irq_dispose_mapping(rtc->irq_periodic);
+	dev_set_drvdata(&op->dev, NULL);
+	kfree(rtc);
+
+	return 0;
+}
+
+static struct of_device_id mpc5121_rtc_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5121-rtc", },
+	{},
+};
+
+static struct of_platform_driver mpc5121_rtc_driver = {
+	.owner = THIS_MODULE,
+	.name = "mpc5121-rtc",
+	.match_table = mpc5121_rtc_match,
+	.probe = mpc5121_rtc_probe,
+	.remove = __devexit_p(mpc5121_rtc_remove),
+};
+
+static int __init mpc5121_rtc_init(void)
+{
+	return of_register_platform_driver(&mpc5121_rtc_driver);
+}
+module_init(mpc5121_rtc_init);
+
+static void __exit mpc5121_rtc_exit(void)
+{
+	of_unregister_platform_driver(&mpc5121_rtc_driver);
+}
+module_exit(mpc5121_rtc_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (2 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 03/11] rtc: Add MPC5121 Real time clock driver Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-10  2:42   ` Grant Likely
  2010-02-15 17:35   ` [PATCH v4 " Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 05/11] powerpc/mpc5121: create and register NFC device Anatolij Gustschin
                   ` (7 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, linux-mtd, Anatolij Gustschin, Piotr Ziecik

Adds NAND Flash Controller driver for MPC5121 Revision 2.
All device features, except hardware ECC and power management,
are supported.

Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: <linux-mtd@lists.infradead.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
Changes since v2:
 - move the arch bits into separate patch
   (it is the next patch in this series now)
 - use __devinit/__devexit/__devexit_p and __devinitdata

Changes since v1:
 - add logfile with changes since previous version 

Changes since the patch version submitted in May 2009:

 - move mpc5121_nfc.h to the driver .c as there is only one user
 - remove DRV_VERSION macro
 - replace printk() by dev_*()
 - drop unnecessary .suspend and .resume initializations
 - remove duplicate .name/.owner settings
 - fix mpc5121_nfc_init() to "return of_register_platform_driver(&mpc5121_nfc_driver);"
 - move module_init() to just below the init function
 - remove MODULE_VERSION
 - use "mtd: Add MPC5121 NAND Flash Controller driver" as the subject,
   previously it was "mpc5121: Added NAND Flash Controller driver."

 drivers/mtd/nand/Kconfig       |    7 +
 drivers/mtd/nand/Makefile      |    1 +
 drivers/mtd/nand/mpc5121_nfc.c |  916 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 924 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/nand/mpc5121_nfc.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 677cd53..099f002 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -442,6 +442,13 @@ config MTD_NAND_FSL_UPM
 	  Enables support for NAND Flash chips wired onto Freescale PowerPC
 	  processor localbus with User-Programmable Machine support.
 
+config MTD_NAND_MPC5121_NFC
+	tristate "MPC5121 built-in NAND Flash Controller support"
+	depends on PPC_MPC512x
+	help
+	  This enables the driver for the NAND flash controller on the
+	  MPC5121 SoC.
+
 config MTD_NAND_MXC
 	tristate "MXC NAND support"
 	depends on ARCH_MX2 || ARCH_MX3
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 1407bd1..d4ddf05 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -42,5 +42,6 @@ obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
 obj-$(CONFIG_MTD_NAND_W90P910)		+= w90p910_nand.o
 obj-$(CONFIG_MTD_NAND_NOMADIK)		+= nomadik_nand.o
 obj-$(CONFIG_MTD_NAND_BCM_UMI)		+= bcm_umi_nand.o nand_bcm_umi.o
+obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mpc5121_nfc.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
new file mode 100644
index 0000000..191bf99
--- /dev/null
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2004-2008 Freescale Semiconductor, Inc.
+ * Copyright 2009 Semihalf.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009;  for details see www.osadl.org.
+ *
+ * Based on original driver from Freescale Semiconductor
+ * written by John Rigby <jrigby@freescale.com> on basis
+ * of drivers/mtd/nand/mxc_nand.c. Reworked and extended
+ * Piotr Ziecik <kosmo@semihalf.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <asm/mpc5xxx.h>
+
+/* Addresses for NFC MAIN RAM BUFFER areas */
+#define NFC_MAIN_AREA(n)	((n) *  0x200)
+
+/* Addresses for NFC SPARE BUFFER areas */
+#define NFC_SPARE_BUFFERS	8
+#define NFC_SPARE_LEN		0x40
+#define NFC_SPARE_AREA(n)	(0x1000 + ((n) * NFC_SPARE_LEN))
+
+/* MPC5121 NFC registers */
+#define NFC_BUF_ADDR		0x1E04
+#define NFC_FLASH_ADDR		0x1E06
+#define NFC_FLASH_CMD		0x1E08
+#define NFC_CONFIG		0x1E0A
+#define NFC_ECC_STATUS1		0x1E0C
+#define NFC_ECC_STATUS2		0x1E0E
+#define NFC_SPAS		0x1E10
+#define NFC_WRPROT		0x1E12
+#define NFC_NF_WRPRST		0x1E18
+#define NFC_CONFIG1		0x1E1A
+#define NFC_CONFIG2		0x1E1C
+#define NFC_UNLOCKSTART_BLK0	0x1E20
+#define NFC_UNLOCKEND_BLK0	0x1E22
+#define NFC_UNLOCKSTART_BLK1	0x1E24
+#define NFC_UNLOCKEND_BLK1	0x1E26
+#define NFC_UNLOCKSTART_BLK2	0x1E28
+#define NFC_UNLOCKEND_BLK2	0x1E2A
+#define NFC_UNLOCKSTART_BLK3	0x1E2C
+#define NFC_UNLOCKEND_BLK3	0x1E2E
+
+/* Bit Definitions: NFC_BUF_ADDR */
+#define NFC_RBA_MASK		(7 << 0)
+#define NFC_ACTIVE_CS_SHIFT	5
+#define NFC_ACTIVE_CS_MASK	(3 << NFC_ACTIVE_CS_SHIFT)
+
+/* Bit Definitions: NFC_CONFIG */
+#define NFC_BLS_UNLOCKED	(1 << 1)
+
+/* Bit Definitions: NFC_CONFIG1 */
+#define NFC_ECC_4BIT		(1 << 0)
+#define NFC_FULL_PAGE_DMA	(1 << 1)
+#define NFC_SPARE_ONLY		(1 << 2)
+#define NFC_ECC_ENABLE		(1 << 3)
+#define NFC_INT_MASK		(1 << 4)
+#define NFC_BIG_ENDIAN		(1 << 5)
+#define NFC_RESET		(1 << 6)
+#define NFC_CE			(1 << 7)
+#define NFC_ONE_CYCLE		(1 << 8)
+#define NFC_PPB_32		(0 << 9)
+#define NFC_PPB_64		(1 << 9)
+#define NFC_PPB_128		(2 << 9)
+#define NFC_PPB_256		(3 << 9)
+#define NFC_PPB_MASK		(3 << 9)
+#define NFC_FULL_PAGE_INT	(1 << 11)
+
+/* Bit Definitions: NFC_CONFIG2 */
+#define NFC_COMMAND		(1 << 0)
+#define NFC_ADDRESS		(1 << 1)
+#define NFC_INPUT		(1 << 2)
+#define NFC_OUTPUT		(1 << 3)
+#define NFC_ID			(1 << 4)
+#define NFC_STATUS		(1 << 5)
+#define NFC_CMD_FAIL		(1 << 15)
+#define NFC_INT			(1 << 15)
+
+/* Bit Definitions: NFC_WRPROT */
+#define NFC_WPC_LOCK_TIGHT	(1 << 0)
+#define NFC_WPC_LOCK		(1 << 1)
+#define NFC_WPC_UNLOCK		(1 << 2)
+
+#define	DRV_NAME		"mpc5121_nfc"
+
+/* Timeouts */
+#define NFC_RESET_TIMEOUT	1000		/* 1 ms */
+#define NFC_TIMEOUT		(HZ / 10)	/* 1/10 s */
+
+struct mpc5121_nfc_prv {
+	struct mtd_info		mtd;
+	struct nand_chip	chip;
+	int			irq;
+	void __iomem		*regs;
+	struct clk		*clk;
+	wait_queue_head_t	irq_waitq;
+	uint			column;
+	int			spareonly;
+	void __iomem		*csreg;
+	struct device		*dev;
+};
+
+static void mpc5121_nfc_done(struct mtd_info *mtd);
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL };
+#endif
+
+/* Read NFC register */
+static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	return in_be16(prv->regs + reg);
+}
+
+/* Write NFC register */
+static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	out_be16(prv->regs + reg, val);
+}
+
+/* Set bits in NFC register */
+static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
+{
+	nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
+}
+
+/* Clear bits in NFC register */
+static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
+{
+	nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
+}
+
+/* Invoke address cycle */
+static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
+{
+	nfc_write(mtd, NFC_FLASH_ADDR, addr);
+	nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Invoke command cycle */
+static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
+{
+	nfc_write(mtd, NFC_FLASH_CMD, cmd);
+	nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Send data from NFC buffers to NAND flash */
+static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive data from NAND flash */
+static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive ID from NAND flash */
+static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_ID);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive status from NAND flash */
+static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
+	mpc5121_nfc_done(mtd);
+}
+
+/* NFC interrupt handler */
+static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
+{
+	struct mtd_info *mtd = data;
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
+	wake_up(&prv->irq_waitq);
+
+	return IRQ_HANDLED;
+}
+
+/* Wait for operation complete */
+static void mpc5121_nfc_done(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	int rv;
+
+	if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
+		nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
+		rv = wait_event_timeout(prv->irq_waitq,
+			(nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT);
+
+		if (!rv)
+			dev_warn(prv->dev,
+				"Timeout while waiting for interrupt.\n");
+	}
+
+	nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
+}
+
+/* Do address cycle(s) */
+static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	u32 pagemask = chip->pagemask;
+
+	if (column != -1) {
+		mpc5121_nfc_send_addr(mtd, column);
+		if (mtd->writesize > 512)
+			mpc5121_nfc_send_addr(mtd, column >> 8);
+	}
+
+	if (page != -1) {
+		do {
+			mpc5121_nfc_send_addr(mtd, page & 0xFF);
+			page >>= 8;
+			pagemask >>= 8;
+		} while (pagemask);
+	}
+}
+
+/* Control chip select signals */
+static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	if (chip < 0) {
+		nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
+		return;
+	}
+
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
+	nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
+							NFC_ACTIVE_CS_MASK);
+	nfc_set(mtd, NFC_CONFIG1, NFC_CE);
+}
+
+/* Init external chip select logic on ADS5121 board */
+static int ads5121_chipselect_init(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
+	if (dn) {
+		prv->csreg = of_iomap(dn, 0);
+		of_node_put(dn);
+		if (!prv->csreg)
+			return -ENOMEM;
+
+		/* CPLD Register 9 controls NAND /CE Lines */
+		prv->csreg += 9;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* Control chips select signal on ADS5121 board */
+static void ads5121_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct mpc5121_nfc_prv *prv = nand->priv;
+	u8 v;
+
+	v = in_8(prv->csreg);
+	v |= 0x0F;
+
+	if (chip >= 0) {
+		mpc5121_nfc_select_chip(mtd, 0);
+		v &= ~(1 << chip);
+	} else
+		mpc5121_nfc_select_chip(mtd, -1);
+
+	out_8(prv->csreg, v);
+}
+
+/* Read NAND Ready/Busy signal */
+static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+{
+	/*
+	 * NFC handles ready/busy signal internally. Therefore, this function
+	 * always returns status as ready.
+	 */
+	return 1;
+}
+
+/* Write command to NAND flash */
+static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
+							int column, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	prv->column = (column >= 0) ? column : 0;
+	prv->spareonly = 0;
+
+	switch (command) {
+	case NAND_CMD_PAGEPROG:
+		mpc5121_nfc_send_prog_page(mtd);
+		break;
+	/*
+	 * NFC does not support sub-page reads and writes,
+	 * so emulate them using full page transfers.
+	 */
+	case NAND_CMD_READ0:
+		column = 0;
+		break;
+
+	case NAND_CMD_READ1:
+		prv->column += 256;
+		command = NAND_CMD_READ0;
+		column = 0;
+		break;
+
+	case NAND_CMD_READOOB:
+		prv->spareonly = 1;
+		command = NAND_CMD_READ0;
+		column = 0;
+		break;
+
+	case NAND_CMD_SEQIN:
+		mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+		column = 0;
+		break;
+
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_READID:
+	case NAND_CMD_STATUS:
+		break;
+
+	default:
+		return;
+	}
+
+	mpc5121_nfc_send_cmd(mtd, command);
+	mpc5121_nfc_addr_cycle(mtd, column, page);
+
+	switch (command) {
+	case NAND_CMD_READ0:
+		if (mtd->writesize > 512)
+			mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART);
+		mpc5121_nfc_send_read_page(mtd);
+		break;
+
+	case NAND_CMD_READID:
+		mpc5121_nfc_send_read_id(mtd);
+		break;
+
+	case NAND_CMD_STATUS:
+		mpc5121_nfc_send_read_status(mtd);
+		if (chip->options & NAND_BUSWIDTH_16)
+			prv->column = 1;
+		else
+			prv->column = 0;
+		break;
+	}
+}
+
+/* Copy data from/to NFC spare buffers. */
+static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
+						u8 *buffer, uint size, int wr)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct mpc5121_nfc_prv *prv = nand->priv;
+	uint o, s, sbsize, blksize;
+
+	/*
+	 * NAND spare area is available through NFC spare buffers.
+	 * The NFC divides spare area into (page_size / 512) chunks.
+	 * Each chunk is placed into separate spare memory area, using
+	 * first (spare_size / num_of_chunks) bytes of the buffer.
+	 *
+	 * For NAND device in which the spare area is not divided fully
+	 * by the number of chunks, number of used bytes in each spare
+	 * buffer is rounded down to the nearest even number of bytes,
+	 * and all remaining bytes are added to the last used spare area.
+	 *
+	 * For more information read section 26.6.10 of MPC5121e
+	 * Microcontroller Reference Manual, Rev. 3.
+	 */
+
+	/* Calculate number of valid bytes in each spare buffer */
+	sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;
+
+	while (size) {
+		/* Calculate spare buffer number */
+		s = offset / sbsize;
+		if (s > NFC_SPARE_BUFFERS - 1)
+			s = NFC_SPARE_BUFFERS - 1;
+
+		/*
+		 * Calculate offset to requested data block in selected spare
+		 * buffer and its size.
+		 */
+		o = offset - (s * sbsize);
+		blksize = min(sbsize - o, size);
+
+		if (wr)
+			memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o,
+							buffer, blksize);
+		else
+			memcpy_fromio(buffer,
+				prv->regs + NFC_SPARE_AREA(s) + o, blksize);
+
+		buffer += blksize;
+		offset += blksize;
+		size -= blksize;
+	};
+}
+
+/* Copy data from/to NFC main and spare buffers */
+static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
+									int wr)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	uint c = prv->column;
+	uint l;
+
+	/* Handle spare area access */
+	if (prv->spareonly || c >= mtd->writesize) {
+		/* Calculate offset from beginning of spare area */
+		if (c >= mtd->writesize)
+			c -= mtd->writesize;
+
+		prv->column += len;
+		mpc5121_nfc_copy_spare(mtd, c, buf, len, wr);
+		return;
+	}
+
+	/*
+	 * Handle main area access - limit copy length to prevent
+	 * crossing main/spare boundary.
+	 */
+	l = min((uint)len, mtd->writesize - c);
+	prv->column += l;
+
+	if (wr)
+		memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
+	else
+		memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
+
+	/* Handle crossing main/spare boundary */
+	if (l != len) {
+		buf += l;
+		len -= l;
+		mpc5121_nfc_buf_copy(mtd, buf, len, wr);
+	}
+}
+
+/* Read data from NFC buffers */
+static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+}
+
+/* Write data to NFC buffers */
+static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
+						const u_char *buf, int len)
+{
+	mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+}
+
+/* Compare buffer with NAND flash */
+static int mpc5121_nfc_verify_buf(struct mtd_info *mtd,
+						const u_char *buf, int len)
+{
+	u_char tmp[256];
+	uint bsize;
+
+	while (len) {
+		bsize = min(len, 256);
+		mpc5121_nfc_read_buf(mtd, tmp, bsize);
+
+		if (memcmp(buf, tmp, bsize))
+			return 1;
+
+		buf += bsize;
+		len -= bsize;
+	}
+
+	return 0;
+}
+
+/* Read byte from NFC buffers */
+static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+{
+	u8 tmp;
+
+	mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
+
+	return tmp;
+}
+
+/* Read word from NFC buffers */
+static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
+{
+	u16 tmp;
+
+	mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+
+	return tmp;
+}
+
+/*
+ * Read NFC configuration from Reset Config Word
+ *
+ * NFC is configured during reset in basis of information stored
+ * in Reset Config Word. There is no other way to set NAND block
+ * size, spare size and bus width.
+ */
+static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	struct mpc512x_reset_module *rm;
+	struct device_node *rmnode;
+	uint rcw_pagesize = 0;
+	uint rcw_sparesize = 0;
+	uint rcw_width;
+	uint rcwh;
+	uint romloc, ps;
+
+	rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+	if (!rmnode) {
+		dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' "
+					"node in device tree!\n");
+		return -ENODEV;
+	}
+
+	rm = of_iomap(rmnode, 0);
+	if (!rm) {
+		dev_err(prv->dev, "Error mapping reset module node!\n");
+		return -EBUSY;
+	}
+
+	rcwh = in_be32(&rm->rcwhr);
+
+	/* Bit 6: NFC bus width */
+	rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1;
+
+	/* Bit 7: NFC Page/Spare size */
+	ps = (rcwh >> 7) & 0x1;
+
+	/* Bits [22:21]: ROM Location */
+	romloc = (rcwh >> 21) & 0x3;
+
+	/* Decode RCW bits */
+	switch ((ps << 2) | romloc) {
+	case 0x00:
+	case 0x01:
+		rcw_pagesize = 512;
+		rcw_sparesize = 16;
+		break;
+	case 0x02:
+	case 0x03:
+		rcw_pagesize = 4096;
+		rcw_sparesize = 128;
+		break;
+	case 0x04:
+	case 0x05:
+		rcw_pagesize = 2048;
+		rcw_sparesize = 64;
+		break;
+	case 0x06:
+	case 0x07:
+		rcw_pagesize = 4096;
+		rcw_sparesize = 218;
+		break;
+	}
+
+	mtd->writesize = rcw_pagesize;
+	mtd->oobsize = rcw_sparesize;
+	if (rcw_width == 2)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	dev_notice(prv->dev, "Configured for "
+				"%u-bit NAND, page size %u "
+				"with %u spare.\n",
+				rcw_width * 8, rcw_pagesize,
+				rcw_sparesize);
+	iounmap(rm);
+	of_node_put(rmnode);
+	return 0;
+}
+
+/* Free driver resources */
+static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	if (prv->clk) {
+		clk_disable(prv->clk);
+		clk_put(prv->clk);
+	}
+
+	if (prv->csreg)
+		iounmap(prv->csreg);
+}
+
+static int __devinit mpc5121_nfc_probe(struct of_device *op,
+					const struct of_device_id *match)
+{
+	struct device_node *rootnode, *dn = op->node;
+	struct device *dev = &op->dev;
+	struct mpc5121_nfc_prv *prv;
+	struct resource res;
+	struct mtd_info *mtd;
+#ifdef CONFIG_MTD_PARTITIONS
+	struct mtd_partition *parts;
+#endif
+	struct nand_chip *chip;
+	unsigned long regs_paddr, regs_size;
+	const uint *chips_no;
+	int resettime = 0;
+	int retval = 0;
+	int rev, len;
+
+	/*
+	 * Check SoC revision. This driver supports only NFC
+	 * in MPC5121 revision 2.
+	 */
+	rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
+	if (rev != 2) {
+		dev_err(dev, "SoC revision %u is not supported!\n", rev);
+		return -ENXIO;
+	}
+
+	prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
+	if (!prv) {
+		dev_err(dev, "Memory exhausted!\n");
+		return -ENOMEM;
+	}
+
+	mtd = &prv->mtd;
+	chip = &prv->chip;
+
+	mtd->priv = chip;
+	chip->priv = prv;
+	prv->dev = dev;
+
+	/* Read NFC configuration from Reset Config Word */
+	retval = mpc5121_nfc_read_hw_config(mtd);
+	if (retval) {
+		dev_err(dev, "Unable to read NFC config!\n");
+		return retval;
+	}
+
+	prv->irq = irq_of_parse_and_map(dn, 0);
+	if (prv->irq == NO_IRQ) {
+		dev_err(dev, "Error mapping IRQ!\n");
+		return -EINVAL;
+	}
+
+	retval = of_address_to_resource(dn, 0, &res);
+	if (retval) {
+		dev_err(dev, "Error parsing memory region!\n");
+		return retval;
+	}
+
+	chips_no = of_get_property(dn, "chips", &len);
+	if (!chips_no || len != sizeof(*chips_no)) {
+		dev_err(dev, "Invalid/missing 'chips' property!\n");
+		return -EINVAL;
+	}
+
+	regs_paddr = res.start;
+	regs_size = res.end - res.start + 1;
+
+	if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
+		dev_err(dev, "Error requesting memory region!\n");
+		return -EBUSY;
+	}
+
+	prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
+	if (!prv->regs) {
+		dev_err(dev, "Error mapping memory region!\n");
+		return -ENOMEM;
+	}
+
+	mtd->name = "MPC5121 NAND";
+	chip->dev_ready = mpc5121_nfc_dev_ready;
+	chip->cmdfunc = mpc5121_nfc_command;
+	chip->read_byte = mpc5121_nfc_read_byte;
+	chip->read_word = mpc5121_nfc_read_word;
+	chip->read_buf = mpc5121_nfc_read_buf;
+	chip->write_buf = mpc5121_nfc_write_buf;
+	chip->verify_buf = mpc5121_nfc_verify_buf;
+	chip->select_chip = mpc5121_nfc_select_chip;
+	chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
+	chip->ecc.mode = NAND_ECC_SOFT;
+
+	/* Support external chip-select logic on ADS5121 board */
+	rootnode = of_find_node_by_path("/");
+	if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
+		retval = ads5121_chipselect_init(mtd);
+		if (retval) {
+			dev_err(dev, "Chipselect init error!\n");
+			of_node_put(rootnode);
+			return retval;
+		}
+
+		chip->select_chip = ads5121_select_chip;
+	}
+	of_node_put(rootnode);
+
+	/* Enable NFC clock */
+	prv->clk = clk_get(dev, "nfc_clk");
+	if (!prv->clk) {
+		dev_err(dev, "Unable to acquire NFC clock!\n");
+		retval = -ENODEV;
+		goto error;
+	}
+
+	clk_enable(prv->clk);
+
+	/* Reset NAND Flash controller */
+	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
+	while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
+		if (resettime++ >= NFC_RESET_TIMEOUT) {
+			dev_err(dev, "Timeout while resetting NFC!\n");
+			retval = -EINVAL;
+			goto error;
+		}
+
+		udelay(1);
+	}
+
+	/* Enable write to NFC memory */
+	nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
+
+	/* Enable write to all NAND pages */
+	nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
+	nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
+	nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
+
+	/*
+	 * Setup NFC:
+	 *	- Big Endian transfers,
+	 *	- Interrupt after full page read/write.
+	 */
+	nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
+							NFC_FULL_PAGE_INT);
+
+	/* Set spare area size */
+	nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
+
+	init_waitqueue_head(&prv->irq_waitq);
+	retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
+									mtd);
+	if (retval) {
+		dev_err(dev, "Error requesting IRQ!\n");
+		goto error;
+	}
+
+	/* Detect NAND chips */
+	if (nand_scan(mtd, *chips_no)) {
+		dev_err(dev, "NAND Flash not found !\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		retval = -ENXIO;
+		goto error;
+	}
+
+	/* Set erase block size */
+	switch (mtd->erasesize / mtd->writesize) {
+	case 32:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
+		break;
+
+	case 64:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
+		break;
+
+	case 128:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
+		break;
+
+	case 256:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
+		break;
+
+	default:
+		dev_err(dev, "Unsupported NAND flash!\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		retval = -ENXIO;
+		goto error;
+	}
+
+	dev_set_drvdata(dev, mtd);
+
+	/* Register device in MTD */
+#ifdef CONFIG_MTD_PARTITIONS
+	retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0);
+#ifdef CONFIG_MTD_OF_PARTS
+	if (retval == 0)
+		retval = of_mtd_parse_partitions(dev, dn, &parts);
+#endif
+	if (retval < 0) {
+		dev_err(dev, "Error parsing MTD partitions!\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		retval = -EINVAL;
+		goto error;
+	}
+
+	if (retval > 0)
+		retval = add_mtd_partitions(mtd, parts, retval);
+	else
+#endif
+		retval = add_mtd_device(mtd);
+
+	if (retval) {
+		dev_err(dev, "Error adding MTD device!\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		goto error;
+	}
+
+	return 0;
+error:
+	mpc5121_nfc_free(dev, mtd);
+	return retval;
+}
+
+static int __devexit mpc5121_nfc_remove(struct of_device *op)
+{
+	struct device *dev = &op->dev;
+	struct mtd_info *mtd = dev_get_drvdata(dev);
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	nand_release(mtd);
+	devm_free_irq(dev, prv->irq, mtd);
+	mpc5121_nfc_free(dev, mtd);
+
+	return 0;
+}
+
+static struct of_device_id mpc5121_nfc_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5121-nfc", },
+	{},
+};
+
+static struct of_platform_driver mpc5121_nfc_driver = {
+	.match_table	= mpc5121_nfc_match,
+	.probe		= mpc5121_nfc_probe,
+	.remove		= __devexit_p(mpc5121_nfc_remove),
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init mpc5121_nfc_init(void)
+{
+	return of_register_platform_driver(&mpc5121_nfc_driver);
+}
+
+module_init(mpc5121_nfc_init);
+
+static void __exit mpc5121_nfc_cleanup(void)
+{
+	of_unregister_platform_driver(&mpc5121_nfc_driver);
+}
+
+module_exit(mpc5121_nfc_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
+MODULE_LICENSE("GPL");
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 05/11] powerpc/mpc5121: create and register NFC device
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (3 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 06/11] dma: Add MPC512x DMA driver Anatolij Gustschin
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anatolij Gustschin, wd, dzu

Instantiate NAND Flash Controller device if it's
description is found in the device tree.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
 arch/powerpc/platforms/512x/mpc512x_shared.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index ac0400e..8bb34b2 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -86,9 +86,17 @@ static struct of_device_id __initdata of_bus_ids[] = {
 
 void __init mpc512x_declare_of_platform_devices(void)
 {
+	struct device_node *np;
+
 	if (of_platform_bus_probe(NULL, of_bus_ids, NULL))
 		printk(KERN_ERR __FILE__ ": "
 			"Error while probing of_platform bus\n");
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-nfc");
+	if (np) {
+		of_platform_device_create(np, NULL, NULL);
+		of_node_put(np);
+	}
 }
 
 void __init mpc512x_init(void)
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 06/11] dma: Add MPC512x DMA driver
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (4 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 05/11] powerpc/mpc5121: create and register NFC device Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-10  2:44   ` Grant Likely
  2010-03-01 13:46   ` Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 07/11] powerpc/fsl_soc.c: prepare for addition of mpc5121 USB code Anatolij Gustschin
                   ` (5 subsequent siblings)
  11 siblings, 2 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, Dan Williams, Anatolij Gustschin, Piotr Ziecik

From: Piotr Ziecik <kosmo@semihalf.com>

Adds initial version of MPC512x DMA driver.
Only memory to memory transfers are currenly supported.

Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Dan Williams <dan.j.williams@intel.com>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
No changes since v2

Changes since v1:
 - move content of the mpc512x.h into the drivers .c file as
   it is only used by this DMA driver
 - use __devinit/__devexit/__devexit_p as requested
 - add unregistration of the dma device
 - remove meaningless comment

Changes since patch version submitted in May 2009:
 - don't use wildcards in compatible property, use "fsl,mpc5121-dma"
 - don't add "fsl,mpc5121-dma" compatible to of_bus_ids[] as the
   dma device is part of IMMR

 drivers/dma/Kconfig       |    7 +
 drivers/dma/Makefile      |    1 +
 drivers/dma/mpc512x_dma.c |  800 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 808 insertions(+), 0 deletions(-)
 create mode 100644 drivers/dma/mpc512x_dma.c

diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index e02d74b..ac67a53 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -69,6 +69,13 @@ config FSL_DMA
 	  The Elo is the DMA controller on some 82xx and 83xx parts, and the
 	  Elo Plus is the DMA controller on 85xx and 86xx parts.
 
+config MPC512X_DMA
+	tristate "Freescale MPC512x built-in DMA engine support"
+	depends on PPC_MPC512x
+	select DMA_ENGINE
+	---help---
+	  Enable support for the Freescale MPC512x built-in DMA engine.
+
 config MV_XOR
 	bool "Marvell XOR engine support"
 	depends on PLAT_ORION
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 807053d..4696bcf 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -4,6 +4,7 @@ obj-$(CONFIG_DMATEST) += dmatest.o
 obj-$(CONFIG_INTEL_IOATDMA) += ioat/
 obj-$(CONFIG_INTEL_IOP_ADMA) += iop-adma.o
 obj-$(CONFIG_FSL_DMA) += fsldma.o
+obj-$(CONFIG_MPC512X_DMA) += mpc512x_dma.o
 obj-$(CONFIG_MV_XOR) += mv_xor.o
 obj-$(CONFIG_DW_DMAC) += dw_dmac.o
 obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
new file mode 100644
index 0000000..3fdf1f4
--- /dev/null
+++ b/drivers/dma/mpc512x_dma.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
+ * Copyright (C) Semihalf 2009
+ *
+ * Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
+ * (defines, structures and comments) was taken from MPC5121 DMA driver
+ * written by Hongjun Chen <hong-jun.chen@freescale.com>.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009;  for details see www.osadl.org.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
+/*
+ * This is initial version of MPC5121 DMA driver. Only memory to memory
+ * transfers are supported (tested using dmatest module).
+ */
+
+#include <linux/module.h>
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <linux/random.h>
+
+/* Number of DMA Transfer descriptors allocated per channel */
+#define MPC_DMA_DESCRIPTORS	64
+
+/* Macro definitions */
+#define MPC_DMA_CHANNELS	64
+#define MPC_DMA_TCD_OFFSET	0x1000
+
+/* Arbitration mode of group and channel */
+#define MPC_DMA_DMACR_EDCG	(1 << 31)
+#define MPC_DMA_DMACR_ERGA	(1 << 3)
+#define MPC_DMA_DMACR_ERCA	(1 << 2)
+
+/* Error codes */
+#define MPC_DMA_DMAES_VLD	(1 << 31)
+#define MPC_DMA_DMAES_GPE	(1 << 15)
+#define MPC_DMA_DMAES_CPE	(1 << 14)
+#define MPC_DMA_DMAES_ERRCHN(err) \
+				(((err) >> 8) & 0x3f)
+#define MPC_DMA_DMAES_SAE	(1 << 7)
+#define MPC_DMA_DMAES_SOE	(1 << 6)
+#define MPC_DMA_DMAES_DAE	(1 << 5)
+#define MPC_DMA_DMAES_DOE	(1 << 4)
+#define MPC_DMA_DMAES_NCE	(1 << 3)
+#define MPC_DMA_DMAES_SGE	(1 << 2)
+#define MPC_DMA_DMAES_SBE	(1 << 1)
+#define MPC_DMA_DMAES_DBE	(1 << 0)
+
+#define MPC_DMA_TSIZE_1		0x00
+#define MPC_DMA_TSIZE_2		0x01
+#define MPC_DMA_TSIZE_4		0x02
+#define MPC_DMA_TSIZE_16	0x04
+#define MPC_DMA_TSIZE_32	0x05
+
+/* MPC5121 DMA engine registers */
+struct __attribute__ ((__packed__)) mpc_dma_regs {
+	/* 0x00 */
+	u32 dmacr;		/* DMA control register */
+	u32 dmaes;		/* DMA error status */
+	/* 0x08 */
+	u32 dmaerqh;		/* DMA enable request high(channels 63~32) */
+	u32 dmaerql;		/* DMA enable request low(channels 31~0) */
+	u32 dmaeeih;		/* DMA enable error interrupt high(ch63~32) */
+	u32 dmaeeil;		/* DMA enable error interrupt low(ch31~0) */
+	/* 0x18 */
+	u8 dmaserq;		/* DMA set enable request */
+	u8 dmacerq;		/* DMA clear enable request */
+	u8 dmaseei;		/* DMA set enable error interrupt */
+	u8 dmaceei;		/* DMA clear enable error interrupt */
+	/* 0x1c */
+	u8 dmacint;		/* DMA clear interrupt request */
+	u8 dmacerr;		/* DMA clear error */
+	u8 dmassrt;		/* DMA set start bit */
+	u8 dmacdne;		/* DMA clear DONE status bit */
+	/* 0x20 */
+	u32 dmainth;		/* DMA interrupt request high(ch63~32) */
+	u32 dmaintl;		/* DMA interrupt request low(ch31~0) */
+	u32 dmaerrh;		/* DMA error high(ch63~32) */
+	u32 dmaerrl;		/* DMA error low(ch31~0) */
+	/* 0x30 */
+	u32 dmahrsh;		/* DMA hw request status high(ch63~32) */
+	u32 dmahrsl;		/* DMA hardware request status low(ch31~0) */
+	u32 dmaihsa;		/* DMA interrupt high select AXE(ch63~32) */
+	u32 dmailsa;		/* DMA interrupt low select AXE(ch31~0) */
+	/* 0x40 ~ 0xff */
+	u32 reserve0[48];	/* Reserved */
+	/* 0x100 */
+	u8 dchpri[MPC_DMA_CHANNELS];
+	/* DMA channels(0~63) priority */
+};
+
+struct __attribute__ ((__packed__)) mpc_dma_tcd {
+	/* 0x00 */
+	u32 saddr;		/* Source address */
+
+	u32 smod:5;		/* Source address modulo */
+	u32 ssize:3;		/* Source data transfer size */
+	u32 dmod:5;		/* Destination address modulo */
+	u32 dsize:3;		/* Destination data transfer size */
+	u32 soff:16;		/* Signed source address offset */
+
+	/* 0x08 */
+	u32 nbytes;		/* Inner "minor" byte count */
+	u32 slast;		/* Last source address adjustment */
+	u32 daddr;		/* Destination address */
+
+	/* 0x14 */
+	u32 citer_elink:1;	/* Enable channel-to-channel linking on
+				 * minor loop complete
+				 */
+	u32 citer_linkch:6;	/* Link channel for minor loop complete */
+	u32 citer:9;		/* Current "major" iteration count */
+	u32 doff:16;		/* Signed destination address offset */
+
+	/* 0x18 */
+	u32 dlast_sga;		/* Last Destination address adjustment/scatter
+				 * gather address
+				 */
+
+	/* 0x1c */
+	u32 biter_elink:1;	/* Enable channel-to-channel linking on major
+				 * loop complete
+				 */
+	u32 biter_linkch:6;
+	u32 biter:9;		/* Beginning "major" iteration count */
+	u32 bwc:2;		/* Bandwidth control */
+	u32 major_linkch:6;	/* Link channel number */
+	u32 done:1;		/* Channel done */
+	u32 active:1;		/* Channel active */
+	u32 major_elink:1;	/* Enable channel-to-channel linking on major
+				 * loop complete
+				 */
+	u32 e_sg:1;		/* Enable scatter/gather processing */
+	u32 d_req:1;		/* Disable request */
+	u32 int_half:1;		/* Enable an interrupt when major counter is
+				 * half complete
+				 */
+	u32 int_maj:1;		/* Enable an interrupt when major iteration
+				 * count completes
+				 */
+	u32 start:1;		/* Channel start */
+};
+
+struct mpc_dma_desc {
+	struct dma_async_tx_descriptor	desc;
+	struct mpc_dma_tcd		*tcd;
+	dma_addr_t			tcd_paddr;
+	int				error;
+	struct list_head		node;
+};
+
+struct mpc_dma_chan {
+	struct dma_chan			chan;
+	struct list_head		free;
+	struct list_head		prepared;
+	struct list_head		queued;
+	struct list_head		active;
+	struct list_head		completed;
+	struct mpc_dma_tcd		*tcd;
+	dma_addr_t			tcd_paddr;
+	dma_cookie_t			completed_cookie;
+
+	/* Lock for this structure */
+	spinlock_t			lock;
+};
+
+struct mpc_dma {
+	struct dma_device		dma;
+	struct tasklet_struct		tasklet;
+	struct mpc_dma_chan		channels[MPC_DMA_CHANNELS];
+	struct mpc_dma_regs __iomem	*regs;
+	struct mpc_dma_tcd __iomem	*tcd;
+	int				irq;
+	uint				error_status;
+
+	/* Lock for error_status field in this structure */
+	spinlock_t			error_status_lock;
+};
+
+#define DRV_NAME	"mpc512x_dma"
+
+/* Convert struct dma_chan to struct mpc_dma_chan */
+static inline struct mpc_dma_chan *dma_chan_to_mpc_dma_chan(struct dma_chan *c)
+{
+	return container_of(c, struct mpc_dma_chan, chan);
+}
+
+/* Convert struct dma_chan to struct mpc_dma */
+static inline struct mpc_dma *dma_chan_to_mpc_dma(struct dma_chan *c)
+{
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(c);
+	return container_of(mchan, struct mpc_dma, channels[c->chan_id]);
+}
+
+/*
+ * Execute all queued DMA descriptors.
+ *
+ * Following requirements must be met while calling mpc_dma_execute():
+ * 	a) mchan->lock is acquired,
+ * 	b) mchan->active list is empty,
+ * 	c) mchan->queued list contains at least one entry.
+ */
+static void mpc_dma_execute(struct mpc_dma_chan *mchan)
+{
+	struct mpc_dma *mdma = dma_chan_to_mpc_dma(&mchan->chan);
+	struct mpc_dma_desc *first = NULL;
+	struct mpc_dma_desc *prev = NULL;
+	struct mpc_dma_desc *mdesc;
+	int cid = mchan->chan.chan_id;
+
+	/* Move all queued descriptors to active list */
+	list_splice_tail_init(&mchan->queued, &mchan->active);
+
+	/* Chain descriptors into one transaction */
+	list_for_each_entry(mdesc, &mchan->active, node) {
+		if (!first)
+			first = mdesc;
+
+		if (!prev) {
+			prev = mdesc;
+			continue;
+		}
+
+		prev->tcd->dlast_sga = mdesc->tcd_paddr;
+		prev->tcd->e_sg = 1;
+		mdesc->tcd->start = 1;
+
+		prev = mdesc;
+	}
+
+	prev->tcd->start = 0;
+	prev->tcd->int_maj = 1;
+
+	/* Send first descriptor in chain into hardware */
+	memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_dma_tcd));
+	out_8(&mdma->regs->dmassrt, cid);
+}
+
+/* Handle interrupt on one half of DMA controller (32 channels) */
+static void mpc_dma_irq_process(struct mpc_dma *mdma, u32 is, u32 es, int off)
+{
+	struct mpc_dma_chan *mchan;
+	struct mpc_dma_desc *mdesc;
+	u32 status = is | es;
+	int ch;
+
+	while ((ch = fls(status) - 1) >= 0) {
+		status &= ~(1 << ch);
+		mchan = &mdma->channels[ch + off];
+
+		spin_lock(&mchan->lock);
+
+		/* Check error status */
+		if (es & (1 << ch))
+			list_for_each_entry(mdesc, &mchan->active, node)
+				mdesc->error = -EIO;
+
+		/* Execute queued descriptors */
+		list_splice_tail_init(&mchan->active, &mchan->completed);
+		if (!list_empty(&mchan->queued))
+			mpc_dma_execute(mchan);
+
+		spin_unlock(&mchan->lock);
+	}
+}
+
+/* Interrupt handler */
+static irqreturn_t mpc_dma_irq(int irq, void *data)
+{
+	struct mpc_dma *mdma = data;
+	uint es;
+
+	/* Save error status register */
+	es = in_be32(&mdma->regs->dmaes);
+	spin_lock(&mdma->error_status_lock);
+	if ((es & MPC_DMA_DMAES_VLD) && mdma->error_status == 0)
+		mdma->error_status = es;
+	spin_unlock(&mdma->error_status_lock);
+
+	/* Handle interrupt on each channel */
+	mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth),
+					in_be32(&mdma->regs->dmaerrh), 32);
+	mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl),
+					in_be32(&mdma->regs->dmaerrl), 0);
+
+	/* Ack interrupt on all channels */
+	out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
+	out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
+	out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
+	out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
+
+	/* Schedule tasklet */
+	tasklet_schedule(&mdma->tasklet);
+
+	return IRQ_HANDLED;
+}
+
+/* DMA Tasklet */
+static void mpc_dma_tasklet(unsigned long data)
+{
+	struct mpc_dma *mdma = (void *)data;
+	dma_cookie_t last_cookie = 0;
+	struct mpc_dma_chan *mchan;
+	struct mpc_dma_desc *mdesc;
+	struct dma_async_tx_descriptor *desc;
+	unsigned long flags;
+	LIST_HEAD(list);
+	uint es;
+	int i;
+
+	spin_lock_irqsave(&mdma->error_status_lock, flags);
+	es = mdma->error_status;
+	mdma->error_status = 0;
+	spin_unlock_irqrestore(&mdma->error_status_lock, flags);
+
+	/* Print nice error report */
+	if (es) {
+		dev_err(mdma->dma.dev,
+			"Hardware reported following error(s) on channel %u:\n",
+						      MPC_DMA_DMAES_ERRCHN(es));
+
+		if (es & MPC_DMA_DMAES_GPE)
+			dev_err(mdma->dma.dev, "- Group Priority Error\n");
+		if (es & MPC_DMA_DMAES_CPE)
+			dev_err(mdma->dma.dev, "- Channel Priority Error\n");
+		if (es & MPC_DMA_DMAES_SAE)
+			dev_err(mdma->dma.dev, "- Source Address Error\n");
+		if (es & MPC_DMA_DMAES_SOE)
+			dev_err(mdma->dma.dev, "- Source Offset"
+						" Configuration Error\n");
+		if (es & MPC_DMA_DMAES_DAE)
+			dev_err(mdma->dma.dev, "- Destination Address"
+								" Error\n");
+		if (es & MPC_DMA_DMAES_DOE)
+			dev_err(mdma->dma.dev, "- Destination Offset"
+						" Configuration Error\n");
+		if (es & MPC_DMA_DMAES_NCE)
+			dev_err(mdma->dma.dev, "- NBytes/Citter"
+						" Configuration Error\n");
+		if (es & MPC_DMA_DMAES_SGE)
+			dev_err(mdma->dma.dev, "- Scatter/Gather"
+						" Configuration Error\n");
+		if (es & MPC_DMA_DMAES_SBE)
+			dev_err(mdma->dma.dev, "- Source Bus Error\n");
+		if (es & MPC_DMA_DMAES_DBE)
+			dev_err(mdma->dma.dev, "- Destination Bus Error\n");
+	}
+
+	for (i = 0; i < mdma->dma.chancnt; i++) {
+		mchan = &mdma->channels[i];
+
+		/* Get all completed descriptors */
+		spin_lock_irqsave(&mchan->lock, flags);
+		if (!list_empty(&mchan->completed))
+			list_splice_tail_init(&mchan->completed, &list);
+		spin_unlock_irqrestore(&mchan->lock, flags);
+
+		if (list_empty(&list))
+			continue;
+
+		/* Execute callbacks and run dependencies */
+		list_for_each_entry(mdesc, &list, node) {
+			desc = &mdesc->desc;
+
+			if (desc->callback)
+				desc->callback(desc->callback_param);
+
+			last_cookie = desc->cookie;
+			dma_run_dependencies(desc);
+		}
+
+		/* Free descriptors */
+		spin_lock_irqsave(&mchan->lock, flags);
+		list_splice_tail_init(&list, &mchan->free);
+		mchan->completed_cookie = last_cookie;
+		spin_unlock_irqrestore(&mchan->lock, flags);
+	}
+}
+
+/* Submit descriptor to hardware */
+static dma_cookie_t mpc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
+{
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(txd->chan);
+	struct mpc_dma_desc *mdesc;
+	unsigned long flags;
+	dma_cookie_t cookie;
+
+	mdesc = container_of(txd, struct mpc_dma_desc, desc);
+
+	spin_lock_irqsave(&mchan->lock, flags);
+
+	/* Move descriptor to queue */
+	list_move_tail(&mdesc->node, &mchan->queued);
+
+	/* If channel is idle, execute all queued descriptors */
+	if (list_empty(&mchan->active))
+		mpc_dma_execute(mchan);
+
+	/* Update cookie */
+	cookie = mchan->chan.cookie + 1;
+	if (cookie <= 0)
+		cookie = 1;
+
+	mchan->chan.cookie = cookie;
+	mdesc->desc.cookie = cookie;
+
+	spin_unlock_irqrestore(&mchan->lock, flags);
+
+	return cookie;
+}
+
+/* Alloc channel resources */
+static int mpc_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+	struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+	struct mpc_dma_desc *mdesc;
+	struct mpc_dma_tcd *tcd;
+	dma_addr_t tcd_paddr;
+	unsigned long flags;
+	LIST_HEAD(descs);
+	int i;
+
+	/* Alloc DMA memory for Transfer Control Descriptors */
+	tcd = dma_alloc_coherent(mdma->dma.dev,
+			MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+							&tcd_paddr, GFP_KERNEL);
+	if (!tcd)
+		return -ENOMEM;
+
+	/* Alloc descriptors for this channel */
+	for (i = 0; i < MPC_DMA_DESCRIPTORS; i++) {
+		mdesc = kzalloc(sizeof(struct mpc_dma_desc), GFP_KERNEL);
+		if (!mdesc) {
+			dev_notice(mdma->dma.dev, "Memory allocation error. "
+					"Allocated only %u descriptors\n", i);
+			break;
+		}
+
+		dma_async_tx_descriptor_init(&mdesc->desc, chan);
+		mdesc->desc.flags = DMA_CTRL_ACK;
+		mdesc->desc.tx_submit = mpc_dma_tx_submit;
+
+		mdesc->tcd = &tcd[i];
+		mdesc->tcd_paddr = tcd_paddr + (i * sizeof(struct mpc_dma_tcd));
+
+		list_add_tail(&mdesc->node, &descs);
+	}
+
+	/* Return error only if no descriptors were allocated */
+	if (i == 0) {
+		dma_free_coherent(mdma->dma.dev,
+			MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+								tcd, tcd_paddr);
+		return -ENOMEM;
+	}
+
+	spin_lock_irqsave(&mchan->lock, flags);
+	mchan->tcd = tcd;
+	mchan->tcd_paddr = tcd_paddr;
+	list_splice_tail_init(&descs, &mchan->free);
+	spin_unlock_irqrestore(&mchan->lock, flags);
+
+	/* Enable Error Interrupt */
+	out_8(&mdma->regs->dmaseei, chan->chan_id);
+
+	return 0;
+}
+
+/* Free channel resources */
+static void mpc_dma_free_chan_resources(struct dma_chan *chan)
+{
+	struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+	struct mpc_dma_desc *mdesc, *tmp;
+	struct mpc_dma_tcd *tcd;
+	dma_addr_t tcd_paddr;
+	unsigned long flags;
+	LIST_HEAD(descs);
+
+	spin_lock_irqsave(&mchan->lock, flags);
+
+	/* Channel must be idle */
+	BUG_ON(!list_empty(&mchan->prepared));
+	BUG_ON(!list_empty(&mchan->queued));
+	BUG_ON(!list_empty(&mchan->active));
+	BUG_ON(!list_empty(&mchan->completed));
+
+	/* Move data */
+	list_splice_tail_init(&mchan->free, &descs);
+	tcd = mchan->tcd;
+	tcd_paddr = mchan->tcd_paddr;
+
+	spin_unlock_irqrestore(&mchan->lock, flags);
+
+	/* Free DMA memory used by descriptors */
+	dma_free_coherent(mdma->dma.dev,
+			MPC_DMA_DESCRIPTORS * sizeof(struct mpc_dma_tcd),
+								tcd, tcd_paddr);
+
+	/* Free descriptors */
+	list_for_each_entry_safe(mdesc, tmp, &descs, node)
+		kfree(mdesc);
+
+	/* Disable Error Interrupt */
+	out_8(&mdma->regs->dmaceei, chan->chan_id);
+}
+
+/* Send all pending descriptor to hardware */
+static void mpc_dma_issue_pending(struct dma_chan *chan)
+{
+	/*
+	 * We are posting descriptors to the hardware as soon as
+	 * they are ready, so this function does nothing.
+	 */
+}
+
+/* Check request completion status */
+static enum dma_status
+mpc_dma_is_tx_complete(struct dma_chan *chan, dma_cookie_t cookie,
+					dma_cookie_t *done, dma_cookie_t *used)
+{
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+	unsigned long flags;
+	dma_cookie_t last_used;
+	dma_cookie_t last_complete;
+
+	spin_lock_irqsave(&mchan->lock, flags);
+	last_used = mchan->chan.cookie;
+	last_complete = mchan->completed_cookie;
+	spin_unlock_irqrestore(&mchan->lock, flags);
+
+	if (done)
+		*done = last_complete;
+
+	if (used)
+		*used = last_used;
+
+	return dma_async_is_complete(cookie, last_complete, last_used);
+}
+
+/* Prepare descriptor for memory to memory copy */
+static struct dma_async_tx_descriptor *
+mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t src,
+					size_t len, unsigned long flags)
+{
+	struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+	struct mpc_dma_desc *mdesc = NULL;
+	struct mpc_dma_tcd *tcd;
+	unsigned long iflags;
+
+	/* Get free descriptor */
+	spin_lock_irqsave(&mchan->lock, iflags);
+	if (!list_empty(&mchan->free)) {
+		mdesc = list_first_entry(&mchan->free, struct mpc_dma_desc,
+									node);
+		list_del(&mdesc->node);
+	}
+	spin_unlock_irqrestore(&mchan->lock, iflags);
+
+	if (!mdesc)
+		return NULL;
+
+	mdesc->error = 0;
+	tcd = mdesc->tcd;
+
+	/* Prepare Transfer Control Descriptor for this transaction */
+	memset(tcd, 0, sizeof(struct mpc_dma_tcd));
+
+	if (IS_ALIGNED(src | dst | len, 32)) {
+		tcd->ssize = MPC_DMA_TSIZE_32;
+		tcd->dsize = MPC_DMA_TSIZE_32;
+		tcd->soff = 32;
+		tcd->doff = 32;
+	} else if (IS_ALIGNED(src | dst | len, 16)) {
+		tcd->ssize = MPC_DMA_TSIZE_16;
+		tcd->dsize = MPC_DMA_TSIZE_16;
+		tcd->soff = 16;
+		tcd->doff = 16;
+	} else if (IS_ALIGNED(src | dst | len, 4)) {
+		tcd->ssize = MPC_DMA_TSIZE_4;
+		tcd->dsize = MPC_DMA_TSIZE_4;
+		tcd->soff = 4;
+		tcd->doff = 4;
+	} else if (IS_ALIGNED(src | dst | len, 2)) {
+		tcd->ssize = MPC_DMA_TSIZE_2;
+		tcd->dsize = MPC_DMA_TSIZE_2;
+		tcd->soff = 2;
+		tcd->doff = 2;
+	} else {
+		tcd->ssize = MPC_DMA_TSIZE_1;
+		tcd->dsize = MPC_DMA_TSIZE_1;
+		tcd->soff = 1;
+		tcd->doff = 1;
+	}
+
+	tcd->saddr = src;
+	tcd->daddr = dst;
+	tcd->nbytes = len;
+	tcd->biter = 1;
+	tcd->citer = 1;
+
+	/* Place descriptor in prepared list */
+	spin_lock_irqsave(&mchan->lock, iflags);
+	list_add_tail(&mdesc->node, &mchan->prepared);
+	spin_unlock_irqrestore(&mchan->lock, iflags);
+
+	return &mdesc->desc;
+}
+
+static int __devinit mpc_dma_probe(struct of_device *op,
+					const struct of_device_id *match)
+{
+	struct device_node *dn = op->node;
+	struct device *dev = &op->dev;
+	struct dma_device *dma;
+	struct mpc_dma *mdma;
+	struct mpc_dma_chan *mchan;
+	struct resource res;
+	ulong regs_start, regs_size;
+	int retval, i;
+
+	mdma = devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERNEL);
+	if (!mdma) {
+		dev_err(dev, "Memory exhausted!\n");
+		return -ENOMEM;
+	}
+
+	mdma->irq = irq_of_parse_and_map(dn, 0);
+	if (mdma->irq == NO_IRQ) {
+		dev_err(dev, "Error mapping IRQ!\n");
+		return -EINVAL;
+	}
+
+	retval = of_address_to_resource(dn, 0, &res);
+	if (retval) {
+		dev_err(dev, "Error parsing memory region!\n");
+		return retval;
+	}
+
+	regs_start = res.start;
+	regs_size = res.end - res.start + 1;
+
+	if (!devm_request_mem_region(dev, regs_start, regs_size, DRV_NAME)) {
+		dev_err(dev, "Error requesting memory region!\n");
+		return -EBUSY;
+	}
+
+	mdma->regs = devm_ioremap(dev, regs_start, regs_size);
+	if (!mdma->regs) {
+		dev_err(dev, "Error mapping memory region!\n");
+		return -ENOMEM;
+	}
+
+	mdma->tcd = (struct mpc_dma_tcd *)((u8 *)(mdma->regs)
+							+ MPC_DMA_TCD_OFFSET);
+
+	retval = devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0, DRV_NAME,
+									mdma);
+	if (retval) {
+		dev_err(dev, "Error requesting IRQ!\n");
+		return -EINVAL;
+	}
+
+	spin_lock_init(&mdma->error_status_lock);
+
+	dma = &mdma->dma;
+	dma->dev = dev;
+	dma->chancnt = MPC_DMA_CHANNELS;
+	dma->device_alloc_chan_resources = mpc_dma_alloc_chan_resources;
+	dma->device_free_chan_resources = mpc_dma_free_chan_resources;
+	dma->device_issue_pending = mpc_dma_issue_pending;
+	dma->device_is_tx_complete = mpc_dma_is_tx_complete;
+	dma->device_prep_dma_memcpy = mpc_dma_prep_memcpy;
+
+	INIT_LIST_HEAD(&dma->channels);
+	dma_cap_set(DMA_MEMCPY, dma->cap_mask);
+
+	for (i = 0; i < dma->chancnt; i++) {
+		mchan = &mdma->channels[i];
+
+		mchan->chan.device = dma;
+		mchan->chan.chan_id = i;
+		mchan->chan.cookie = 1;
+		mchan->completed_cookie = mchan->chan.cookie;
+
+		INIT_LIST_HEAD(&mchan->free);
+		INIT_LIST_HEAD(&mchan->prepared);
+		INIT_LIST_HEAD(&mchan->queued);
+		INIT_LIST_HEAD(&mchan->active);
+		INIT_LIST_HEAD(&mchan->completed);
+
+		spin_lock_init(&mchan->lock);
+		list_add_tail(&mchan->chan.device_node, &dma->channels);
+	}
+
+	tasklet_init(&mdma->tasklet, mpc_dma_tasklet, (unsigned long)mdma);
+
+	/*
+	 * Configure DMA Engine:
+	 * - Dynamic clock,
+	 * - Round-robin group arbitration,
+	 * - Round-robin channel arbitration.
+	 */
+	out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
+				MPC_DMA_DMACR_ERGA | MPC_DMA_DMACR_ERCA);
+
+	/* Disable hardware DMA requests */
+	out_be32(&mdma->regs->dmaerqh, 0);
+	out_be32(&mdma->regs->dmaerql, 0);
+
+	/* Disable error interrupts */
+	out_be32(&mdma->regs->dmaeeih, 0);
+	out_be32(&mdma->regs->dmaeeil, 0);
+
+	/* Clear interrupts status */
+	out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
+	out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
+	out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
+	out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
+
+	/* Route interrupts to IPIC */
+	out_be32(&mdma->regs->dmaihsa, 0);
+	out_be32(&mdma->regs->dmailsa, 0);
+
+	/* Register DMA engine */
+	dev_set_drvdata(dev, mdma);
+	retval = dma_async_device_register(dma);
+	if (retval) {
+		devm_free_irq(dev, mdma->irq, mdma);
+		irq_dispose_mapping(mdma->irq);
+	}
+
+	return retval;
+}
+
+static int __devexit mpc_dma_remove(struct of_device *op)
+{
+	struct device *dev = &op->dev;
+	struct mpc_dma *mdma = dev_get_drvdata(dev);
+
+	dma_async_device_unregister(&mdma->dma);
+	devm_free_irq(dev, mdma->irq, mdma);
+	irq_dispose_mapping(mdma->irq);
+
+	return 0;
+}
+
+static struct of_device_id mpc_dma_match[] = {
+	{ .compatible = "fsl,mpc5121-dma", },
+	{},
+};
+
+static struct of_platform_driver mpc_dma_driver = {
+	.match_table	= mpc_dma_match,
+	.probe		= mpc_dma_probe,
+	.remove		= __devexit_p(mpc_dma_remove),
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init mpc_dma_init(void)
+{
+	return of_register_platform_driver(&mpc_dma_driver);
+}
+module_init(mpc_dma_init);
+
+static void __exit mpc_dma_exit(void)
+{
+	of_unregister_platform_driver(&mpc_dma_driver);
+}
+module_exit(mpc_dma_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Piotr Ziecik <kosmo@semihalf.com>");
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 07/11] powerpc/fsl_soc.c: prepare for addition of mpc5121 USB code
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (5 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 06/11] dma: Add MPC512x DMA driver Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 08/11] powerpc/mpc5121: add USB host support Anatolij Gustschin
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anatolij Gustschin, wd, dzu

Factor out common code for registering a FSL EHCI platform
device into new fsl_usb2_register_device() function. This
is done to avoid code duplication while adding code for
instantiating of MPC5121 dual role USB platform devices.
Then, the subsequent patch can use
for_each_compatible_node(np, NULL, "fsl,mpc5121-usb2-dr") {
	...
	fsl_usb2_register_device();
}

Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
Note to avoid confusion: this patch is new in this series
and is needed because for mpc5121 "fsl,mpc5121-usb2-dr" is
used as the compatible property as requested. "fsl-usb2-dr"
won't be used for mpc5121 any more.

 arch/powerpc/sysdev/fsl_soc.c |  219 ++++++++++++++++++-----------------------
 1 files changed, 98 insertions(+), 121 deletions(-)

diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index b91f7ac..7bd6436 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -209,6 +209,37 @@ static int __init of_add_fixed_phys(void)
 arch_initcall(of_add_fixed_phys);
 #endif /* CONFIG_FIXED_PHY */
 
+struct fsl_usb2_dev_data {
+	char *dr_mode;		/* controller mode */
+	char *drivers[2];	/* drivers to instantiate for this mode */
+	enum fsl_usb2_operating_modes op_mode;	/* operating mode */
+};
+
+struct fsl_usb2_dev_data dr_data[] __initdata = {
+	{ "host",	{ "fsl-ehci",	NULL,		}, FSL_USB2_DR_HOST,  },
+	{ "otg",	{ "fsl-ehci",	"fsl-usb2-udc",	}, FSL_USB2_DR_OTG,   },
+	{ "periferal",	{ "fsl-usb2-udc", NULL,		}, FSL_USB2_DR_DEVICE,},
+};
+
+struct fsl_usb2_dev_data mph_data[] __initdata = {
+	{ NULL,		{ "fsl-ehci",	NULL,		}, FSL_USB2_MPH_HOST, },
+};
+
+struct fsl_usb2_dev_data * __init get_dr_data(struct device_node *np)
+{
+	const unsigned char *prop;
+	int i;
+
+	prop = of_get_property(np, "dr_mode", NULL);
+	if (prop) {
+		for (i = 0; i < ARRAY_SIZE(dr_data); i++) {
+			if (!strcmp(prop, dr_data[i].dr_mode))
+				return &dr_data[i];
+		}
+	}
+	return &dr_data[0]; /* mode not specified, use host */
+}
+
 static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
 {
 	if (!phy_type)
@@ -225,151 +256,97 @@ static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type)
 	return FSL_USB2_PHY_NONE;
 }
 
-static int __init fsl_usb_of_init(void)
+int __init fsl_usb2_register_device(struct device_node *np,
+			struct fsl_usb2_dev_data *dev_data,
+			struct fsl_usb2_platform_data *pdata,
+			unsigned int idx)
 {
-	struct device_node *np;
-	unsigned int i = 0;
-	struct platform_device *usb_dev_mph = NULL, *usb_dev_dr_host = NULL,
-		*usb_dev_dr_client = NULL;
+	struct platform_device *usb_dev;
+	const unsigned char *prop;
+	struct resource r[2];
+	int registered = 0;
 	int ret;
+	int i;
+
+	if (!(dev_data && pdata))
+		return -EINVAL;
+
+	memset(&r, 0, sizeof(r));
+	ret = of_address_to_resource(np, 0, &r[0]);
+	if (ret)
+		return -ENODEV;
+
+	ret = of_irq_to_resource(np, 0, &r[1]);
+	if (ret == NO_IRQ)
+		return -ENODEV;
+
+	pdata->operating_mode = dev_data->op_mode;
+
+	prop = of_get_property(np, "phy_type", NULL);
+	pdata->phy_mode = determine_usb_phy(prop);
+	ret = 0;
+	for (i = 0; i < ARRAY_SIZE(dev_data->drivers); i++) {
+		if (!dev_data->drivers[i])
+			break;
+		usb_dev = platform_device_register_simple(
+					dev_data->drivers[i], idx, r, 2);
+		if (IS_ERR(usb_dev)) {
+			ret = PTR_ERR(usb_dev);
+			goto out;
+		}
 
-	for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
+		usb_dev->dev.coherent_dma_mask = 0xffffffffUL;
+		usb_dev->dev.dma_mask = &usb_dev->dev.coherent_dma_mask;
+		ret = platform_device_add_data(usb_dev, pdata,
+				sizeof(struct fsl_usb2_platform_data));
 		if (ret)
-			goto err;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		usb_dev_mph =
-		    platform_device_register_simple("fsl-ehci", i, r, 2);
-		if (IS_ERR(usb_dev_mph)) {
-			ret = PTR_ERR(usb_dev_mph);
-			goto err;
-		}
+			platform_device_unregister(usb_dev);
+		else
+			registered++;
+	}
+out:
+	if (!registered)
+		irq_dispose_mapping(r[1].end);
 
-		usb_dev_mph->dev.coherent_dma_mask = 0xffffffffUL;
-		usb_dev_mph->dev.dma_mask = &usb_dev_mph->dev.coherent_dma_mask;
+	return ret;
+}
 
-		usb_data.operating_mode = FSL_USB2_MPH_HOST;
+static int __init fsl_usb_of_init(void)
+{
+	struct device_node *np;
+	const unsigned char *prop;
+	struct fsl_usb2_platform_data pdata;
+	unsigned int idx = 0;
+	int ret;
 
+	for_each_compatible_node(np, NULL, "fsl-usb2-mph") {
+		memset(&pdata, 0, sizeof(pdata));
 		prop = of_get_property(np, "port0", NULL);
 		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT0_ENABLED;
+			pdata.port_enables |= FSL_USB2_PORT0_ENABLED;
 
 		prop = of_get_property(np, "port1", NULL);
 		if (prop)
-			usb_data.port_enables |= FSL_USB2_PORT1_ENABLED;
+			pdata.port_enables |= FSL_USB2_PORT1_ENABLED;
 
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		ret =
-		    platform_device_add_data(usb_dev_mph, &usb_data,
-					     sizeof(struct
-						    fsl_usb2_platform_data));
+		ret = fsl_usb2_register_device(np, mph_data, &pdata, idx++);
 		if (ret)
-			goto unreg_mph;
-		i++;
+			return ret;
 	}
 
 	for_each_compatible_node(np, NULL, "fsl-usb2-dr") {
-		struct resource r[2];
-		struct fsl_usb2_platform_data usb_data;
-		const unsigned char *prop = NULL;
-
 		if (!of_device_is_available(np))
 			continue;
 
-		memset(&r, 0, sizeof(r));
-		memset(&usb_data, 0, sizeof(usb_data));
-
-		ret = of_address_to_resource(np, 0, &r[0]);
+		memset(&pdata, 0, sizeof(pdata));
+		ret = fsl_usb2_register_device(np, get_dr_data(np),
+						&pdata, idx++);
 		if (ret)
-			goto unreg_mph;
-
-		of_irq_to_resource(np, 0, &r[1]);
-
-		prop = of_get_property(np, "dr_mode", NULL);
-
-		if (!prop || !strcmp(prop, "host")) {
-			usb_data.operating_mode = FSL_USB2_DR_HOST;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "peripheral")) {
-			usb_data.operating_mode = FSL_USB2_DR_DEVICE;
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else if (prop && !strcmp(prop, "otg")) {
-			usb_data.operating_mode = FSL_USB2_DR_OTG;
-			usb_dev_dr_host = platform_device_register_simple(
-					"fsl-ehci", i, r, 2);
-			if (IS_ERR(usb_dev_dr_host)) {
-				ret = PTR_ERR(usb_dev_dr_host);
-				goto err;
-			}
-			usb_dev_dr_client = platform_device_register_simple(
-					"fsl-usb2-udc", i, r, 2);
-			if (IS_ERR(usb_dev_dr_client)) {
-				ret = PTR_ERR(usb_dev_dr_client);
-				goto err;
-			}
-		} else {
-			ret = -EINVAL;
-			goto err;
-		}
-
-		prop = of_get_property(np, "phy_type", NULL);
-		usb_data.phy_mode = determine_usb_phy(prop);
-
-		if (usb_dev_dr_host) {
-			usb_dev_dr_host->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_host->dev.dma_mask = &usb_dev_dr_host->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_host,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
-		}
-		if (usb_dev_dr_client) {
-			usb_dev_dr_client->dev.coherent_dma_mask = 0xffffffffUL;
-			usb_dev_dr_client->dev.dma_mask = &usb_dev_dr_client->
-				dev.coherent_dma_mask;
-			if ((ret = platform_device_add_data(usb_dev_dr_client,
-						&usb_data, sizeof(struct
-						fsl_usb2_platform_data))))
-				goto unreg_dr;
-		}
-		i++;
+			return ret;
 	}
-	return 0;
 
-unreg_dr:
-	if (usb_dev_dr_host)
-		platform_device_unregister(usb_dev_dr_host);
-	if (usb_dev_dr_client)
-		platform_device_unregister(usb_dev_dr_client);
-unreg_mph:
-	if (usb_dev_mph)
-		platform_device_unregister(usb_dev_mph);
-err:
-	return ret;
+	return 0;
 }
-
 arch_initcall(fsl_usb_of_init);
 
 #if defined(CONFIG_FSL_SOC_BOOKE) || defined(CONFIG_PPC_86xx)
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 08/11] powerpc/mpc5121: add USB host support
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (6 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 07/11] powerpc/fsl_soc.c: prepare for addition of mpc5121 USB code Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-05 13:42 ` [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, linux-usb, Bruce Schmid, Anatolij Gustschin

Platform specific code for MPC5121 USB Host support.

The patch also contains changes to FSL EHCI platform driver
needed to support MPC5121 USB controller. MPC5121 Rev 2.0
silicon EHCI registers are in big endian format. The
appropriate flags are set using the information in the
platform data structure. 83xx system interface registers
are not available on 512x, so the access to these registers
is isolated for 512x. Furthermore the USB controller clock
must be enabled before 512x register access which is done
by providing platform specific init callback.

The 512x internal USB PHY doesn't provide supply voltage.
For boards using different power switches allow specifying
DRVVBUS and PWR_FAULT signal polarity of the MPC5121 internal
PHY using "fsl,invert-drvvbus" and "fsl,invert-pwr-fault"
properties in the device tree USB node.

Signed-off-by: Bruce Schmid <duck@freescale.com>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: linux-usb@vger.kernel.org
Cc: Grant Likely <grant.likely@secretlab.ca>
---
Changes since V2:
 - drop fsl,big-endian-regs property and set the appropriate
   flag in the platform code.
 - test for "fsl,mpc5121-usb2-dr" compatible nodes directly
   and instantiate the platform devices if this node is
   present. Enable the USB controller clocks only for
   devices described in the device tree
 - update the dts-bindings description and provide an
   example for mpc5121ads USB node
 
Changes since v1:
 - prefix the property names with 'fsl,'
 - drop currently unused USB_FSL_BIG_ENDIAN_MMIO config option
 - remove unrelated changes which can be addressed by
   separate patch
 - fix commit message

Note that EHCI FSL driver extention in this patch
applies on top of the following two patches (in the
linux-next tree):

commit 23c3314b88f91db51bd198ed92e34cffb67788dd
Author: Anton Vorontsov <avorontsov@ru.mvista.com>
Date:   Mon Dec 14 18:41:12 2009 +0300

    USB: ehci-fsl: Add power management support

commit bf4bf2d9f646eb0cc531d213a13ffcedf9d6785f
Author: Anton Vorontsov <avorontsov@ru.mvista.com>
Date:   Mon Dec 14 18:41:05 2009 +0300

    USB: ehci-fsl: Fix sparse warnings

 Documentation/powerpc/dts-bindings/fsl/usb.txt |   22 ++++
 arch/powerpc/platforms/512x/Kconfig            |    3 +
 arch/powerpc/platforms/512x/Makefile           |    2 +-
 arch/powerpc/platforms/512x/mpc5121_usb.c      |  138 ++++++++++++++++++++++++
 arch/powerpc/platforms/512x/mpc512x.h          |    1 +
 arch/powerpc/platforms/512x/mpc512x_shared.c   |    1 +
 arch/powerpc/sysdev/fsl_soc.c                  |   13 +++
 arch/powerpc/sysdev/fsl_soc.h                  |    9 ++
 drivers/usb/host/ehci-fsl.c                    |  111 ++++++++++++++-----
 drivers/usb/host/ehci-fsl.h                    |   19 +++-
 drivers/usb/host/ehci-mem.c                    |    2 +-
 include/linux/fsl_devices.h                    |   10 ++
 12 files changed, 298 insertions(+), 33 deletions(-)
 create mode 100644 arch/powerpc/platforms/512x/mpc5121_usb.c

diff --git a/Documentation/powerpc/dts-bindings/fsl/usb.txt b/Documentation/powerpc/dts-bindings/fsl/usb.txt
index b001524..76a7c2c 100644
--- a/Documentation/powerpc/dts-bindings/fsl/usb.txt
+++ b/Documentation/powerpc/dts-bindings/fsl/usb.txt
@@ -8,6 +8,7 @@ and additions :
 Required properties :
  - compatible : Should be "fsl-usb2-mph" for multi port host USB
    controllers, or "fsl-usb2-dr" for dual role USB controllers
+   or "fsl,mpc5121-usb2-dr" for dual role USB controllers of MPC5121
  - phy_type : For multi port host USB controllers, should be one of
    "ulpi", or "serial". For dual role USB controllers, should be
    one of "ulpi", "utmi", "utmi_wide", or "serial".
@@ -33,6 +34,12 @@ Recommended properties :
  - interrupt-parent : the phandle for the interrupt controller that
    services interrupts for this device.
 
+Optional properties :
+ - fsl,invert-drvvbus : boolean; for MPC5121 only. Indicates the port
+   power polarity of internal PHY signal DRVVBUS is inverted.
+ - fsl,invert-pwr-fault : boolean; for MPC5121 only. Indicates the
+   PWR_FAULT signal polarity is inverted.
+
 Example multi port host USB controller device node :
 	usb@22000 {
 		compatible = "fsl-usb2-mph";
@@ -57,3 +64,18 @@ Example dual role USB controller device node :
 		dr_mode = "otg";
 		phy = "ulpi";
 	};
+
+Example dual role USB controller device node for MPC5121ADS:
+
+	usb@4000 {
+		compatible = "fsl,mpc5121-usb2-dr";
+		reg = <0x4000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		interrupt-parent = < &ipic >;
+		interrupts = <44 0x8>;
+		dr_mode = "otg";
+		phy_type = "utmi_wide";
+		fsl,invert-drvvbus;
+		fsl,invert-pwr-fault;
+	};
diff --git a/arch/powerpc/platforms/512x/Kconfig b/arch/powerpc/platforms/512x/Kconfig
index 4dac9b0..fed7b5d 100644
--- a/arch/powerpc/platforms/512x/Kconfig
+++ b/arch/powerpc/platforms/512x/Kconfig
@@ -9,6 +9,9 @@ config PPC_MPC512x
 config PPC_MPC5121
 	bool
 	select PPC_MPC512x
+	select USB_ARCH_HAS_EHCI
+	select USB_EHCI_BIG_ENDIAN_DESC
+	select USB_EHCI_BIG_ENDIAN_MMIO
 
 config MPC5121_ADS
 	bool "Freescale MPC5121E ADS"
diff --git a/arch/powerpc/platforms/512x/Makefile b/arch/powerpc/platforms/512x/Makefile
index 90be2f5..49adabc 100644
--- a/arch/powerpc/platforms/512x/Makefile
+++ b/arch/powerpc/platforms/512x/Makefile
@@ -1,6 +1,6 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y				+= clock.o mpc512x_shared.o
+obj-y				+= clock.o mpc512x_shared.o mpc5121_usb.o
 obj-$(CONFIG_MPC5121_ADS)	+= mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC5121_GENERIC)	+= mpc5121_generic.o
diff --git a/arch/powerpc/platforms/512x/mpc5121_usb.c b/arch/powerpc/platforms/512x/mpc5121_usb.c
new file mode 100644
index 0000000..9536750
--- /dev/null
+++ b/arch/powerpc/platforms/512x/mpc5121_usb.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
+ *
+ * Author: Bruce Schmid <duck@freescale.com>, Tue Oct 2 2007
+ *
+ * Description:
+ * MPC5121 USB platform-specific routines
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/fsl_devices.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/stddef.h>
+#include <linux/of_platform.h>
+#include <sysdev/fsl_soc.h>
+
+#define USBGENCTRL		0x200		/* NOTE: big endian */
+#define GC_WU_INT_CLR		(1 << 5)	/* Wakeup int clear */
+#define GC_ULPI_SEL		(1 << 4)	/* ULPI i/f select (usb0 only)*/
+#define GC_PPP			(1 << 3)	/* Inv. Port Power Polarity */
+#define GC_PFP			(1 << 2)	/* Inv. Power Fault Polarity */
+#define GC_WU_ULPI_EN		(1 << 1)	/* Wakeup on ULPI event */
+#define GC_WU_IE		(1 << 1)	/* Wakeup interrupt enable */
+
+#define ISIPHYCTRL		0x204		/* NOTE: big endian */
+#define PHYCTRL_PHYE		(1 << 4)	/* On-chip UTMI PHY enable */
+#define PHYCTRL_BSENH		(1 << 3)	/* Bit Stuff Enable High */
+#define PHYCTRL_BSEN		(1 << 2)	/* Bit Stuff Enable */
+#define PHYCTRL_LSFE		(1 << 1)	/* Line State Filter Enable */
+#define PHYCTRL_PXE		(1 << 0)	/* PHY oscillator enable */
+
+#define USB_ULPI		0x3000
+#define USB_UTMI		0x4000
+
+static struct dr_clk {
+	struct clk *clk;
+	const char *clk_name;
+} mpc512x_usb_dr_clk[2] = {
+	{ NULL, "usb1_clk", },
+	{ NULL, "usb2_clk", },
+};
+
+static inline struct dr_clk *get_pdev_clk(struct platform_device *pdev)
+{
+	switch (pdev->resource->start & 0xf000) {
+	case USB_ULPI:
+		return &mpc512x_usb_dr_clk[0];
+	case USB_UTMI:
+		return &mpc512x_usb_dr_clk[1];
+	default:
+		return NULL;
+	}
+}
+
+static int mpc5121_usb_dr_init(struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct dr_clk *dr_clk;
+
+	dr_clk = get_pdev_clk(pdev);
+	if (!dr_clk)
+		return -EINVAL;
+
+	/* enable the clock if we haven't already */
+	if (!dr_clk->clk) {
+		dr_clk->clk = clk_get(&pdev->dev, dr_clk->clk_name);
+		if (IS_ERR(dr_clk->clk)) {
+			dev_err(&pdev->dev, "%s: clk_get failed\n",
+				dr_clk->clk_name);
+			dr_clk->clk = NULL;
+			return -ENODEV;
+		}
+		clk_enable(dr_clk->clk);
+	}
+
+	pdata->big_endian_desc = 1;
+	pdata->big_endian_mmio = 1;
+	pdata->es = 1;
+
+	if (pdata->phy_mode == FSL_USB2_PHY_UTMI_WIDE) {
+		struct device_node *np;
+		u32 reg = 0;
+
+		np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-usb2-dr");
+		if (!np) {
+			pr_err("No USB node found\n");
+			return -ENODEV;
+		}
+
+		if (of_get_property(np, "fsl,invert-drvvbus", NULL))
+			reg |= GC_PPP;
+
+		if (of_get_property(np, "fsl,invert-pwr-fault", NULL))
+			reg |= GC_PFP;
+
+		of_node_put(np);
+		out_be32(pdata->regs + ISIPHYCTRL, PHYCTRL_PHYE | PHYCTRL_PXE);
+		out_be32(pdata->regs + USBGENCTRL, reg);
+	}
+	return 0;
+}
+
+static void mpc5121_usb_dr_uninit(struct platform_device *pdev)
+{
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+	struct dr_clk *dr_clk;
+
+	pdata->regs = NULL;
+
+	dr_clk = get_pdev_clk(pdev);
+	if (!dr_clk)
+		return;
+
+	if (dr_clk->clk) {
+		clk_disable(dr_clk->clk);
+		clk_put(dr_clk->clk);
+		dr_clk->clk = NULL;
+	}
+}
+
+void __init mpc5121_usb_init(void)
+{
+	fsl_platform_usb_ops.init = mpc5121_usb_dr_init;
+	fsl_platform_usb_ops.uninit = mpc5121_usb_dr_uninit;
+}
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index b2daca0..d72b2c7 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -16,4 +16,5 @@ extern void __init mpc512x_init(void);
 extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 extern void mpc512x_restart(char *cmd);
+extern void __init mpc5121_usb_init(void);
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 8bb34b2..4de8175 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -104,4 +104,5 @@ void __init mpc512x_init(void)
 	mpc512x_declare_of_platform_devices();
 	mpc5121_clk_init();
 	mpc512x_restart_init();
+	mpc5121_usb_init();
 }
diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c
index 7bd6436..75a0c07 100644
--- a/arch/powerpc/sysdev/fsl_soc.c
+++ b/arch/powerpc/sysdev/fsl_soc.c
@@ -209,6 +209,9 @@ static int __init of_add_fixed_phys(void)
 arch_initcall(of_add_fixed_phys);
 #endif /* CONFIG_FIXED_PHY */
 
+struct fsl_platform_usb_ops fsl_platform_usb_ops;
+EXPORT_SYMBOL(fsl_platform_usb_ops);
+
 struct fsl_usb2_dev_data {
 	char *dr_mode;		/* controller mode */
 	char *drivers[2];	/* drivers to instantiate for this mode */
@@ -345,6 +348,16 @@ static int __init fsl_usb_of_init(void)
 			return ret;
 	}
 
+	for_each_compatible_node(np, NULL, "fsl,mpc5121-usb2-dr") {
+		memset(&pdata, 0, sizeof(pdata));
+		pdata.platform_init = fsl_platform_usb_ops.init;
+		pdata.platform_uninit = fsl_platform_usb_ops.uninit;
+		ret = fsl_usb2_register_device(np, get_dr_data(np),
+						&pdata, idx++);
+		if (ret)
+			return ret;
+	}
+
 	return 0;
 }
 arch_initcall(fsl_usb_of_init);
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 42381bb..19754be 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -35,5 +35,14 @@ struct platform_diu_data_ops {
 extern struct platform_diu_data_ops diu_ops;
 #endif
 
+struct platform_device;
+
+struct fsl_platform_usb_ops {
+	int (*init)(struct platform_device *);
+	void (*uninit)(struct platform_device *);
+};
+
+extern struct fsl_platform_usb_ops fsl_platform_usb_ops;
+
 #endif
 #endif
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 0e26aa1..6b3f1df 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -57,7 +57,7 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 	pr_debug("initializing FSL-SOC USB Controller\n");
 
 	/* Need platform data for setup */
-	pdata = (struct fsl_usb2_platform_data *)pdev->dev.platform_data;
+	pdata = pdev->dev.platform_data;
 	if (!pdata) {
 		dev_err(&pdev->dev,
 			"No platform data for %s.\n", dev_name(&pdev->dev));
@@ -116,13 +116,39 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 		goto err3;
 	}
 
-	/* Enable USB controller */
-	temp = in_be32(hcd->regs + 0x500);
-	out_be32(hcd->regs + 0x500, temp | 0x4);
+	pdata->regs = hcd->regs;
+
+	/*
+	 * do platform specific init: check the clock, grab/config pins, etc.
+	 */
+	if (pdata->platform_init && pdata->platform_init(pdev)) {
+		retval = -ENODEV;
+		goto err3;
+	}
+
+	/*
+	 * Check if it is MPC5121 SoC, otherwise set pdata->have_sysif_regs
+	 * flag for 83xx or 8536 system interface registers.
+	 */
+	if (pdata->big_endian_mmio)
+		temp = in_be32(hcd->regs + FSL_SOC_USB_ID);
+	else
+		temp = in_le32(hcd->regs + FSL_SOC_USB_ID);
+
+	if ((temp & ID_MSK) != (~((temp & NID_MSK) >> 8) & ID_MSK))
+		pdata->have_sysif_regs = 1;
+
+	/* Enable USB controller, 83xx or 8536 */
+	if (pdata->have_sysif_regs)
+		setbits32(hcd->regs + FSL_SOC_USB_CTRL, 0x4);
 
 	/* Set to Host mode */
-	temp = in_le32(hcd->regs + 0x1a8);
-	out_le32(hcd->regs + 0x1a8, temp | 0x3);
+	if (pdata->big_endian_mmio) {
+		setbits32(hcd->regs + FSL_SOC_USB_USBMODE, USBMODE_CM_HOST);
+	} else {
+		clrsetbits_le32(hcd->regs + FSL_SOC_USB_USBMODE,
+				USBMODE_CM_MASK, USBMODE_CM_HOST);
+	}
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 	if (retval != 0)
@@ -137,6 +163,8 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 	usb_put_hcd(hcd);
       err1:
 	dev_err(&pdev->dev, "init %s fail, %d\n", dev_name(&pdev->dev), retval);
+	if (pdata->platform_uninit)
+		pdata->platform_uninit(pdev);
 	return retval;
 }
 
@@ -154,17 +182,30 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
 static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
 			       struct platform_device *pdev)
 {
+	struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
+
 	usb_remove_hcd(hcd);
+
+	/*
+	 * do platform specific un-initialization:
+	 * release iomux pins, disable clock, etc.
+	 */
+	if (pdata->platform_uninit)
+		pdata->platform_uninit(pdev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 }
 
-static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
-			      enum fsl_usb2_phy_modes phy_mode,
-			      unsigned int port_offset)
+static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
+			       enum fsl_usb2_phy_modes phy_mode,
+			       unsigned int port_offset)
 {
-	u32 portsc = 0;
+	u32 portsc;
+
+	portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
+	portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
+
 	switch (phy_mode) {
 	case FSL_USB2_PHY_ULPI:
 		portsc |= PORT_PTS_ULPI;
@@ -184,20 +225,21 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
 	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
-static void mpc83xx_usb_setup(struct usb_hcd *hcd)
+static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
 {
-	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct usb_hcd *hcd = ehci_to_hcd(ehci);
 	struct fsl_usb2_platform_data *pdata;
 	void __iomem *non_ehci = hcd->regs;
-	u32 temp;
+	u32 tmp;
+
+	pdata = hcd->self.controller->platform_data;
 
-	pdata =
-	    (struct fsl_usb2_platform_data *)hcd->self.controller->
-	    platform_data;
 	/* Enable PHY interface in the control reg. */
-	temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
-	out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
-	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+	if (pdata->have_sysif_regs) {
+		tmp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+		out_be32(non_ehci + FSL_SOC_USB_CTRL, tmp | 0x00000004);
+		out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
+	}
 
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 	/*
@@ -214,7 +256,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 
 	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 			(pdata->operating_mode == FSL_USB2_DR_OTG))
-		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+		ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 		unsigned int chip, rev, svr;
@@ -228,27 +270,31 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 			ehci->has_fsl_port_bug = 1;
 
 		if (pdata->port_enables & FSL_USB2_PORT0_ENABLED)
-			mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
+			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 0);
 		if (pdata->port_enables & FSL_USB2_PORT1_ENABLED)
-			mpc83xx_setup_phy(ehci, pdata->phy_mode, 1);
+			ehci_fsl_setup_phy(ehci, pdata->phy_mode, 1);
 	}
 
 	/* put controller in host mode. */
-	ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+	tmp = USBMODE_CM_HOST | (pdata->es ? USBMODE_ES : 0);
+	ehci_writel(ehci, tmp, non_ehci + FSL_SOC_USB_USBMODE);
+
+	if (pdata->have_sysif_regs) {
 #ifdef CONFIG_PPC_85xx
-	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
-	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
+		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x00000008);
+		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000080);
 #else
-	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
-	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
+		out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
+		out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 #endif
-	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+		out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
+	}
 }
 
 /* called after powerup, by probe or system-pm "wakeup" */
 static int ehci_fsl_reinit(struct ehci_hcd *ehci)
 {
-	mpc83xx_usb_setup(ehci_to_hcd(ehci));
+	ehci_fsl_usb_setup(ehci);
 	ehci_port_power(ehci, 0);
 
 	return 0;
@@ -259,6 +305,11 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
 {
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	int retval;
+	struct fsl_usb2_platform_data *pdata;
+
+	pdata = hcd->self.controller->platform_data;
+	ehci->big_endian_desc = pdata->big_endian_desc;
+	ehci->big_endian_mmio = pdata->big_endian_mmio;
 
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
@@ -369,7 +420,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
 	 * generic hardware linkage
 	 */
 	.irq = ehci_irq,
-	.flags = HCD_USB2,
+	.flags = HCD_USB2 | HCD_MEMORY,
 
 	/*
 	 * basic lifecycle operations
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index b5e59db..3525bb4 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2005 freescale semiconductor
+/* Copyright (C) 2005-2009 Freescale Semiconductor, Inc. All rights reserved.
  * Copyright (c) 2005 MontaVista Software
  *
  * This program is free software; you can redistribute  it and/or modify it
@@ -19,6 +19,11 @@
 #define _EHCI_FSL_H
 
 /* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_ID		0x0
+#define ID_MSK			0x3f
+#define NID_MSK			0x3f00
+#define FSL_SOC_USB_SBUSCFG	0x90
+#define FSL_SOC_USB_BURSTSIZE	0x160
 #define FSL_SOC_USB_ULPIVP	0x170
 #define FSL_SOC_USB_PORTSC1	0x184
 #define PORT_PTS_MSK		(3<<30)
@@ -26,8 +31,20 @@
 #define PORT_PTS_ULPI		(2<<30)
 #define	PORT_PTS_SERIAL		(3<<30)
 #define PORT_PTS_PTW		(1<<28)
+#define PORT_PTS_PHCD		(1<<23)
 #define FSL_SOC_USB_PORTSC2	0x188
 #define FSL_SOC_USB_USBMODE	0x1a8
+#define USBMODE_CM_MASK		(3 << 0)	/* controller mode mask */
+#define USBMODE_CM_HOST		(3 << 0)	/* controller mode: host */
+#define USBMODE_ES		(1 << 2)	/* (Big) Endian Select */
+
+#define FSL_SOC_USB_USBGENCTRL 	0x200
+#define USBGENCTRL_PPP 		(1 << 3)
+#define USBGENCTRL_PFP		(1 << 2)
+#define FSL_SOC_USB_ISIPHYCTRL	0x204
+#define ISIPHYCTRL_PXE		(1)
+#define ISIPHYCTRL_PHYE		(1 << 4)
+
 #define FSL_SOC_USB_SNOOP1	0x400	/* NOTE: big-endian */
 #define FSL_SOC_USB_SNOOP2	0x404	/* NOTE: big-endian */
 #define FSL_SOC_USB_AGECNTTHRSH	0x408	/* NOTE: big-endian */
diff --git a/drivers/usb/host/ehci-mem.c b/drivers/usb/host/ehci-mem.c
index aeda96e..1e7e004 100644
--- a/drivers/usb/host/ehci-mem.c
+++ b/drivers/usb/host/ehci-mem.c
@@ -40,7 +40,7 @@ static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
 {
 	memset (qtd, 0, sizeof *qtd);
 	qtd->qtd_dma = dma;
-	qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
+	qtd->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
 	qtd->hw_next = EHCI_LIST_END(ehci);
 	qtd->hw_alt_next = EHCI_LIST_END(ehci);
 	INIT_LIST_HEAD (&qtd->qtd_list);
diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h
index 28e33fe..dfe603f 100644
--- a/include/linux/fsl_devices.h
+++ b/include/linux/fsl_devices.h
@@ -58,11 +58,21 @@ enum fsl_usb2_phy_modes {
 	FSL_USB2_PHY_SERIAL,
 };
 
+struct platform_device;
 struct fsl_usb2_platform_data {
 	/* board specific information */
 	enum fsl_usb2_operating_modes	operating_mode;
 	enum fsl_usb2_phy_modes		phy_mode;
 	unsigned int			port_enables;
+
+	char				*name;		/* pretty print */
+	int (*platform_init) (struct platform_device *);
+	void (*platform_uninit) (struct platform_device *);
+	void __iomem			*regs;	/* ioremap'd register base */
+	unsigned			big_endian_mmio:1;
+	unsigned			big_endian_desc:1;
+	unsigned			es:1;		/* need USBMODE:ES */
+	unsigned			have_sysif_regs:1;
 };
 
 /* Flags in fsl_usb2_mph_platform_data */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (7 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 08/11] powerpc/mpc5121: add USB host support Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-16 18:06   ` Grant Likely
  2010-02-05 13:42 ` [PATCH v3 10/11] powerpc/mpc5121: update mpc5121ads DTS Anatolij Gustschin
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, John Rigby, Anatolij Gustschin

MPC5121 DIU configuration/setup as initialized by the boot
loader currently will get lost while booting Linux. As a
result displaying the boot splash is not possible through
the boot process.

To prevent this we reserve configured DIU frame buffer
address range while booting and preserve AOI descriptor
and gamma table so that DIU continues displaying through
the whole boot process. On first open from user space
DIU frame buffer driver releases the reserved frame
buffer area and continues to operate as usual.

The patch also moves drivers/video/fsl-diu-fb.h file to
include/linux as we use some DIU structures in platform
code.

'diu_ops' callbacks in platform code borrowed from John's
DIU code.

Signed-off-by: John Rigby <jrigby@gmail.com>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
No changes since v2

Changes since v1:
 - specify align attribute before "diu_shared_fb" variable
   name to fix checkpatch warning

 arch/powerpc/platforms/512x/mpc5121_ads.c     |    7 +
 arch/powerpc/platforms/512x/mpc5121_generic.c |   12 +
 arch/powerpc/platforms/512x/mpc512x.h         |    3 +
 arch/powerpc/platforms/512x/mpc512x_shared.c  |  283 +++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.h                 |    1 +
 drivers/video/fsl-diu-fb.c                    |   40 +++-
 {drivers/video => include/linux}/fsl-diu-fb.h |    0
 7 files changed, 341 insertions(+), 5 deletions(-)
 rename {drivers/video => include/linux}/fsl-diu-fb.h (100%)

diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index ee6ae12..aa4d5a8 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -42,6 +42,7 @@ static void __init mpc5121_ads_setup_arch(void)
 	for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
 		mpc83xx_add_bridge(np);
 #endif
+	mpc512x_setup_diu();
 }
 
 static void __init mpc5121_ads_init_IRQ(void)
@@ -60,11 +61,17 @@ static int __init mpc5121_ads_probe(void)
 	return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
 }
 
+void __init mpc5121_ads_init_early(void)
+{
+	mpc512x_init_diu();
+}
+
 define_machine(mpc5121_ads) {
 	.name			= "MPC5121 ADS",
 	.probe			= mpc5121_ads_probe,
 	.setup_arch		= mpc5121_ads_setup_arch,
 	.init			= mpc512x_init,
+	.init_early		= mpc5121_ads_init_early,
 	.init_IRQ		= mpc5121_ads_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
index a6c0e3a..c5ecb3d 100644
--- a/arch/powerpc/platforms/512x/mpc5121_generic.c
+++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
@@ -48,10 +48,22 @@ static int __init mpc5121_generic_probe(void)
 	return board[i] != NULL;
 }
 
+void __init mpc512x_generic_init_early(void)
+{
+	mpc512x_init_diu();
+}
+
+void __init mpc512x_generic_setup_arch(void)
+{
+	mpc512x_setup_diu();
+}
+
 define_machine(mpc5121_generic) {
 	.name			= "MPC5121 generic",
 	.probe			= mpc5121_generic_probe,
 	.init			= mpc512x_init,
+	.init_early		= mpc512x_generic_init_early,
+	.setup_arch		= mpc512x_generic_setup_arch,
 	.init_IRQ		= mpc512x_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index d72b2c7..1cfe9d5 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -17,4 +17,7 @@ extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 extern void mpc512x_restart(char *cmd);
 extern void __init mpc5121_usb_init(void);
+extern void __init mpc512x_init_diu(void);
+extern void __init mpc512x_setup_diu(void);
+extern struct fsl_diu_shared_fb diu_shared_fb;
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 4de8175..65b0a5d 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -16,7 +16,11 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/of_platform.h>
+#include <linux/fsl-diu-fb.h>
+#include <linux/bootmem.h>
+#include <sysdev/fsl_soc.h>
 
+#include <asm/cacheflush.h>
 #include <asm/machdep.h>
 #include <asm/ipic.h>
 #include <asm/prom.h>
@@ -57,6 +61,285 @@ void mpc512x_restart(char *cmd)
 		;
 }
 
+
+struct fsl_diu_shared_fb {
+	char		gamma[0x300];	/* 32-bit aligned! */
+	struct diu_ad	ad0;		/* 32-bit aligned! */
+	phys_addr_t	fb_phys;
+	size_t		fb_len;
+	bool		in_use;
+};
+
+unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
+				      int monitor_port)
+{
+	unsigned int pix_fmt;
+
+	switch (bits_per_pixel) {
+	case 32:
+		pix_fmt = 0x88883316;
+		break;
+	case 24:
+		pix_fmt = 0x88082219;
+		break;
+	case 16:
+		pix_fmt = 0x65053118;
+		break;
+	default:
+		pix_fmt = 0x00000400;
+	}
+	return pix_fmt;
+}
+
+void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+void mpc512x_set_monitor_port(int monitor_port)
+{
+}
+
+#define CCM_SCFR1	0x0000000c
+#define DIU_DIV_MASK	0x000000ff
+void mpc512x_set_pixel_clock(unsigned int pixclock)
+{
+	unsigned long bestval, bestfreq, speed_ccb, busfreq;
+	unsigned long minpixclock, maxpixclock, pixval;
+	struct device_node *np;
+	void __iomem *ccm;
+	u32 temp;
+	long err;
+	int i;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+	if (!np) {
+		pr_err("Can't find clock control module.\n");
+		return;
+	}
+
+	ccm = of_iomap(np, 0);
+	if (!ccm) {
+		pr_err("Can't map clock control module reg.\n");
+		of_node_put(np);
+		return;
+	}
+	of_node_put(np);
+
+	busfreq = 200000000;
+	np = of_find_node_by_type(NULL, "cpu");
+	if (np) {
+		unsigned int size;
+		const unsigned int *prop =
+			of_get_property(np, "bus-frequency", &size);
+		if (prop)
+			busfreq = *prop;
+		of_node_put(np);
+	}
+
+	/* Pixel Clock configuration */
+	pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
+	speed_ccb = busfreq * 4;
+
+	/* Calculate the pixel clock with the smallest error */
+	/* calculate the following in steps to avoid overflow */
+	pr_debug("DIU pixclock in ps - %d\n", pixclock);
+	temp = 1;
+	temp *= 1000000000;
+	temp /= pixclock;
+	temp *= 1000;
+	pixclock = temp;
+	pr_debug("DIU pixclock freq - %u\n", pixclock);
+
+	temp *= 5;
+	temp /= 100;  /* pixclock * 0.05 */
+	pr_debug("deviation = %d\n", temp);
+	minpixclock = pixclock - temp;
+	maxpixclock = pixclock + temp;
+	pr_debug("DIU minpixclock - %lu\n", minpixclock);
+	pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
+	pixval = speed_ccb/pixclock;
+	pr_debug("DIU pixval = %lu\n", pixval);
+
+	err = 100000000;
+	bestval = pixval;
+	pr_debug("DIU bestval = %lu\n", bestval);
+
+	bestfreq = 0;
+	for (i = -1; i <= 1; i++) {
+		temp = speed_ccb / (pixval+i);
+		pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
+			i, pixval, temp);
+		if ((temp < minpixclock) || (temp > maxpixclock))
+			pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
+				minpixclock, maxpixclock);
+		else if (abs(temp - pixclock) < err) {
+			pr_debug("Entered the else if block %d\n", i);
+			err = abs(temp - pixclock);
+			bestval = pixval + i;
+			bestfreq = temp;
+		}
+	}
+
+	pr_debug("DIU chose = %lx\n", bestval);
+	pr_debug("DIU error = %ld\n NomPixClk ", err);
+	pr_debug("DIU: Best Freq = %lx\n", bestfreq);
+	/* Modify DIU_DIV in CCM SCFR1 */
+	temp = in_be32(ccm + CCM_SCFR1);
+	pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
+	temp &= ~DIU_DIV_MASK;
+	temp |= (bestval & DIU_DIV_MASK);
+	out_be32(ccm + CCM_SCFR1, temp);
+	pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
+	iounmap(ccm);
+}
+
+ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0 - 5121 LCD\n");
+}
+
+int mpc512x_set_sysfs_monitor_port(int val)
+{
+	return 0;
+}
+
+struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
+EXPORT_SYMBOL_GPL(diu_shared_fb);
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+    defined(CONFIG_FB_FSL_DIU_MODULE)
+static inline void mpc512x_free_bootmem(struct page *page)
+{
+	__ClearPageReserved(page);
+	BUG_ON(PageTail(page));
+	BUG_ON(atomic_read(&page->_count) > 1);
+	atomic_set(&page->_count, 1);
+	__free_page(page);
+	totalram_pages++;
+}
+
+void mpc512x_release_bootmem(void)
+{
+	unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK;
+	unsigned long size = diu_shared_fb.fb_len;
+	unsigned long start, end;
+
+	if (diu_shared_fb.in_use) {
+		start = PFN_UP(addr);
+		end = PFN_DOWN(addr + size);
+
+		for (; start < end; start++)
+			mpc512x_free_bootmem(pfn_to_page(start));
+
+		diu_shared_fb.in_use = false;
+	}
+	diu_ops.release_bootmem	= NULL;
+}
+#endif
+
+/*
+ * Check if DIU was pre-initialized. If so, perform steps
+ * needed to continue displaying through the whole boot process.
+ * Move area descriptor and gamma table elsewhere, they are
+ * destroyed by bootmem allocator otherwise. The frame buffer
+ * address range will be reserved in setup_arch() after bootmem
+ * allocator is up.
+ */
+void __init mpc512x_init_diu(void)
+{
+	struct device_node *np;
+	void __iomem *diu_reg;
+	phys_addr_t desc;
+	void __iomem *vaddr;
+	unsigned long mode, pix_fmt, res, bpp;
+	unsigned long dst;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,diu");
+	if (!np) {
+		pr_err("No DIU node\n");
+		return;
+	}
+
+	diu_reg = of_iomap(np, 0);
+	of_node_put(np);
+	if (!diu_reg) {
+		pr_err("Can't map DIU\n");
+		return;
+	}
+
+	mode = in_be32(diu_reg + 0x1c);
+	if (mode != 1) {
+		pr_info("%s: DIU OFF\n", __func__);
+		goto out;
+	}
+
+	desc = in_be32(diu_reg);
+	vaddr = ioremap(desc, sizeof(struct diu_ad));
+	if (!vaddr) {
+		pr_err("Can't map DIU area desc.\n");
+		goto out;
+	}
+	memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad));
+	/* flush fb area descriptor */
+	dst = (unsigned long)&diu_shared_fb.ad0;
+	flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1);
+
+	res = in_be32(diu_reg + 0x28);
+	pix_fmt = in_le32(vaddr);
+	bpp = ((pix_fmt >> 16) & 0x3) + 1;
+	diu_shared_fb.fb_phys = in_le32(vaddr + 4);
+	diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp;
+	diu_shared_fb.in_use = true;
+	iounmap(vaddr);
+
+	desc = in_be32(diu_reg + 0xc);
+	vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma));
+	if (!vaddr) {
+		pr_err("Can't map DIU area desc.\n");
+		diu_shared_fb.in_use = false;
+		goto out;
+	}
+	memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma));
+	/* flush gamma table */
+	dst = (unsigned long)&diu_shared_fb.gamma;
+	flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1);
+
+	iounmap(vaddr);
+	out_be32(diu_reg + 0xc, virt_to_phys(&diu_shared_fb.gamma));
+	out_be32(diu_reg + 4, 0);
+	out_be32(diu_reg + 8, 0);
+	out_be32(diu_reg, virt_to_phys(&diu_shared_fb.ad0));
+
+out:
+	iounmap(diu_reg);
+}
+
+void __init mpc512x_setup_diu(void)
+{
+	int ret;
+
+	if (diu_shared_fb.in_use) {
+		ret = reserve_bootmem(diu_shared_fb.fb_phys,
+				      diu_shared_fb.fb_len,
+				      BOOTMEM_EXCLUSIVE);
+		if (ret) {
+			pr_err("%s: reserve bootmem failed\n", __func__);
+			diu_shared_fb.in_use = false;
+		}
+	}
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+    defined(CONFIG_FB_FSL_DIU_MODULE)
+	diu_ops.get_pixel_format	= mpc512x_get_pixel_format;
+	diu_ops.set_gamma_table		= mpc512x_set_gamma_table;
+	diu_ops.set_monitor_port	= mpc512x_set_monitor_port;
+	diu_ops.set_pixel_clock		= mpc512x_set_pixel_clock;
+	diu_ops.show_monitor_port	= mpc512x_show_monitor_port;
+	diu_ops.set_sysfs_monitor_port	= mpc512x_set_sysfs_monitor_port;
+	diu_ops.release_bootmem		= mpc512x_release_bootmem;
+#endif
+}
+
 void __init mpc512x_init_IRQ(void)
 {
 	struct device_node *np;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 19754be..346057d 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -30,6 +30,7 @@ struct platform_diu_data_ops {
 	void (*set_pixel_clock) (unsigned int pixclock);
 	ssize_t (*show_monitor_port) (int monitor_port, char *buf);
 	int (*set_sysfs_monitor_port) (int val);
+	void (*release_bootmem) (void);
 };
 
 extern struct platform_diu_data_ops diu_ops;
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 72d68b3..29c7f31 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -34,7 +34,7 @@
 #include <linux/of_platform.h>
 
 #include <sysdev/fsl_soc.h>
-#include "fsl-diu-fb.h"
+#include <linux/fsl-diu-fb.h>
 
 /*
  * These parameters give default parameters
@@ -178,6 +178,21 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
 		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
 		.vmode		= FB_VMODE_NONINTERLACED
 	},
+	{
+		.name		= "800x480-60",
+		.refresh	= 60,
+		.xres		= 800,
+		.yres		= 480,
+		.pixclock	= 31250,
+		.left_margin	= 86,
+		.right_margin	= 42,
+		.upper_margin	= 33,
+		.lower_margin	= 10,
+		.hsync_len	= 128,
+		.vsync_len	= 2,
+		.sync		= FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED
+	},
 };
 
 static char *fb_mode = "1024x768-32@60";
@@ -329,8 +344,11 @@ static int fsl_diu_enable_panel(struct fb_info *info)
 	if (mfbi->type != MFB_TYPE_OFF) {
 		switch (mfbi->index) {
 		case 0:				/* plane 0 */
-			if (hw->desc[0] != ad->paddr)
+			if (in_be32(&hw->desc[0]) != ad->paddr) {
+				out_be32(&dr.diu_reg->diu_mode, 0);
 				out_be32(&hw->desc[0], ad->paddr);
+				out_be32(&dr.diu_reg->diu_mode, 1);
+			}
 			break;
 		case 1:				/* plane 1 AOI 0 */
 			cmfbi = machine_data->fsl_diu_info[2]->par;
@@ -389,7 +407,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
 
 	switch (mfbi->index) {
 	case 0:					/* plane 0 */
-		if (hw->desc[0] != machine_data->dummy_ad->paddr)
+		if (in_be32(&hw->desc[0]) != machine_data->dummy_ad->paddr)
 			out_be32(&hw->desc[0],
 				machine_data->dummy_ad->paddr);
 		break;
@@ -1100,6 +1118,10 @@ static int fsl_diu_open(struct fb_info *info, int user)
 	struct mfb_info *mfbi = info->par;
 	int res = 0;
 
+	/* free boot splash memory on first /dev/fb0 open */
+	if (!mfbi->index && diu_ops.release_bootmem)
+		diu_ops.release_bootmem();
+
 	spin_lock(&diu_lock);
 	mfbi->count++;
 	if (mfbi->count == 1) {
@@ -1427,6 +1449,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	int ret, i, error = 0;
 	struct resource res;
 	struct fsl_diu_data *machine_data;
+	int diu_mode;
 
 	machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
 	if (!machine_data)
@@ -1463,7 +1486,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 		goto error2;
 	}
 
-	out_be32(&dr.diu_reg->diu_mode, 0);		/* disable DIU anyway*/
+	diu_mode = in_be32(&dr.diu_reg->diu_mode);
+	if (diu_mode != MFB_MODE1)
+		out_be32(&dr.diu_reg->diu_mode, 0);	/* disable DIU */
 
 	/* Get the IRQ of the DIU */
 	machine_data->irq = irq_of_parse_and_map(np, 0);
@@ -1511,7 +1536,12 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	machine_data->dummy_ad->offset_xyd = 0;
 	machine_data->dummy_ad->next_ad = 0;
 
-	out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+	/* Let DIU display splash screen if it was pre-initialized
+	 * by the bootloader, set dummy area descriptor otherwise.
+	 */
+	if (diu_mode != MFB_MODE1)
+		out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+
 	out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
 	out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
 
diff --git a/drivers/video/fsl-diu-fb.h b/include/linux/fsl-diu-fb.h
similarity index 100%
rename from drivers/video/fsl-diu-fb.h
rename to include/linux/fsl-diu-fb.h
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 10/11] powerpc/mpc5121: update mpc5121ads DTS
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (8 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-16 18:11   ` Grant Likely
  2010-02-05 13:42 ` [PATCH v3 11/11] powerpc/mpc5121: Add default config for MPC5121 Anatolij Gustschin
  2010-02-09  8:48 ` [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
  11 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, Anatolij Gustschin, Piotr Ziecik

Collects several changes needed after applying
previous mpc5121 platform and driver patches:

- Add mpc5121 reset module node
- Clean up and fix NAND description, remove unused properties
  here and correct NAND flash chip size.
- Clean up I2C nodes: remove obsolete "cell-index" properties,
  add "fsl,preserve-clocking" property
- Add I2C RTC node for m41t61 RTC
- Add I2C nodes for AD7414 temperature sensor and AT24C32CD3 EEPROM
- Fix compatible property in DMA node
- Clean up CAN nodes, remove unused "cell-index" properties
- Fix compatible property in DIU node
- USB node changes:
    - use "fsl,mpc5121-usb2-dr" compatible property only
    - remove "port0" and "port1" properties as these are only used
      for multi-port host(MHP) module which is not available
      on MPC5121.
    - use 'fsl,invert-drvvbus' and 'fsl,invert-pwr-fault' in
      USB node for internal PHY to specify polarities
      of the appropriate port pins.

Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Detlev Zundel <dzu@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
Changes since v2:
 - update USB nodes, drop "fsl-usb2-dr" property and
   use fsl,mpc5121-usb2-dr" only

Changes since v1:
 - move RTC node for m41t61 RTC to the node for I2C0
 - add nodes for AD74114 and AT24C32CD3 devices
 - remove obsolete "cell-index" properties from i2c nodes
   and add "fsl,preserve-clocking" property
 - Clean up CAN nodes
 - prefix USB properties with 'fsl,'

 arch/powerpc/boot/dts/mpc5121ads.dts |   55 ++++++++++++++++++++-------------
 1 files changed, 33 insertions(+), 22 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index c353dac..d2b2db7 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -62,17 +62,12 @@
 		interrupt-parent = < &ipic >;
 		#address-cells = <1>;
 		#size-cells = <1>;
-		bank-width = <1>;
 		// ADS has two Hynix 512MB Nand flash chips in a single
-		// stacked package .
+		// stacked package.
 		chips = <2>;
-		nand0@0 {
-			label = "nand0";
-			reg = <0x00000000 0x02000000>; 	// first 32 MB of chip 0
-		};
-		nand1@20000000 {
-			label = "nand1";
-			reg = <0x20000000 0x02000000>; 	// first 32 MB of chip 1
+		nand@0 {
+			label = "nand";
+			reg = <0x00000000 0x40000000>;	// 512MB + 512MB
 		};
 	};
 
@@ -166,6 +161,11 @@
 			interrupt-parent = < &ipic >;
 		};
 
+		reset@e00 {	// Reset module
+			compatible = "fsl,mpc5121-reset";
+			reg = <0xe00 0x100>;
+		};
+
 		clock@f00 {	// Clock control
 			compatible = "fsl,mpc5121-clock";
 			reg = <0xf00 0x100>;
@@ -185,17 +185,15 @@
 			interrupt-parent = < &ipic >;
 		};
 
-		mscan@1300 {
+		can@1300 {
 			compatible = "fsl,mpc5121-mscan";
-			cell-index = <0>;
 			interrupts = <12 0x8>;
 			interrupt-parent = < &ipic >;
 			reg = <0x1300 0x80>;
 		};
 
-		mscan@1380 {
+		can@1380 {
 			compatible = "fsl,mpc5121-mscan";
-			cell-index = <1>;
 			interrupts = <13 0x8>;
 			interrupt-parent = < &ipic >;
 			reg = <0x1380 0x80>;
@@ -205,17 +203,31 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
-			cell-index = <0>;
 			reg = <0x1700 0x20>;
 			interrupts = <9 0x8>;
 			interrupt-parent = < &ipic >;
+			fsl,preserve-clocking;
+
+			hwmon@4a {
+				compatible = "adi,ad7414";
+				reg = <0x4a>;
+			};
+
+			eeprom@50 {
+				compatible = "at,24c32";
+				reg = <0x50>;
+			};
+
+			rtc@68 {
+				compatible = "stm,m41t62";
+				reg = <0x68>;
+			};
 		};
 
 		i2c@1720 {
 			#address-cells = <1>;
 			#size-cells = <0>;
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
-			cell-index = <1>;
 			reg = <0x1720 0x20>;
 			interrupts = <10 0x8>;
 			interrupt-parent = < &ipic >;
@@ -225,7 +237,6 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			compatible = "fsl,mpc5121-i2c", "fsl-i2c";
-			cell-index = <2>;
 			reg = <0x1740 0x20>;
 			interrupts = <11 0x8>;
 			interrupt-parent = < &ipic >;
@@ -244,7 +255,7 @@
 		};
 
 		display@2100 {
-			compatible = "fsl,mpc5121-diu", "fsl-diu";
+			compatible = "fsl,mpc5121-diu", "fsl,diu";
 			reg = <0x2100 0x100>;
 			interrupts = <64 0x8>;
 			interrupt-parent = < &ipic >;
@@ -277,7 +288,7 @@
 
 		// USB1 using external ULPI PHY
 		//usb@3000 {
-		//	compatible = "fsl,mpc5121-usb2-dr", "fsl-usb2-dr";
+		//	compatible = "fsl,mpc5121-usb2-dr";
 		//	reg = <0x3000 0x1000>;
 		//	#address-cells = <1>;
 		//	#size-cells = <0>;
@@ -285,12 +296,11 @@
 		//	interrupts = <43 0x8>;
 		//	dr_mode = "otg";
 		//	phy_type = "ulpi";
-		//	port1;
 		//};
 
 		// USB0 using internal UTMI PHY
 		usb@4000 {
-			compatible = "fsl,mpc5121-usb2-dr", "fsl-usb2-dr";
+			compatible = "fsl,mpc5121-usb2-dr";
 			reg = <0x4000 0x1000>;
 			#address-cells = <1>;
 			#size-cells = <0>;
@@ -298,7 +308,8 @@
 			interrupts = <44 0x8>;
 			dr_mode = "otg";
 			phy_type = "utmi_wide";
-			port0;
+			fsl,invert-drvvbus;
+			fsl,invert-pwr-fault;
 		};
 
 		// IO control
@@ -365,7 +376,7 @@
 		};
 
 		dma@14000 {
-			compatible = "fsl,mpc5121-dma2";
+			compatible = "fsl,mpc5121-dma";
 			reg = <0x14000 0x1800>;
 			interrupts = <65 0x8>;
 			interrupt-parent = < &ipic >;
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v3 11/11] powerpc/mpc5121: Add default config for MPC5121
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (9 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 10/11] powerpc/mpc5121: update mpc5121ads DTS Anatolij Gustschin
@ 2010-02-05 13:42 ` Anatolij Gustschin
  2010-02-09  8:48 ` [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
  11 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-05 13:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Anatolij Gustschin, wd, dzu

Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Detlev Zundel <dzu@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
Provide this file for easier testing. Note that FEC
support is not enabled in this config. Enable it
manualy if FEC patches will be used for testing.

Changes since v1:
 - place defconfig file under arch/powerpc/configs/mpc512x_defconfig

 arch/powerpc/configs/mpc512x_defconfig | 1694 ++++++++++++++++++++++++++++++++
 1 files changed, 1694 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/configs/mpc512x_defconfig

diff --git a/arch/powerpc/configs/mpc512x_defconfig b/arch/powerpc/configs/mpc512x_defconfig
new file mode 100644
index 0000000..a047272
--- /dev/null
+++ b/arch/powerpc/configs/mpc512x_defconfig
@@ -0,0 +1,1694 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.33-rc6
+# Fri Feb  5 11:48:29 2010
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_PPC_BOOK3S_32=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_BOOK3S=y
+CONFIG_6xx=y
+CONFIG_PPC_FPU=y
+# CONFIG_ALTIVEC is not set
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_PPC_HAVE_PMU_SUPPORT=y
+# CONFIG_SMP is not set
+CONFIG_NOT_COHERENT_CACHE=y
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+# CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_NR_IRQS=512
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+# CONFIG_PPC_UDBG_16550 is not set
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
+CONFIG_DEFAULT_UIMAGE=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+CONFIG_CONSTRUCTORS=y
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_TREE_RCU=y
+# CONFIG_TREE_PREEMPT_RCU is not set
+# CONFIG_TINY_RCU is not set
+# CONFIG_RCU_TRACE is not set
+CONFIG_RCU_FANOUT=32
+# CONFIG_RCU_FANOUT_EXACT is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+CONFIG_RD_BZIP2=y
+CONFIG_RD_LZMA=y
+CONFIG_RD_LZO=y
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_HAVE_PERF_EVENTS=y
+
+#
+# Kernel Performance Events And Counters
+#
+# CONFIG_PERF_EVENTS is not set
+# CONFIG_PERF_COUNTERS is not set
+CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+
+#
+# GCOV-based kernel profiling
+#
+# CONFIG_SLOW_WORK is not set
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_BLOCK=y
+CONFIG_LBDAF=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_DEADLINE=y
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_DEADLINE=y
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="deadline"
+# CONFIG_INLINE_SPIN_TRYLOCK is not set
+# CONFIG_INLINE_SPIN_TRYLOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK is not set
+# CONFIG_INLINE_SPIN_LOCK_BH is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQ is not set
+# CONFIG_INLINE_SPIN_LOCK_IRQSAVE is not set
+CONFIG_INLINE_SPIN_UNLOCK=y
+# CONFIG_INLINE_SPIN_UNLOCK_BH is not set
+CONFIG_INLINE_SPIN_UNLOCK_IRQ=y
+# CONFIG_INLINE_SPIN_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_READ_TRYLOCK is not set
+# CONFIG_INLINE_READ_LOCK is not set
+# CONFIG_INLINE_READ_LOCK_BH is not set
+# CONFIG_INLINE_READ_LOCK_IRQ is not set
+# CONFIG_INLINE_READ_LOCK_IRQSAVE is not set
+CONFIG_INLINE_READ_UNLOCK=y
+# CONFIG_INLINE_READ_UNLOCK_BH is not set
+CONFIG_INLINE_READ_UNLOCK_IRQ=y
+# CONFIG_INLINE_READ_UNLOCK_IRQRESTORE is not set
+# CONFIG_INLINE_WRITE_TRYLOCK is not set
+# CONFIG_INLINE_WRITE_LOCK is not set
+# CONFIG_INLINE_WRITE_LOCK_BH is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQ is not set
+# CONFIG_INLINE_WRITE_LOCK_IRQSAVE is not set
+CONFIG_INLINE_WRITE_UNLOCK=y
+# CONFIG_INLINE_WRITE_UNLOCK_BH is not set
+CONFIG_INLINE_WRITE_UNLOCK_IRQ=y
+# CONFIG_INLINE_WRITE_UNLOCK_IRQRESTORE is not set
+# CONFIG_MUTEX_SPIN_ON_OWNER is not set
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_CHRP is not set
+CONFIG_PPC_MPC512x=y
+CONFIG_PPC_MPC5121=y
+CONFIG_MPC5121_ADS=y
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+# CONFIG_PPC_86xx is not set
+# CONFIG_EMBEDDED6xx is not set
+# CONFIG_AMIGAONE is not set
+CONFIG_PPC_OF_BOOT_TRAMPOLINE=y
+CONFIG_IPIC=y
+# CONFIG_MPIC is not set
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+# CONFIG_HIGH_RES_TIMERS is not set
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_IOMMU_HELPER is not set
+# CONFIG_SWIOTLB is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+CONFIG_SPARSE_IRQ=y
+CONFIG_MAX_ACTIVE_REGIONS=32
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MIGRATION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+# CONFIG_KSM is not set
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+# CONFIG_CMDLINE_BOOL is not set
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+# CONFIG_SECCOMP is not set
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_FSL_SOC=y
+CONFIG_PPC_PCI_CHOICE=y
+# CONFIG_PCI is not set
+# CONFIG_PCI_DOMAINS is not set
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+# CONFIG_ADVANCED_OPTIONS is not set
+
+#
+# Default settings for advanced configuration options are used
+#
+CONFIG_LOWMEM_SIZE=0x30000000
+CONFIG_PAGE_OFFSET=0xc0000000
+CONFIG_KERNEL_START=0xc0000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE=0xc0000000
+CONFIG_CONSISTENT_SIZE=0x00200000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+# CONFIG_IP_PNP_BOOTP is not set
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_RDS is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
+# CONFIG_IEEE802154 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_CAN=y
+CONFIG_CAN_RAW=y
+CONFIG_CAN_BCM=y
+
+#
+# CAN Device Drivers
+#
+CONFIG_CAN_VCAN=y
+CONFIG_CAN_DEV=y
+# CONFIG_CAN_CALC_BITTIMING is not set
+CONFIG_CAN_MSCAN=y
+# CONFIG_CAN_SJA1000 is not set
+
+#
+# CAN USB interfaces
+#
+# CONFIG_CAN_EMS_USB is not set
+CONFIG_CAN_DEBUG_DEVICES=y
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_DEVTMPFS is not set
+CONFIG_STANDALONE=y
+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
+CONFIG_FW_LOADER=y
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_TESTS is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_OF_PARTS=y
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP_OF=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+CONFIG_MTD_NAND_MPC5121_NFC=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+CONFIG_OF_MDIO=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+# CONFIG_BLK_DEV_LOOP is not set
+
+#
+# DRBD disabled because PROC_FS, INET or CONNECTOR not selected
+#
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_XIP=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_AD525X_DPOT is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_ISL29003 is not set
+# CONFIG_DS1682 is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_MAX6875 is not set
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+# CONFIG_SCSI_PROC_FS is not set
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+CONFIG_CHR_DEV_SG=y
+# CONFIG_CHR_DEV_SCH is not set
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_LIBFCOE is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
+# CONFIG_ATA is not set
+# CONFIG_MD is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+CONFIG_MARVELL_PHY=y
+CONFIG_DAVICOM_PHY=y
+CONFIG_QSEMI_PHY=y
+CONFIG_LXT_PHY=y
+CONFIG_CICADA_PHY=y
+CONFIG_VITESSE_PHY=y
+CONFIG_SMSC_PHY=y
+CONFIG_BROADCOM_PHY=y
+CONFIG_ICPLUS_PHY=y
+CONFIG_REALTEK_PHY=y
+CONFIG_NATIONAL_PHY=y
+CONFIG_STE10XP=y
+CONFIG_LSI_ET1011C_PHY=y
+CONFIG_FIXED_PHY=y
+CONFIG_MDIO_BITBANG=y
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_B44 is not set
+# CONFIG_KS8842 is not set
+# CONFIG_KS8851_MLL is not set
+# CONFIG_XILINX_EMACLITE is not set
+CONFIG_FS_ENET=y
+CONFIG_FS_ENET_MPC5121_FEC=y
+CONFIG_FS_ENET_HAS_FEC=y
+CONFIG_FS_ENET_MDIO_FEC=y
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_WLAN is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+# CONFIG_INPUT_SPARSEKMAP is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ADP5588 is not set
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_QT2160 is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_MAX7359 is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_OPENCORES is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_SENTELIC is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_MOUSE_SYNAPTICS_I2C is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+CONFIG_SERIO_SERPORT=y
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+# CONFIG_SERIO_XILINX_XPS_PS2 is not set
+# CONFIG_SERIO_ALTERA_PS2 is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+# CONFIG_SERIAL_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_MPC52xx=y
+CONFIG_SERIAL_MPC52xx_CONSOLE=y
+CONFIG_SERIAL_MPC52xx_CONSOLE_BAUD=115200
+# CONFIG_SERIAL_GRLIB_GAISLER_APBUART is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_COMPAT=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_DESIGNWARE is not set
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+
+#
+# PPS support
+#
+# CONFIG_PPS is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_PMIC_ADP5520 is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM831X is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_AB3100_CORE is not set
+# CONFIG_MFD_88PM8607 is not set
+# CONFIG_REGULATOR is not set
+CONFIG_MEDIA_SUPPORT=y
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+CONFIG_VIDEO_V4L1_COMPAT=y
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=y
+
+#
+# Multimedia drivers
+#
+CONFIG_IR_CORE=y
+CONFIG_VIDEO_IR=y
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMISE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_MEDIA_TUNER_MC44S803=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+CONFIG_VIDEO_ADV_DEBUG=y
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+CONFIG_VIDEO_IR_I2C=y
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TDA9875 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# RDS decoders
+#
+# CONFIG_VIDEO_SAA6588 is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_ADV7180 is not set
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_MT9V011 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SAA7110 is not set
+CONFIG_VIDEO_SAA711X=y
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+# CONFIG_VIDEO_THS7303 is not set
+# CONFIG_VIDEO_ADV7343 is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+# CONFIG_SOC_CAMERA is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VIDEO_CLASS is not set
+CONFIG_USB_VIDEO_CLASS_INPUT_EVDEV=y
+CONFIG_USB_GSPCA=m
+# CONFIG_USB_M5602 is not set
+# CONFIG_USB_STV06XX is not set
+# CONFIG_USB_GL860 is not set
+# CONFIG_USB_GSPCA_CONEX is not set
+# CONFIG_USB_GSPCA_ETOMS is not set
+# CONFIG_USB_GSPCA_FINEPIX is not set
+# CONFIG_USB_GSPCA_JEILINJ is not set
+# CONFIG_USB_GSPCA_MARS is not set
+# CONFIG_USB_GSPCA_MR97310A is not set
+# CONFIG_USB_GSPCA_OV519 is not set
+# CONFIG_USB_GSPCA_OV534 is not set
+# CONFIG_USB_GSPCA_PAC207 is not set
+# CONFIG_USB_GSPCA_PAC7302 is not set
+# CONFIG_USB_GSPCA_PAC7311 is not set
+# CONFIG_USB_GSPCA_SN9C20X is not set
+# CONFIG_USB_GSPCA_SONIXB is not set
+# CONFIG_USB_GSPCA_SONIXJ is not set
+# CONFIG_USB_GSPCA_SPCA500 is not set
+# CONFIG_USB_GSPCA_SPCA501 is not set
+# CONFIG_USB_GSPCA_SPCA505 is not set
+# CONFIG_USB_GSPCA_SPCA506 is not set
+# CONFIG_USB_GSPCA_SPCA508 is not set
+# CONFIG_USB_GSPCA_SPCA561 is not set
+# CONFIG_USB_GSPCA_SQ905 is not set
+# CONFIG_USB_GSPCA_SQ905C is not set
+# CONFIG_USB_GSPCA_STK014 is not set
+# CONFIG_USB_GSPCA_STV0680 is not set
+# CONFIG_USB_GSPCA_SUNPLUS is not set
+# CONFIG_USB_GSPCA_T613 is not set
+# CONFIG_USB_GSPCA_TV8532 is not set
+# CONFIG_USB_GSPCA_VC032X is not set
+# CONFIG_USB_GSPCA_ZC3XX is not set
+# CONFIG_VIDEO_PVRUSB2 is not set
+# CONFIG_VIDEO_HDPVR is not set
+# CONFIG_VIDEO_EM28XX is not set
+# CONFIG_VIDEO_CX231XX is not set
+# CONFIG_VIDEO_USBVISION is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_ZC0301 is not set
+CONFIG_USB_PWC_INPUT_EVDEV=y
+# CONFIG_USB_ZR364XX is not set
+# CONFIG_USB_STKWEBCAM is not set
+# CONFIG_USB_S2255 is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_I2C_SI4713 is not set
+# CONFIG_RADIO_SI4713 is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_RADIO_SI470X is not set
+# CONFIG_USB_MR800 is not set
+# CONFIG_RADIO_TEA5764 is not set
+# CONFIG_RADIO_TEF6862 is not set
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_OF is not set
+# CONFIG_FB_VGA16 is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_FSL_DIU=y
+# CONFIG_FB_IBM_GXT4500 is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_LOGO is not set
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_DRAGONRISE=y
+# CONFIG_DRAGONRISE_FF is not set
+CONFIG_HID_EZKEY=y
+CONFIG_HID_KYE=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_TWINHAN=y
+CONFIG_HID_KENSINGTON=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+CONFIG_HID_GREENASIA=y
+# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_SMARTJOYPLUS=y
+# CONFIG_SMARTJOYPLUS_FF is not set
+CONFIG_HID_TOPSEED=y
+CONFIG_HID_THRUSTMASTER=y
+# CONFIG_THRUSTMASTER_FF is not set
+CONFIG_HID_ZEROPLUS=y
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+# CONFIG_USB_DEVICEFS is not set
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_EHCI_BIG_ENDIAN_DESC=y
+# CONFIG_XPS_USB_HCD_XILINX is not set
+CONFIG_USB_EHCI_FSL=y
+CONFIG_USB_EHCI_HCD_PPC_OF=y
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+# CONFIG_USB_ISP1362_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
+#
+
+#
+# also be needed; see USB_STORAGE Help for more info
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_NOP_USB_XCEIV is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+CONFIG_RTC_DRV_M41T80=y
+# CONFIG_RTC_DRV_M41T80_WDT is not set
+# CONFIG_RTC_DRV_BQ32K is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+# CONFIG_RTC_DRV_RX8025 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_MSM6242 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_RP5C01 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_GENERIC is not set
+CONFIG_RTC_DRV_MPC5121=y
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+# CONFIG_FSL_DMA is not set
+CONFIG_MPC512X_DMA=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+# CONFIG_NET_DMA is not set
+# CONFIG_ASYNC_TX_DMA is not set
+# CONFIG_DMATEST is not set
+# CONFIG_AUXDISPLAY is not set
+# CONFIG_UIO is not set
+
+#
+# TI VLYNQ
+#
+# CONFIG_STAGING is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+CONFIG_EXT2_FS_XIP=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_FS_XIP=y
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_NILFS2_FS is not set
+CONFIG_FILE_LOCKING=y
+CONFIG_FSNOTIFY=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY is not set
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+# CONFIG_PROC_KCORE is not set
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_XATTR is not set
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_ZLIB=y
+# CONFIG_UBIFS_FS_DEBUG is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+# CONFIG_NLS_CODEPAGE_850 is not set
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+# CONFIG_DLM is not set
+# CONFIG_BINARY_PRINTF is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+CONFIG_CRC16=y
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_DECOMPRESS_GZIP=y
+CONFIG_DECOMPRESS_BZIP2=y
+CONFIG_DECOMPRESS_LZMA=y
+CONFIG_DECOMPRESS_LZO=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
+CONFIG_GENERIC_ATOMIC64=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_STRIP_ASM_SYMS is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+# CONFIG_DEBUG_KERNEL is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_TRACING_SUPPORT=y
+# CONFIG_FTRACE is not set
+# CONFIG_DMA_API_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_PPC_DISABLE_WERROR is not set
+CONFIG_PPC_WERROR=y
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_IRQSTACKS is not set
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_DEFAULT_SECURITY_SELINUX is not set
+# CONFIG_DEFAULT_SECURITY_SMACK is not set
+# CONFIG_DEFAULT_SECURITY_TOMOYO is not set
+CONFIG_DEFAULT_SECURITY_DAC=y
+CONFIG_DEFAULT_SECURITY=""
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+# CONFIG_CRYPTO_VMAC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_GHASH is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_ZLIB is not set
+CONFIG_CRYPTO_LZO=y
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+CONFIG_PPC_CLOCK=y
+CONFIG_PPC_LIB_RHEAP=y
+# CONFIG_VIRTUALIZATION is not set
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 00/11] Update support for MPC512x
  2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
                   ` (10 preceding siblings ...)
  2010-02-05 13:42 ` [PATCH v3 11/11] powerpc/mpc5121: Add default config for MPC5121 Anatolij Gustschin
@ 2010-02-09  8:48 ` Anatolij Gustschin
  11 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-09  8:48 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: wd, dzu, linux-usb, linuxppc-dev, linux-mtd, rtc-linux, Dan Williams

On Fri,  5 Feb 2010 14:42:46 +0100
Anatolij Gustschin <agust@denx.de> wrote:

> The patches are based on v2.6.33-rc6 and cover the following
> items:

These patches can also be pulled from
git://git.denx.de/linux-2.6-denx.git mpc512x-v2.6.33-devel
branch now.

Anatolij

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support
  2010-02-05 13:42 ` [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support Anatolij Gustschin
@ 2010-02-09 23:24   ` Wolfram Sang
  2010-02-15 16:38     ` Anatolij Gustschin
  2010-02-10  2:32   ` Grant Likely
  1 sibling, 1 reply; 48+ messages in thread
From: Wolfram Sang @ 2010-02-09 23:24 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linuxppc-dev, wd, dzu, Piotr Ziecik

[-- Attachment #1: Type: text/plain, Size: 5161 bytes --]

Hi,

On Fri, Feb 05, 2010 at 02:42:48PM +0100, Anatolij Gustschin wrote:
> Add reset module registers representation and
> machine restart callback for mpc5121 platform.
> 

Two comments:

> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
> ---
> Changes since v2:
>  - call mpc512x_restart_init() explicitely from platform
>    init code
> 
> Changes since v1:
>  - use 'struct mpc512x_reset_module *' type for 'reset_module_base'
>  - remove empty line
>  - remove leftover colon and use pr_err() instead of printk.
> 
>  arch/powerpc/include/asm/mpc5xxx.h            |   14 +++++++++-
>  arch/powerpc/platforms/512x/mpc5121_ads.c     |    1 +
>  arch/powerpc/platforms/512x/mpc5121_generic.c |    1 +
>  arch/powerpc/platforms/512x/mpc512x.h         |    1 +
>  arch/powerpc/platforms/512x/mpc512x_shared.c  |   34 +++++++++++++++++++++++++
>  5 files changed, 50 insertions(+), 1 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/mpc5xxx.h b/arch/powerpc/include/asm/mpc5xxx.h
> index 5ce9c5f..0004986 100644
> --- a/arch/powerpc/include/asm/mpc5xxx.h
> +++ b/arch/powerpc/include/asm/mpc5xxx.h
> @@ -18,5 +18,17 @@
>  
>  extern unsigned long mpc5xxx_get_bus_frequency(struct device_node *node);
>  
> -#endif /* __ASM_POWERPC_MPC5xxx_H__ */
> +/* MPC512x Reset module registers */
> +struct mpc512x_reset_module {
> +	u32	rcwlr;	/* Reset Configuration Word Low Register */
> +	u32	rcwhr;	/* Reset Configuration Word High Register */
> +	u32	reserved1;
> +	u32	reserved2;
> +	u32	rsr;	/* Reset Status Register */
> +	u32	rmr;	/* Reset Mode Register */
> +	u32	rpr;	/* Reset Protection Register */
> +	u32	rcr;	/* Reset Control Register */
> +	u32	rcer;	/* Reset Control Enable Register */
> +};
>  
> +#endif /* __ASM_POWERPC_MPC5xxx_H__ */
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
> index 0f8f2e9..ee6ae12 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
> @@ -68,4 +68,5 @@ define_machine(mpc5121_ads) {
>  	.init_IRQ		= mpc5121_ads_init_IRQ,
>  	.get_irq		= ipic_get_irq,
>  	.calibrate_decr		= generic_calibrate_decr,
> +	.restart		= mpc512x_restart,
>  };
> diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
> index 9b8c9b0..a6c0e3a 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_generic.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
> @@ -55,4 +55,5 @@ define_machine(mpc5121_generic) {
>  	.init_IRQ		= mpc512x_init_IRQ,
>  	.get_irq		= ipic_get_irq,
>  	.calibrate_decr		= generic_calibrate_decr,
> +	.restart		= mpc512x_restart,
>  };
> diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
> index ac3da1a..b2daca0 100644
> --- a/arch/powerpc/platforms/512x/mpc512x.h
> +++ b/arch/powerpc/platforms/512x/mpc512x.h
> @@ -15,4 +15,5 @@ extern void __init mpc512x_init_IRQ(void);
>  extern void __init mpc512x_init(void);
>  extern int __init mpc5121_clk_init(void);
>  void __init mpc512x_declare_of_platform_devices(void);
> +extern void mpc512x_restart(char *cmd);
>  #endif				/* __MPC512X_H__ */
> diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
> index b683165..ac0400e 100644
> --- a/arch/powerpc/platforms/512x/mpc512x_shared.c
> +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
> @@ -21,9 +21,42 @@
>  #include <asm/ipic.h>
>  #include <asm/prom.h>
>  #include <asm/time.h>
> +#include <asm/mpc5xxx.h>
>  
>  #include "mpc512x.h"
>  
> +static struct mpc512x_reset_module __iomem *reset_module_base;
> +
> +static int __init mpc512x_restart_init(void)
> +{
> +	struct device_node *np;
> +
> +	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
> +	if (!np)
> +		return -1;
> +
> +	reset_module_base = of_iomap(np, 0);
> +	of_node_put(np);
> +
> +	return 0;
> +}
> +
> +void mpc512x_restart(char *cmd)
> +{
> +	struct mpc512x_reset_module *rm = reset_module_base;

Why not using reset_module_base directly?

> +
> +	if (rm) {
> +		/* Enable software reset "RSTE" */
> +		out_be32(&rm->rpr, 0x52535445);
> +		/* Set software hard reset */
> +		out_be32(&rm->rcr, 0x2);
> +	} else {
> +		pr_err("Restart module not mapped.\n");
> +	}
> +	for (;;)
> +		;
> +}
> +
>  void __init mpc512x_init_IRQ(void)
>  {
>  	struct device_node *np;
> @@ -62,4 +95,5 @@ void __init mpc512x_init(void)
>  {
>  	mpc512x_declare_of_platform_devices();
>  	mpc5121_clk_init();
> +	mpc512x_restart_init();

If the return value is not checked here, you could as well make the function
void. (Not much one could do in the error-case, too.)

>  }
> -- 

Regards,

   Wolfram

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support
  2010-02-05 13:42 ` [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support Anatolij Gustschin
  2010-02-09 23:24   ` Wolfram Sang
@ 2010-02-10  2:32   ` Grant Likely
  2010-02-15 16:51     ` [PATCH v4 " Anatolij Gustschin
  1 sibling, 1 reply; 48+ messages in thread
From: Grant Likely @ 2010-02-10  2:32 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linuxppc-dev, wd, dzu, Piotr Ziecik

On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Add reset module registers representation and
> machine restart callback for mpc5121 platform.
>
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
> ---
> Changes since v2:
> =A0- call mpc512x_restart_init() explicitely from platform
> =A0 init code
>
> Changes since v1:
> =A0- use 'struct mpc512x_reset_module *' type for 'reset_module_base'
> =A0- remove empty line
> =A0- remove leftover colon and use pr_err() instead of printk.
>
> =A0arch/powerpc/include/asm/mpc5xxx.h =A0 =A0 =A0 =A0 =A0 =A0| =A0 14 +++=
++++++-
> =A0arch/powerpc/platforms/512x/mpc5121_ads.c =A0 =A0 | =A0 =A01 +
> =A0arch/powerpc/platforms/512x/mpc5121_generic.c | =A0 =A01 +
> =A0arch/powerpc/platforms/512x/mpc512x.h =A0 =A0 =A0 =A0 | =A0 =A01 +
> =A0arch/powerpc/platforms/512x/mpc512x_shared.c =A0| =A0 34 +++++++++++++=
++++++++++++
> =A05 files changed, 50 insertions(+), 1 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/mpc5xxx.h b/arch/powerpc/include/as=
m/mpc5xxx.h
> index 5ce9c5f..0004986 100644
> --- a/arch/powerpc/include/asm/mpc5xxx.h
> +++ b/arch/powerpc/include/asm/mpc5xxx.h
> @@ -18,5 +18,17 @@
>
> =A0extern unsigned long mpc5xxx_get_bus_frequency(struct device_node *nod=
e);
>
> -#endif /* __ASM_POWERPC_MPC5xxx_H__ */
> +/* MPC512x Reset module registers */
> +struct mpc512x_reset_module {
> + =A0 =A0 =A0 u32 =A0 =A0 rcwlr; =A0/* Reset Configuration Word Low Regis=
ter */
> + =A0 =A0 =A0 u32 =A0 =A0 rcwhr; =A0/* Reset Configuration Word High Regi=
ster */
> + =A0 =A0 =A0 u32 =A0 =A0 reserved1;
> + =A0 =A0 =A0 u32 =A0 =A0 reserved2;
> + =A0 =A0 =A0 u32 =A0 =A0 rsr; =A0 =A0/* Reset Status Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rmr; =A0 =A0/* Reset Mode Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rpr; =A0 =A0/* Reset Protection Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rcr; =A0 =A0/* Reset Control Register */
> + =A0 =A0 =A0 u32 =A0 =A0 rcer; =A0 /* Reset Control Enable Register */
> +};

This isn't useful for 5200.  Create a new file.
arch/powerpc/include/asm/mpc5121.h

g.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 03/11] rtc: Add MPC5121 Real time clock driver
  2010-02-05 13:42 ` [PATCH v3 03/11] rtc: Add MPC5121 Real time clock driver Anatolij Gustschin
@ 2010-02-10  2:39   ` Grant Likely
  2010-02-10 18:25     ` [rtc-linux] " Alessandro Zummo
  0 siblings, 1 reply; 48+ messages in thread
From: Grant Likely @ 2010-02-10  2:39 UTC (permalink / raw)
  To: Anatolij Gustschin, Alessandro Zummo
  Cc: wd, rtc-linux, linuxppc-dev, dzu, Piotr Ziecik

On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Add support for MPC5121 real time clock module.
>
> Signed-off-by: John Rigby <jcrigby@gmail.com>
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: <rtc-linux@googlegroups.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>

Acked-by: Grant Likely <grant.likely@secretlab.ca>

Alessandro, do you want me to carry this one in my powerpc tree along
with the rest of the 5121 patches, or do you want to carry it?  There
aren't any commit ordering issues on this one.

g.

> ---
>
> Changes since v2:
> =A0- change commit message to describe what the patch is
> =A0- use __devinit/__devexit/__devexit_p for the probe/remove hooks
> =A0 and __devinitdata for the match table
> =A0- register device after it is completely set up
>
> Changes since v1 (as requested by Alessandro Zummo):
> =A0- Remove history from the driver file, the same history is in
> =A0 commit message
> =A0- implement alarm/irq interface using ->ops structure, don't
> =A0 use ops->ioctl() any more
> =A0- Clean up probe()
> =A0- replace printk() by dev_*()
> =A0- add arch dependency in Kconfig
> =A0- add requested include linux/init.h
> =A0- move MODULE_XXX to the end
> =A0- use rtc_valid_tm() when returning 'tm'
> =A0- use __init/__exit/__exit_p as this is not a hotpluggable device
>
> =A0drivers/rtc/Kconfig =A0 =A0 =A0 | =A0 10 ++
> =A0drivers/rtc/Makefile =A0 =A0 =A0| =A0 =A01 +
> =A0drivers/rtc/rtc-mpc5121.c | =A0387 +++++++++++++++++++++++++++++++++++=
++++++++++
> =A03 files changed, 398 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/rtc/rtc-mpc5121.c
>
> diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
> index 8167e9e..2bb8a8b 100644
> --- a/drivers/rtc/Kconfig
> +++ b/drivers/rtc/Kconfig
> @@ -868,4 +868,14 @@ config RTC_DRV_MC13783
> =A0 =A0 =A0 =A0help
> =A0 =A0 =A0 =A0 =A0This enables support for the Freescale MC13783 PMIC RT=
C
>
> +config RTC_DRV_MPC5121
> + =A0 =A0 =A0 tristate "Freescale MPC5121 built-in RTC"
> + =A0 =A0 =A0 depends on PPC_MPC512x && RTC_CLASS
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 If you say yes here you will get support for the
> + =A0 =A0 =A0 =A0 built-in RTC MPC5121.
> +
> + =A0 =A0 =A0 =A0 This driver can also be built as a module. If so, the m=
odule
> + =A0 =A0 =A0 =A0 will be called rtc-mpc5121.
> +
> =A0endif # RTC_CLASS
> diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
> index e5160fd..b7148af 100644
> --- a/drivers/rtc/Makefile
> +++ b/drivers/rtc/Makefile
> @@ -55,6 +55,7 @@ obj-$(CONFIG_RTC_DRV_MAX6900) +=3D rtc-max6900.o
> =A0obj-$(CONFIG_RTC_DRV_MAX6902) =A0+=3D rtc-max6902.o
> =A0obj-$(CONFIG_RTC_DRV_MC13783) =A0+=3D rtc-mc13783.o
> =A0obj-$(CONFIG_RTC_DRV_MSM6242) =A0+=3D rtc-msm6242.o
> +obj-$(CONFIG_RTC_DRV_MPC5121) =A0+=3D rtc-mpc5121.o
> =A0obj-$(CONFIG_RTC_DRV_MV) =A0 =A0 =A0 +=3D rtc-mv.o
> =A0obj-$(CONFIG_RTC_DRV_NUC900) =A0 +=3D rtc-nuc900.o
> =A0obj-$(CONFIG_RTC_DRV_OMAP) =A0 =A0 +=3D rtc-omap.o
> diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c
> new file mode 100644
> index 0000000..4313ca0
> --- /dev/null
> +++ b/drivers/rtc/rtc-mpc5121.c
> @@ -0,0 +1,387 @@
> +/*
> + * Real-time clock driver for MPC5121
> + *
> + * Copyright 2007, Domen Puncer <domen.puncer@telargo.com>
> + * Copyright 2008, Freescale Semiconductor, Inc. All rights reserved.
> + *
> + * 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 <linux/init.h>
> +#include <linux/module.h>
> +#include <linux/rtc.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +#include <linux/io.h>
> +
> +struct mpc5121_rtc_regs {
> + =A0 =A0 =A0 u8 set_time; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x00 */
> + =A0 =A0 =A0 u8 hour_set; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x01 */
> + =A0 =A0 =A0 u8 minute_set; =A0 =A0 =A0 =A0 =A0/* RTC + 0x02 */
> + =A0 =A0 =A0 u8 second_set; =A0 =A0 =A0 =A0 =A0/* RTC + 0x03 */
> +
> + =A0 =A0 =A0 u8 set_date; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x04 */
> + =A0 =A0 =A0 u8 month_set; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x05 */
> + =A0 =A0 =A0 u8 weekday_set; =A0 =A0 =A0 =A0 /* RTC + 0x06 */
> + =A0 =A0 =A0 u8 date_set; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x07 */
> +
> + =A0 =A0 =A0 u8 write_sw; =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x08 */
> + =A0 =A0 =A0 u8 sw_set; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x09 */
> + =A0 =A0 =A0 u16 year_set; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x0a */
> +
> + =A0 =A0 =A0 u8 alm_enable; =A0 =A0 =A0 =A0 =A0/* RTC + 0x0c */
> + =A0 =A0 =A0 u8 alm_hour_set; =A0 =A0 =A0 =A0/* RTC + 0x0d */
> + =A0 =A0 =A0 u8 alm_min_set; =A0 =A0 =A0 =A0 /* RTC + 0x0e */
> + =A0 =A0 =A0 u8 int_enable; =A0 =A0 =A0 =A0 =A0/* RTC + 0x0f */
> +
> + =A0 =A0 =A0 u8 reserved1;
> + =A0 =A0 =A0 u8 hour; =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x11 */
> + =A0 =A0 =A0 u8 minute; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x12 */
> + =A0 =A0 =A0 u8 second; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x13 */
> +
> + =A0 =A0 =A0 u8 month; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x14 */
> + =A0 =A0 =A0 u8 wday_mday; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x15 */
> + =A0 =A0 =A0 u16 year; =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x16 */
> +
> + =A0 =A0 =A0 u8 int_alm; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x18 */
> + =A0 =A0 =A0 u8 int_sw; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* RTC + 0x19 */
> + =A0 =A0 =A0 u8 alm_status; =A0 =A0 =A0 =A0 =A0/* RTC + 0x1a */
> + =A0 =A0 =A0 u8 sw_minute; =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1b */
> +
> + =A0 =A0 =A0 u8 bus_error_1; =A0 =A0 =A0 =A0 /* RTC + 0x1c */
> + =A0 =A0 =A0 u8 int_day; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1d */
> + =A0 =A0 =A0 u8 int_min; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1e */
> + =A0 =A0 =A0 u8 int_sec; =A0 =A0 =A0 =A0 =A0 =A0 /* RTC + 0x1f */
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* target_time:
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0intended to be used for hibernation but hib=
ernation
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0does not work on silicon rev 1.5 so use it =
for non-volatile
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0storage of offset between the actual_time r=
egister and linux
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0time
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 target_time; =A0 =A0 =A0 =A0/* RTC + 0x20 */
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* actual_time:
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0readonly time since VBAT_RTC was last conne=
cted
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 actual_time; =A0 =A0 =A0 =A0/* RTC + 0x24 */
> + =A0 =A0 =A0 u32 keep_alive; =A0 =A0 =A0 =A0 /* RTC + 0x28 */
> +};
> +
> +struct mpc5121_rtc_data {
> + =A0 =A0 =A0 unsigned irq;
> + =A0 =A0 =A0 unsigned irq_periodic;
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs;
> + =A0 =A0 =A0 struct rtc_device *rtc;
> + =A0 =A0 =A0 struct rtc_wkalrm wkalarm;
> +};
> +
> +/*
> + * Update second/minute/hour registers.
> + *
> + * This is just so alarm will work.
> + */
> +static void mpc5121_rtc_update_smh(struct mpc5121_rtc_regs __iomem *regs=
,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0stru=
ct rtc_time *tm)
> +{
> + =A0 =A0 =A0 out_8(&regs->second_set, tm->tm_sec);
> + =A0 =A0 =A0 out_8(&regs->minute_set, tm->tm_min);
> + =A0 =A0 =A0 out_8(&regs->hour_set, tm->tm_hour);
> +
> + =A0 =A0 =A0 /* set time sequence */
> + =A0 =A0 =A0 out_8(&regs->set_time, 0x1);
> + =A0 =A0 =A0 out_8(&regs->set_time, 0x3);
> + =A0 =A0 =A0 out_8(&regs->set_time, 0x1);
> + =A0 =A0 =A0 out_8(&regs->set_time, 0x0);
> +}
> +
> +static int mpc5121_rtc_read_time(struct device *dev, struct rtc_time *tm=
)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 unsigned long now;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* linux time is actual_time plus the offset saved in tar=
get_time
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 now =3D in_be32(&regs->actual_time) + in_be32(&regs->target=
_time);
> +
> + =A0 =A0 =A0 rtc_time_to_tm(now, tm);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* update second minute hour registers
> + =A0 =A0 =A0 =A0* so alarms will work
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 mpc5121_rtc_update_smh(regs, tm);
> +
> + =A0 =A0 =A0 return rtc_valid_tm(tm);
> +}
> +
> +static int mpc5121_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 int ret;
> + =A0 =A0 =A0 unsigned long now;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* The actual_time register is read only so we write the =
offset
> + =A0 =A0 =A0 =A0* between it and linux time to the target_time register.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 ret =3D rtc_tm_to_time(tm, &now);
> + =A0 =A0 =A0 if (ret =3D=3D 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&regs->target_time, now - in_be32(=
&regs->actual_time));
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* update second minute hour registers
> + =A0 =A0 =A0 =A0* so alarms will work
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 mpc5121_rtc_update_smh(regs, tm);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_read_alarm(struct device *dev, struct rtc_wkalrm =
*alarm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 *alarm =3D rtc->wkalarm;
> +
> + =A0 =A0 =A0 alarm->pending =3D in_8(&regs->alm_status);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *=
alarm)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* the alarm has no seconds so deal with it
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (alarm->time.tm_sec) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_sec =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_min++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (alarm->time.tm_min >=3D 60) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_min =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time.tm_hour++;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (alarm->time.tm_hour >=
=3D 24)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 alarm->time=
.tm_hour =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 alarm->time.tm_mday =3D -1;
> + =A0 =A0 =A0 alarm->time.tm_mon =3D -1;
> + =A0 =A0 =A0 alarm->time.tm_year =3D -1;
> +
> + =A0 =A0 =A0 out_8(&regs->alm_min_set, alarm->time.tm_min);
> + =A0 =A0 =A0 out_8(&regs->alm_hour_set, alarm->time.tm_hour);
> +
> + =A0 =A0 =A0 out_8(&regs->alm_enable, alarm->enabled);
> +
> + =A0 =A0 =A0 rtc->wkalarm =3D *alarm;
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static irqreturn_t mpc5121_rtc_handler(int irq, void *dev)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata((struct de=
vice *)dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 if (in_8(&regs->int_alm)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* acknowledge and clear status */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->int_alm, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->alm_status, 1);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_=
AF);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return IRQ_HANDLED;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return IRQ_NONE;
> +}
> +
> +static irqreturn_t mpc5121_rtc_handler_upd(int irq, void *dev)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata((struct de=
vice *)dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 if (in_8(&regs->int_sec) && (in_8(&regs->int_enable) & 0x1)=
) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* acknowledge */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_8(&regs->int_sec, 1);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_=
UF);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return IRQ_HANDLED;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return IRQ_NONE;
> +}
> +
> +static int mpc5121_rtc_alarm_irq_enable(struct device *dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 unsigned int enabled)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 int val;
> +
> + =A0 =A0 =A0 if (enabled)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D 1;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D 0;
> +
> + =A0 =A0 =A0 out_8(&regs->alm_enable, val);
> + =A0 =A0 =A0 rtc->wkalarm.enabled =3D val;
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static int mpc5121_rtc_update_irq_enable(struct device *dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0unsigned int enabled)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> + =A0 =A0 =A0 int val;
> +
> + =A0 =A0 =A0 val =3D in_8(&regs->int_enable);
> +
> + =A0 =A0 =A0 if (enabled)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val =3D (val & ~0x8) | 0x1;
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 val &=3D ~0x1;
> +
> + =A0 =A0 =A0 out_8(&regs->int_enable, val);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static const struct rtc_class_ops mpc5121_rtc_ops =3D {
> + =A0 =A0 =A0 .read_time =3D mpc5121_rtc_read_time,
> + =A0 =A0 =A0 .set_time =3D mpc5121_rtc_set_time,
> + =A0 =A0 =A0 .read_alarm =3D mpc5121_rtc_read_alarm,
> + =A0 =A0 =A0 .set_alarm =3D mpc5121_rtc_set_alarm,
> + =A0 =A0 =A0 .alarm_irq_enable =3D mpc5121_rtc_alarm_irq_enable,
> + =A0 =A0 =A0 .update_irq_enable =3D mpc5121_rtc_update_irq_enable,
> +};
> +
> +static int __devinit mpc5121_rtc_probe(struct of_device *op,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 const struct of_device_id *match)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc;
> + =A0 =A0 =A0 int err =3D 0;
> + =A0 =A0 =A0 u32 ka;
> +
> + =A0 =A0 =A0 rtc =3D kzalloc(sizeof(*rtc), GFP_KERNEL);
> + =A0 =A0 =A0 if (!rtc)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> +
> + =A0 =A0 =A0 rtc->regs =3D of_iomap(op->node, 0);
> + =A0 =A0 =A0 if (!rtc->regs) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "%s: couldn't map io spac=
e\n", __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D -ENOSYS;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_free;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 device_init_wakeup(&op->dev, 1);
> +
> + =A0 =A0 =A0 dev_set_drvdata(&op->dev, rtc);
> +
> + =A0 =A0 =A0 rtc->irq =3D irq_of_parse_and_map(op->node, 1);
> + =A0 =A0 =A0 err =3D request_irq(rtc->irq, mpc5121_rtc_handler, IRQF_DIS=
ABLED,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 "mpc5121-rtc", &op->dev);
> + =A0 =A0 =A0 if (err) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "%s: could not request ir=
q: %i\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 __func__, rtc->irq);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_dispose;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rtc->irq_periodic =3D irq_of_parse_and_map(op->node, 0);
> + =A0 =A0 =A0 err =3D request_irq(rtc->irq_periodic, mpc5121_rtc_handler_=
upd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 IRQF_DISABL=
ED, "mpc5121-rtc_upd", &op->dev);
> + =A0 =A0 =A0 if (err) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(&op->dev, "%s: could not request ir=
q: %i\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 __func__, rtc->irq_periodic);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_dispose2;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 ka =3D in_be32(&rtc->regs->keep_alive);
> + =A0 =A0 =A0 if (ka & 0x02) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(&op->dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "mpc5121-rtc: Battery or os=
cillator failure!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&rtc->regs->keep_alive, ka);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rtc->rtc =3D rtc_device_register("mpc5121-rtc", &op->dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 &mpc5121_rtc_ops, THIS_MODULE);
> + =A0 =A0 =A0 if (IS_ERR(rtc->rtc)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D PTR_ERR(rtc->rtc);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out_free_irq;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return 0;
> +
> +out_free_irq:
> + =A0 =A0 =A0 free_irq(rtc->irq_periodic, &op->dev);
> +out_dispose2:
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq_periodic);
> + =A0 =A0 =A0 free_irq(rtc->irq, &op->dev);
> +out_dispose:
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq);
> + =A0 =A0 =A0 iounmap(rtc->regs);
> +out_free:
> + =A0 =A0 =A0 kfree(rtc);
> +
> + =A0 =A0 =A0 return err;
> +}
> +
> +static int __devexit mpc5121_rtc_remove(struct of_device *op)
> +{
> + =A0 =A0 =A0 struct mpc5121_rtc_data *rtc =3D dev_get_drvdata(&op->dev);
> + =A0 =A0 =A0 struct mpc5121_rtc_regs __iomem *regs =3D rtc->regs;
> +
> + =A0 =A0 =A0 /* disable interrupt, so there are no nasty surprises */
> + =A0 =A0 =A0 out_8(&regs->alm_enable, 0);
> + =A0 =A0 =A0 out_8(&regs->int_enable, in_8(&regs->int_enable) & ~0x1);
> +
> + =A0 =A0 =A0 rtc_device_unregister(rtc->rtc);
> + =A0 =A0 =A0 iounmap(rtc->regs);
> + =A0 =A0 =A0 free_irq(rtc->irq, &op->dev);
> + =A0 =A0 =A0 free_irq(rtc->irq_periodic, &op->dev);
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq);
> + =A0 =A0 =A0 irq_dispose_mapping(rtc->irq_periodic);
> + =A0 =A0 =A0 dev_set_drvdata(&op->dev, NULL);
> + =A0 =A0 =A0 kfree(rtc);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static struct of_device_id mpc5121_rtc_match[] __devinitdata =3D {
> + =A0 =A0 =A0 { .compatible =3D "fsl,mpc5121-rtc", },
> + =A0 =A0 =A0 {},
> +};
> +
> +static struct of_platform_driver mpc5121_rtc_driver =3D {
> + =A0 =A0 =A0 .owner =3D THIS_MODULE,
> + =A0 =A0 =A0 .name =3D "mpc5121-rtc",
> + =A0 =A0 =A0 .match_table =3D mpc5121_rtc_match,
> + =A0 =A0 =A0 .probe =3D mpc5121_rtc_probe,
> + =A0 =A0 =A0 .remove =3D __devexit_p(mpc5121_rtc_remove),
> +};
> +
> +static int __init mpc5121_rtc_init(void)
> +{
> + =A0 =A0 =A0 return of_register_platform_driver(&mpc5121_rtc_driver);
> +}
> +module_init(mpc5121_rtc_init);
> +
> +static void __exit mpc5121_rtc_exit(void)
> +{
> + =A0 =A0 =A0 of_unregister_platform_driver(&mpc5121_rtc_driver);
> +}
> +module_exit(mpc5121_rtc_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("John Rigby <jcrigby@gmail.com>");
> --
> 1.6.3.3
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver
  2010-02-05 13:42 ` [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver Anatolij Gustschin
@ 2010-02-10  2:42   ` Grant Likely
  2010-03-30 13:15     ` Artem Bityutskiy
  2010-02-15 17:35   ` [PATCH v4 " Anatolij Gustschin
  1 sibling, 1 reply; 48+ messages in thread
From: Grant Likely @ 2010-02-10  2:42 UTC (permalink / raw)
  To: Anatolij Gustschin, David Woodhouse
  Cc: wd, dzu, linuxppc-dev, linux-mtd, Piotr Ziecik

On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Adds NAND Flash Controller driver for MPC5121 Revision 2.
> All device features, except hardware ECC and power management,
> are supported.
>
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: <linux-mtd@lists.infradead.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>

On *very* brief review...

Acked-by: Grant Likely <grant.likely@secretlab.ca>

David, there are ordering issues on this patch with arch-specific
code.  If the patch looks okay to you, then can I pick it up into my
tree?

Thanks,
g.

> ---
> Changes since v2:
> =A0- move the arch bits into separate patch
> =A0 (it is the next patch in this series now)
> =A0- use __devinit/__devexit/__devexit_p and __devinitdata
>
> Changes since v1:
> =A0- add logfile with changes since previous version
>
> Changes since the patch version submitted in May 2009:
>
> =A0- move mpc5121_nfc.h to the driver .c as there is only one user
> =A0- remove DRV_VERSION macro
> =A0- replace printk() by dev_*()
> =A0- drop unnecessary .suspend and .resume initializations
> =A0- remove duplicate .name/.owner settings
> =A0- fix mpc5121_nfc_init() to "return of_register_platform_driver(&mpc51=
21_nfc_driver);"
> =A0- move module_init() to just below the init function
> =A0- remove MODULE_VERSION
> =A0- use "mtd: Add MPC5121 NAND Flash Controller driver" as the subject,
> =A0 previously it was "mpc5121: Added NAND Flash Controller driver."
>
> =A0drivers/mtd/nand/Kconfig =A0 =A0 =A0 | =A0 =A07 +
> =A0drivers/mtd/nand/Makefile =A0 =A0 =A0| =A0 =A01 +
> =A0drivers/mtd/nand/mpc5121_nfc.c | =A0916 ++++++++++++++++++++++++++++++=
++++++++++
> =A03 files changed, 924 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/mtd/nand/mpc5121_nfc.c
>
> diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
> index 677cd53..099f002 100644
> --- a/drivers/mtd/nand/Kconfig
> +++ b/drivers/mtd/nand/Kconfig
> @@ -442,6 +442,13 @@ config MTD_NAND_FSL_UPM
> =A0 =A0 =A0 =A0 =A0Enables support for NAND Flash chips wired onto Freesc=
ale PowerPC
> =A0 =A0 =A0 =A0 =A0processor localbus with User-Programmable Machine supp=
ort.
>
> +config MTD_NAND_MPC5121_NFC
> + =A0 =A0 =A0 tristate "MPC5121 built-in NAND Flash Controller support"
> + =A0 =A0 =A0 depends on PPC_MPC512x
> + =A0 =A0 =A0 help
> + =A0 =A0 =A0 =A0 This enables the driver for the NAND flash controller o=
n the
> + =A0 =A0 =A0 =A0 MPC5121 SoC.
> +
> =A0config MTD_NAND_MXC
> =A0 =A0 =A0 =A0tristate "MXC NAND support"
> =A0 =A0 =A0 =A0depends on ARCH_MX2 || ARCH_MX3
> diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
> index 1407bd1..d4ddf05 100644
> --- a/drivers/mtd/nand/Makefile
> +++ b/drivers/mtd/nand/Makefile
> @@ -42,5 +42,6 @@ obj-$(CONFIG_MTD_NAND_TXX9NDFMC) =A0 =A0 =A0+=3D txx9nd=
fmc.o
> =A0obj-$(CONFIG_MTD_NAND_W90P910) =A0 =A0 =A0 =A0 +=3D w90p910_nand.o
> =A0obj-$(CONFIG_MTD_NAND_NOMADIK) =A0 =A0 =A0 =A0 +=3D nomadik_nand.o
> =A0obj-$(CONFIG_MTD_NAND_BCM_UMI) =A0 =A0 =A0 =A0 +=3D bcm_umi_nand.o nan=
d_bcm_umi.o
> +obj-$(CONFIG_MTD_NAND_MPC5121_NFC) =A0 =A0 +=3D mpc5121_nfc.o
>
> =A0nand-objs :=3D nand_base.o nand_bbt.o
> diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nf=
c.c
> new file mode 100644
> index 0000000..191bf99
> --- /dev/null
> +++ b/drivers/mtd/nand/mpc5121_nfc.c
> @@ -0,0 +1,916 @@
> +/*
> + * Copyright 2004-2008 Freescale Semiconductor, Inc.
> + * Copyright 2009 Semihalf.
> + *
> + * Approved as OSADL project by a majority of OSADL members and funded
> + * by OSADL membership fees in 2009; =A0for details see www.osadl.org.
> + *
> + * Based on original driver from Freescale Semiconductor
> + * written by John Rigby <jrigby@freescale.com> on basis
> + * of drivers/mtd/nand/mxc_nand.c. Reworked and extended
> + * Piotr Ziecik <kosmo@semihalf.com>.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License
> + * as published by the Free Software Foundation; either version 2
> + * of the License, or (at your option) any later version.
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
> + * MA 02110-1301, USA.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/mtd/mtd.h>
> +#include <linux/mtd/nand.h>
> +#include <linux/mtd/partitions.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +
> +#include <asm/mpc5xxx.h>
> +
> +/* Addresses for NFC MAIN RAM BUFFER areas */
> +#define NFC_MAIN_AREA(n) =A0 =A0 =A0 ((n) * =A00x200)
> +
> +/* Addresses for NFC SPARE BUFFER areas */
> +#define NFC_SPARE_BUFFERS =A0 =A0 =A08
> +#define NFC_SPARE_LEN =A0 =A0 =A0 =A0 =A00x40
> +#define NFC_SPARE_AREA(n) =A0 =A0 =A0(0x1000 + ((n) * NFC_SPARE_LEN))
> +
> +/* MPC5121 NFC registers */
> +#define NFC_BUF_ADDR =A0 =A0 =A0 =A0 =A0 0x1E04
> +#define NFC_FLASH_ADDR =A0 =A0 =A0 =A0 0x1E06
> +#define NFC_FLASH_CMD =A0 =A0 =A0 =A0 =A00x1E08
> +#define NFC_CONFIG =A0 =A0 =A0 =A0 =A0 =A0 0x1E0A
> +#define NFC_ECC_STATUS1 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x1E0C
> +#define NFC_ECC_STATUS2 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x1E0E
> +#define NFC_SPAS =A0 =A0 =A0 =A0 =A0 =A0 =A0 0x1E10
> +#define NFC_WRPROT =A0 =A0 =A0 =A0 =A0 =A0 0x1E12
> +#define NFC_NF_WRPRST =A0 =A0 =A0 =A0 =A00x1E18
> +#define NFC_CONFIG1 =A0 =A0 =A0 =A0 =A0 =A00x1E1A
> +#define NFC_CONFIG2 =A0 =A0 =A0 =A0 =A0 =A00x1E1C
> +#define NFC_UNLOCKSTART_BLK0 =A0 0x1E20
> +#define NFC_UNLOCKEND_BLK0 =A0 =A0 0x1E22
> +#define NFC_UNLOCKSTART_BLK1 =A0 0x1E24
> +#define NFC_UNLOCKEND_BLK1 =A0 =A0 0x1E26
> +#define NFC_UNLOCKSTART_BLK2 =A0 0x1E28
> +#define NFC_UNLOCKEND_BLK2 =A0 =A0 0x1E2A
> +#define NFC_UNLOCKSTART_BLK3 =A0 0x1E2C
> +#define NFC_UNLOCKEND_BLK3 =A0 =A0 0x1E2E
> +
> +/* Bit Definitions: NFC_BUF_ADDR */
> +#define NFC_RBA_MASK =A0 =A0 =A0 =A0 =A0 (7 << 0)
> +#define NFC_ACTIVE_CS_SHIFT =A0 =A05
> +#define NFC_ACTIVE_CS_MASK =A0 =A0 (3 << NFC_ACTIVE_CS_SHIFT)
> +
> +/* Bit Definitions: NFC_CONFIG */
> +#define NFC_BLS_UNLOCKED =A0 =A0 =A0 (1 << 1)
> +
> +/* Bit Definitions: NFC_CONFIG1 */
> +#define NFC_ECC_4BIT =A0 =A0 =A0 =A0 =A0 (1 << 0)
> +#define NFC_FULL_PAGE_DMA =A0 =A0 =A0(1 << 1)
> +#define NFC_SPARE_ONLY =A0 =A0 =A0 =A0 (1 << 2)
> +#define NFC_ECC_ENABLE =A0 =A0 =A0 =A0 (1 << 3)
> +#define NFC_INT_MASK =A0 =A0 =A0 =A0 =A0 (1 << 4)
> +#define NFC_BIG_ENDIAN =A0 =A0 =A0 =A0 (1 << 5)
> +#define NFC_RESET =A0 =A0 =A0 =A0 =A0 =A0 =A0(1 << 6)
> +#define NFC_CE =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (1 << 7)
> +#define NFC_ONE_CYCLE =A0 =A0 =A0 =A0 =A0(1 << 8)
> +#define NFC_PPB_32 =A0 =A0 =A0 =A0 =A0 =A0 (0 << 9)
> +#define NFC_PPB_64 =A0 =A0 =A0 =A0 =A0 =A0 (1 << 9)
> +#define NFC_PPB_128 =A0 =A0 =A0 =A0 =A0 =A0(2 << 9)
> +#define NFC_PPB_256 =A0 =A0 =A0 =A0 =A0 =A0(3 << 9)
> +#define NFC_PPB_MASK =A0 =A0 =A0 =A0 =A0 (3 << 9)
> +#define NFC_FULL_PAGE_INT =A0 =A0 =A0(1 << 11)
> +
> +/* Bit Definitions: NFC_CONFIG2 */
> +#define NFC_COMMAND =A0 =A0 =A0 =A0 =A0 =A0(1 << 0)
> +#define NFC_ADDRESS =A0 =A0 =A0 =A0 =A0 =A0(1 << 1)
> +#define NFC_INPUT =A0 =A0 =A0 =A0 =A0 =A0 =A0(1 << 2)
> +#define NFC_OUTPUT =A0 =A0 =A0 =A0 =A0 =A0 (1 << 3)
> +#define NFC_ID =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (1 << 4)
> +#define NFC_STATUS =A0 =A0 =A0 =A0 =A0 =A0 (1 << 5)
> +#define NFC_CMD_FAIL =A0 =A0 =A0 =A0 =A0 (1 << 15)
> +#define NFC_INT =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0(1 << 15)
> +
> +/* Bit Definitions: NFC_WRPROT */
> +#define NFC_WPC_LOCK_TIGHT =A0 =A0 (1 << 0)
> +#define NFC_WPC_LOCK =A0 =A0 =A0 =A0 =A0 (1 << 1)
> +#define NFC_WPC_UNLOCK =A0 =A0 =A0 =A0 (1 << 2)
> +
> +#define =A0 =A0 =A0 =A0DRV_NAME =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"mpc5121_=
nfc"
> +
> +/* Timeouts */
> +#define NFC_RESET_TIMEOUT =A0 =A0 =A01000 =A0 =A0 =A0 =A0 =A0 =A0/* 1 ms=
 */
> +#define NFC_TIMEOUT =A0 =A0 =A0 =A0 =A0 =A0(HZ / 10) =A0 =A0 =A0 /* 1/10=
 s */
> +
> +struct mpc5121_nfc_prv {
> + =A0 =A0 =A0 struct mtd_info =A0 =A0 =A0 =A0 mtd;
> + =A0 =A0 =A0 struct nand_chip =A0 =A0 =A0 =A0chip;
> + =A0 =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq;
> + =A0 =A0 =A0 void __iomem =A0 =A0 =A0 =A0 =A0 =A0*regs;
> + =A0 =A0 =A0 struct clk =A0 =A0 =A0 =A0 =A0 =A0 =A0*clk;
> + =A0 =A0 =A0 wait_queue_head_t =A0 =A0 =A0 irq_waitq;
> + =A0 =A0 =A0 uint =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0column;
> + =A0 =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 spareonly;
> + =A0 =A0 =A0 void __iomem =A0 =A0 =A0 =A0 =A0 =A0*csreg;
> + =A0 =A0 =A0 struct device =A0 =A0 =A0 =A0 =A0 *dev;
> +};
> +
> +static void mpc5121_nfc_done(struct mtd_info *mtd);
> +
> +#ifdef CONFIG_MTD_PARTITIONS
> +static const char *mpc5121_nfc_pprobes[] =3D { "cmdlinepart", NULL };
> +#endif
> +
> +/* Read NFC register */
> +static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> +
> + =A0 =A0 =A0 return in_be16(prv->regs + reg);
> +}
> +
> +/* Write NFC register */
> +static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> +
> + =A0 =A0 =A0 out_be16(prv->regs + reg, val);
> +}
> +
> +/* Set bits in NFC register */
> +static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
> +{
> + =A0 =A0 =A0 nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
> +}
> +
> +/* Clear bits in NFC register */
> +static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
> +{
> + =A0 =A0 =A0 nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
> +}
> +
> +/* Invoke address cycle */
> +static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
> +{
> + =A0 =A0 =A0 nfc_write(mtd, NFC_FLASH_ADDR, addr);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
> + =A0 =A0 =A0 mpc5121_nfc_done(mtd);
> +}
> +
> +/* Invoke command cycle */
> +static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
> +{
> + =A0 =A0 =A0 nfc_write(mtd, NFC_FLASH_CMD, cmd);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
> + =A0 =A0 =A0 mpc5121_nfc_done(mtd);
> +}
> +
> +/* Send data from NFC buffers to NAND flash */
> +static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
> + =A0 =A0 =A0 mpc5121_nfc_done(mtd);
> +}
> +
> +/* Receive data from NAND flash */
> +static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
> + =A0 =A0 =A0 mpc5121_nfc_done(mtd);
> +}
> +
> +/* Receive ID from NAND flash */
> +static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG2, NFC_ID);
> + =A0 =A0 =A0 mpc5121_nfc_done(mtd);
> +}
> +
> +/* Receive status from NAND flash */
> +static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
> + =A0 =A0 =A0 mpc5121_nfc_done(mtd);
> +}
> +
> +/* NFC interrupt handler */
> +static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
> +{
> + =A0 =A0 =A0 struct mtd_info *mtd =3D data;
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> +
> + =A0 =A0 =A0 nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
> + =A0 =A0 =A0 wake_up(&prv->irq_waitq);
> +
> + =A0 =A0 =A0 return IRQ_HANDLED;
> +}
> +
> +/* Wait for operation complete */
> +static void mpc5121_nfc_done(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> + =A0 =A0 =A0 int rv;
> +
> + =A0 =A0 =A0 if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) =3D=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rv =3D wait_event_timeout(prv->irq_waitq,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (nfc_read(mtd, NFC_CONFIG2)=
 & NFC_INT), NFC_TIMEOUT);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!rv)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_warn(prv->dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Timeout wh=
ile waiting for interrupt.\n");
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
> +}
> +
> +/* Do address cycle(s) */
> +static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int=
 page)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 u32 pagemask =3D chip->pagemask;
> +
> + =A0 =A0 =A0 if (column !=3D -1) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_addr(mtd, column);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (mtd->writesize > 512)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_addr(mtd, =
column >> 8);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (page !=3D -1) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 do {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_addr(mtd, =
page & 0xFF);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 page >>=3D 8;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pagemask >>=3D 8;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 } while (pagemask);
> + =A0 =A0 =A0 }
> +}
> +
> +/* Control chip select signals */
> +static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
> +{
> + =A0 =A0 =A0 if (chip < 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
> + =A0 =A0 =A0 nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NFC_ACTIVE_CS_MASK);
> + =A0 =A0 =A0 nfc_set(mtd, NFC_CONFIG1, NFC_CE);
> +}
> +
> +/* Init external chip select logic on ADS5121 board */
> +static int ads5121_chipselect_init(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> + =A0 =A0 =A0 struct device_node *dn;
> +
> + =A0 =A0 =A0 dn =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-=
cpld");
> + =A0 =A0 =A0 if (dn) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->csreg =3D of_iomap(dn, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(dn);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!prv->csreg)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* CPLD Register 9 controls NAND /CE Lines =
*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->csreg +=3D 9;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 0;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return -EINVAL;
> +}
> +
> +/* Control chips select signal on ADS5121 board */
> +static void ads5121_select_chip(struct mtd_info *mtd, int chip)
> +{
> + =A0 =A0 =A0 struct nand_chip *nand =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D nand->priv;
> + =A0 =A0 =A0 u8 v;
> +
> + =A0 =A0 =A0 v =3D in_8(prv->csreg);
> + =A0 =A0 =A0 v |=3D 0x0F;
> +
> + =A0 =A0 =A0 if (chip >=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_select_chip(mtd, 0);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 v &=3D ~(1 << chip);
> + =A0 =A0 =A0 } else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_select_chip(mtd, -1);
> +
> + =A0 =A0 =A0 out_8(prv->csreg, v);
> +}
> +
> +/* Read NAND Ready/Busy signal */
> +static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* NFC handles ready/busy signal internally. Therefore, t=
his function
> + =A0 =A0 =A0 =A0* always returns status as ready.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 return 1;
> +}
> +
> +/* Write command to NAND flash */
> +static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int column, int page)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> +
> + =A0 =A0 =A0 prv->column =3D (column >=3D 0) ? column : 0;
> + =A0 =A0 =A0 prv->spareonly =3D 0;
> +
> + =A0 =A0 =A0 switch (command) {
> + =A0 =A0 =A0 case NAND_CMD_PAGEPROG:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_prog_page(mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* NFC does not support sub-page reads and writes,
> + =A0 =A0 =A0 =A0* so emulate them using full page transfers.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 case NAND_CMD_READ0:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 column =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case NAND_CMD_READ1:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->column +=3D 256;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 command =3D NAND_CMD_READ0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 column =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case NAND_CMD_READOOB:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->spareonly =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 command =3D NAND_CMD_READ0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 column =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case NAND_CMD_SEQIN:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_command(mtd, NAND_CMD_READ0, co=
lumn, page);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 column =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case NAND_CMD_ERASE1:
> + =A0 =A0 =A0 case NAND_CMD_ERASE2:
> + =A0 =A0 =A0 case NAND_CMD_READID:
> + =A0 =A0 =A0 case NAND_CMD_STATUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mpc5121_nfc_send_cmd(mtd, command);
> + =A0 =A0 =A0 mpc5121_nfc_addr_cycle(mtd, column, page);
> +
> + =A0 =A0 =A0 switch (command) {
> + =A0 =A0 =A0 case NAND_CMD_READ0:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (mtd->writesize > 512)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_cmd(mtd, N=
AND_CMD_READSTART);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_read_page(mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case NAND_CMD_READID:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_read_id(mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case NAND_CMD_STATUS:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_send_read_status(mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (chip->options & NAND_BUSWIDTH_16)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->column =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->column =3D 0;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +}
> +
> +/* Copy data from/to NFC spare buffers. */
> +static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 u8 *buffer, uint size, int wr)
> +{
> + =A0 =A0 =A0 struct nand_chip *nand =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D nand->priv;
> + =A0 =A0 =A0 uint o, s, sbsize, blksize;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* NAND spare area is available through NFC spare buffers=
.
> + =A0 =A0 =A0 =A0* The NFC divides spare area into (page_size / 512) chun=
ks.
> + =A0 =A0 =A0 =A0* Each chunk is placed into separate spare memory area, =
using
> + =A0 =A0 =A0 =A0* first (spare_size / num_of_chunks) bytes of the buffer=
.
> + =A0 =A0 =A0 =A0*
> + =A0 =A0 =A0 =A0* For NAND device in which the spare area is not divided=
 fully
> + =A0 =A0 =A0 =A0* by the number of chunks, number of used bytes in each =
spare
> + =A0 =A0 =A0 =A0* buffer is rounded down to the nearest even number of b=
ytes,
> + =A0 =A0 =A0 =A0* and all remaining bytes are added to the last used spa=
re area.
> + =A0 =A0 =A0 =A0*
> + =A0 =A0 =A0 =A0* For more information read section 26.6.10 of MPC5121e
> + =A0 =A0 =A0 =A0* Microcontroller Reference Manual, Rev. 3.
> + =A0 =A0 =A0 =A0*/
> +
> + =A0 =A0 =A0 /* Calculate number of valid bytes in each spare buffer */
> + =A0 =A0 =A0 sbsize =3D (mtd->oobsize / (mtd->writesize / 512)) & ~1;
> +
> + =A0 =A0 =A0 while (size) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Calculate spare buffer number */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D offset / sbsize;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (s > NFC_SPARE_BUFFERS - 1)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 s =3D NFC_SPARE_BUFFERS - 1=
;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* Calculate offset to requested data blo=
ck in selected spare
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* buffer and its size.
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 o =3D offset - (s * sbsize);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 blksize =3D min(sbsize - o, size);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (wr)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy_toio(prv->regs + NFC=
_SPARE_AREA(s) + o,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 buffer, blksize);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy_fromio(buffer,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->regs +=
 NFC_SPARE_AREA(s) + o, blksize);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 buffer +=3D blksize;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 offset +=3D blksize;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 size -=3D blksize;
> + =A0 =A0 =A0 };
> +}
> +
> +/* Copy data from/to NFC main and spare buffers */
> +static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int =
len,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 int wr=
)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> + =A0 =A0 =A0 uint c =3D prv->column;
> + =A0 =A0 =A0 uint l;
> +
> + =A0 =A0 =A0 /* Handle spare area access */
> + =A0 =A0 =A0 if (prv->spareonly || c >=3D mtd->writesize) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Calculate offset from beginning of spare=
 area */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (c >=3D mtd->writesize)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 c -=3D mtd->writesize;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prv->column +=3D len;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_copy_spare(mtd, c, buf, len, wr=
);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Handle main area access - limit copy length to prevent
> + =A0 =A0 =A0 =A0* crossing main/spare boundary.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 l =3D min((uint)len, mtd->writesize - c);
> + =A0 =A0 =A0 prv->column +=3D l;
> +
> + =A0 =A0 =A0 if (wr)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + =
c, buf, l);
> + =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 memcpy_fromio(buf, prv->regs + NFC_MAIN_ARE=
A(0) + c, l);
> +
> + =A0 =A0 =A0 /* Handle crossing main/spare boundary */
> + =A0 =A0 =A0 if (l !=3D len) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 buf +=3D l;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 len -=3D l;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_buf_copy(mtd, buf, len, wr);
> + =A0 =A0 =A0 }
> +}
> +
> +/* Read data from NFC buffers */
> +static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int =
len)
> +{
> + =A0 =A0 =A0 mpc5121_nfc_buf_copy(mtd, buf, len, 0);
> +}
> +
> +/* Write data to NFC buffers */
> +static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 const u_char *buf, int len)
> +{
> + =A0 =A0 =A0 mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
> +}
> +
> +/* Compare buffer with NAND flash */
> +static int mpc5121_nfc_verify_buf(struct mtd_info *mtd,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 const u_char *buf, int len)
> +{
> + =A0 =A0 =A0 u_char tmp[256];
> + =A0 =A0 =A0 uint bsize;
> +
> + =A0 =A0 =A0 while (len) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 bsize =3D min(len, 256);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc5121_nfc_read_buf(mtd, tmp, bsize);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (memcmp(buf, tmp, bsize))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return 1;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 buf +=3D bsize;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 len -=3D bsize;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/* Read byte from NFC buffers */
> +static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 u8 tmp;
> +
> + =A0 =A0 =A0 mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
> +
> + =A0 =A0 =A0 return tmp;
> +}
> +
> +/* Read word from NFC buffers */
> +static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 u16 tmp;
> +
> + =A0 =A0 =A0 mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
> +
> + =A0 =A0 =A0 return tmp;
> +}
> +
> +/*
> + * Read NFC configuration from Reset Config Word
> + *
> + * NFC is configured during reset in basis of information stored
> + * in Reset Config Word. There is no other way to set NAND block
> + * size, spare size and bus width.
> + */
> +static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> + =A0 =A0 =A0 struct mpc512x_reset_module *rm;
> + =A0 =A0 =A0 struct device_node *rmnode;
> + =A0 =A0 =A0 uint rcw_pagesize =3D 0;
> + =A0 =A0 =A0 uint rcw_sparesize =3D 0;
> + =A0 =A0 =A0 uint rcw_width;
> + =A0 =A0 =A0 uint rcwh;
> + =A0 =A0 =A0 uint romloc, ps;
> +
> + =A0 =A0 =A0 rmnode =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5121=
-reset");
> + =A0 =A0 =A0 if (!rmnode) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(prv->dev, "Missing 'fsl,mpc5121-res=
et' "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 "node in device tree!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENODEV;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rm =3D of_iomap(rmnode, 0);
> + =A0 =A0 =A0 if (!rm) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(prv->dev, "Error mapping reset modu=
le node!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EBUSY;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 rcwh =3D in_be32(&rm->rcwhr);
> +
> + =A0 =A0 =A0 /* Bit 6: NFC bus width */
> + =A0 =A0 =A0 rcw_width =3D ((rcwh >> 6) & 0x1) ? 2 : 1;
> +
> + =A0 =A0 =A0 /* Bit 7: NFC Page/Spare size */
> + =A0 =A0 =A0 ps =3D (rcwh >> 7) & 0x1;
> +
> + =A0 =A0 =A0 /* Bits [22:21]: ROM Location */
> + =A0 =A0 =A0 romloc =3D (rcwh >> 21) & 0x3;
> +
> + =A0 =A0 =A0 /* Decode RCW bits */
> + =A0 =A0 =A0 switch ((ps << 2) | romloc) {
> + =A0 =A0 =A0 case 0x00:
> + =A0 =A0 =A0 case 0x01:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_pagesize =3D 512;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_sparesize =3D 16;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case 0x02:
> + =A0 =A0 =A0 case 0x03:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_pagesize =3D 4096;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_sparesize =3D 128;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case 0x04:
> + =A0 =A0 =A0 case 0x05:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_pagesize =3D 2048;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_sparesize =3D 64;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case 0x06:
> + =A0 =A0 =A0 case 0x07:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_pagesize =3D 4096;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_sparesize =3D 218;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mtd->writesize =3D rcw_pagesize;
> + =A0 =A0 =A0 mtd->oobsize =3D rcw_sparesize;
> + =A0 =A0 =A0 if (rcw_width =3D=3D 2)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 chip->options |=3D NAND_BUSWIDTH_16;
> +
> + =A0 =A0 =A0 dev_notice(prv->dev, "Configured for "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "%u-bit NAN=
D, page size %u "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "with %u sp=
are.\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_width *=
 8, rcw_pagesize,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 rcw_sparesi=
ze);
> + =A0 =A0 =A0 iounmap(rm);
> + =A0 =A0 =A0 of_node_put(rmnode);
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/* Free driver resources */
> +static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
> +{
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> +
> + =A0 =A0 =A0 if (prv->clk) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 clk_disable(prv->clk);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 clk_put(prv->clk);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (prv->csreg)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 iounmap(prv->csreg);
> +}
> +
> +static int __devinit mpc5121_nfc_probe(struct of_device *op,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 const struct of_device_id *match)
> +{
> + =A0 =A0 =A0 struct device_node *rootnode, *dn =3D op->node;
> + =A0 =A0 =A0 struct device *dev =3D &op->dev;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv;
> + =A0 =A0 =A0 struct resource res;
> + =A0 =A0 =A0 struct mtd_info *mtd;
> +#ifdef CONFIG_MTD_PARTITIONS
> + =A0 =A0 =A0 struct mtd_partition *parts;
> +#endif
> + =A0 =A0 =A0 struct nand_chip *chip;
> + =A0 =A0 =A0 unsigned long regs_paddr, regs_size;
> + =A0 =A0 =A0 const uint *chips_no;
> + =A0 =A0 =A0 int resettime =3D 0;
> + =A0 =A0 =A0 int retval =3D 0;
> + =A0 =A0 =A0 int rev, len;
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Check SoC revision. This driver supports only NFC
> + =A0 =A0 =A0 =A0* in MPC5121 revision 2.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 rev =3D (mfspr(SPRN_SVR) >> 4) & 0xF;
> + =A0 =A0 =A0 if (rev !=3D 2) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "SoC revision %u is not suppor=
ted!\n", rev);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENXIO;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 prv =3D devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
> + =A0 =A0 =A0 if (!prv) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Memory exhausted!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mtd =3D &prv->mtd;
> + =A0 =A0 =A0 chip =3D &prv->chip;
> +
> + =A0 =A0 =A0 mtd->priv =3D chip;
> + =A0 =A0 =A0 chip->priv =3D prv;
> + =A0 =A0 =A0 prv->dev =3D dev;
> +
> + =A0 =A0 =A0 /* Read NFC configuration from Reset Config Word */
> + =A0 =A0 =A0 retval =3D mpc5121_nfc_read_hw_config(mtd);
> + =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Unable to read NFC config!\n"=
);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return retval;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 prv->irq =3D irq_of_parse_and_map(dn, 0);
> + =A0 =A0 =A0 if (prv->irq =3D=3D NO_IRQ) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error mapping IRQ!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 retval =3D of_address_to_resource(dn, 0, &res);
> + =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error parsing memory region!\=
n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return retval;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 chips_no =3D of_get_property(dn, "chips", &len);
> + =A0 =A0 =A0 if (!chips_no || len !=3D sizeof(*chips_no)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Invalid/missing 'chips' prope=
rty!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 regs_paddr =3D res.start;
> + =A0 =A0 =A0 regs_size =3D res.end - res.start + 1;
> +
> + =A0 =A0 =A0 if (!devm_request_mem_region(dev, regs_paddr, regs_size, DR=
V_NAME)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error requesting memory regio=
n!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EBUSY;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 prv->regs =3D devm_ioremap(dev, regs_paddr, regs_size);
> + =A0 =A0 =A0 if (!prv->regs) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error mapping memory region!\=
n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mtd->name =3D "MPC5121 NAND";
> + =A0 =A0 =A0 chip->dev_ready =3D mpc5121_nfc_dev_ready;
> + =A0 =A0 =A0 chip->cmdfunc =3D mpc5121_nfc_command;
> + =A0 =A0 =A0 chip->read_byte =3D mpc5121_nfc_read_byte;
> + =A0 =A0 =A0 chip->read_word =3D mpc5121_nfc_read_word;
> + =A0 =A0 =A0 chip->read_buf =3D mpc5121_nfc_read_buf;
> + =A0 =A0 =A0 chip->write_buf =3D mpc5121_nfc_write_buf;
> + =A0 =A0 =A0 chip->verify_buf =3D mpc5121_nfc_verify_buf;
> + =A0 =A0 =A0 chip->select_chip =3D mpc5121_nfc_select_chip;
> + =A0 =A0 =A0 chip->options =3D NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
> + =A0 =A0 =A0 chip->ecc.mode =3D NAND_ECC_SOFT;
> +
> + =A0 =A0 =A0 /* Support external chip-select logic on ADS5121 board */
> + =A0 =A0 =A0 rootnode =3D of_find_node_by_path("/");
> + =A0 =A0 =A0 if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D ads5121_chipselect_init(mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Chipselect in=
it error!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(rootnode);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return retval;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 chip->select_chip =3D ads5121_select_chip;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 of_node_put(rootnode);
> +
> + =A0 =A0 =A0 /* Enable NFC clock */
> + =A0 =A0 =A0 prv->clk =3D clk_get(dev, "nfc_clk");
> + =A0 =A0 =A0 if (!prv->clk) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Unable to acquire NFC clock!\=
n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D -ENODEV;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 clk_enable(prv->clk);
> +
> + =A0 =A0 =A0 /* Reset NAND Flash controller */
> + =A0 =A0 =A0 nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
> + =A0 =A0 =A0 while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (resettime++ >=3D NFC_RESET_TIMEOUT) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Timeout while=
 resetting NFC!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 udelay(1);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Enable write to NFC memory */
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
> +
> + =A0 =A0 =A0 /* Enable write to all NAND pages */
> + =A0 =A0 =A0 nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
> + =A0 =A0 =A0 nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Setup NFC:
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0- Big Endian transfers,
> + =A0 =A0 =A0 =A0* =A0 =A0 =A0- Interrupt after full page read/write.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 NFC_FULL_PAGE_INT);
> +
> + =A0 =A0 =A0 /* Set spare area size */
> + =A0 =A0 =A0 nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
> +
> + =A0 =A0 =A0 init_waitqueue_head(&prv->irq_waitq);
> + =A0 =A0 =A0 retval =3D devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq=
, 0, DRV_NAME,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mtd);
> + =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error requesting IRQ!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Detect NAND chips */
> + =A0 =A0 =A0 if (nand_scan(mtd, *chips_no)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "NAND Flash not found !\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 devm_free_irq(dev, prv->irq, mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D -ENXIO;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Set erase block size */
> + =A0 =A0 =A0 switch (mtd->erasesize / mtd->writesize) {
> + =A0 =A0 =A0 case 32:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case 64:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case 128:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 case 256:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> +
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Unsupported NAND flash!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 devm_free_irq(dev, prv->irq, mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D -ENXIO;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 dev_set_drvdata(dev, mtd);
> +
> + =A0 =A0 =A0 /* Register device in MTD */
> +#ifdef CONFIG_MTD_PARTITIONS
> + =A0 =A0 =A0 retval =3D parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &=
parts, 0);
> +#ifdef CONFIG_MTD_OF_PARTS
> + =A0 =A0 =A0 if (retval =3D=3D 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D of_mtd_parse_partitions(dev, dn,=
 &parts);
> +#endif
> + =A0 =A0 =A0 if (retval < 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error parsing MTD partitions!=
\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 devm_free_irq(dev, prv->irq, mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 if (retval > 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D add_mtd_partitions(mtd, parts, r=
etval);
> + =A0 =A0 =A0 else
> +#endif
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 retval =3D add_mtd_device(mtd);
> +
> + =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error adding MTD device!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 devm_free_irq(dev, prv->irq, mtd);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto error;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return 0;
> +error:
> + =A0 =A0 =A0 mpc5121_nfc_free(dev, mtd);
> + =A0 =A0 =A0 return retval;
> +}
> +
> +static int __devexit mpc5121_nfc_remove(struct of_device *op)
> +{
> + =A0 =A0 =A0 struct device *dev =3D &op->dev;
> + =A0 =A0 =A0 struct mtd_info *mtd =3D dev_get_drvdata(dev);
> + =A0 =A0 =A0 struct nand_chip *chip =3D mtd->priv;
> + =A0 =A0 =A0 struct mpc5121_nfc_prv *prv =3D chip->priv;
> +
> + =A0 =A0 =A0 nand_release(mtd);
> + =A0 =A0 =A0 devm_free_irq(dev, prv->irq, mtd);
> + =A0 =A0 =A0 mpc5121_nfc_free(dev, mtd);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static struct of_device_id mpc5121_nfc_match[] __devinitdata =3D {
> + =A0 =A0 =A0 { .compatible =3D "fsl,mpc5121-nfc", },
> + =A0 =A0 =A0 {},
> +};
> +
> +static struct of_platform_driver mpc5121_nfc_driver =3D {
> + =A0 =A0 =A0 .match_table =A0 =A0=3D mpc5121_nfc_match,
> + =A0 =A0 =A0 .probe =A0 =A0 =A0 =A0 =A0=3D mpc5121_nfc_probe,
> + =A0 =A0 =A0 .remove =A0 =A0 =A0 =A0 =3D __devexit_p(mpc5121_nfc_remove)=
,
> + =A0 =A0 =A0 .driver =A0 =A0 =A0 =A0 =3D {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .name =A0 =3D DRV_NAME,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .owner =A0=3D THIS_MODULE,
> + =A0 =A0 =A0 },
> +};
> +
> +static int __init mpc5121_nfc_init(void)
> +{
> + =A0 =A0 =A0 return of_register_platform_driver(&mpc5121_nfc_driver);
> +}
> +
> +module_init(mpc5121_nfc_init);
> +
> +static void __exit mpc5121_nfc_cleanup(void)
> +{
> + =A0 =A0 =A0 of_unregister_platform_driver(&mpc5121_nfc_driver);
> +}
> +
> +module_exit(mpc5121_nfc_cleanup);
> +
> +MODULE_AUTHOR("Freescale Semiconductor, Inc.");
> +MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
> +MODULE_LICENSE("GPL");
> --
> 1.6.3.3
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 06/11] dma: Add MPC512x DMA driver
  2010-02-05 13:42 ` [PATCH v3 06/11] dma: Add MPC512x DMA driver Anatolij Gustschin
@ 2010-02-10  2:44   ` Grant Likely
  2010-03-01 13:46   ` Anatolij Gustschin
  1 sibling, 0 replies; 48+ messages in thread
From: Grant Likely @ 2010-02-10  2:44 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: wd, dzu, linuxppc-dev, Dan Williams, Piotr Ziecik

On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> From: Piotr Ziecik <kosmo@semihalf.com>
>
> Adds initial version of MPC512x DMA driver.
> Only memory to memory transfers are currenly supported.
>
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>

on brief review...

Acked-by: Grant Likely <grant.likely@secretlab.ca>



> ---
> No changes since v2
>
> Changes since v1:
> =A0- move content of the mpc512x.h into the drivers .c file as
> =A0 it is only used by this DMA driver
> =A0- use __devinit/__devexit/__devexit_p as requested
> =A0- add unregistration of the dma device
> =A0- remove meaningless comment
>
> Changes since patch version submitted in May 2009:
> =A0- don't use wildcards in compatible property, use "fsl,mpc5121-dma"
> =A0- don't add "fsl,mpc5121-dma" compatible to of_bus_ids[] as the
> =A0 dma device is part of IMMR
>
> =A0drivers/dma/Kconfig =A0 =A0 =A0 | =A0 =A07 +
> =A0drivers/dma/Makefile =A0 =A0 =A0| =A0 =A01 +
> =A0drivers/dma/mpc512x_dma.c | =A0800 +++++++++++++++++++++++++++++++++++=
++++++++++
> =A03 files changed, 808 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/dma/mpc512x_dma.c
>
> diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
> index e02d74b..ac67a53 100644
> --- a/drivers/dma/Kconfig
> +++ b/drivers/dma/Kconfig
> @@ -69,6 +69,13 @@ config FSL_DMA
> =A0 =A0 =A0 =A0 =A0The Elo is the DMA controller on some 82xx and 83xx pa=
rts, and the
> =A0 =A0 =A0 =A0 =A0Elo Plus is the DMA controller on 85xx and 86xx parts.
>
> +config MPC512X_DMA
> + =A0 =A0 =A0 tristate "Freescale MPC512x built-in DMA engine support"
> + =A0 =A0 =A0 depends on PPC_MPC512x
> + =A0 =A0 =A0 select DMA_ENGINE
> + =A0 =A0 =A0 ---help---
> + =A0 =A0 =A0 =A0 Enable support for the Freescale MPC512x built-in DMA e=
ngine.
> +
> =A0config MV_XOR
> =A0 =A0 =A0 =A0bool "Marvell XOR engine support"
> =A0 =A0 =A0 =A0depends on PLAT_ORION
> diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
> index 807053d..4696bcf 100644
> --- a/drivers/dma/Makefile
> +++ b/drivers/dma/Makefile
> @@ -4,6 +4,7 @@ obj-$(CONFIG_DMATEST) +=3D dmatest.o
> =A0obj-$(CONFIG_INTEL_IOATDMA) +=3D ioat/
> =A0obj-$(CONFIG_INTEL_IOP_ADMA) +=3D iop-adma.o
> =A0obj-$(CONFIG_FSL_DMA) +=3D fsldma.o
> +obj-$(CONFIG_MPC512X_DMA) +=3D mpc512x_dma.o
> =A0obj-$(CONFIG_MV_XOR) +=3D mv_xor.o
> =A0obj-$(CONFIG_DW_DMAC) +=3D dw_dmac.o
> =A0obj-$(CONFIG_AT_HDMAC) +=3D at_hdmac.o
> diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
> new file mode 100644
> index 0000000..3fdf1f4
> --- /dev/null
> +++ b/drivers/dma/mpc512x_dma.c
> @@ -0,0 +1,800 @@
> +/*
> + * Copyright (C) Freescale Semicondutor, Inc. 2007, 2008.
> + * Copyright (C) Semihalf 2009
> + *
> + * Written by Piotr Ziecik <kosmo@semihalf.com>. Hardware description
> + * (defines, structures and comments) was taken from MPC5121 DMA driver
> + * written by Hongjun Chen <hong-jun.chen@freescale.com>.
> + *
> + * Approved as OSADL project by a majority of OSADL members and funded
> + * by OSADL membership fees in 2009; =A0for details see www.osadl.org.
> + *
> + * This program is free software; you can redistribute it and/or modify =
it
> + * under the terms of the GNU General Public License as published by the=
 Free
> + * Software Foundation; either version 2 of the License, or (at your opt=
ion)
> + * any later version.
> + *
> + * This program is distributed in the hope that it will be useful, but W=
ITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. =A0See the GNU General Public Licen=
se for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License alo=
ng with
> + * this program; if not, write to the Free Software Foundation, Inc., 59
> + * Temple Place - Suite 330, Boston, MA =A002111-1307, USA.
> + *
> + * The full GNU General Public License is included in this distribution =
in the
> + * file called COPYING.
> + */
> +
> +/*
> + * This is initial version of MPC5121 DMA driver. Only memory to memory
> + * transfers are supported (tested using dmatest module).
> + */
> +
> +#include <linux/module.h>
> +#include <linux/dmaengine.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/of_device.h>
> +#include <linux/of_platform.h>
> +
> +#include <linux/random.h>
> +
> +/* Number of DMA Transfer descriptors allocated per channel */
> +#define MPC_DMA_DESCRIPTORS =A0 =A064
> +
> +/* Macro definitions */
> +#define MPC_DMA_CHANNELS =A0 =A0 =A0 64
> +#define MPC_DMA_TCD_OFFSET =A0 =A0 0x1000
> +
> +/* Arbitration mode of group and channel */
> +#define MPC_DMA_DMACR_EDCG =A0 =A0 (1 << 31)
> +#define MPC_DMA_DMACR_ERGA =A0 =A0 (1 << 3)
> +#define MPC_DMA_DMACR_ERCA =A0 =A0 (1 << 2)
> +
> +/* Error codes */
> +#define MPC_DMA_DMAES_VLD =A0 =A0 =A0(1 << 31)
> +#define MPC_DMA_DMAES_GPE =A0 =A0 =A0(1 << 15)
> +#define MPC_DMA_DMAES_CPE =A0 =A0 =A0(1 << 14)
> +#define MPC_DMA_DMAES_ERRCHN(err) \
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 (((err) >> =
8) & 0x3f)
> +#define MPC_DMA_DMAES_SAE =A0 =A0 =A0(1 << 7)
> +#define MPC_DMA_DMAES_SOE =A0 =A0 =A0(1 << 6)
> +#define MPC_DMA_DMAES_DAE =A0 =A0 =A0(1 << 5)
> +#define MPC_DMA_DMAES_DOE =A0 =A0 =A0(1 << 4)
> +#define MPC_DMA_DMAES_NCE =A0 =A0 =A0(1 << 3)
> +#define MPC_DMA_DMAES_SGE =A0 =A0 =A0(1 << 2)
> +#define MPC_DMA_DMAES_SBE =A0 =A0 =A0(1 << 1)
> +#define MPC_DMA_DMAES_DBE =A0 =A0 =A0(1 << 0)
> +
> +#define MPC_DMA_TSIZE_1 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x00
> +#define MPC_DMA_TSIZE_2 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x01
> +#define MPC_DMA_TSIZE_4 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A00x02
> +#define MPC_DMA_TSIZE_16 =A0 =A0 =A0 0x04
> +#define MPC_DMA_TSIZE_32 =A0 =A0 =A0 0x05
> +
> +/* MPC5121 DMA engine registers */
> +struct __attribute__ ((__packed__)) mpc_dma_regs {
> + =A0 =A0 =A0 /* 0x00 */
> + =A0 =A0 =A0 u32 dmacr; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* DMA control regist=
er */
> + =A0 =A0 =A0 u32 dmaes; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* DMA error status *=
/
> + =A0 =A0 =A0 /* 0x08 */
> + =A0 =A0 =A0 u32 dmaerqh; =A0 =A0 =A0 =A0 =A0 =A0/* DMA enable request h=
igh(channels 63~32) */
> + =A0 =A0 =A0 u32 dmaerql; =A0 =A0 =A0 =A0 =A0 =A0/* DMA enable request l=
ow(channels 31~0) */
> + =A0 =A0 =A0 u32 dmaeeih; =A0 =A0 =A0 =A0 =A0 =A0/* DMA enable error int=
errupt high(ch63~32) */
> + =A0 =A0 =A0 u32 dmaeeil; =A0 =A0 =A0 =A0 =A0 =A0/* DMA enable error int=
errupt low(ch31~0) */
> + =A0 =A0 =A0 /* 0x18 */
> + =A0 =A0 =A0 u8 dmaserq; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA set enable reque=
st */
> + =A0 =A0 =A0 u8 dmacerq; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA clear enable req=
uest */
> + =A0 =A0 =A0 u8 dmaseei; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA set enable error=
 interrupt */
> + =A0 =A0 =A0 u8 dmaceei; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA clear enable err=
or interrupt */
> + =A0 =A0 =A0 /* 0x1c */
> + =A0 =A0 =A0 u8 dmacint; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA clear interrupt =
request */
> + =A0 =A0 =A0 u8 dmacerr; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA clear error */
> + =A0 =A0 =A0 u8 dmassrt; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA set start bit */
> + =A0 =A0 =A0 u8 dmacdne; =A0 =A0 =A0 =A0 =A0 =A0 /* DMA clear DONE statu=
s bit */
> + =A0 =A0 =A0 /* 0x20 */
> + =A0 =A0 =A0 u32 dmainth; =A0 =A0 =A0 =A0 =A0 =A0/* DMA interrupt reques=
t high(ch63~32) */
> + =A0 =A0 =A0 u32 dmaintl; =A0 =A0 =A0 =A0 =A0 =A0/* DMA interrupt reques=
t low(ch31~0) */
> + =A0 =A0 =A0 u32 dmaerrh; =A0 =A0 =A0 =A0 =A0 =A0/* DMA error high(ch63~=
32) */
> + =A0 =A0 =A0 u32 dmaerrl; =A0 =A0 =A0 =A0 =A0 =A0/* DMA error low(ch31~0=
) */
> + =A0 =A0 =A0 /* 0x30 */
> + =A0 =A0 =A0 u32 dmahrsh; =A0 =A0 =A0 =A0 =A0 =A0/* DMA hw request statu=
s high(ch63~32) */
> + =A0 =A0 =A0 u32 dmahrsl; =A0 =A0 =A0 =A0 =A0 =A0/* DMA hardware request=
 status low(ch31~0) */
> + =A0 =A0 =A0 u32 dmaihsa; =A0 =A0 =A0 =A0 =A0 =A0/* DMA interrupt high s=
elect AXE(ch63~32) */
> + =A0 =A0 =A0 u32 dmailsa; =A0 =A0 =A0 =A0 =A0 =A0/* DMA interrupt low se=
lect AXE(ch31~0) */
> + =A0 =A0 =A0 /* 0x40 ~ 0xff */
> + =A0 =A0 =A0 u32 reserve0[48]; =A0 =A0 =A0 /* Reserved */
> + =A0 =A0 =A0 /* 0x100 */
> + =A0 =A0 =A0 u8 dchpri[MPC_DMA_CHANNELS];
> + =A0 =A0 =A0 /* DMA channels(0~63) priority */
> +};
> +
> +struct __attribute__ ((__packed__)) mpc_dma_tcd {
> + =A0 =A0 =A0 /* 0x00 */
> + =A0 =A0 =A0 u32 saddr; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Source address */
> +
> + =A0 =A0 =A0 u32 smod:5; =A0 =A0 =A0 =A0 =A0 =A0 /* Source address modul=
o */
> + =A0 =A0 =A0 u32 ssize:3; =A0 =A0 =A0 =A0 =A0 =A0/* Source data transfer=
 size */
> + =A0 =A0 =A0 u32 dmod:5; =A0 =A0 =A0 =A0 =A0 =A0 /* Destination address =
modulo */
> + =A0 =A0 =A0 u32 dsize:3; =A0 =A0 =A0 =A0 =A0 =A0/* Destination data tra=
nsfer size */
> + =A0 =A0 =A0 u32 soff:16; =A0 =A0 =A0 =A0 =A0 =A0/* Signed source addres=
s offset */
> +
> + =A0 =A0 =A0 /* 0x08 */
> + =A0 =A0 =A0 u32 nbytes; =A0 =A0 =A0 =A0 =A0 =A0 /* Inner "minor" byte c=
ount */
> + =A0 =A0 =A0 u32 slast; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Last source addres=
s adjustment */
> + =A0 =A0 =A0 u32 daddr; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Destination addres=
s */
> +
> + =A0 =A0 =A0 /* 0x14 */
> + =A0 =A0 =A0 u32 citer_elink:1; =A0 =A0 =A0/* Enable channel-to-channel =
linking on
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* minor =
loop complete
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 citer_linkch:6; =A0 =A0 /* Link channel for minor loop =
complete */
> + =A0 =A0 =A0 u32 citer:9; =A0 =A0 =A0 =A0 =A0 =A0/* Current "major" iter=
ation count */
> + =A0 =A0 =A0 u32 doff:16; =A0 =A0 =A0 =A0 =A0 =A0/* Signed destination a=
ddress offset */
> +
> + =A0 =A0 =A0 /* 0x18 */
> + =A0 =A0 =A0 u32 dlast_sga; =A0 =A0 =A0 =A0 =A0/* Last Destination addre=
ss adjustment/scatter
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* gather=
 address
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> +
> + =A0 =A0 =A0 /* 0x1c */
> + =A0 =A0 =A0 u32 biter_elink:1; =A0 =A0 =A0/* Enable channel-to-channel =
linking on major
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* loop c=
omplete
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 biter_linkch:6;
> + =A0 =A0 =A0 u32 biter:9; =A0 =A0 =A0 =A0 =A0 =A0/* Beginning "major" it=
eration count */
> + =A0 =A0 =A0 u32 bwc:2; =A0 =A0 =A0 =A0 =A0 =A0 =A0/* Bandwidth control =
*/
> + =A0 =A0 =A0 u32 major_linkch:6; =A0 =A0 /* Link channel number */
> + =A0 =A0 =A0 u32 done:1; =A0 =A0 =A0 =A0 =A0 =A0 /* Channel done */
> + =A0 =A0 =A0 u32 active:1; =A0 =A0 =A0 =A0 =A0 /* Channel active */
> + =A0 =A0 =A0 u32 major_elink:1; =A0 =A0 =A0/* Enable channel-to-channel =
linking on major
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* loop c=
omplete
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 e_sg:1; =A0 =A0 =A0 =A0 =A0 =A0 /* Enable scatter/gathe=
r processing */
> + =A0 =A0 =A0 u32 d_req:1; =A0 =A0 =A0 =A0 =A0 =A0/* Disable request */
> + =A0 =A0 =A0 u32 int_half:1; =A0 =A0 =A0 =A0 /* Enable an interrupt when=
 major counter is
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* half c=
omplete
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 int_maj:1; =A0 =A0 =A0 =A0 =A0/* Enable an interrupt wh=
en major iteration
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0* count =
completes
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 u32 start:1; =A0 =A0 =A0 =A0 =A0 =A0/* Channel start */
> +};
> +
> +struct mpc_dma_desc {
> + =A0 =A0 =A0 struct dma_async_tx_descriptor =A0desc;
> + =A0 =A0 =A0 struct mpc_dma_tcd =A0 =A0 =A0 =A0 =A0 =A0 =A0*tcd;
> + =A0 =A0 =A0 dma_addr_t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tcd_p=
addr;
> + =A0 =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 error;
> + =A0 =A0 =A0 struct list_head =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0node;
> +};
> +
> +struct mpc_dma_chan {
> + =A0 =A0 =A0 struct dma_chan =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 chan;
> + =A0 =A0 =A0 struct list_head =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0free;
> + =A0 =A0 =A0 struct list_head =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0prepared;
> + =A0 =A0 =A0 struct list_head =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0queued;
> + =A0 =A0 =A0 struct list_head =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0active;
> + =A0 =A0 =A0 struct list_head =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0completed;
> + =A0 =A0 =A0 struct mpc_dma_tcd =A0 =A0 =A0 =A0 =A0 =A0 =A0*tcd;
> + =A0 =A0 =A0 dma_addr_t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0tcd_p=
addr;
> + =A0 =A0 =A0 dma_cookie_t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0complet=
ed_cookie;
> +
> + =A0 =A0 =A0 /* Lock for this structure */
> + =A0 =A0 =A0 spinlock_t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0lock;
> +};
> +
> +struct mpc_dma {
> + =A0 =A0 =A0 struct dma_device =A0 =A0 =A0 =A0 =A0 =A0 =A0 dma;
> + =A0 =A0 =A0 struct tasklet_struct =A0 =A0 =A0 =A0 =A0 tasklet;
> + =A0 =A0 =A0 struct mpc_dma_chan =A0 =A0 =A0 =A0 =A0 =A0 channels[MPC_DM=
A_CHANNELS];
> + =A0 =A0 =A0 struct mpc_dma_regs __iomem =A0 =A0 *regs;
> + =A0 =A0 =A0 struct mpc_dma_tcd __iomem =A0 =A0 =A0*tcd;
> + =A0 =A0 =A0 int =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 irq;
> + =A0 =A0 =A0 uint =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0error_status;
> +
> + =A0 =A0 =A0 /* Lock for error_status field in this structure */
> + =A0 =A0 =A0 spinlock_t =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0error=
_status_lock;
> +};
> +
> +#define DRV_NAME =A0 =A0 =A0 "mpc512x_dma"
> +
> +/* Convert struct dma_chan to struct mpc_dma_chan */
> +static inline struct mpc_dma_chan *dma_chan_to_mpc_dma_chan(struct dma_c=
han *c)
> +{
> + =A0 =A0 =A0 return container_of(c, struct mpc_dma_chan, chan);
> +}
> +
> +/* Convert struct dma_chan to struct mpc_dma */
> +static inline struct mpc_dma *dma_chan_to_mpc_dma(struct dma_chan *c)
> +{
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan =3D dma_chan_to_mpc_dma_chan(c);
> + =A0 =A0 =A0 return container_of(mchan, struct mpc_dma, channels[c->chan=
_id]);
> +}
> +
> +/*
> + * Execute all queued DMA descriptors.
> + *
> + * Following requirements must be met while calling mpc_dma_execute():
> + * =A0 =A0 a) mchan->lock is acquired,
> + * =A0 =A0 b) mchan->active list is empty,
> + * =A0 =A0 c) mchan->queued list contains at least one entry.
> + */
> +static void mpc_dma_execute(struct mpc_dma_chan *mchan)
> +{
> + =A0 =A0 =A0 struct mpc_dma *mdma =3D dma_chan_to_mpc_dma(&mchan->chan);
> + =A0 =A0 =A0 struct mpc_dma_desc *first =3D NULL;
> + =A0 =A0 =A0 struct mpc_dma_desc *prev =3D NULL;
> + =A0 =A0 =A0 struct mpc_dma_desc *mdesc;
> + =A0 =A0 =A0 int cid =3D mchan->chan.chan_id;
> +
> + =A0 =A0 =A0 /* Move all queued descriptors to active list */
> + =A0 =A0 =A0 list_splice_tail_init(&mchan->queued, &mchan->active);
> +
> + =A0 =A0 =A0 /* Chain descriptors into one transaction */
> + =A0 =A0 =A0 list_for_each_entry(mdesc, &mchan->active, node) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!first)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 first =3D mdesc;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!prev) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 prev =3D mdesc;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prev->tcd->dlast_sga =3D mdesc->tcd_paddr;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prev->tcd->e_sg =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc->tcd->start =3D 1;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 prev =3D mdesc;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 prev->tcd->start =3D 0;
> + =A0 =A0 =A0 prev->tcd->int_maj =3D 1;
> +
> + =A0 =A0 =A0 /* Send first descriptor in chain into hardware */
> + =A0 =A0 =A0 memcpy_toio(&mdma->tcd[cid], first->tcd, sizeof(struct mpc_=
dma_tcd));
> + =A0 =A0 =A0 out_8(&mdma->regs->dmassrt, cid);
> +}
> +
> +/* Handle interrupt on one half of DMA controller (32 channels) */
> +static void mpc_dma_irq_process(struct mpc_dma *mdma, u32 is, u32 es, in=
t off)
> +{
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan;
> + =A0 =A0 =A0 struct mpc_dma_desc *mdesc;
> + =A0 =A0 =A0 u32 status =3D is | es;
> + =A0 =A0 =A0 int ch;
> +
> + =A0 =A0 =A0 while ((ch =3D fls(status) - 1) >=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 status &=3D ~(1 << ch);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan =3D &mdma->channels[ch + off];
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_lock(&mchan->lock);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Check error status */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & (1 << ch))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_for_each_entry(mdesc, =
&mchan->active, node)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc->erro=
r =3D -EIO;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Execute queued descriptors */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_splice_tail_init(&mchan->active, &mcha=
n->completed);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!list_empty(&mchan->queued))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_dma_execute(mchan);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock(&mchan->lock);
> + =A0 =A0 =A0 }
> +}
> +
> +/* Interrupt handler */
> +static irqreturn_t mpc_dma_irq(int irq, void *data)
> +{
> + =A0 =A0 =A0 struct mpc_dma *mdma =3D data;
> + =A0 =A0 =A0 uint es;
> +
> + =A0 =A0 =A0 /* Save error status register */
> + =A0 =A0 =A0 es =3D in_be32(&mdma->regs->dmaes);
> + =A0 =A0 =A0 spin_lock(&mdma->error_status_lock);
> + =A0 =A0 =A0 if ((es & MPC_DMA_DMAES_VLD) && mdma->error_status =3D=3D 0=
)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdma->error_status =3D es;
> + =A0 =A0 =A0 spin_unlock(&mdma->error_status_lock);
> +
> + =A0 =A0 =A0 /* Handle interrupt on each channel */
> + =A0 =A0 =A0 mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmainth),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 in_be32(&mdma->regs->dmaerrh), 32);
> + =A0 =A0 =A0 mpc_dma_irq_process(mdma, in_be32(&mdma->regs->dmaintl),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 in_be32(&mdma->regs->dmaerrl), 0);
> +
> + =A0 =A0 =A0 /* Ack interrupt on all channels */
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
> +
> + =A0 =A0 =A0 /* Schedule tasklet */
> + =A0 =A0 =A0 tasklet_schedule(&mdma->tasklet);
> +
> + =A0 =A0 =A0 return IRQ_HANDLED;
> +}
> +
> +/* DMA Tasklet */
> +static void mpc_dma_tasklet(unsigned long data)
> +{
> + =A0 =A0 =A0 struct mpc_dma *mdma =3D (void *)data;
> + =A0 =A0 =A0 dma_cookie_t last_cookie =3D 0;
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan;
> + =A0 =A0 =A0 struct mpc_dma_desc *mdesc;
> + =A0 =A0 =A0 struct dma_async_tx_descriptor *desc;
> + =A0 =A0 =A0 unsigned long flags;
> + =A0 =A0 =A0 LIST_HEAD(list);
> + =A0 =A0 =A0 uint es;
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 spin_lock_irqsave(&mdma->error_status_lock, flags);
> + =A0 =A0 =A0 es =3D mdma->error_status;
> + =A0 =A0 =A0 mdma->error_status =3D 0;
> + =A0 =A0 =A0 spin_unlock_irqrestore(&mdma->error_status_lock, flags);
> +
> + =A0 =A0 =A0 /* Print nice error report */
> + =A0 =A0 =A0 if (es) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "Hardware reported followin=
g error(s) on channel %u:\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MPC_DMA_DMAES_ERRCHN(es));
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_GPE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- G=
roup Priority Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_CPE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- C=
hannel Priority Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_SAE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- S=
ource Address Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_SOE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- S=
ource Offset"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 " Configuration Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_DAE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- D=
estination Address"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 " Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_DOE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- D=
estination Offset"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 " Configuration Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_NCE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- N=
Bytes/Citter"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 " Configuration Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_SGE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- S=
catter/Gather"
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 " Configuration Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_SBE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- S=
ource Bus Error\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (es & MPC_DMA_DMAES_DBE)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(mdma->dma.dev, "- D=
estination Bus Error\n");
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 for (i =3D 0; i < mdma->dma.chancnt; i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan =3D &mdma->channels[i];
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Get all completed descriptors */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, flags);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!list_empty(&mchan->completed))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_splice_tail_init(&mcha=
n->completed, &list);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, flags)=
;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (list_empty(&list))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 continue;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Execute callbacks and run dependencies *=
/
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_for_each_entry(mdesc, &list, node) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 desc =3D &mdesc->desc;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (desc->callback)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 desc->callb=
ack(desc->callback_param);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 last_cookie =3D desc->cooki=
e;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dma_run_dependencies(desc);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* Free descriptors */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, flags);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_splice_tail_init(&list, &mchan->free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan->completed_cookie =3D last_cookie;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, flags)=
;
> + =A0 =A0 =A0 }
> +}
> +
> +/* Submit descriptor to hardware */
> +static dma_cookie_t mpc_dma_tx_submit(struct dma_async_tx_descriptor *tx=
d)
> +{
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan =3D dma_chan_to_mpc_dma_chan(txd=
->chan);
> + =A0 =A0 =A0 struct mpc_dma_desc *mdesc;
> + =A0 =A0 =A0 unsigned long flags;
> + =A0 =A0 =A0 dma_cookie_t cookie;
> +
> + =A0 =A0 =A0 mdesc =3D container_of(txd, struct mpc_dma_desc, desc);
> +
> + =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, flags);
> +
> + =A0 =A0 =A0 /* Move descriptor to queue */
> + =A0 =A0 =A0 list_move_tail(&mdesc->node, &mchan->queued);
> +
> + =A0 =A0 =A0 /* If channel is idle, execute all queued descriptors */
> + =A0 =A0 =A0 if (list_empty(&mchan->active))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc_dma_execute(mchan);
> +
> + =A0 =A0 =A0 /* Update cookie */
> + =A0 =A0 =A0 cookie =3D mchan->chan.cookie + 1;
> + =A0 =A0 =A0 if (cookie <=3D 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 cookie =3D 1;
> +
> + =A0 =A0 =A0 mchan->chan.cookie =3D cookie;
> + =A0 =A0 =A0 mdesc->desc.cookie =3D cookie;
> +
> + =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, flags);
> +
> + =A0 =A0 =A0 return cookie;
> +}
> +
> +/* Alloc channel resources */
> +static int mpc_dma_alloc_chan_resources(struct dma_chan *chan)
> +{
> + =A0 =A0 =A0 struct mpc_dma *mdma =3D dma_chan_to_mpc_dma(chan);
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan =3D dma_chan_to_mpc_dma_chan(cha=
n);
> + =A0 =A0 =A0 struct mpc_dma_desc *mdesc;
> + =A0 =A0 =A0 struct mpc_dma_tcd *tcd;
> + =A0 =A0 =A0 dma_addr_t tcd_paddr;
> + =A0 =A0 =A0 unsigned long flags;
> + =A0 =A0 =A0 LIST_HEAD(descs);
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 /* Alloc DMA memory for Transfer Control Descriptors */
> + =A0 =A0 =A0 tcd =3D dma_alloc_coherent(mdma->dma.dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MPC_DMA_DESCRIPTORS * sizeo=
f(struct mpc_dma_tcd),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &tcd_paddr, GFP_KERNEL);
> + =A0 =A0 =A0 if (!tcd)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> +
> + =A0 =A0 =A0 /* Alloc descriptors for this channel */
> + =A0 =A0 =A0 for (i =3D 0; i < MPC_DMA_DESCRIPTORS; i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc =3D kzalloc(sizeof(struct mpc_dma_des=
c), GFP_KERNEL);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (!mdesc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_notice(mdma->dma.dev, "=
Memory allocation error. "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 "Allocated only %u descriptors\n", i);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dma_async_tx_descriptor_init(&mdesc->desc, =
chan);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc->desc.flags =3D DMA_CTRL_ACK;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc->desc.tx_submit =3D mpc_dma_tx_submit=
;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc->tcd =3D &tcd[i];
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc->tcd_paddr =3D tcd_paddr + (i * sizeo=
f(struct mpc_dma_tcd));
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_add_tail(&mdesc->node, &descs);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Return error only if no descriptors were allocated */
> + =A0 =A0 =A0 if (i =3D=3D 0) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dma_free_coherent(mdma->dma.dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MPC_DMA_DESCRIPTORS * sizeo=
f(struct mpc_dma_tcd),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd, tcd_paddr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, flags);
> + =A0 =A0 =A0 mchan->tcd =3D tcd;
> + =A0 =A0 =A0 mchan->tcd_paddr =3D tcd_paddr;
> + =A0 =A0 =A0 list_splice_tail_init(&descs, &mchan->free);
> + =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, flags);
> +
> + =A0 =A0 =A0 /* Enable Error Interrupt */
> + =A0 =A0 =A0 out_8(&mdma->regs->dmaseei, chan->chan_id);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +/* Free channel resources */
> +static void mpc_dma_free_chan_resources(struct dma_chan *chan)
> +{
> + =A0 =A0 =A0 struct mpc_dma *mdma =3D dma_chan_to_mpc_dma(chan);
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan =3D dma_chan_to_mpc_dma_chan(cha=
n);
> + =A0 =A0 =A0 struct mpc_dma_desc *mdesc, *tmp;
> + =A0 =A0 =A0 struct mpc_dma_tcd *tcd;
> + =A0 =A0 =A0 dma_addr_t tcd_paddr;
> + =A0 =A0 =A0 unsigned long flags;
> + =A0 =A0 =A0 LIST_HEAD(descs);
> +
> + =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, flags);
> +
> + =A0 =A0 =A0 /* Channel must be idle */
> + =A0 =A0 =A0 BUG_ON(!list_empty(&mchan->prepared));
> + =A0 =A0 =A0 BUG_ON(!list_empty(&mchan->queued));
> + =A0 =A0 =A0 BUG_ON(!list_empty(&mchan->active));
> + =A0 =A0 =A0 BUG_ON(!list_empty(&mchan->completed));
> +
> + =A0 =A0 =A0 /* Move data */
> + =A0 =A0 =A0 list_splice_tail_init(&mchan->free, &descs);
> + =A0 =A0 =A0 tcd =3D mchan->tcd;
> + =A0 =A0 =A0 tcd_paddr =3D mchan->tcd_paddr;
> +
> + =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, flags);
> +
> + =A0 =A0 =A0 /* Free DMA memory used by descriptors */
> + =A0 =A0 =A0 dma_free_coherent(mdma->dma.dev,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MPC_DMA_DESCRIPTORS * sizeo=
f(struct mpc_dma_tcd),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd, tcd_paddr);
> +
> + =A0 =A0 =A0 /* Free descriptors */
> + =A0 =A0 =A0 list_for_each_entry_safe(mdesc, tmp, &descs, node)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 kfree(mdesc);
> +
> + =A0 =A0 =A0 /* Disable Error Interrupt */
> + =A0 =A0 =A0 out_8(&mdma->regs->dmaceei, chan->chan_id);
> +}
> +
> +/* Send all pending descriptor to hardware */
> +static void mpc_dma_issue_pending(struct dma_chan *chan)
> +{
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* We are posting descriptors to the hardware as soon as
> + =A0 =A0 =A0 =A0* they are ready, so this function does nothing.
> + =A0 =A0 =A0 =A0*/
> +}
> +
> +/* Check request completion status */
> +static enum dma_status
> +mpc_dma_is_tx_complete(struct dma_chan *chan, dma_cookie_t cookie,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 dma_cookie_t *done, dma_cookie_t *used)
> +{
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan =3D dma_chan_to_mpc_dma_chan(cha=
n);
> + =A0 =A0 =A0 unsigned long flags;
> + =A0 =A0 =A0 dma_cookie_t last_used;
> + =A0 =A0 =A0 dma_cookie_t last_complete;
> +
> + =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, flags);
> + =A0 =A0 =A0 last_used =3D mchan->chan.cookie;
> + =A0 =A0 =A0 last_complete =3D mchan->completed_cookie;
> + =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, flags);
> +
> + =A0 =A0 =A0 if (done)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *done =3D last_complete;
> +
> + =A0 =A0 =A0 if (used)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 *used =3D last_used;
> +
> + =A0 =A0 =A0 return dma_async_is_complete(cookie, last_complete, last_us=
ed);
> +}
> +
> +/* Prepare descriptor for memory to memory copy */
> +static struct dma_async_tx_descriptor *
> +mpc_dma_prep_memcpy(struct dma_chan *chan, dma_addr_t dst, dma_addr_t sr=
c,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 size_t len, unsigned long flags)
> +{
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan =3D dma_chan_to_mpc_dma_chan(cha=
n);
> + =A0 =A0 =A0 struct mpc_dma_desc *mdesc =3D NULL;
> + =A0 =A0 =A0 struct mpc_dma_tcd *tcd;
> + =A0 =A0 =A0 unsigned long iflags;
> +
> + =A0 =A0 =A0 /* Get free descriptor */
> + =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, iflags);
> + =A0 =A0 =A0 if (!list_empty(&mchan->free)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdesc =3D list_first_entry(&mchan->free, st=
ruct mpc_dma_desc,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 node);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_del(&mdesc->node);
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, iflags);
> +
> + =A0 =A0 =A0 if (!mdesc)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return NULL;
> +
> + =A0 =A0 =A0 mdesc->error =3D 0;
> + =A0 =A0 =A0 tcd =3D mdesc->tcd;
> +
> + =A0 =A0 =A0 /* Prepare Transfer Control Descriptor for this transaction=
 */
> + =A0 =A0 =A0 memset(tcd, 0, sizeof(struct mpc_dma_tcd));
> +
> + =A0 =A0 =A0 if (IS_ALIGNED(src | dst | len, 32)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->ssize =3D MPC_DMA_TSIZE_32;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->dsize =3D MPC_DMA_TSIZE_32;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->soff =3D 32;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->doff =3D 32;
> + =A0 =A0 =A0 } else if (IS_ALIGNED(src | dst | len, 16)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->ssize =3D MPC_DMA_TSIZE_16;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->dsize =3D MPC_DMA_TSIZE_16;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->soff =3D 16;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->doff =3D 16;
> + =A0 =A0 =A0 } else if (IS_ALIGNED(src | dst | len, 4)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->ssize =3D MPC_DMA_TSIZE_4;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->dsize =3D MPC_DMA_TSIZE_4;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->soff =3D 4;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->doff =3D 4;
> + =A0 =A0 =A0 } else if (IS_ALIGNED(src | dst | len, 2)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->ssize =3D MPC_DMA_TSIZE_2;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->dsize =3D MPC_DMA_TSIZE_2;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->soff =3D 2;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->doff =3D 2;
> + =A0 =A0 =A0 } else {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->ssize =3D MPC_DMA_TSIZE_1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->dsize =3D MPC_DMA_TSIZE_1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->soff =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 tcd->doff =3D 1;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 tcd->saddr =3D src;
> + =A0 =A0 =A0 tcd->daddr =3D dst;
> + =A0 =A0 =A0 tcd->nbytes =3D len;
> + =A0 =A0 =A0 tcd->biter =3D 1;
> + =A0 =A0 =A0 tcd->citer =3D 1;
> +
> + =A0 =A0 =A0 /* Place descriptor in prepared list */
> + =A0 =A0 =A0 spin_lock_irqsave(&mchan->lock, iflags);
> + =A0 =A0 =A0 list_add_tail(&mdesc->node, &mchan->prepared);
> + =A0 =A0 =A0 spin_unlock_irqrestore(&mchan->lock, iflags);
> +
> + =A0 =A0 =A0 return &mdesc->desc;
> +}
> +
> +static int __devinit mpc_dma_probe(struct of_device *op,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 const struct of_device_id *match)
> +{
> + =A0 =A0 =A0 struct device_node *dn =3D op->node;
> + =A0 =A0 =A0 struct device *dev =3D &op->dev;
> + =A0 =A0 =A0 struct dma_device *dma;
> + =A0 =A0 =A0 struct mpc_dma *mdma;
> + =A0 =A0 =A0 struct mpc_dma_chan *mchan;
> + =A0 =A0 =A0 struct resource res;
> + =A0 =A0 =A0 ulong regs_start, regs_size;
> + =A0 =A0 =A0 int retval, i;
> +
> + =A0 =A0 =A0 mdma =3D devm_kzalloc(dev, sizeof(struct mpc_dma), GFP_KERN=
EL);
> + =A0 =A0 =A0 if (!mdma) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Memory exhausted!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mdma->irq =3D irq_of_parse_and_map(dn, 0);
> + =A0 =A0 =A0 if (mdma->irq =3D=3D NO_IRQ) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error mapping IRQ!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 retval =3D of_address_to_resource(dn, 0, &res);
> + =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error parsing memory region!\=
n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return retval;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 regs_start =3D res.start;
> + =A0 =A0 =A0 regs_size =3D res.end - res.start + 1;
> +
> + =A0 =A0 =A0 if (!devm_request_mem_region(dev, regs_start, regs_size, DR=
V_NAME)) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error requesting memory regio=
n!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EBUSY;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mdma->regs =3D devm_ioremap(dev, regs_start, regs_size);
> + =A0 =A0 =A0 if (!mdma->regs) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error mapping memory region!\=
n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -ENOMEM;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mdma->tcd =3D (struct mpc_dma_tcd *)((u8 *)(mdma->regs)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 + MPC_DMA_TCD_OFFSET);
> +
> + =A0 =A0 =A0 retval =3D devm_request_irq(dev, mdma->irq, &mpc_dma_irq, 0=
, DRV_NAME,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mdma);
> + =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dev_err(dev, "Error requesting IRQ!\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 spin_lock_init(&mdma->error_status_lock);
> +
> + =A0 =A0 =A0 dma =3D &mdma->dma;
> + =A0 =A0 =A0 dma->dev =3D dev;
> + =A0 =A0 =A0 dma->chancnt =3D MPC_DMA_CHANNELS;
> + =A0 =A0 =A0 dma->device_alloc_chan_resources =3D mpc_dma_alloc_chan_res=
ources;
> + =A0 =A0 =A0 dma->device_free_chan_resources =3D mpc_dma_free_chan_resou=
rces;
> + =A0 =A0 =A0 dma->device_issue_pending =3D mpc_dma_issue_pending;
> + =A0 =A0 =A0 dma->device_is_tx_complete =3D mpc_dma_is_tx_complete;
> + =A0 =A0 =A0 dma->device_prep_dma_memcpy =3D mpc_dma_prep_memcpy;
> +
> + =A0 =A0 =A0 INIT_LIST_HEAD(&dma->channels);
> + =A0 =A0 =A0 dma_cap_set(DMA_MEMCPY, dma->cap_mask);
> +
> + =A0 =A0 =A0 for (i =3D 0; i < dma->chancnt; i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan =3D &mdma->channels[i];
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan->chan.device =3D dma;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan->chan.chan_id =3D i;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan->chan.cookie =3D 1;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 mchan->completed_cookie =3D mchan->chan.coo=
kie;
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 INIT_LIST_HEAD(&mchan->free);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 INIT_LIST_HEAD(&mchan->prepared);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 INIT_LIST_HEAD(&mchan->queued);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 INIT_LIST_HEAD(&mchan->active);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 INIT_LIST_HEAD(&mchan->completed);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 spin_lock_init(&mchan->lock);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 list_add_tail(&mchan->chan.device_node, &dm=
a->channels);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 tasklet_init(&mdma->tasklet, mpc_dma_tasklet, (unsigned lon=
g)mdma);
> +
> + =A0 =A0 =A0 /*
> + =A0 =A0 =A0 =A0* Configure DMA Engine:
> + =A0 =A0 =A0 =A0* - Dynamic clock,
> + =A0 =A0 =A0 =A0* - Round-robin group arbitration,
> + =A0 =A0 =A0 =A0* - Round-robin channel arbitration.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmacr, MPC_DMA_DMACR_EDCG |
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 MPC_DMA_DMA=
CR_ERGA | MPC_DMA_DMACR_ERCA);
> +
> + =A0 =A0 =A0 /* Disable hardware DMA requests */
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaerqh, 0);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaerql, 0);
> +
> + =A0 =A0 =A0 /* Disable error interrupts */
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaeeih, 0);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaeeil, 0);
> +
> + =A0 =A0 =A0 /* Clear interrupts status */
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmainth, 0xFFFFFFFF);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaintl, 0xFFFFFFFF);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaerrh, 0xFFFFFFFF);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaerrl, 0xFFFFFFFF);
> +
> + =A0 =A0 =A0 /* Route interrupts to IPIC */
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmaihsa, 0);
> + =A0 =A0 =A0 out_be32(&mdma->regs->dmailsa, 0);
> +
> + =A0 =A0 =A0 /* Register DMA engine */
> + =A0 =A0 =A0 dev_set_drvdata(dev, mdma);
> + =A0 =A0 =A0 retval =3D dma_async_device_register(dma);
> + =A0 =A0 =A0 if (retval) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 devm_free_irq(dev, mdma->irq, mdma);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 irq_dispose_mapping(mdma->irq);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 return retval;
> +}
> +
> +static int __devexit mpc_dma_remove(struct of_device *op)
> +{
> + =A0 =A0 =A0 struct device *dev =3D &op->dev;
> + =A0 =A0 =A0 struct mpc_dma *mdma =3D dev_get_drvdata(dev);
> +
> + =A0 =A0 =A0 dma_async_device_unregister(&mdma->dma);
> + =A0 =A0 =A0 devm_free_irq(dev, mdma->irq, mdma);
> + =A0 =A0 =A0 irq_dispose_mapping(mdma->irq);
> +
> + =A0 =A0 =A0 return 0;
> +}
> +
> +static struct of_device_id mpc_dma_match[] =3D {
> + =A0 =A0 =A0 { .compatible =3D "fsl,mpc5121-dma", },
> + =A0 =A0 =A0 {},
> +};
> +
> +static struct of_platform_driver mpc_dma_driver =3D {
> + =A0 =A0 =A0 .match_table =A0 =A0=3D mpc_dma_match,
> + =A0 =A0 =A0 .probe =A0 =A0 =A0 =A0 =A0=3D mpc_dma_probe,
> + =A0 =A0 =A0 .remove =A0 =A0 =A0 =A0 =3D __devexit_p(mpc_dma_remove),
> + =A0 =A0 =A0 .driver =A0 =A0 =A0 =A0 =3D {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .name =A0 =3D DRV_NAME,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .owner =A0=3D THIS_MODULE,
> + =A0 =A0 =A0 },
> +};
> +
> +static int __init mpc_dma_init(void)
> +{
> + =A0 =A0 =A0 return of_register_platform_driver(&mpc_dma_driver);
> +}
> +module_init(mpc_dma_init);
> +
> +static void __exit mpc_dma_exit(void)
> +{
> + =A0 =A0 =A0 of_unregister_platform_driver(&mpc_dma_driver);
> +}
> +module_exit(mpc_dma_exit);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("Piotr Ziecik <kosmo@semihalf.com>");
> --
> 1.6.3.3
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [rtc-linux] Re: [PATCH v3 03/11] rtc: Add MPC5121 Real time clock  driver
  2010-02-10  2:39   ` Grant Likely
@ 2010-02-10 18:25     ` Alessandro Zummo
  0 siblings, 0 replies; 48+ messages in thread
From: Alessandro Zummo @ 2010-02-10 18:25 UTC (permalink / raw)
  To: rtc-linux
  Cc: Alessandro Zummo, wd, dzu, linuxppc-dev, Anatolij Gustschin,
	Piotr Ziecik

On Tue, 9 Feb 2010 19:39:35 -0700
Grant Likely <grant.likely@secretlab.ca> wrote:

> Acked-by: Grant Likely <grant.likely@secretlab.ca>
> 
> Alessandro, do you want me to carry this one in my powerpc tree along
> with the rest of the 5121 patches, or do you want to carry it?  There
> aren't any commit ordering issues on this one.

 Yes please. thanks.

 Acked-by: Alessandro Zummo <a.zummo@towertech.it>

-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Torino, Italy

  http://www.towertech.it

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support
  2010-02-09 23:24   ` Wolfram Sang
@ 2010-02-15 16:38     ` Anatolij Gustschin
  0 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-15 16:38 UTC (permalink / raw)
  To: Wolfram Sang; +Cc: linuxppc-dev, wd, dzu, Piotr Ziecik

Hi Wolfram,

On Wed, 10 Feb 2010 00:24:06 +0100
Wolfram Sang <w.sang@pengutronix.de> wrote:

> Two comments:
...
> > +void mpc512x_restart(char *cmd)
> > +{
> > +	struct mpc512x_reset_module *rm = reset_module_base;
> 
> Why not using reset_module_base directly?

I will fix it in v4 patch.

> > @@ -62,4 +95,5 @@ void __init mpc512x_init(void)
> >  {
> >  	mpc512x_declare_of_platform_devices();
> >  	mpc5121_clk_init();
> > +	mpc512x_restart_init();
> 
> If the return value is not checked here, you could as well make the function
> void. (Not much one could do in the error-case, too.)

Will fix it too, thanks!

Anatolij

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH v4 02/11] powerpc/mpc5121: Add machine restart support
  2010-02-10  2:32   ` Grant Likely
@ 2010-02-15 16:51     ` Anatolij Gustschin
  2010-02-15 20:58       ` Wolfram Sang
  0 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-15 16:51 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Piotr Ziecik, dzu, Anatolij Gustschin, Wolfgang Denk

Add reset module registers representation and
machine restart callback for mpc5121 platform.

Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
Changes since v3:
 - move reset module struct definition to
   arch/powerpc/include/asm/mpc5121.h header file.
   Because of this change we also need to fix [PATCH v3 04/11]
   "mtd: Add MPC5121 NAND Flash Controller driver" to include
   the correct header. v4 for this patch will use correct header.
 - fix mpc512x_restart_init():
     Return value was not checked anywhere, so make the function void.
     Also use 'reset_module_base' directly.

Changes since v2:
 - call mpc512x_restart_init() explicitely from platform
   init code

Changes since v1:
 - use 'struct mpc512x_reset_module *' type for 'reset_module_base'
 - remove empty line
 - remove leftover colon and use pr_err() instead of printk.

 arch/powerpc/include/asm/mpc5121.h            |   24 ++++++++++++++++++++
 arch/powerpc/platforms/512x/mpc5121_ads.c     |    1 +
 arch/powerpc/platforms/512x/mpc5121_generic.c |    1 +
 arch/powerpc/platforms/512x/mpc512x.h         |    1 +
 arch/powerpc/platforms/512x/mpc512x_shared.c  |   30 +++++++++++++++++++++++++
 5 files changed, 57 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/include/asm/mpc5121.h

diff --git a/arch/powerpc/include/asm/mpc5121.h b/arch/powerpc/include/asm/mpc5121.h
new file mode 100644
index 0000000..e6a30bb
--- /dev/null
+++ b/arch/powerpc/include/asm/mpc5121.h
@@ -0,0 +1,24 @@
+/*
+ * MPC5121 Prototypes and definitions
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.
+ */
+
+#ifndef __ASM_POWERPC_MPC5121_H__
+#define __ASM_POWERPC_MPC5121_H__
+
+/* MPC512x Reset module registers */
+struct mpc512x_reset_module {
+	u32	rcwlr;	/* Reset Configuration Word Low Register */
+	u32	rcwhr;	/* Reset Configuration Word High Register */
+	u32	reserved1;
+	u32	reserved2;
+	u32	rsr;	/* Reset Status Register */
+	u32	rmr;	/* Reset Mode Register */
+	u32	rpr;	/* Reset Protection Register */
+	u32	rcr;	/* Reset Control Register */
+	u32	rcer;	/* Reset Control Enable Register */
+};
+
+#endif /* __ASM_POWERPC_MPC5121_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index 0f8f2e9..ee6ae12 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -68,4 +68,5 @@ define_machine(mpc5121_ads) {
 	.init_IRQ		= mpc5121_ads_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
+	.restart		= mpc512x_restart,
 };
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
index 9b8c9b0..a6c0e3a 100644
--- a/arch/powerpc/platforms/512x/mpc5121_generic.c
+++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
@@ -55,4 +55,5 @@ define_machine(mpc5121_generic) {
 	.init_IRQ		= mpc512x_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
+	.restart		= mpc512x_restart,
 };
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index ac3da1a..b2daca0 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -15,4 +15,5 @@ extern void __init mpc512x_init_IRQ(void);
 extern void __init mpc512x_init(void);
 extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
+extern void mpc512x_restart(char *cmd);
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index b683165..a45824a 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -21,9 +21,38 @@
 #include <asm/ipic.h>
 #include <asm/prom.h>
 #include <asm/time.h>
+#include <asm/mpc5121.h>
 
 #include "mpc512x.h"
 
+static struct mpc512x_reset_module __iomem *reset_module_base;
+
+static void __init mpc512x_restart_init(void)
+{
+	struct device_node *np;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+	if (!np)
+		return;
+
+	reset_module_base = of_iomap(np, 0);
+	of_node_put(np);
+}
+
+void mpc512x_restart(char *cmd)
+{
+	if (reset_module_base) {
+		/* Enable software reset "RSTE" */
+		out_be32(&reset_module_base->rpr, 0x52535445);
+		/* Set software hard reset */
+		out_be32(&reset_module_base->rcr, 0x2);
+	} else {
+		pr_err("Restart module not mapped.\n");
+	}
+	for (;;)
+		;
+}
+
 void __init mpc512x_init_IRQ(void)
 {
 	struct device_node *np;
@@ -62,4 +91,5 @@ void __init mpc512x_init(void)
 {
 	mpc512x_declare_of_platform_devices();
 	mpc5121_clk_init();
+	mpc512x_restart_init();
 }
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH v4 04/11] mtd: Add MPC5121 NAND Flash Controller driver
  2010-02-05 13:42 ` [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver Anatolij Gustschin
  2010-02-10  2:42   ` Grant Likely
@ 2010-02-15 17:35   ` Anatolij Gustschin
  2010-02-16  8:11     ` Artem Bityutskiy
  1 sibling, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-15 17:35 UTC (permalink / raw)
  To: linuxppc-dev
  Cc: Piotr Ziecik, Detlev Zundel, linux-mtd, Anatolij Gustschin,
	David Woodhouse, Wolfgang Denk

Adds NAND Flash Controller driver for MPC5121 Revision 2.
All device features, except hardware ECC and power management,
are supported.

Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
Signed-off-by: Wolfgang Denk <wd@denx.de>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Cc: <linux-mtd@lists.infradead.org>
Cc: Grant Likely <grant.likely@secretlab.ca>
Cc: John Rigby <jcrigby@gmail.com>
---
Changes since v3:
 - include 'asm/mpc5121.h' header instead of 'asm/mpc5xxx.h'.
   This change is needed because arch patch adding reset
   module definition was reworked and doesn't add mpc5121
   specific definitions to common header for mpc52xx/mpc5121.

Changes since v2:
 - move the arch bits into separate patch
   (it is the next patch in this series now)
 - use __devinit/__devexit/__devexit_p and __devinitdata

Changes since v1:
 - add logfile with changes since previous version 

Changes since the patch version submitted in May 2009:

 - move mpc5121_nfc.h to the driver .c as there is only one user
 - remove DRV_VERSION macro
 - replace printk() by dev_*()
 - drop unnecessary .suspend and .resume initializations
 - remove duplicate .name/.owner settings
 - fix mpc5121_nfc_init() to "return of_register_platform_driver(&mpc5121_nfc_driver);"
 - move module_init() to just below the init function
 - remove MODULE_VERSION
 - use "mtd: Add MPC5121 NAND Flash Controller driver" as the subject,
   previously it was "mpc5121: Added NAND Flash Controller driver.

 drivers/mtd/nand/Kconfig       |    7 +
 drivers/mtd/nand/Makefile      |    1 +
 drivers/mtd/nand/mpc5121_nfc.c |  916 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 924 insertions(+), 0 deletions(-)
 create mode 100644 drivers/mtd/nand/mpc5121_nfc.c

diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 677cd53..099f002 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -442,6 +442,13 @@ config MTD_NAND_FSL_UPM
 	  Enables support for NAND Flash chips wired onto Freescale PowerPC
 	  processor localbus with User-Programmable Machine support.
 
+config MTD_NAND_MPC5121_NFC
+	tristate "MPC5121 built-in NAND Flash Controller support"
+	depends on PPC_MPC512x
+	help
+	  This enables the driver for the NAND flash controller on the
+	  MPC5121 SoC.
+
 config MTD_NAND_MXC
 	tristate "MXC NAND support"
 	depends on ARCH_MX2 || ARCH_MX3
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 1407bd1..d4ddf05 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -42,5 +42,6 @@ obj-$(CONFIG_MTD_NAND_TXX9NDFMC)	+= txx9ndfmc.o
 obj-$(CONFIG_MTD_NAND_W90P910)		+= w90p910_nand.o
 obj-$(CONFIG_MTD_NAND_NOMADIK)		+= nomadik_nand.o
 obj-$(CONFIG_MTD_NAND_BCM_UMI)		+= bcm_umi_nand.o nand_bcm_umi.o
+obj-$(CONFIG_MTD_NAND_MPC5121_NFC)	+= mpc5121_nfc.o
 
 nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
new file mode 100644
index 0000000..d7333f4
--- /dev/null
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -0,0 +1,916 @@
+/*
+ * Copyright 2004-2008 Freescale Semiconductor, Inc.
+ * Copyright 2009 Semihalf.
+ *
+ * Approved as OSADL project by a majority of OSADL members and funded
+ * by OSADL membership fees in 2009;  for details see www.osadl.org.
+ *
+ * Based on original driver from Freescale Semiconductor
+ * written by John Rigby <jrigby@freescale.com> on basis
+ * of drivers/mtd/nand/mxc_nand.c. Reworked and extended
+ * Piotr Ziecik <kosmo@semihalf.com>.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/partitions.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <asm/mpc5121.h>
+
+/* Addresses for NFC MAIN RAM BUFFER areas */
+#define NFC_MAIN_AREA(n)	((n) *  0x200)
+
+/* Addresses for NFC SPARE BUFFER areas */
+#define NFC_SPARE_BUFFERS	8
+#define NFC_SPARE_LEN		0x40
+#define NFC_SPARE_AREA(n)	(0x1000 + ((n) * NFC_SPARE_LEN))
+
+/* MPC5121 NFC registers */
+#define NFC_BUF_ADDR		0x1E04
+#define NFC_FLASH_ADDR		0x1E06
+#define NFC_FLASH_CMD		0x1E08
+#define NFC_CONFIG		0x1E0A
+#define NFC_ECC_STATUS1		0x1E0C
+#define NFC_ECC_STATUS2		0x1E0E
+#define NFC_SPAS		0x1E10
+#define NFC_WRPROT		0x1E12
+#define NFC_NF_WRPRST		0x1E18
+#define NFC_CONFIG1		0x1E1A
+#define NFC_CONFIG2		0x1E1C
+#define NFC_UNLOCKSTART_BLK0	0x1E20
+#define NFC_UNLOCKEND_BLK0	0x1E22
+#define NFC_UNLOCKSTART_BLK1	0x1E24
+#define NFC_UNLOCKEND_BLK1	0x1E26
+#define NFC_UNLOCKSTART_BLK2	0x1E28
+#define NFC_UNLOCKEND_BLK2	0x1E2A
+#define NFC_UNLOCKSTART_BLK3	0x1E2C
+#define NFC_UNLOCKEND_BLK3	0x1E2E
+
+/* Bit Definitions: NFC_BUF_ADDR */
+#define NFC_RBA_MASK		(7 << 0)
+#define NFC_ACTIVE_CS_SHIFT	5
+#define NFC_ACTIVE_CS_MASK	(3 << NFC_ACTIVE_CS_SHIFT)
+
+/* Bit Definitions: NFC_CONFIG */
+#define NFC_BLS_UNLOCKED	(1 << 1)
+
+/* Bit Definitions: NFC_CONFIG1 */
+#define NFC_ECC_4BIT		(1 << 0)
+#define NFC_FULL_PAGE_DMA	(1 << 1)
+#define NFC_SPARE_ONLY		(1 << 2)
+#define NFC_ECC_ENABLE		(1 << 3)
+#define NFC_INT_MASK		(1 << 4)
+#define NFC_BIG_ENDIAN		(1 << 5)
+#define NFC_RESET		(1 << 6)
+#define NFC_CE			(1 << 7)
+#define NFC_ONE_CYCLE		(1 << 8)
+#define NFC_PPB_32		(0 << 9)
+#define NFC_PPB_64		(1 << 9)
+#define NFC_PPB_128		(2 << 9)
+#define NFC_PPB_256		(3 << 9)
+#define NFC_PPB_MASK		(3 << 9)
+#define NFC_FULL_PAGE_INT	(1 << 11)
+
+/* Bit Definitions: NFC_CONFIG2 */
+#define NFC_COMMAND		(1 << 0)
+#define NFC_ADDRESS		(1 << 1)
+#define NFC_INPUT		(1 << 2)
+#define NFC_OUTPUT		(1 << 3)
+#define NFC_ID			(1 << 4)
+#define NFC_STATUS		(1 << 5)
+#define NFC_CMD_FAIL		(1 << 15)
+#define NFC_INT			(1 << 15)
+
+/* Bit Definitions: NFC_WRPROT */
+#define NFC_WPC_LOCK_TIGHT	(1 << 0)
+#define NFC_WPC_LOCK		(1 << 1)
+#define NFC_WPC_UNLOCK		(1 << 2)
+
+#define	DRV_NAME		"mpc5121_nfc"
+
+/* Timeouts */
+#define NFC_RESET_TIMEOUT	1000		/* 1 ms */
+#define NFC_TIMEOUT		(HZ / 10)	/* 1/10 s */
+
+struct mpc5121_nfc_prv {
+	struct mtd_info		mtd;
+	struct nand_chip	chip;
+	int			irq;
+	void __iomem		*regs;
+	struct clk		*clk;
+	wait_queue_head_t	irq_waitq;
+	uint			column;
+	int			spareonly;
+	void __iomem		*csreg;
+	struct device		*dev;
+};
+
+static void mpc5121_nfc_done(struct mtd_info *mtd);
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *mpc5121_nfc_pprobes[] = { "cmdlinepart", NULL };
+#endif
+
+/* Read NFC register */
+static inline u16 nfc_read(struct mtd_info *mtd, uint reg)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	return in_be16(prv->regs + reg);
+}
+
+/* Write NFC register */
+static inline void nfc_write(struct mtd_info *mtd, uint reg, u16 val)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	out_be16(prv->regs + reg, val);
+}
+
+/* Set bits in NFC register */
+static inline void nfc_set(struct mtd_info *mtd, uint reg, u16 bits)
+{
+	nfc_write(mtd, reg, nfc_read(mtd, reg) | bits);
+}
+
+/* Clear bits in NFC register */
+static inline void nfc_clear(struct mtd_info *mtd, uint reg, u16 bits)
+{
+	nfc_write(mtd, reg, nfc_read(mtd, reg) & ~bits);
+}
+
+/* Invoke address cycle */
+static inline void mpc5121_nfc_send_addr(struct mtd_info *mtd, u16 addr)
+{
+	nfc_write(mtd, NFC_FLASH_ADDR, addr);
+	nfc_write(mtd, NFC_CONFIG2, NFC_ADDRESS);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Invoke command cycle */
+static inline void mpc5121_nfc_send_cmd(struct mtd_info *mtd, u16 cmd)
+{
+	nfc_write(mtd, NFC_FLASH_CMD, cmd);
+	nfc_write(mtd, NFC_CONFIG2, NFC_COMMAND);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Send data from NFC buffers to NAND flash */
+static inline void mpc5121_nfc_send_prog_page(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_INPUT);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive data from NAND flash */
+static inline void mpc5121_nfc_send_read_page(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_OUTPUT);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive ID from NAND flash */
+static inline void mpc5121_nfc_send_read_id(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_ID);
+	mpc5121_nfc_done(mtd);
+}
+
+/* Receive status from NAND flash */
+static inline void mpc5121_nfc_send_read_status(struct mtd_info *mtd)
+{
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_RBA_MASK);
+	nfc_write(mtd, NFC_CONFIG2, NFC_STATUS);
+	mpc5121_nfc_done(mtd);
+}
+
+/* NFC interrupt handler */
+static irqreturn_t mpc5121_nfc_irq(int irq, void *data)
+{
+	struct mtd_info *mtd = data;
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	nfc_set(mtd, NFC_CONFIG1, NFC_INT_MASK);
+	wake_up(&prv->irq_waitq);
+
+	return IRQ_HANDLED;
+}
+
+/* Wait for operation complete */
+static void mpc5121_nfc_done(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	int rv;
+
+	if ((nfc_read(mtd, NFC_CONFIG2) & NFC_INT) == 0) {
+		nfc_clear(mtd, NFC_CONFIG1, NFC_INT_MASK);
+		rv = wait_event_timeout(prv->irq_waitq,
+			(nfc_read(mtd, NFC_CONFIG2) & NFC_INT), NFC_TIMEOUT);
+
+		if (!rv)
+			dev_warn(prv->dev,
+				"Timeout while waiting for interrupt.\n");
+	}
+
+	nfc_clear(mtd, NFC_CONFIG2, NFC_INT);
+}
+
+/* Do address cycle(s) */
+static void mpc5121_nfc_addr_cycle(struct mtd_info *mtd, int column, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	u32 pagemask = chip->pagemask;
+
+	if (column != -1) {
+		mpc5121_nfc_send_addr(mtd, column);
+		if (mtd->writesize > 512)
+			mpc5121_nfc_send_addr(mtd, column >> 8);
+	}
+
+	if (page != -1) {
+		do {
+			mpc5121_nfc_send_addr(mtd, page & 0xFF);
+			page >>= 8;
+			pagemask >>= 8;
+		} while (pagemask);
+	}
+}
+
+/* Control chip select signals */
+static void mpc5121_nfc_select_chip(struct mtd_info *mtd, int chip)
+{
+	if (chip < 0) {
+		nfc_clear(mtd, NFC_CONFIG1, NFC_CE);
+		return;
+	}
+
+	nfc_clear(mtd, NFC_BUF_ADDR, NFC_ACTIVE_CS_MASK);
+	nfc_set(mtd, NFC_BUF_ADDR, (chip << NFC_ACTIVE_CS_SHIFT) &
+							NFC_ACTIVE_CS_MASK);
+	nfc_set(mtd, NFC_CONFIG1, NFC_CE);
+}
+
+/* Init external chip select logic on ADS5121 board */
+static int ads5121_chipselect_init(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	struct device_node *dn;
+
+	dn = of_find_compatible_node(NULL, NULL, "fsl,mpc5121ads-cpld");
+	if (dn) {
+		prv->csreg = of_iomap(dn, 0);
+		of_node_put(dn);
+		if (!prv->csreg)
+			return -ENOMEM;
+
+		/* CPLD Register 9 controls NAND /CE Lines */
+		prv->csreg += 9;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
+/* Control chips select signal on ADS5121 board */
+static void ads5121_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct mpc5121_nfc_prv *prv = nand->priv;
+	u8 v;
+
+	v = in_8(prv->csreg);
+	v |= 0x0F;
+
+	if (chip >= 0) {
+		mpc5121_nfc_select_chip(mtd, 0);
+		v &= ~(1 << chip);
+	} else
+		mpc5121_nfc_select_chip(mtd, -1);
+
+	out_8(prv->csreg, v);
+}
+
+/* Read NAND Ready/Busy signal */
+static int mpc5121_nfc_dev_ready(struct mtd_info *mtd)
+{
+	/*
+	 * NFC handles ready/busy signal internally. Therefore, this function
+	 * always returns status as ready.
+	 */
+	return 1;
+}
+
+/* Write command to NAND flash */
+static void mpc5121_nfc_command(struct mtd_info *mtd, unsigned command,
+							int column, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	prv->column = (column >= 0) ? column : 0;
+	prv->spareonly = 0;
+
+	switch (command) {
+	case NAND_CMD_PAGEPROG:
+		mpc5121_nfc_send_prog_page(mtd);
+		break;
+	/*
+	 * NFC does not support sub-page reads and writes,
+	 * so emulate them using full page transfers.
+	 */
+	case NAND_CMD_READ0:
+		column = 0;
+		break;
+
+	case NAND_CMD_READ1:
+		prv->column += 256;
+		command = NAND_CMD_READ0;
+		column = 0;
+		break;
+
+	case NAND_CMD_READOOB:
+		prv->spareonly = 1;
+		command = NAND_CMD_READ0;
+		column = 0;
+		break;
+
+	case NAND_CMD_SEQIN:
+		mpc5121_nfc_command(mtd, NAND_CMD_READ0, column, page);
+		column = 0;
+		break;
+
+	case NAND_CMD_ERASE1:
+	case NAND_CMD_ERASE2:
+	case NAND_CMD_READID:
+	case NAND_CMD_STATUS:
+		break;
+
+	default:
+		return;
+	}
+
+	mpc5121_nfc_send_cmd(mtd, command);
+	mpc5121_nfc_addr_cycle(mtd, column, page);
+
+	switch (command) {
+	case NAND_CMD_READ0:
+		if (mtd->writesize > 512)
+			mpc5121_nfc_send_cmd(mtd, NAND_CMD_READSTART);
+		mpc5121_nfc_send_read_page(mtd);
+		break;
+
+	case NAND_CMD_READID:
+		mpc5121_nfc_send_read_id(mtd);
+		break;
+
+	case NAND_CMD_STATUS:
+		mpc5121_nfc_send_read_status(mtd);
+		if (chip->options & NAND_BUSWIDTH_16)
+			prv->column = 1;
+		else
+			prv->column = 0;
+		break;
+	}
+}
+
+/* Copy data from/to NFC spare buffers. */
+static void mpc5121_nfc_copy_spare(struct mtd_info *mtd, uint offset,
+						u8 *buffer, uint size, int wr)
+{
+	struct nand_chip *nand = mtd->priv;
+	struct mpc5121_nfc_prv *prv = nand->priv;
+	uint o, s, sbsize, blksize;
+
+	/*
+	 * NAND spare area is available through NFC spare buffers.
+	 * The NFC divides spare area into (page_size / 512) chunks.
+	 * Each chunk is placed into separate spare memory area, using
+	 * first (spare_size / num_of_chunks) bytes of the buffer.
+	 *
+	 * For NAND device in which the spare area is not divided fully
+	 * by the number of chunks, number of used bytes in each spare
+	 * buffer is rounded down to the nearest even number of bytes,
+	 * and all remaining bytes are added to the last used spare area.
+	 *
+	 * For more information read section 26.6.10 of MPC5121e
+	 * Microcontroller Reference Manual, Rev. 3.
+	 */
+
+	/* Calculate number of valid bytes in each spare buffer */
+	sbsize = (mtd->oobsize / (mtd->writesize / 512)) & ~1;
+
+	while (size) {
+		/* Calculate spare buffer number */
+		s = offset / sbsize;
+		if (s > NFC_SPARE_BUFFERS - 1)
+			s = NFC_SPARE_BUFFERS - 1;
+
+		/*
+		 * Calculate offset to requested data block in selected spare
+		 * buffer and its size.
+		 */
+		o = offset - (s * sbsize);
+		blksize = min(sbsize - o, size);
+
+		if (wr)
+			memcpy_toio(prv->regs + NFC_SPARE_AREA(s) + o,
+							buffer, blksize);
+		else
+			memcpy_fromio(buffer,
+				prv->regs + NFC_SPARE_AREA(s) + o, blksize);
+
+		buffer += blksize;
+		offset += blksize;
+		size -= blksize;
+	};
+}
+
+/* Copy data from/to NFC main and spare buffers */
+static void mpc5121_nfc_buf_copy(struct mtd_info *mtd, u_char *buf, int len,
+									int wr)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	uint c = prv->column;
+	uint l;
+
+	/* Handle spare area access */
+	if (prv->spareonly || c >= mtd->writesize) {
+		/* Calculate offset from beginning of spare area */
+		if (c >= mtd->writesize)
+			c -= mtd->writesize;
+
+		prv->column += len;
+		mpc5121_nfc_copy_spare(mtd, c, buf, len, wr);
+		return;
+	}
+
+	/*
+	 * Handle main area access - limit copy length to prevent
+	 * crossing main/spare boundary.
+	 */
+	l = min((uint)len, mtd->writesize - c);
+	prv->column += l;
+
+	if (wr)
+		memcpy_toio(prv->regs + NFC_MAIN_AREA(0) + c, buf, l);
+	else
+		memcpy_fromio(buf, prv->regs + NFC_MAIN_AREA(0) + c, l);
+
+	/* Handle crossing main/spare boundary */
+	if (l != len) {
+		buf += l;
+		len -= l;
+		mpc5121_nfc_buf_copy(mtd, buf, len, wr);
+	}
+}
+
+/* Read data from NFC buffers */
+static void mpc5121_nfc_read_buf(struct mtd_info *mtd, u_char *buf, int len)
+{
+	mpc5121_nfc_buf_copy(mtd, buf, len, 0);
+}
+
+/* Write data to NFC buffers */
+static void mpc5121_nfc_write_buf(struct mtd_info *mtd,
+						const u_char *buf, int len)
+{
+	mpc5121_nfc_buf_copy(mtd, (u_char *)buf, len, 1);
+}
+
+/* Compare buffer with NAND flash */
+static int mpc5121_nfc_verify_buf(struct mtd_info *mtd,
+						const u_char *buf, int len)
+{
+	u_char tmp[256];
+	uint bsize;
+
+	while (len) {
+		bsize = min(len, 256);
+		mpc5121_nfc_read_buf(mtd, tmp, bsize);
+
+		if (memcmp(buf, tmp, bsize))
+			return 1;
+
+		buf += bsize;
+		len -= bsize;
+	}
+
+	return 0;
+}
+
+/* Read byte from NFC buffers */
+static u8 mpc5121_nfc_read_byte(struct mtd_info *mtd)
+{
+	u8 tmp;
+
+	mpc5121_nfc_read_buf(mtd, &tmp, sizeof(tmp));
+
+	return tmp;
+}
+
+/* Read word from NFC buffers */
+static u16 mpc5121_nfc_read_word(struct mtd_info *mtd)
+{
+	u16 tmp;
+
+	mpc5121_nfc_read_buf(mtd, (u_char *)&tmp, sizeof(tmp));
+
+	return tmp;
+}
+
+/*
+ * Read NFC configuration from Reset Config Word
+ *
+ * NFC is configured during reset in basis of information stored
+ * in Reset Config Word. There is no other way to set NAND block
+ * size, spare size and bus width.
+ */
+static int mpc5121_nfc_read_hw_config(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+	struct mpc512x_reset_module *rm;
+	struct device_node *rmnode;
+	uint rcw_pagesize = 0;
+	uint rcw_sparesize = 0;
+	uint rcw_width;
+	uint rcwh;
+	uint romloc, ps;
+
+	rmnode = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-reset");
+	if (!rmnode) {
+		dev_err(prv->dev, "Missing 'fsl,mpc5121-reset' "
+					"node in device tree!\n");
+		return -ENODEV;
+	}
+
+	rm = of_iomap(rmnode, 0);
+	if (!rm) {
+		dev_err(prv->dev, "Error mapping reset module node!\n");
+		return -EBUSY;
+	}
+
+	rcwh = in_be32(&rm->rcwhr);
+
+	/* Bit 6: NFC bus width */
+	rcw_width = ((rcwh >> 6) & 0x1) ? 2 : 1;
+
+	/* Bit 7: NFC Page/Spare size */
+	ps = (rcwh >> 7) & 0x1;
+
+	/* Bits [22:21]: ROM Location */
+	romloc = (rcwh >> 21) & 0x3;
+
+	/* Decode RCW bits */
+	switch ((ps << 2) | romloc) {
+	case 0x00:
+	case 0x01:
+		rcw_pagesize = 512;
+		rcw_sparesize = 16;
+		break;
+	case 0x02:
+	case 0x03:
+		rcw_pagesize = 4096;
+		rcw_sparesize = 128;
+		break;
+	case 0x04:
+	case 0x05:
+		rcw_pagesize = 2048;
+		rcw_sparesize = 64;
+		break;
+	case 0x06:
+	case 0x07:
+		rcw_pagesize = 4096;
+		rcw_sparesize = 218;
+		break;
+	}
+
+	mtd->writesize = rcw_pagesize;
+	mtd->oobsize = rcw_sparesize;
+	if (rcw_width == 2)
+		chip->options |= NAND_BUSWIDTH_16;
+
+	dev_notice(prv->dev, "Configured for "
+				"%u-bit NAND, page size %u "
+				"with %u spare.\n",
+				rcw_width * 8, rcw_pagesize,
+				rcw_sparesize);
+	iounmap(rm);
+	of_node_put(rmnode);
+	return 0;
+}
+
+/* Free driver resources */
+static void mpc5121_nfc_free(struct device *dev, struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	if (prv->clk) {
+		clk_disable(prv->clk);
+		clk_put(prv->clk);
+	}
+
+	if (prv->csreg)
+		iounmap(prv->csreg);
+}
+
+static int __devinit mpc5121_nfc_probe(struct of_device *op,
+					const struct of_device_id *match)
+{
+	struct device_node *rootnode, *dn = op->node;
+	struct device *dev = &op->dev;
+	struct mpc5121_nfc_prv *prv;
+	struct resource res;
+	struct mtd_info *mtd;
+#ifdef CONFIG_MTD_PARTITIONS
+	struct mtd_partition *parts;
+#endif
+	struct nand_chip *chip;
+	unsigned long regs_paddr, regs_size;
+	const uint *chips_no;
+	int resettime = 0;
+	int retval = 0;
+	int rev, len;
+
+	/*
+	 * Check SoC revision. This driver supports only NFC
+	 * in MPC5121 revision 2.
+	 */
+	rev = (mfspr(SPRN_SVR) >> 4) & 0xF;
+	if (rev != 2) {
+		dev_err(dev, "SoC revision %u is not supported!\n", rev);
+		return -ENXIO;
+	}
+
+	prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
+	if (!prv) {
+		dev_err(dev, "Memory exhausted!\n");
+		return -ENOMEM;
+	}
+
+	mtd = &prv->mtd;
+	chip = &prv->chip;
+
+	mtd->priv = chip;
+	chip->priv = prv;
+	prv->dev = dev;
+
+	/* Read NFC configuration from Reset Config Word */
+	retval = mpc5121_nfc_read_hw_config(mtd);
+	if (retval) {
+		dev_err(dev, "Unable to read NFC config!\n");
+		return retval;
+	}
+
+	prv->irq = irq_of_parse_and_map(dn, 0);
+	if (prv->irq == NO_IRQ) {
+		dev_err(dev, "Error mapping IRQ!\n");
+		return -EINVAL;
+	}
+
+	retval = of_address_to_resource(dn, 0, &res);
+	if (retval) {
+		dev_err(dev, "Error parsing memory region!\n");
+		return retval;
+	}
+
+	chips_no = of_get_property(dn, "chips", &len);
+	if (!chips_no || len != sizeof(*chips_no)) {
+		dev_err(dev, "Invalid/missing 'chips' property!\n");
+		return -EINVAL;
+	}
+
+	regs_paddr = res.start;
+	regs_size = res.end - res.start + 1;
+
+	if (!devm_request_mem_region(dev, regs_paddr, regs_size, DRV_NAME)) {
+		dev_err(dev, "Error requesting memory region!\n");
+		return -EBUSY;
+	}
+
+	prv->regs = devm_ioremap(dev, regs_paddr, regs_size);
+	if (!prv->regs) {
+		dev_err(dev, "Error mapping memory region!\n");
+		return -ENOMEM;
+	}
+
+	mtd->name = "MPC5121 NAND";
+	chip->dev_ready = mpc5121_nfc_dev_ready;
+	chip->cmdfunc = mpc5121_nfc_command;
+	chip->read_byte = mpc5121_nfc_read_byte;
+	chip->read_word = mpc5121_nfc_read_word;
+	chip->read_buf = mpc5121_nfc_read_buf;
+	chip->write_buf = mpc5121_nfc_write_buf;
+	chip->verify_buf = mpc5121_nfc_verify_buf;
+	chip->select_chip = mpc5121_nfc_select_chip;
+	chip->options = NAND_NO_AUTOINCR | NAND_USE_FLASH_BBT;
+	chip->ecc.mode = NAND_ECC_SOFT;
+
+	/* Support external chip-select logic on ADS5121 board */
+	rootnode = of_find_node_by_path("/");
+	if (of_device_is_compatible(rootnode, "fsl,mpc5121ads")) {
+		retval = ads5121_chipselect_init(mtd);
+		if (retval) {
+			dev_err(dev, "Chipselect init error!\n");
+			of_node_put(rootnode);
+			return retval;
+		}
+
+		chip->select_chip = ads5121_select_chip;
+	}
+	of_node_put(rootnode);
+
+	/* Enable NFC clock */
+	prv->clk = clk_get(dev, "nfc_clk");
+	if (!prv->clk) {
+		dev_err(dev, "Unable to acquire NFC clock!\n");
+		retval = -ENODEV;
+		goto error;
+	}
+
+	clk_enable(prv->clk);
+
+	/* Reset NAND Flash controller */
+	nfc_set(mtd, NFC_CONFIG1, NFC_RESET);
+	while (nfc_read(mtd, NFC_CONFIG1) & NFC_RESET) {
+		if (resettime++ >= NFC_RESET_TIMEOUT) {
+			dev_err(dev, "Timeout while resetting NFC!\n");
+			retval = -EINVAL;
+			goto error;
+		}
+
+		udelay(1);
+	}
+
+	/* Enable write to NFC memory */
+	nfc_write(mtd, NFC_CONFIG, NFC_BLS_UNLOCKED);
+
+	/* Enable write to all NAND pages */
+	nfc_write(mtd, NFC_UNLOCKSTART_BLK0, 0x0000);
+	nfc_write(mtd, NFC_UNLOCKEND_BLK0, 0xFFFF);
+	nfc_write(mtd, NFC_WRPROT, NFC_WPC_UNLOCK);
+
+	/*
+	 * Setup NFC:
+	 *	- Big Endian transfers,
+	 *	- Interrupt after full page read/write.
+	 */
+	nfc_write(mtd, NFC_CONFIG1, NFC_BIG_ENDIAN | NFC_INT_MASK |
+							NFC_FULL_PAGE_INT);
+
+	/* Set spare area size */
+	nfc_write(mtd, NFC_SPAS, mtd->oobsize >> 1);
+
+	init_waitqueue_head(&prv->irq_waitq);
+	retval = devm_request_irq(dev, prv->irq, &mpc5121_nfc_irq, 0, DRV_NAME,
+									mtd);
+	if (retval) {
+		dev_err(dev, "Error requesting IRQ!\n");
+		goto error;
+	}
+
+	/* Detect NAND chips */
+	if (nand_scan(mtd, *chips_no)) {
+		dev_err(dev, "NAND Flash not found !\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		retval = -ENXIO;
+		goto error;
+	}
+
+	/* Set erase block size */
+	switch (mtd->erasesize / mtd->writesize) {
+	case 32:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_32);
+		break;
+
+	case 64:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_64);
+		break;
+
+	case 128:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_128);
+		break;
+
+	case 256:
+		nfc_set(mtd, NFC_CONFIG1, NFC_PPB_256);
+		break;
+
+	default:
+		dev_err(dev, "Unsupported NAND flash!\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		retval = -ENXIO;
+		goto error;
+	}
+
+	dev_set_drvdata(dev, mtd);
+
+	/* Register device in MTD */
+#ifdef CONFIG_MTD_PARTITIONS
+	retval = parse_mtd_partitions(mtd, mpc5121_nfc_pprobes, &parts, 0);
+#ifdef CONFIG_MTD_OF_PARTS
+	if (retval == 0)
+		retval = of_mtd_parse_partitions(dev, dn, &parts);
+#endif
+	if (retval < 0) {
+		dev_err(dev, "Error parsing MTD partitions!\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		retval = -EINVAL;
+		goto error;
+	}
+
+	if (retval > 0)
+		retval = add_mtd_partitions(mtd, parts, retval);
+	else
+#endif
+		retval = add_mtd_device(mtd);
+
+	if (retval) {
+		dev_err(dev, "Error adding MTD device!\n");
+		devm_free_irq(dev, prv->irq, mtd);
+		goto error;
+	}
+
+	return 0;
+error:
+	mpc5121_nfc_free(dev, mtd);
+	return retval;
+}
+
+static int __devexit mpc5121_nfc_remove(struct of_device *op)
+{
+	struct device *dev = &op->dev;
+	struct mtd_info *mtd = dev_get_drvdata(dev);
+	struct nand_chip *chip = mtd->priv;
+	struct mpc5121_nfc_prv *prv = chip->priv;
+
+	nand_release(mtd);
+	devm_free_irq(dev, prv->irq, mtd);
+	mpc5121_nfc_free(dev, mtd);
+
+	return 0;
+}
+
+static struct of_device_id mpc5121_nfc_match[] __devinitdata = {
+	{ .compatible = "fsl,mpc5121-nfc", },
+	{},
+};
+
+static struct of_platform_driver mpc5121_nfc_driver = {
+	.match_table	= mpc5121_nfc_match,
+	.probe		= mpc5121_nfc_probe,
+	.remove		= __devexit_p(mpc5121_nfc_remove),
+	.driver		= {
+		.name	= DRV_NAME,
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init mpc5121_nfc_init(void)
+{
+	return of_register_platform_driver(&mpc5121_nfc_driver);
+}
+
+module_init(mpc5121_nfc_init);
+
+static void __exit mpc5121_nfc_cleanup(void)
+{
+	of_unregister_platform_driver(&mpc5121_nfc_driver);
+}
+
+module_exit(mpc5121_nfc_cleanup);
+
+MODULE_AUTHOR("Freescale Semiconductor, Inc.");
+MODULE_DESCRIPTION("MPC5121 NAND MTD driver");
+MODULE_LICENSE("GPL");
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 02/11] powerpc/mpc5121: Add machine restart support
  2010-02-15 16:51     ` [PATCH v4 " Anatolij Gustschin
@ 2010-02-15 20:58       ` Wolfram Sang
  0 siblings, 0 replies; 48+ messages in thread
From: Wolfram Sang @ 2010-02-15 20:58 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linuxppc-dev, Piotr Ziecik, dzu, Wolfgang Denk

[-- Attachment #1: Type: text/plain, Size: 627 bytes --]

On Mon, Feb 15, 2010 at 05:51:33PM +0100, Anatolij Gustschin wrote:
> Add reset module registers representation and
> machine restart callback for mpc5121 platform.
> 
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
> ---

Reviewed-by: Wolfram Sang <w.sang@pengutronix.de>

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 04/11] mtd: Add MPC5121 NAND Flash Controller driver
  2010-02-15 17:35   ` [PATCH v4 " Anatolij Gustschin
@ 2010-02-16  8:11     ` Artem Bityutskiy
  2010-02-23 15:54       ` Kári Davíðsson
  0 siblings, 1 reply; 48+ messages in thread
From: Artem Bityutskiy @ 2010-02-16  8:11 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: Piotr Ziecik, Detlev Zundel, linuxppc-dev, linux-mtd, David Woodhouse

On Mon, 2010-02-15 at 18:35 +0100, Anatolij Gustschin wrote:
> Adds NAND Flash Controller driver for MPC5121 Revision 2.
> All device features, except hardware ECC and power management,
> are supported.
> 
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
> Cc: <linux-mtd@lists.infradead.org>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
> ---
> Changes since v3:
>  - include 'asm/mpc5121.h' header instead of 'asm/mpc5xxx.h'.
>    This change is needed because arch patch adding reset
>    module definition was reworked and doesn't add mpc5121
>    specific definitions to common header for mpc52xx/mpc5121.
> 
> Changes since v2:
>  - move the arch bits into separate patch
>    (it is the next patch in this series now)
>  - use __devinit/__devexit/__devexit_p and __devinitdata
> 
> Changes since v1:
>  - add logfile with changes since previous version 
> 
> Changes since the patch version submitted in May 2009:
> 
>  - move mpc5121_nfc.h to the driver .c as there is only one user
>  - remove DRV_VERSION macro
>  - replace printk() by dev_*()
>  - drop unnecessary .suspend and .resume initializations
>  - remove duplicate .name/.owner settings
>  - fix mpc5121_nfc_init() to "return of_register_platform_driver(&mpc5121_nfc_driver);"
>  - move module_init() to just below the init function
>  - remove MODULE_VERSION
>  - use "mtd: Add MPC5121 NAND Flash Controller driver" as the subject,
>    previously it was "mpc5121: Added NAND Flash Controller driver.
> 
>  drivers/mtd/nand/Kconfig       |    7 +
>  drivers/mtd/nand/Makefile      |    1 +
>  drivers/mtd/nand/mpc5121_nfc.c |  916 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 924 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/mtd/nand/mpc5121_nfc.c

Pushed to my l2-mtd-2.6.git / dunno.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support
  2010-02-05 13:42 ` [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
@ 2010-02-16 18:06   ` Grant Likely
  2010-02-18 16:15     ` York Sun
                       ` (5 more replies)
  0 siblings, 6 replies; 48+ messages in thread
From: Grant Likely @ 2010-02-16 18:06 UTC (permalink / raw)
  To: Anatolij Gustschin, York Sun, Kumar Gala
  Cc: John Rigby, linuxppc-dev, wd, dzu

On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> MPC5121 DIU configuration/setup as initialized by the boot
> loader currently will get lost while booting Linux. As a
> result displaying the boot splash is not possible through
> the boot process.
>
> To prevent this we reserve configured DIU frame buffer
> address range while booting and preserve AOI descriptor
> and gamma table so that DIU continues displaying through
> the whole boot process. On first open from user space
> DIU frame buffer driver releases the reserved frame
> buffer area and continues to operate as usual.
>
> The patch also moves drivers/video/fsl-diu-fb.h file to
> include/linux as we use some DIU structures in platform
> code.
>
> 'diu_ops' callbacks in platform code borrowed from John's
> DIU code.
>
> Signed-off-by: John Rigby <jrigby@gmail.com>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> ---
[...]
> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> index 72d68b3..29c7f31 100644
> --- a/drivers/video/fsl-diu-fb.c
> +++ b/drivers/video/fsl-diu-fb.c
> @@ -34,7 +34,7 @@
> =A0#include <linux/of_platform.h>
>
> =A0#include <sysdev/fsl_soc.h>
> -#include "fsl-diu-fb.h"
> +#include <linux/fsl-diu-fb.h>
>
> =A0/*
> =A0* These parameters give default parameters
> @@ -178,6 +178,21 @@ static struct fb_videomode __devinitdata fsl_diu_mod=
e_db[] =3D {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.sync =A0 =A0 =A0 =A0 =A0 =3D FB_SYNC_COMP=
_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0.vmode =A0 =A0 =A0 =A0 =A0=3D FB_VMODE_NON=
INTERLACED
> =A0 =A0 =A0 =A0},
> + =A0 =A0 =A0 {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .name =A0 =A0 =A0 =A0 =A0 =3D "800x480-60",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .refresh =A0 =A0 =A0 =A0=3D 60,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .xres =A0 =A0 =A0 =A0 =A0 =3D 800,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .yres =A0 =A0 =A0 =A0 =A0 =3D 480,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .pixclock =A0 =A0 =A0 =3D 31250,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .left_margin =A0 =A0=3D 86,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .right_margin =A0 =3D 42,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .upper_margin =A0 =3D 33,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .lower_margin =A0 =3D 10,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .hsync_len =A0 =A0 =A0=3D 128,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .vsync_len =A0 =A0 =A0=3D 2,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .sync =A0 =A0 =A0 =A0 =A0 =3D FB_SYNC_COMP_=
HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 .vmode =A0 =A0 =A0 =A0 =A0=3D FB_VMODE_NONI=
NTERLACED
> + =A0 =A0 =A0 },
> =A0};

This hunk bothers me.  It looks like the type of data that belongs
either in some common shared .c file, or encoded into the device tree.
 It seems to be data about the display panel, instead of data about
the framebuffer driver.  I know that the driver already uses this
pattern, but before I merge this patch and further rely on that
pattern, I think it is worth discussing.

Kumar, York, thoughts?

g.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 10/11] powerpc/mpc5121: update mpc5121ads DTS
  2010-02-05 13:42 ` [PATCH v3 10/11] powerpc/mpc5121: update mpc5121ads DTS Anatolij Gustschin
@ 2010-02-16 18:11   ` Grant Likely
  2010-02-16 19:32     ` [PATCH] powerpc: mpc5121: correct DIU compatible property Anatolij Gustschin
  0 siblings, 1 reply; 48+ messages in thread
From: Grant Likely @ 2010-02-16 18:11 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linuxppc-dev, wd, dzu, Piotr Ziecik

On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> Collects several changes needed after applying
> previous mpc5121 platform and driver patches:

I'll merge this one, but...

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0display@2100 {
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-diu", "fsl-diu";
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 compatible =3D "fsl,mpc5121=
-diu", "fsl,diu";

I want to see the "fsl,diu" value removed.  It is meaningless (the
8xxx and 5121 dius are similar, but they are not identical), and the
driver should bind against "fsl,mpc5121-diu" directly.  Can you please
send a followup patch to fix this?

Thanks,
g.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH] powerpc: mpc5121: correct DIU compatible property
  2010-02-16 18:11   ` Grant Likely
@ 2010-02-16 19:32     ` Anatolij Gustschin
  2010-02-16 19:51       ` Grant Likely
  0 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-16 19:32 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: wd, dzu, Anatolij Gustschin, kosmo

The DIU driver should bind against "fsl,mpc5121-diu"
directly. Add this compatible property to the match
table and fix DTS and platform code accordingly.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 arch/powerpc/boot/dts/mpc5121ads.dts         |    2 +-
 arch/powerpc/platforms/512x/mpc512x_shared.c |    2 +-
 drivers/video/fsl-diu-fb.c                   |    5 +++++
 3 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/arch/powerpc/boot/dts/mpc5121ads.dts b/arch/powerpc/boot/dts/mpc5121ads.dts
index d2b2db7..c9ef6bb 100644
--- a/arch/powerpc/boot/dts/mpc5121ads.dts
+++ b/arch/powerpc/boot/dts/mpc5121ads.dts
@@ -255,7 +255,7 @@
 		};
 
 		display@2100 {
-			compatible = "fsl,mpc5121-diu", "fsl,diu";
+			compatible = "fsl,mpc5121-diu";
 			reg = <0x2100 0x100>;
 			interrupts = <64 0x8>;
 			interrupt-parent = < &ipic >;
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index 1751c0d..3a5ff75 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -250,7 +250,7 @@ void __init mpc512x_init_diu(void)
 	unsigned long mode, pix_fmt, res, bpp;
 	unsigned long dst;
 
-	np = of_find_compatible_node(NULL, NULL, "fsl,diu");
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
 	if (!np) {
 		pr_err("No DIU node\n");
 		return;
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 29c7f31..5db701b 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -1663,6 +1663,11 @@ static int __init fsl_diu_setup(char *options)
 #endif
 
 static struct of_device_id fsl_diu_match[] = {
+#ifdef CONFIG_PPC_MPC512x
+	{
+		.compatible = "fsl,mpc5121-diu",
+	},
+#endif
 	{
 		.compatible = "fsl,diu",
 	},
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH] powerpc: mpc5121: correct DIU compatible property
  2010-02-16 19:32     ` [PATCH] powerpc: mpc5121: correct DIU compatible property Anatolij Gustschin
@ 2010-02-16 19:51       ` Grant Likely
  0 siblings, 0 replies; 48+ messages in thread
From: Grant Likely @ 2010-02-16 19:51 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linuxppc-dev, wd, dzu, kosmo

On Tue, Feb 16, 2010 at 12:32 PM, Anatolij Gustschin <agust@denx.de> wrote:
> The DIU driver should bind against "fsl,mpc5121-diu"
> directly. Add this compatible property to the match
> table and fix DTS and platform code accordingly.
>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> ---
> =A0arch/powerpc/boot/dts/mpc5121ads.dts =A0 =A0 =A0 =A0 | =A0 =A02 +-
> =A0arch/powerpc/platforms/512x/mpc512x_shared.c | =A0 =A02 +-
> =A0drivers/video/fsl-diu-fb.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =
=A05 +++++

Merged, but only the dts and fsl-diu-fb.c hunks.  I haven't merged the
mpc512x_shared.c changes because I haven't merged your diu patches yet
(as discussed in a previous email).

g.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support
  2010-02-16 18:06   ` Grant Likely
@ 2010-02-18 16:15     ` York Sun
  2010-02-27 21:58     ` [PATCH 0/3] Rework MPC5121 DIU support (for 2.6.34) Anatolij Gustschin
                       ` (4 subsequent siblings)
  5 siblings, 0 replies; 48+ messages in thread
From: York Sun @ 2010-02-18 16:15 UTC (permalink / raw)
  To: Grant Likely; +Cc: wd, dzu, John Rigby, linuxppc-dev, Anatolij Gustschin

On Tue, 2010-02-16 at 11:06 -0700, Grant Likely wrote:
> [...]
> > diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> > index 72d68b3..29c7f31 100644
> > --- a/drivers/video/fsl-diu-fb.c
> > +++ b/drivers/video/fsl-diu-fb.c
> > @@ -34,7 +34,7 @@
> >  #include <linux/of_platform.h>
> >
> >  #include <sysdev/fsl_soc.h>
> > -#include "fsl-diu-fb.h"
> > +#include <linux/fsl-diu-fb.h>
> >
> >  /*
> >  * These parameters give default parameters
> > @@ -178,6 +178,21 @@ static struct fb_videomode __devinitdata fsl_diu_mode_db[] = {
> >                .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> >                .vmode          = FB_VMODE_NONINTERLACED
> >        },
> > +       {
> > +               .name           = "800x480-60",
> > +               .refresh        = 60,
> > +               .xres           = 800,
> > +               .yres           = 480,
> > +               .pixclock       = 31250,
> > +               .left_margin    = 86,
> > +               .right_margin   = 42,
> > +               .upper_margin   = 33,
> > +               .lower_margin   = 10,
> > +               .hsync_len      = 128,
> > +               .vsync_len      = 2,
> > +               .sync           = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> > +               .vmode          = FB_VMODE_NONINTERLACED
> > +       },
> >  };
> 
> This hunk bothers me.  It looks like the type of data that belongs
> either in some common shared .c file, or encoded into the device tree.
>  It seems to be data about the display panel, instead of data about
> the framebuffer driver.  I know that the driver already uses this
> pattern, but before I merge this patch and further rely on that
> pattern, I think it is worth discussing.
> 
> Kumar, York, thoughts?
> 
> g.
> 

It is a hardware related configuration. It is only used during booting
before other configuration comes available.

I am OK to move it to anywhere as long as it doesn't get confused or
lost.

York

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v4 04/11] mtd: Add MPC5121 NAND Flash Controller driver
  2010-02-16  8:11     ` Artem Bityutskiy
@ 2010-02-23 15:54       ` Kári Davíðsson
  0 siblings, 0 replies; 48+ messages in thread
From: Kári Davíðsson @ 2010-02-23 15:54 UTC (permalink / raw)
  To: dedekind1
  Cc: Piotr Ziecik, Detlev Zundel, linuxppc-dev, linux-mtd,
	Anatolij Gustschin, David Woodhouse

Any special reason this in MPC5121 Revision 2 only?
I did not see anything that contradicted the rev 3 manual in the code.

But there is one harmless bug (since the NFC_CMD_FAIL symbol is never used), i.e.

git diff
diff --git a/drivers/mtd/nand/mpc5121_nfc.c b/drivers/mtd/nand/mpc5121_nfc.c
index 191bf99..38a99ef 100644
--- a/drivers/mtd/nand/mpc5121_nfc.c
+++ b/drivers/mtd/nand/mpc5121_nfc.c
@@ -100,7 +100,7 @@
  #define NFC_OUTPUT             (1 << 3)
  #define NFC_ID                 (1 << 4)
  #define NFC_STATUS             (1 << 5)
-#define NFC_CMD_FAIL           (1 << 15)
+#define NFC_CMD_FAIL           (1 << 14)
  #define NFC_INT                        (1 << 15)

  /* Bit Definitions: NFC_WRPROT */

The NAND chip is is detected (given that I disable the Revison check),
but the /dev7mtd0 is not accessable as block device. Is that normal?
The UBIFS also gives up I am assuming because the /dev/mtd0 is not block device.

rg
kd

On 02/16/2010 08:11 AM, Artem Bityutskiy wrote:
> On Mon, 2010-02-15 at 18:35 +0100, Anatolij Gustschin wrote:
>> Adds NAND Flash Controller driver for MPC5121 Revision 2.
>> All device features, except hardware ECC and power management,
>> are supported.
>>
>> Signed-off-by: Piotr Ziecik<kosmo@semihalf.com>
>> Signed-off-by: Wolfgang Denk<wd@denx.de>
>> Signed-off-by: Anatolij Gustschin<agust@denx.de>
>> Acked-by: Grant Likely<grant.likely@secretlab.ca>
>> Cc:<linux-mtd@lists.infradead.org>
>> Cc: Grant Likely<grant.likely@secretlab.ca>
>> Cc: John Rigby<jcrigby@gmail.com>
>> ---
>> Changes since v3:
>>   - include 'asm/mpc5121.h' header instead of 'asm/mpc5xxx.h'.
>>     This change is needed because arch patch adding reset
>>     module definition was reworked and doesn't add mpc5121
>>     specific definitions to common header for mpc52xx/mpc5121.
>>
>> Changes since v2:
>>   - move the arch bits into separate patch
>>     (it is the next patch in this series now)
>>   - use __devinit/__devexit/__devexit_p and __devinitdata
>>
>> Changes since v1:
>>   - add logfile with changes since previous version
>>
>> Changes since the patch version submitted in May 2009:
>>
>>   - move mpc5121_nfc.h to the driver .c as there is only one user
>>   - remove DRV_VERSION macro
>>   - replace printk() by dev_*()
>>   - drop unnecessary .suspend and .resume initializations
>>   - remove duplicate .name/.owner settings
>>   - fix mpc5121_nfc_init() to "return of_register_platform_driver(&mpc5121_nfc_driver);"
>>   - move module_init() to just below the init function
>>   - remove MODULE_VERSION
>>   - use "mtd: Add MPC5121 NAND Flash Controller driver" as the subject,
>>     previously it was "mpc5121: Added NAND Flash Controller driver.
>>
>>   drivers/mtd/nand/Kconfig       |    7 +
>>   drivers/mtd/nand/Makefile      |    1 +
>>   drivers/mtd/nand/mpc5121_nfc.c |  916 ++++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 924 insertions(+), 0 deletions(-)
>>   create mode 100644 drivers/mtd/nand/mpc5121_nfc.c
>
> Pushed to my l2-mtd-2.6.git / dunno.
>

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 0/3] Rework MPC5121 DIU support (for 2.6.34)
  2010-02-16 18:06   ` Grant Likely
  2010-02-18 16:15     ` York Sun
@ 2010-02-27 21:58     ` Anatolij Gustschin
  2010-02-28  7:04       ` Grant Likely
  2010-02-27 21:58     ` [PATCH 1/3] video: add support for getting video mode from device tree Anatolij Gustschin
                       ` (3 subsequent siblings)
  5 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-27 21:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-fbdev, wd, dzu, jrigby, Anatolij Gustschin, yorksun

This patch series rework DIU support patch submitted
previously with the patch series for updating MPC5121
support in mainline. It doesn't add new panel timing data
to the framebuffer driver anymore. Instead we now allow
encoding this data in the device tree. First two patches
add this support.

The third patch for DIU support is rebased, but still
depends on patches for adding MPC5121 USB support (because
it touches shared platform code).

It is intended for inclusion in 2.6.34, since without
DIU support patch framebuffer doesn't work on mpc5121.

Anatolij Gustschin (3):
  video: add support for getting video mode from device tree
  fbdev: fsl-diu-fb.c: allow setting panel video mode from DT
  powerpc/mpc5121: shared DIU framebuffer support

 arch/powerpc/platforms/512x/mpc5121_ads.c     |    7 +
 arch/powerpc/platforms/512x/mpc5121_generic.c |   13 ++
 arch/powerpc/platforms/512x/mpc512x.h         |    3 +
 arch/powerpc/platforms/512x/mpc512x_shared.c  |  282 +++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.h                 |    1 +
 drivers/video/Kconfig                         |    6 +
 drivers/video/Makefile                        |    1 +
 drivers/video/fsl-diu-fb.c                    |   88 +++++---
 drivers/video/fsl-diu-fb.h                    |  223 -------------------
 drivers/video/ofmode.c                        |   95 +++++++++
 drivers/video/ofmode.h                        |    6 +
 include/linux/fsl-diu-fb.h                    |  223 +++++++++++++++++++
 12 files changed, 693 insertions(+), 255 deletions(-)
 delete mode 100644 drivers/video/fsl-diu-fb.h
 create mode 100644 drivers/video/ofmode.c
 create mode 100644 drivers/video/ofmode.h
 create mode 100644 include/linux/fsl-diu-fb.h

^ permalink raw reply	[flat|nested] 48+ messages in thread

* [PATCH 1/3] video: add support for getting video mode from device tree
  2010-02-16 18:06   ` Grant Likely
  2010-02-18 16:15     ` York Sun
  2010-02-27 21:58     ` [PATCH 0/3] Rework MPC5121 DIU support (for 2.6.34) Anatolij Gustschin
@ 2010-02-27 21:58     ` Anatolij Gustschin
  2010-02-28  6:30       ` Grant Likely
  2010-02-27 21:58     ` [PATCH 2/3] fbdev: fsl-diu-fb.c: allow setting panel video mode from DT Anatolij Gustschin
                       ` (2 subsequent siblings)
  5 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-27 21:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-fbdev, wd, dzu, jrigby, Anatolij Gustschin, yorksun

Framebuffer drivers may want to get panel timing info
from the device tree. This patch adds appropriate support.
Subsequent patch for FSL DIU frame buffer driver makes use
of this functionality.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 drivers/video/Kconfig  |    5 +++
 drivers/video/Makefile |    1 +
 drivers/video/ofmode.c |   95 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/video/ofmode.h |    6 +++
 4 files changed, 107 insertions(+), 0 deletions(-)
 create mode 100644 drivers/video/ofmode.c
 create mode 100644 drivers/video/ofmode.h

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 5a5c303..dc1beb0 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -203,6 +203,11 @@ config FB_MACMODES
        depends on FB
        default n
 
+config FB_OF_MODE
+       tristate
+       depends on FB && OF
+       default n
+
 config FB_BACKLIGHT
 	bool
 	depends on FB
diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 4ecb30c..c4a912b 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_FB_SVGALIB)       += svgalib.o
 obj-$(CONFIG_FB_MACMODES)      += macmodes.o
 obj-$(CONFIG_FB_DDC)           += fb_ddc.o
 obj-$(CONFIG_FB_DEFERRED_IO)   += fb_defio.o
+obj-$(CONFIG_FB_OF_MODE)       += ofmode.o
 
 # Hardware specific drivers go first
 obj-$(CONFIG_FB_AMIGA)            += amifb.o c2p_planar.o
diff --git a/drivers/video/ofmode.c b/drivers/video/ofmode.c
new file mode 100644
index 0000000..78caad1
--- /dev/null
+++ b/drivers/video/ofmode.c
@@ -0,0 +1,95 @@
+/*
+ * Get video mode settings from Flattened Device Tree.
+ *
+ * Copyright (C) 2010 DENX Software Engineering.
+ * Anatolij Gustschin <agust@denx.de>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License version 2. See the file COPYING in the main directory
+ * of this archive for more details.
+ */
+
+#include <linux/fb.h>
+#include <linux/of.h>
+
+int __devinit of_get_video_mode(struct device_node *np,
+				struct fb_info *info)
+{
+	struct fb_videomode dt_mode;
+	const u32 *prop;
+	unsigned int len;
+
+	if (!np || !info)
+		return -EINVAL;
+
+	prop = of_get_property(np, "width", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.xres = *prop;
+
+	prop = of_get_property(np, "height", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.yres = *prop;
+
+	prop = of_get_property(np, "depth", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	info->var.bits_per_pixel = *prop;
+
+	prop = of_get_property(np, "linebytes", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	info->fix.line_length = *prop;
+
+	prop = of_get_property(np, "refresh", &len);
+	if (prop && len == sizeof(u32))
+		dt_mode.refresh = *prop; /* optional */
+
+	prop = of_get_property(np, "pixclock", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.pixclock = *prop;
+
+	prop = of_get_property(np, "left_margin", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.left_margin = *prop;
+
+	prop = of_get_property(np, "right_margin", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.right_margin = *prop;
+
+	prop = of_get_property(np, "upper_margin", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.upper_margin = *prop;
+
+	prop = of_get_property(np, "lower_margin", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.lower_margin = *prop;
+
+	prop = of_get_property(np, "hsync_len", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.hsync_len = *prop;
+
+	prop = of_get_property(np, "vsync_len", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.vsync_len = *prop;
+
+	prop = of_get_property(np, "sync", &len);
+	if (!prop || len != sizeof(u32))
+		goto err;
+	dt_mode.sync = *prop;
+
+	fb_videomode_to_var(&info->var, &dt_mode);
+
+	return 0;
+err:
+	pr_err("%s: Can't find expected mode entry\n", np->full_name);
+	return -EINVAL;
+}
diff --git a/drivers/video/ofmode.h b/drivers/video/ofmode.h
new file mode 100644
index 0000000..9a13bec
--- /dev/null
+++ b/drivers/video/ofmode.h
@@ -0,0 +1,6 @@
+#ifndef _OFMODE_H
+#define _OFMODE_H
+
+extern int __devinit of_get_video_mode(struct device_node *np,
+					struct fb_info *info);
+#endif
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 2/3] fbdev: fsl-diu-fb.c: allow setting panel video mode from DT
  2010-02-16 18:06   ` Grant Likely
                       ` (2 preceding siblings ...)
  2010-02-27 21:58     ` [PATCH 1/3] video: add support for getting video mode from device tree Anatolij Gustschin
@ 2010-02-27 21:58     ` Anatolij Gustschin
  2010-02-28  6:52       ` Grant Likely
  2010-02-27 21:58     ` [PATCH 3/3] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
  2010-02-27 22:09     ` [PATCH v3 09/11] " Anatolij Gustschin
  5 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-27 21:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-fbdev, wd, dzu, jrigby, Anatolij Gustschin, yorksun

Add support for specifying display panel data in the device
tree. If no panel data is provided in the device tree, default
video mode will be used as usual.

Signed-off-by: Anatolij Gustschin <agust@denx.de>
---
 drivers/video/Kconfig      |    1 +
 drivers/video/fsl-diu-fb.c |   63 +++++++++++++++++++++++++-------------------
 2 files changed, 37 insertions(+), 27 deletions(-)

diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index dc1beb0..c805ecd 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -1850,6 +1850,7 @@ config FB_FSL_DIU
 	select FB_CFB_COPYAREA
 	select FB_CFB_IMAGEBLIT
 	select PPC_LIB_RHEAP
+	select FB_OF_MODE
 	---help---
 	  Framebuffer driver for the Freescale SoC DIU
 
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 4637bcb..19ca1da 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -36,6 +36,8 @@
 #include <sysdev/fsl_soc.h>
 #include "fsl-diu-fb.h"
 
+#include "ofmode.h"
+
 /*
  * These parameters give default parameters
  * for video output 1024x768,
@@ -1168,7 +1170,7 @@ static int init_fbinfo(struct fb_info *info)
 	return 0;
 }
 
-static int __devinit install_fb(struct fb_info *info)
+static int __devinit install_fb(struct device_node *np, struct fb_info *info)
 {
 	int rc;
 	struct mfb_info *mfbi = info->par;
@@ -1177,33 +1179,40 @@ static int __devinit install_fb(struct fb_info *info)
 	if (init_fbinfo(info))
 		return -EINVAL;
 
-	if (mfbi->index == 0)	/* plane 0 */
-		aoi_mode = fb_mode;
-	else
+	if (mfbi->index == 0) {	/* plane 0 */
+		/* use default mode for plane0 if there is no mode in DTB */
+		if (of_get_video_mode(np, info) < 0)
+			aoi_mode = fb_mode;
+		else
+			aoi_mode = NULL;
+	} else
 		aoi_mode = init_aoi_mode;
-	pr_debug("mode used = %s\n", aoi_mode);
-	rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
-	     ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mode, default_bpp);
 
-	switch (rc) {
-	case 1:
-		pr_debug("using mode specified in @mode\n");
-		break;
-	case 2:
-		pr_debug("using mode specified in @mode "
-			"with ignored refresh rate\n");
-		break;
-	case 3:
-		pr_debug("using mode default mode\n");
-		break;
-	case 4:
-		pr_debug("using mode from list\n");
-		break;
-	default:
-		pr_debug("rc = %d\n", rc);
-		pr_debug("failed to find mode\n");
-		return -EINVAL;
-		break;
+	if (aoi_mode) {
+		pr_debug("mode used = %s\n", aoi_mode);
+		rc = fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mode_db,
+				  ARRAY_SIZE(fsl_diu_mode_db),
+				  &fsl_diu_default_mode, default_bpp);
+		switch (rc) {
+		case 1:
+			pr_debug("using mode specified in @mode\n");
+			break;
+		case 2:
+			pr_debug("using mode specified in @mode "
+				"with ignored refresh rate\n");
+			break;
+		case 3:
+			pr_debug("using mode default mode\n");
+			break;
+		case 4:
+			pr_debug("using mode from list\n");
+			break;
+		default:
+			pr_debug("rc = %d\n", rc);
+			pr_debug("failed to find mode\n");
+			return -EINVAL;
+			break;
+		}
 	}
 
 	pr_debug("xres_virtual %d\n", info->var.xres_virtual);
@@ -1521,7 +1530,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 		mfbi->ad = (struct diu_ad *)((u32)pool.ad.vaddr
 					+ pool.ad.offset) + i;
 		mfbi->ad->paddr = pool.ad.paddr + i * sizeof(struct diu_ad);
-		ret = install_fb(machine_data->fsl_diu_info[i]);
+		ret = install_fb(np, machine_data->fsl_diu_info[i]);
 		if (ret) {
 			dev_err(&ofdev->dev,
 				"Failed to register framebuffer %d\n",
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* [PATCH 3/3] powerpc/mpc5121: shared DIU framebuffer support
  2010-02-16 18:06   ` Grant Likely
                       ` (3 preceding siblings ...)
  2010-02-27 21:58     ` [PATCH 2/3] fbdev: fsl-diu-fb.c: allow setting panel video mode from DT Anatolij Gustschin
@ 2010-02-27 21:58     ` Anatolij Gustschin
  2010-02-28  6:50       ` Grant Likely
  2010-02-27 22:09     ` [PATCH v3 09/11] " Anatolij Gustschin
  5 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-27 21:58 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: linux-fbdev, wd, dzu, jrigby, Anatolij Gustschin, yorksun

MPC5121 DIU configuration/setup as initialized by the boot
loader currently will get lost while booting Linux. As a
result displaying the boot splash is not possible through
the boot process.

To prevent this we reserve configured DIU frame buffer
address range while booting and preserve AOI descriptor
and gamma table so that DIU continues displaying through
the whole boot process. On first open from user space
DIU frame buffer driver releases the reserved frame
buffer area and continues to operate as usual.

The patch also moves drivers/video/fsl-diu-fb.h file to
include/linux as we use some DIU structures in platform
code.

'diu_ops' callbacks in platform code borrowed from John's
DIU code.

Signed-off-by: John Rigby <jrigby@gmail.com>
Signed-off-by: Anatolij Gustschin <agust@denx.de>
Cc: Grant Likely <grant.likely@secretlab.ca>
---
 arch/powerpc/platforms/512x/mpc5121_ads.c     |    7 +
 arch/powerpc/platforms/512x/mpc5121_generic.c |   13 ++
 arch/powerpc/platforms/512x/mpc512x.h         |    3 +
 arch/powerpc/platforms/512x/mpc512x_shared.c  |  282 +++++++++++++++++++++++++
 arch/powerpc/sysdev/fsl_soc.h                 |    1 +
 drivers/video/fsl-diu-fb.c                    |   25 ++-
 drivers/video/fsl-diu-fb.h                    |  223 -------------------
 include/linux/fsl-diu-fb.h                    |  223 +++++++++++++++++++
 8 files changed, 549 insertions(+), 228 deletions(-)
 delete mode 100644 drivers/video/fsl-diu-fb.h
 create mode 100644 include/linux/fsl-diu-fb.h

diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/platforms/512x/mpc5121_ads.c
index ee6ae12..aa4d5a8 100644
--- a/arch/powerpc/platforms/512x/mpc5121_ads.c
+++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
@@ -42,6 +42,7 @@ static void __init mpc5121_ads_setup_arch(void)
 	for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
 		mpc83xx_add_bridge(np);
 #endif
+	mpc512x_setup_diu();
 }
 
 static void __init mpc5121_ads_init_IRQ(void)
@@ -60,11 +61,17 @@ static int __init mpc5121_ads_probe(void)
 	return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
 }
 
+void __init mpc5121_ads_init_early(void)
+{
+	mpc512x_init_diu();
+}
+
 define_machine(mpc5121_ads) {
 	.name			= "MPC5121 ADS",
 	.probe			= mpc5121_ads_probe,
 	.setup_arch		= mpc5121_ads_setup_arch,
 	.init			= mpc512x_init,
+	.init_early		= mpc5121_ads_init_early,
 	.init_IRQ		= mpc5121_ads_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc/platforms/512x/mpc5121_generic.c
index a6c0e3a..3aaa281 100644
--- a/arch/powerpc/platforms/512x/mpc5121_generic.c
+++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
@@ -28,6 +28,7 @@
  */
 static char *board[] __initdata = {
 	"prt,prtlvt",
+	"ifm,pdm360ng",
 	NULL
 };
 
@@ -48,10 +49,22 @@ static int __init mpc5121_generic_probe(void)
 	return board[i] != NULL;
 }
 
+void __init mpc512x_generic_init_early(void)
+{
+	mpc512x_init_diu();
+}
+
+void __init mpc512x_generic_setup_arch(void)
+{
+	mpc512x_setup_diu();
+}
+
 define_machine(mpc5121_generic) {
 	.name			= "MPC5121 generic",
 	.probe			= mpc5121_generic_probe,
 	.init			= mpc512x_init,
+	.init_early		= mpc512x_generic_init_early,
+	.setup_arch		= mpc512x_generic_setup_arch,
 	.init_IRQ		= mpc512x_init_IRQ,
 	.get_irq		= ipic_get_irq,
 	.calibrate_decr		= generic_calibrate_decr,
diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platforms/512x/mpc512x.h
index d72b2c7..1cfe9d5 100644
--- a/arch/powerpc/platforms/512x/mpc512x.h
+++ b/arch/powerpc/platforms/512x/mpc512x.h
@@ -17,4 +17,7 @@ extern int __init mpc5121_clk_init(void);
 void __init mpc512x_declare_of_platform_devices(void);
 extern void mpc512x_restart(char *cmd);
 extern void __init mpc5121_usb_init(void);
+extern void __init mpc512x_init_diu(void);
+extern void __init mpc512x_setup_diu(void);
+extern struct fsl_diu_shared_fb diu_shared_fb;
 #endif				/* __MPC512X_H__ */
diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/platforms/512x/mpc512x_shared.c
index fbdf65f..a8c50a6 100644
--- a/arch/powerpc/platforms/512x/mpc512x_shared.c
+++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
@@ -16,7 +16,11 @@
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/of_platform.h>
+#include <linux/fsl-diu-fb.h>
+#include <linux/bootmem.h>
+#include <sysdev/fsl_soc.h>
 
+#include <asm/cacheflush.h>
 #include <asm/machdep.h>
 #include <asm/ipic.h>
 #include <asm/prom.h>
@@ -53,6 +57,284 @@ void mpc512x_restart(char *cmd)
 		;
 }
 
+struct fsl_diu_shared_fb {
+	char		gamma[0x300];	/* 32-bit aligned! */
+	struct diu_ad	ad0;		/* 32-bit aligned! */
+	phys_addr_t	fb_phys;
+	size_t		fb_len;
+	bool		in_use;
+};
+
+unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
+				      int monitor_port)
+{
+	unsigned int pix_fmt;
+
+	switch (bits_per_pixel) {
+	case 32:
+		pix_fmt = 0x88883316;
+		break;
+	case 24:
+		pix_fmt = 0x88082219;
+		break;
+	case 16:
+		pix_fmt = 0x65053118;
+		break;
+	default:
+		pix_fmt = 0x00000400;
+	}
+	return pix_fmt;
+}
+
+void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base)
+{
+}
+
+void mpc512x_set_monitor_port(int monitor_port)
+{
+}
+
+#define CCM_SCFR1	0x0000000c
+#define DIU_DIV_MASK	0x000000ff
+void mpc512x_set_pixel_clock(unsigned int pixclock)
+{
+	unsigned long bestval, bestfreq, speed_ccb, busfreq;
+	unsigned long minpixclock, maxpixclock, pixval;
+	struct device_node *np;
+	void __iomem *ccm;
+	u32 temp;
+	long err;
+	int i;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+	if (!np) {
+		pr_err("Can't find clock control module.\n");
+		return;
+	}
+
+	ccm = of_iomap(np, 0);
+	if (!ccm) {
+		pr_err("Can't map clock control module reg.\n");
+		of_node_put(np);
+		return;
+	}
+	of_node_put(np);
+
+	busfreq = 200000000;
+	np = of_find_node_by_type(NULL, "cpu");
+	if (np) {
+		unsigned int size;
+		const unsigned int *prop =
+			of_get_property(np, "bus-frequency", &size);
+		if (prop)
+			busfreq = *prop;
+		of_node_put(np);
+	}
+
+	/* Pixel Clock configuration */
+	pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
+	speed_ccb = busfreq * 4;
+
+	/* Calculate the pixel clock with the smallest error */
+	/* calculate the following in steps to avoid overflow */
+	pr_debug("DIU pixclock in ps - %d\n", pixclock);
+	temp = 1;
+	temp *= 1000000000;
+	temp /= pixclock;
+	temp *= 1000;
+	pixclock = temp;
+	pr_debug("DIU pixclock freq - %u\n", pixclock);
+
+	temp *= 5;
+	temp /= 100;  /* pixclock * 0.05 */
+	pr_debug("deviation = %d\n", temp);
+	minpixclock = pixclock - temp;
+	maxpixclock = pixclock + temp;
+	pr_debug("DIU minpixclock - %lu\n", minpixclock);
+	pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
+	pixval = speed_ccb/pixclock;
+	pr_debug("DIU pixval = %lu\n", pixval);
+
+	err = 100000000;
+	bestval = pixval;
+	pr_debug("DIU bestval = %lu\n", bestval);
+
+	bestfreq = 0;
+	for (i = -1; i <= 1; i++) {
+		temp = speed_ccb / (pixval+i);
+		pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
+			i, pixval, temp);
+		if ((temp < minpixclock) || (temp > maxpixclock))
+			pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
+				minpixclock, maxpixclock);
+		else if (abs(temp - pixclock) < err) {
+			pr_debug("Entered the else if block %d\n", i);
+			err = abs(temp - pixclock);
+			bestval = pixval + i;
+			bestfreq = temp;
+		}
+	}
+
+	pr_debug("DIU chose = %lx\n", bestval);
+	pr_debug("DIU error = %ld\n NomPixClk ", err);
+	pr_debug("DIU: Best Freq = %lx\n", bestfreq);
+	/* Modify DIU_DIV in CCM SCFR1 */
+	temp = in_be32(ccm + CCM_SCFR1);
+	pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
+	temp &= ~DIU_DIV_MASK;
+	temp |= (bestval & DIU_DIV_MASK);
+	out_be32(ccm + CCM_SCFR1, temp);
+	pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
+	iounmap(ccm);
+}
+
+ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "0 - 5121 LCD\n");
+}
+
+int mpc512x_set_sysfs_monitor_port(int val)
+{
+	return 0;
+}
+
+struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
+EXPORT_SYMBOL_GPL(diu_shared_fb);
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+    defined(CONFIG_FB_FSL_DIU_MODULE)
+static inline void mpc512x_free_bootmem(struct page *page)
+{
+	__ClearPageReserved(page);
+	BUG_ON(PageTail(page));
+	BUG_ON(atomic_read(&page->_count) > 1);
+	atomic_set(&page->_count, 1);
+	__free_page(page);
+	totalram_pages++;
+}
+
+void mpc512x_release_bootmem(void)
+{
+	unsigned long addr = diu_shared_fb.fb_phys & PAGE_MASK;
+	unsigned long size = diu_shared_fb.fb_len;
+	unsigned long start, end;
+
+	if (diu_shared_fb.in_use) {
+		start = PFN_UP(addr);
+		end = PFN_DOWN(addr + size);
+
+		for (; start < end; start++)
+			mpc512x_free_bootmem(pfn_to_page(start));
+
+		diu_shared_fb.in_use = false;
+	}
+	diu_ops.release_bootmem	= NULL;
+}
+#endif
+
+/*
+ * Check if DIU was pre-initialized. If so, perform steps
+ * needed to continue displaying through the whole boot process.
+ * Move area descriptor and gamma table elsewhere, they are
+ * destroyed by bootmem allocator otherwise. The frame buffer
+ * address range will be reserved in setup_arch() after bootmem
+ * allocator is up.
+ */
+void __init mpc512x_init_diu(void)
+{
+	struct device_node *np;
+	void __iomem *diu_reg;
+	phys_addr_t desc;
+	void __iomem *vaddr;
+	unsigned long mode, pix_fmt, res, bpp;
+	unsigned long dst;
+
+	np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
+	if (!np) {
+		pr_err("No DIU node\n");
+		return;
+	}
+
+	diu_reg = of_iomap(np, 0);
+	of_node_put(np);
+	if (!diu_reg) {
+		pr_err("Can't map DIU\n");
+		return;
+	}
+
+	mode = in_be32(diu_reg + 0x1c);
+	if (mode != 1) {
+		pr_info("%s: DIU OFF\n", __func__);
+		goto out;
+	}
+
+	desc = in_be32(diu_reg);
+	vaddr = ioremap(desc, sizeof(struct diu_ad));
+	if (!vaddr) {
+		pr_err("Can't map DIU area desc.\n");
+		goto out;
+	}
+	memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad));
+	/* flush fb area descriptor */
+	dst = (unsigned long)&diu_shared_fb.ad0;
+	flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1);
+
+	res = in_be32(diu_reg + 0x28);
+	pix_fmt = in_le32(vaddr);
+	bpp = ((pix_fmt >> 16) & 0x3) + 1;
+	diu_shared_fb.fb_phys = in_le32(vaddr + 4);
+	diu_shared_fb.fb_len = ((res & 0xfff0000) >> 16) * (res & 0xfff) * bpp;
+	diu_shared_fb.in_use = true;
+	iounmap(vaddr);
+
+	desc = in_be32(diu_reg + 0xc);
+	vaddr = ioremap(desc, sizeof(diu_shared_fb.gamma));
+	if (!vaddr) {
+		pr_err("Can't map DIU area desc.\n");
+		diu_shared_fb.in_use = false;
+		goto out;
+	}
+	memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.gamma));
+	/* flush gamma table */
+	dst = (unsigned long)&diu_shared_fb.gamma;
+	flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) - 1);
+
+	iounmap(vaddr);
+	out_be32(diu_reg + 0xc, virt_to_phys(&diu_shared_fb.gamma));
+	out_be32(diu_reg + 4, 0);
+	out_be32(diu_reg + 8, 0);
+	out_be32(diu_reg, virt_to_phys(&diu_shared_fb.ad0));
+
+out:
+	iounmap(diu_reg);
+}
+
+void __init mpc512x_setup_diu(void)
+{
+	int ret;
+
+	if (diu_shared_fb.in_use) {
+		ret = reserve_bootmem(diu_shared_fb.fb_phys,
+				      diu_shared_fb.fb_len,
+				      BOOTMEM_EXCLUSIVE);
+		if (ret) {
+			pr_err("%s: reserve bootmem failed\n", __func__);
+			diu_shared_fb.in_use = false;
+		}
+	}
+
+#if defined(CONFIG_FB_FSL_DIU) || \
+    defined(CONFIG_FB_FSL_DIU_MODULE)
+	diu_ops.get_pixel_format	= mpc512x_get_pixel_format;
+	diu_ops.set_gamma_table		= mpc512x_set_gamma_table;
+	diu_ops.set_monitor_port	= mpc512x_set_monitor_port;
+	diu_ops.set_pixel_clock		= mpc512x_set_pixel_clock;
+	diu_ops.show_monitor_port	= mpc512x_show_monitor_port;
+	diu_ops.set_sysfs_monitor_port	= mpc512x_set_sysfs_monitor_port;
+	diu_ops.release_bootmem		= mpc512x_release_bootmem;
+#endif
+}
+
 void __init mpc512x_init_IRQ(void)
 {
 	struct device_node *np;
diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.h
index 19754be..346057d 100644
--- a/arch/powerpc/sysdev/fsl_soc.h
+++ b/arch/powerpc/sysdev/fsl_soc.h
@@ -30,6 +30,7 @@ struct platform_diu_data_ops {
 	void (*set_pixel_clock) (unsigned int pixclock);
 	ssize_t (*show_monitor_port) (int monitor_port, char *buf);
 	int (*set_sysfs_monitor_port) (int val);
+	void (*release_bootmem) (void);
 };
 
 extern struct platform_diu_data_ops diu_ops;
diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
index 19ca1da..263f7da 100644
--- a/drivers/video/fsl-diu-fb.c
+++ b/drivers/video/fsl-diu-fb.c
@@ -34,7 +34,7 @@
 #include <linux/of_platform.h>
 
 #include <sysdev/fsl_soc.h>
-#include "fsl-diu-fb.h"
+#include <linux/fsl-diu-fb.h>
 
 #include "ofmode.h"
 
@@ -331,8 +331,11 @@ static int fsl_diu_enable_panel(struct fb_info *info)
 	if (mfbi->type != MFB_TYPE_OFF) {
 		switch (mfbi->index) {
 		case 0:				/* plane 0 */
-			if (hw->desc[0] != ad->paddr)
+			if (in_be32(&hw->desc[0]) != ad->paddr) {
+				out_be32(&dr.diu_reg->diu_mode, 0);
 				out_be32(&hw->desc[0], ad->paddr);
+				out_be32(&dr.diu_reg->diu_mode, 1);
+			}
 			break;
 		case 1:				/* plane 1 AOI 0 */
 			cmfbi = machine_data->fsl_diu_info[2]->par;
@@ -391,7 +394,7 @@ static int fsl_diu_disable_panel(struct fb_info *info)
 
 	switch (mfbi->index) {
 	case 0:					/* plane 0 */
-		if (hw->desc[0] != machine_data->dummy_ad->paddr)
+		if (in_be32(&hw->desc[0]) != machine_data->dummy_ad->paddr)
 			out_be32(&hw->desc[0],
 				machine_data->dummy_ad->paddr);
 		break;
@@ -1102,6 +1105,10 @@ static int fsl_diu_open(struct fb_info *info, int user)
 	struct mfb_info *mfbi = info->par;
 	int res = 0;
 
+	/* free boot splash memory on first /dev/fb0 open */
+	if (!mfbi->index && diu_ops.release_bootmem)
+		diu_ops.release_bootmem();
+
 	spin_lock(&diu_lock);
 	mfbi->count++;
 	if (mfbi->count == 1) {
@@ -1436,6 +1443,7 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	int ret, i, error = 0;
 	struct resource res;
 	struct fsl_diu_data *machine_data;
+	int diu_mode;
 
 	machine_data = kzalloc(sizeof(struct fsl_diu_data), GFP_KERNEL);
 	if (!machine_data)
@@ -1472,7 +1480,9 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 		goto error2;
 	}
 
-	out_be32(&dr.diu_reg->diu_mode, 0);		/* disable DIU anyway*/
+	diu_mode = in_be32(&dr.diu_reg->diu_mode);
+	if (diu_mode != MFB_MODE1)
+		out_be32(&dr.diu_reg->diu_mode, 0);	/* disable DIU */
 
 	/* Get the IRQ of the DIU */
 	machine_data->irq = irq_of_parse_and_map(np, 0);
@@ -1520,7 +1530,12 @@ static int __devinit fsl_diu_probe(struct of_device *ofdev,
 	machine_data->dummy_ad->offset_xyd = 0;
 	machine_data->dummy_ad->next_ad = 0;
 
-	out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+	/* Let DIU display splash screen if it was pre-initialized
+	 * by the bootloader, set dummy area descriptor otherwise.
+	 */
+	if (diu_mode != MFB_MODE1)
+		out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->paddr);
+
 	out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->paddr);
 	out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->paddr);
 
diff --git a/drivers/video/fsl-diu-fb.h b/drivers/video/fsl-diu-fb.h
deleted file mode 100644
index fc295d7..0000000
--- a/drivers/video/fsl-diu-fb.h
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
- *
- *  Freescale DIU Frame Buffer device driver
- *
- *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
- *           Paul Widmer <paul.widmer@freescale.com>
- *           Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
- *           York Sun <yorksun@freescale.com>
- *
- *   Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#ifndef __FSL_DIU_FB_H__
-#define __FSL_DIU_FB_H__
-
-/* Arbitrary threshold to determine the allocation method
- * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
- */
-#define MEM_ALLOC_THRESHOLD (1024*768*4+32)
-/* Minimum value that the pixel clock can be set to in pico seconds
- * This is determined by platform clock/3 where the minimum platform
- * clock is 533MHz. This gives 5629 pico seconds.
- */
-#define MIN_PIX_CLK 5629
-#define MAX_PIX_CLK 96096
-
-#include <linux/types.h>
-
-struct mfb_alpha {
-	int enable;
-	int alpha;
-};
-
-struct mfb_chroma_key {
-	int enable;
-	__u8  red_max;
-	__u8  green_max;
-	__u8  blue_max;
-	__u8  red_min;
-	__u8  green_min;
-	__u8  blue_min;
-};
-
-struct aoi_display_offset {
-	int x_aoi_d;
-	int y_aoi_d;
-};
-
-#define MFB_SET_CHROMA_KEY	_IOW('M', 1, struct mfb_chroma_key)
-#define MFB_WAIT_FOR_VSYNC	_IOW('F', 0x20, u_int32_t)
-#define MFB_SET_BRIGHTNESS	_IOW('M', 3, __u8)
-
-#define MFB_SET_ALPHA		0x80014d00
-#define MFB_GET_ALPHA		0x40014d00
-#define MFB_SET_AOID		0x80084d04
-#define MFB_GET_AOID		0x40084d04
-#define MFB_SET_PIXFMT		0x80014d08
-#define MFB_GET_PIXFMT		0x40014d08
-
-#define FBIOGET_GWINFO		0x46E0
-#define FBIOPUT_GWINFO		0x46E1
-
-#ifdef __KERNEL__
-#include <linux/spinlock.h>
-
-/*
- * These are the fields of area descriptor(in DDR memory) for every plane
- */
-struct diu_ad {
-	/* Word 0(32-bit) in DDR memory */
-/* 	__u16 comp; */
-/* 	__u16 pixel_s:2; */
-/* 	__u16 pallete:1; */
-/* 	__u16 red_c:2; */
-/* 	__u16 green_c:2; */
-/* 	__u16 blue_c:2; */
-/* 	__u16 alpha_c:3; */
-/* 	__u16 byte_f:1; */
-/* 	__u16 res0:3; */
-
-	__be32 pix_fmt; /* hard coding pixel format */
-
-	/* Word 1(32-bit) in DDR memory */
-	__le32 addr;
-
-	/* Word 2(32-bit) in DDR memory */
-/* 	__u32 delta_xs:11; */
-/* 	__u32 res1:1; */
-/* 	__u32 delta_ys:11; */
-/* 	__u32 res2:1; */
-/* 	__u32 g_alpha:8; */
-	__le32 src_size_g_alpha;
-
-	/* Word 3(32-bit) in DDR memory */
-/* 	__u32 delta_xi:11; */
-/* 	__u32 res3:5; */
-/* 	__u32 delta_yi:11; */
-/* 	__u32 res4:3; */
-/* 	__u32 flip:2; */
-	__le32 aoi_size;
-
-	/* Word 4(32-bit) in DDR memory */
-	/*__u32 offset_xi:11;
-	__u32 res5:5;
-	__u32 offset_yi:11;
-	__u32 res6:5;
-	*/
-	__le32 offset_xyi;
-
-	/* Word 5(32-bit) in DDR memory */
-	/*__u32 offset_xd:11;
-	__u32 res7:5;
-	__u32 offset_yd:11;
-	__u32 res8:5; */
-	__le32 offset_xyd;
-
-
-	/* Word 6(32-bit) in DDR memory */
-	__u8 ckmax_r;
-	__u8 ckmax_g;
-	__u8 ckmax_b;
-	__u8 res9;
-
-	/* Word 7(32-bit) in DDR memory */
-	__u8 ckmin_r;
-	__u8 ckmin_g;
-	__u8 ckmin_b;
-	__u8 res10;
-/* 	__u32 res10:8; */
-
-	/* Word 8(32-bit) in DDR memory */
-	__le32 next_ad;
-
-	/* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
-	__u32 paddr;
-} __attribute__ ((packed));
-
-/* DIU register map */
-struct diu {
-	__be32 desc[3];
-	__be32 gamma;
-	__be32 pallete;
-	__be32 cursor;
-	__be32 curs_pos;
-	__be32 diu_mode;
-	__be32 bgnd;
-	__be32 bgnd_wb;
-	__be32 disp_size;
-	__be32 wb_size;
-	__be32 wb_mem_addr;
-	__be32 hsyn_para;
-	__be32 vsyn_para;
-	__be32 syn_pol;
-	__be32 thresholds;
-	__be32 int_status;
-	__be32 int_mask;
-	__be32 colorbar[8];
-	__be32 filling;
-	__be32 plut;
-} __attribute__ ((packed));
-
-struct diu_hw {
-	struct diu *diu_reg;
-	spinlock_t reg_lock;
-
-	__u32 mode;		/* DIU operation mode */
-};
-
-struct diu_addr {
-	__u8 __iomem *vaddr;	/* Virtual address */
-	dma_addr_t paddr;	/* Physical address */
-	__u32 	   offset;
-};
-
-struct diu_pool {
-	struct diu_addr ad;
-	struct diu_addr gamma;
-	struct diu_addr pallete;
-	struct diu_addr cursor;
-};
-
-#define FSL_DIU_BASE_OFFSET	0x2C000	/* Offset of DIU */
-#define INT_LCDC		64	/* DIU interrupt number */
-
-#define FSL_AOI_NUM	6	/* 5 AOIs and one dummy AOI */
-				/* 1 for plane 0, 2 for plane 1&2 each */
-
-/* Minimum X and Y resolutions */
-#define MIN_XRES	64
-#define MIN_YRES	64
-
-/* HW cursor parameters */
-#define MAX_CURS		32
-
-/* Modes of operation of DIU */
-#define MFB_MODE0	0	/* DIU off */
-#define MFB_MODE1	1	/* All three planes output to display */
-#define MFB_MODE2	2	/* Plane 1 to display, planes 2+3 written back*/
-#define MFB_MODE3	3	/* All three planes written back to memory */
-#define MFB_MODE4	4	/* Color bar generation */
-
-/* INT_STATUS/INT_MASK field descriptions */
-#define INT_VSYNC	0x01	/* Vsync interrupt  */
-#define INT_VSYNC_WB	0x02	/* Vsync interrupt for write back operation */
-#define INT_UNDRUN	0x04	/* Under run exception interrupt */
-#define INT_PARERR	0x08	/* Display parameters error interrupt */
-#define INT_LS_BF_VS	0x10	/* Lines before vsync. interrupt */
-
-/* Panels'operation modes */
-#define MFB_TYPE_OUTPUT	0	/* Panel output to display */
-#define MFB_TYPE_OFF	1	/* Panel off */
-#define MFB_TYPE_WB	2	/* Panel written back to memory */
-#define MFB_TYPE_TEST	3	/* Panel generate color bar */
-
-#endif /* __KERNEL__ */
-#endif /* __FSL_DIU_FB_H__ */
diff --git a/include/linux/fsl-diu-fb.h b/include/linux/fsl-diu-fb.h
new file mode 100644
index 0000000..fc295d7
--- /dev/null
+++ b/include/linux/fsl-diu-fb.h
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2008 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ *  Freescale DIU Frame Buffer device driver
+ *
+ *  Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ *           Paul Widmer <paul.widmer@freescale.com>
+ *           Srikanth Srinivasan <srikanth.srinivasan@freescale.com>
+ *           York Sun <yorksun@freescale.com>
+ *
+ *   Based on imxfb.c Copyright (C) 2004 S.Hauer, Pengutronix
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __FSL_DIU_FB_H__
+#define __FSL_DIU_FB_H__
+
+/* Arbitrary threshold to determine the allocation method
+ * See mpc8610fb_set_par(), map_video_memory(), and unmap_video_memory()
+ */
+#define MEM_ALLOC_THRESHOLD (1024*768*4+32)
+/* Minimum value that the pixel clock can be set to in pico seconds
+ * This is determined by platform clock/3 where the minimum platform
+ * clock is 533MHz. This gives 5629 pico seconds.
+ */
+#define MIN_PIX_CLK 5629
+#define MAX_PIX_CLK 96096
+
+#include <linux/types.h>
+
+struct mfb_alpha {
+	int enable;
+	int alpha;
+};
+
+struct mfb_chroma_key {
+	int enable;
+	__u8  red_max;
+	__u8  green_max;
+	__u8  blue_max;
+	__u8  red_min;
+	__u8  green_min;
+	__u8  blue_min;
+};
+
+struct aoi_display_offset {
+	int x_aoi_d;
+	int y_aoi_d;
+};
+
+#define MFB_SET_CHROMA_KEY	_IOW('M', 1, struct mfb_chroma_key)
+#define MFB_WAIT_FOR_VSYNC	_IOW('F', 0x20, u_int32_t)
+#define MFB_SET_BRIGHTNESS	_IOW('M', 3, __u8)
+
+#define MFB_SET_ALPHA		0x80014d00
+#define MFB_GET_ALPHA		0x40014d00
+#define MFB_SET_AOID		0x80084d04
+#define MFB_GET_AOID		0x40084d04
+#define MFB_SET_PIXFMT		0x80014d08
+#define MFB_GET_PIXFMT		0x40014d08
+
+#define FBIOGET_GWINFO		0x46E0
+#define FBIOPUT_GWINFO		0x46E1
+
+#ifdef __KERNEL__
+#include <linux/spinlock.h>
+
+/*
+ * These are the fields of area descriptor(in DDR memory) for every plane
+ */
+struct diu_ad {
+	/* Word 0(32-bit) in DDR memory */
+/* 	__u16 comp; */
+/* 	__u16 pixel_s:2; */
+/* 	__u16 pallete:1; */
+/* 	__u16 red_c:2; */
+/* 	__u16 green_c:2; */
+/* 	__u16 blue_c:2; */
+/* 	__u16 alpha_c:3; */
+/* 	__u16 byte_f:1; */
+/* 	__u16 res0:3; */
+
+	__be32 pix_fmt; /* hard coding pixel format */
+
+	/* Word 1(32-bit) in DDR memory */
+	__le32 addr;
+
+	/* Word 2(32-bit) in DDR memory */
+/* 	__u32 delta_xs:11; */
+/* 	__u32 res1:1; */
+/* 	__u32 delta_ys:11; */
+/* 	__u32 res2:1; */
+/* 	__u32 g_alpha:8; */
+	__le32 src_size_g_alpha;
+
+	/* Word 3(32-bit) in DDR memory */
+/* 	__u32 delta_xi:11; */
+/* 	__u32 res3:5; */
+/* 	__u32 delta_yi:11; */
+/* 	__u32 res4:3; */
+/* 	__u32 flip:2; */
+	__le32 aoi_size;
+
+	/* Word 4(32-bit) in DDR memory */
+	/*__u32 offset_xi:11;
+	__u32 res5:5;
+	__u32 offset_yi:11;
+	__u32 res6:5;
+	*/
+	__le32 offset_xyi;
+
+	/* Word 5(32-bit) in DDR memory */
+	/*__u32 offset_xd:11;
+	__u32 res7:5;
+	__u32 offset_yd:11;
+	__u32 res8:5; */
+	__le32 offset_xyd;
+
+
+	/* Word 6(32-bit) in DDR memory */
+	__u8 ckmax_r;
+	__u8 ckmax_g;
+	__u8 ckmax_b;
+	__u8 res9;
+
+	/* Word 7(32-bit) in DDR memory */
+	__u8 ckmin_r;
+	__u8 ckmin_g;
+	__u8 ckmin_b;
+	__u8 res10;
+/* 	__u32 res10:8; */
+
+	/* Word 8(32-bit) in DDR memory */
+	__le32 next_ad;
+
+	/* Word 9(32-bit) in DDR memory, just for 64-bit aligned */
+	__u32 paddr;
+} __attribute__ ((packed));
+
+/* DIU register map */
+struct diu {
+	__be32 desc[3];
+	__be32 gamma;
+	__be32 pallete;
+	__be32 cursor;
+	__be32 curs_pos;
+	__be32 diu_mode;
+	__be32 bgnd;
+	__be32 bgnd_wb;
+	__be32 disp_size;
+	__be32 wb_size;
+	__be32 wb_mem_addr;
+	__be32 hsyn_para;
+	__be32 vsyn_para;
+	__be32 syn_pol;
+	__be32 thresholds;
+	__be32 int_status;
+	__be32 int_mask;
+	__be32 colorbar[8];
+	__be32 filling;
+	__be32 plut;
+} __attribute__ ((packed));
+
+struct diu_hw {
+	struct diu *diu_reg;
+	spinlock_t reg_lock;
+
+	__u32 mode;		/* DIU operation mode */
+};
+
+struct diu_addr {
+	__u8 __iomem *vaddr;	/* Virtual address */
+	dma_addr_t paddr;	/* Physical address */
+	__u32 	   offset;
+};
+
+struct diu_pool {
+	struct diu_addr ad;
+	struct diu_addr gamma;
+	struct diu_addr pallete;
+	struct diu_addr cursor;
+};
+
+#define FSL_DIU_BASE_OFFSET	0x2C000	/* Offset of DIU */
+#define INT_LCDC		64	/* DIU interrupt number */
+
+#define FSL_AOI_NUM	6	/* 5 AOIs and one dummy AOI */
+				/* 1 for plane 0, 2 for plane 1&2 each */
+
+/* Minimum X and Y resolutions */
+#define MIN_XRES	64
+#define MIN_YRES	64
+
+/* HW cursor parameters */
+#define MAX_CURS		32
+
+/* Modes of operation of DIU */
+#define MFB_MODE0	0	/* DIU off */
+#define MFB_MODE1	1	/* All three planes output to display */
+#define MFB_MODE2	2	/* Plane 1 to display, planes 2+3 written back*/
+#define MFB_MODE3	3	/* All three planes written back to memory */
+#define MFB_MODE4	4	/* Color bar generation */
+
+/* INT_STATUS/INT_MASK field descriptions */
+#define INT_VSYNC	0x01	/* Vsync interrupt  */
+#define INT_VSYNC_WB	0x02	/* Vsync interrupt for write back operation */
+#define INT_UNDRUN	0x04	/* Under run exception interrupt */
+#define INT_PARERR	0x08	/* Display parameters error interrupt */
+#define INT_LS_BF_VS	0x10	/* Lines before vsync. interrupt */
+
+/* Panels'operation modes */
+#define MFB_TYPE_OUTPUT	0	/* Panel output to display */
+#define MFB_TYPE_OFF	1	/* Panel off */
+#define MFB_TYPE_WB	2	/* Panel written back to memory */
+#define MFB_TYPE_TEST	3	/* Panel generate color bar */
+
+#endif /* __KERNEL__ */
+#endif /* __FSL_DIU_FB_H__ */
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support
  2010-02-16 18:06   ` Grant Likely
                       ` (4 preceding siblings ...)
  2010-02-27 21:58     ` [PATCH 3/3] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
@ 2010-02-27 22:09     ` Anatolij Gustschin
  5 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-02-27 22:09 UTC (permalink / raw)
  To: Grant Likely; +Cc: wd, dzu, John Rigby, linuxppc-dev, York Sun

On Tue, 16 Feb 2010 11:06:22 -0700
Grant Likely <grant.likely@secretlab.ca> wrote:

> [...]
> > diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> > index 72d68b3..29c7f31 100644
> > --- a/drivers/video/fsl-diu-fb.c
> > +++ b/drivers/video/fsl-diu-fb.c
> > @@ -34,7 +34,7 @@
> > =C2=A0#include <linux/of_platform.h>
> >
> > =C2=A0#include <sysdev/fsl_soc.h>
> > -#include "fsl-diu-fb.h"
> > +#include <linux/fsl-diu-fb.h>
> >
> > =C2=A0/*
> > =C2=A0* These parameters give default parameters
> > @@ -178,6 +178,21 @@ static struct fb_videomode __devinitdata fsl_diu_m=
ode_db[] =3D {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.sync =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =3D FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0.vmode =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0=3D FB_VMODE_NONINTERLACED
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0},
> > + =C2=A0 =C2=A0 =C2=A0 {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .name =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =3D "800x480-60",
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .refresh =C2=A0 =C2=
=A0 =C2=A0 =C2=A0=3D 60,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .xres =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =3D 800,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .yres =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =3D 480,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .pixclock =C2=A0 =C2=
=A0 =C2=A0 =3D 31250,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .left_margin =C2=A0 =
=C2=A0=3D 86,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .right_margin =C2=A0=
 =3D 42,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .upper_margin =C2=A0=
 =3D 33,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .lower_margin =C2=A0=
 =3D 10,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .hsync_len =C2=A0 =
=C2=A0 =C2=A0=3D 128,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .vsync_len =C2=A0 =
=C2=A0 =C2=A0=3D 2,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .sync =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =3D FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 .vmode =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0=3D FB_VMODE_NONINTERLACED
> > + =C2=A0 =C2=A0 =C2=A0 },
> > =C2=A0};
>=20
> This hunk bothers me.  It looks like the type of data that belongs
> either in some common shared .c file, or encoded into the device tree.
>  It seems to be data about the display panel, instead of data about
> the framebuffer driver.  I know that the driver already uses this
> pattern, but before I merge this patch and further rely on that
> pattern, I think it is worth discussing.

In the updated DIU patches I don't add panel timing data to the
framebuffer driver. It is encoded in the device tree now. If this
is acceptable, I'll send another patch adding the documentation
for added bindings.

Thanks,
Anatolij

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 1/3] video: add support for getting video mode from device tree
  2010-02-27 21:58     ` [PATCH 1/3] video: add support for getting video mode from device tree Anatolij Gustschin
@ 2010-02-28  6:30       ` Grant Likely
  2010-02-28  8:44         ` Mitch Bradley
  0 siblings, 1 reply; 48+ messages in thread
From: Grant Likely @ 2010-02-28  6:30 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: linux-fbdev, wd, dzu, jrigby, devicetree-discuss, linuxppc-dev, yorksun

Hi Anatolij,

[added cc: to devicetree-discuss@lists.ozlabs.org]

On Sat, Feb 27, 2010 at 2:58 PM, Anatolij Gustschin <agust@denx.de> wrote:
> Framebuffer drivers may want to get panel timing info
> from the device tree. This patch adds appropriate support.
> Subsequent patch for FSL DIU frame buffer driver makes use
> of this functionality.

I think this is moving in the right direction, but there needs to
debate & review over the binding before committing to anything.
Please write a patch that documents the new binding in
Documentation/powerpc/dts-bindings.  All new bindings should be
documented and reviewed on devicetree-discuss before merging any
drivers that use them into mainline.

>From what I can tell by reading your code, I suspect that the binding
you've designed will solve your immediate problem, but won't be able
to handle anything slightly more complex, but it also looks like the
binding has been designed to be generic, usable by any display device.

First off, I did a tiny amount of research, and I didn't find any
existing OpenFirmware bindings for describing video displays.
Otherwise, I'd suggest considering that.

>From the little bit that I know, it seems that for most video devices
(ie. PCs) the video card discovers the capabilities of the screen by
reading the monitor's EDID data.  However, in your particular case
embedded case, a fixed flat panel is attached, and there isn't any
EDID data provided.  Therefore, you need an alternate method of
describing the display capabilities.  Rather than designing something
entirely new, you may want to consider using the EDID data format
directly; or at least cover the same things that EDID describes.  The
downside to using EDID directly is that it is a packed binary format
that isn't parseable by mere mortals; but the data contained in it
seems about right.  The upside is the kernel already knows what to do
with EDID data.

Otherwise you risk designing something that won't be useful for
anything much outside of your own use case.  For example, the binding
I see from the code cannot handle a display with multiple output
modes.

Also, since you're now in the realm of describing a video display,
which is separate from the display controller, you should consider
describing the display in a separate device tree node.  Maybe
something like this...

video {
        compatible =3D "fsl,mpc5121-diu";
        display {
                compatible =3D "<vendor>,<model>";
                edid =3D [edid-data];
        };
};

Cheers,
g.

>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> ---
> =A0drivers/video/Kconfig =A0| =A0 =A05 +++
> =A0drivers/video/Makefile | =A0 =A01 +
> =A0drivers/video/ofmode.c | =A0 95 ++++++++++++++++++++++++++++++++++++++=
++++++++++
> =A0drivers/video/ofmode.h | =A0 =A06 +++
> =A04 files changed, 107 insertions(+), 0 deletions(-)
> =A0create mode 100644 drivers/video/ofmode.c
> =A0create mode 100644 drivers/video/ofmode.h
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index 5a5c303..dc1beb0 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -203,6 +203,11 @@ config FB_MACMODES
> =A0 =A0 =A0 =A0depends on FB
> =A0 =A0 =A0 =A0default n
>
> +config FB_OF_MODE
> + =A0 =A0 =A0 tristate
> + =A0 =A0 =A0 depends on FB && OF
> + =A0 =A0 =A0 default n
> +
> =A0config FB_BACKLIGHT
> =A0 =A0 =A0 =A0bool
> =A0 =A0 =A0 =A0depends on FB
> diff --git a/drivers/video/Makefile b/drivers/video/Makefile
> index 4ecb30c..c4a912b 100644
> --- a/drivers/video/Makefile
> +++ b/drivers/video/Makefile
> @@ -26,6 +26,7 @@ obj-$(CONFIG_FB_SVGALIB) =A0 =A0 =A0 +=3D svgalib.o
> =A0obj-$(CONFIG_FB_MACMODES) =A0 =A0 =A0+=3D macmodes.o
> =A0obj-$(CONFIG_FB_DDC) =A0 =A0 =A0 =A0 =A0 +=3D fb_ddc.o
> =A0obj-$(CONFIG_FB_DEFERRED_IO) =A0 +=3D fb_defio.o
> +obj-$(CONFIG_FB_OF_MODE) =A0 =A0 =A0 +=3D ofmode.o
>
> =A0# Hardware specific drivers go first
> =A0obj-$(CONFIG_FB_AMIGA) =A0 =A0 =A0 =A0 =A0 =A0+=3D amifb.o c2p_planar.=
o
> diff --git a/drivers/video/ofmode.c b/drivers/video/ofmode.c
> new file mode 100644
> index 0000000..78caad1
> --- /dev/null
> +++ b/drivers/video/ofmode.c
> @@ -0,0 +1,95 @@
> +/*
> + * Get video mode settings from Flattened Device Tree.
> + *
> + * Copyright (C) 2010 DENX Software Engineering.
> + * Anatolij Gustschin <agust@denx.de>
> + *
> + * This file is subject to the terms and conditions of the GNU General
> + * Public License version 2. See the file COPYING in the main directory
> + * of this archive for more details.
> + */
> +
> +#include <linux/fb.h>
> +#include <linux/of.h>
> +
> +int __devinit of_get_video_mode(struct device_node *np,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 struct fb_i=
nfo *info)
> +{
> + =A0 =A0 =A0 struct fb_videomode dt_mode;
> + =A0 =A0 =A0 const u32 *prop;
> + =A0 =A0 =A0 unsigned int len;
> +
> + =A0 =A0 =A0 if (!np || !info)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "width", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.xres =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "height", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.yres =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "depth", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 info->var.bits_per_pixel =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "linebytes", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 info->fix.line_length =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "refresh", &len);
> + =A0 =A0 =A0 if (prop && len =3D=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 dt_mode.refresh =3D *prop; /* optional */
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "pixclock", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.pixclock =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "left_margin", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.left_margin =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "right_margin", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.right_margin =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "upper_margin", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.upper_margin =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "lower_margin", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.lower_margin =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "hsync_len", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.hsync_len =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "vsync_len", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.vsync_len =3D *prop;
> +
> + =A0 =A0 =A0 prop =3D of_get_property(np, "sync", &len);
> + =A0 =A0 =A0 if (!prop || len !=3D sizeof(u32))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto err;
> + =A0 =A0 =A0 dt_mode.sync =3D *prop;
> +
> + =A0 =A0 =A0 fb_videomode_to_var(&info->var, &dt_mode);
> +
> + =A0 =A0 =A0 return 0;
> +err:
> + =A0 =A0 =A0 pr_err("%s: Can't find expected mode entry\n", np->full_nam=
e);
> + =A0 =A0 =A0 return -EINVAL;
> +}
> diff --git a/drivers/video/ofmode.h b/drivers/video/ofmode.h
> new file mode 100644
> index 0000000..9a13bec
> --- /dev/null
> +++ b/drivers/video/ofmode.h
> @@ -0,0 +1,6 @@
> +#ifndef _OFMODE_H
> +#define _OFMODE_H
> +
> +extern int __devinit of_get_video_mode(struct device_node *np,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 =A0 struct fb_info *info);
> +#endif
> --
> 1.6.3.3
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 3/3] powerpc/mpc5121: shared DIU framebuffer support
  2010-02-27 21:58     ` [PATCH 3/3] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
@ 2010-02-28  6:50       ` Grant Likely
  2010-04-28 20:28         ` Anatolij Gustschin
  0 siblings, 1 reply; 48+ messages in thread
From: Grant Likely @ 2010-02-28  6:50 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linux-fbdev, wd, dzu, jrigby, linuxppc-dev, yorksun

On Sat, Feb 27, 2010 at 2:58 PM, Anatolij Gustschin <agust@denx.de> wrote:
> MPC5121 DIU configuration/setup as initialized by the boot
> loader currently will get lost while booting Linux. As a
> result displaying the boot splash is not possible through
> the boot process.
>
> To prevent this we reserve configured DIU frame buffer
> address range while booting and preserve AOI descriptor
> and gamma table so that DIU continues displaying through
> the whole boot process. On first open from user space
> DIU frame buffer driver releases the reserved frame
> buffer area and continues to operate as usual.
>
> The patch also moves drivers/video/fsl-diu-fb.h file to
> include/linux as we use some DIU structures in platform
> code.
>
> 'diu_ops' callbacks in platform code borrowed from John's
> DIU code.
>
> Signed-off-by: John Rigby <jrigby@gmail.com>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Grant Likely <grant.likely@secretlab.ca>

On quick glance this patch seems mostly okay, but this patch should
probably be broken up a bit to simplify review and dissociate
unrelated changes.  For example, the move of fsl-diu-fb.h is a
discrete change that should be split off.  Some more comments
below....

> ---
> =A0arch/powerpc/platforms/512x/mpc5121_ads.c =A0 =A0 | =A0 =A07 +
> =A0arch/powerpc/platforms/512x/mpc5121_generic.c | =A0 13 ++
> =A0arch/powerpc/platforms/512x/mpc512x.h =A0 =A0 =A0 =A0 | =A0 =A03 +
> =A0arch/powerpc/platforms/512x/mpc512x_shared.c =A0| =A0282 +++++++++++++=
++++++++++++
> =A0arch/powerpc/sysdev/fsl_soc.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 | =A0 =
=A01 +
> =A0drivers/video/fsl-diu-fb.c =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =
=A0 25 ++-
> =A0drivers/video/fsl-diu-fb.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =
=A0223 -------------------
> =A0include/linux/fsl-diu-fb.h =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0| =
=A0223 +++++++++++++++++++
> =A08 files changed, 549 insertions(+), 228 deletions(-)
> =A0delete mode 100644 drivers/video/fsl-diu-fb.h
> =A0create mode 100644 include/linux/fsl-diu-fb.h
>
> diff --git a/arch/powerpc/platforms/512x/mpc5121_ads.c b/arch/powerpc/pla=
tforms/512x/mpc5121_ads.c
> index ee6ae12..aa4d5a8 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_ads.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_ads.c
> @@ -42,6 +42,7 @@ static void __init mpc5121_ads_setup_arch(void)
> =A0 =A0 =A0 =A0for_each_compatible_node(np, "pci", "fsl,mpc5121-pci")
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mpc83xx_add_bridge(np);
> =A0#endif
> + =A0 =A0 =A0 mpc512x_setup_diu();
> =A0}
>
> =A0static void __init mpc5121_ads_init_IRQ(void)
> @@ -60,11 +61,17 @@ static int __init mpc5121_ads_probe(void)
> =A0 =A0 =A0 =A0return of_flat_dt_is_compatible(root, "fsl,mpc5121ads");
> =A0}
>
> +void __init mpc5121_ads_init_early(void)
> +{
> + =A0 =A0 =A0 mpc512x_init_diu();
> +}
> +
> =A0define_machine(mpc5121_ads) {
> =A0 =A0 =A0 =A0.name =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D "MPC5121 ADS=
",
> =A0 =A0 =A0 =A0.probe =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D mpc5121_ads_=
probe,
> =A0 =A0 =A0 =A0.setup_arch =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc5121_ads_setup_=
arch,
> =A0 =A0 =A0 =A0.init =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_init=
,
> + =A0 =A0 =A0 .init_early =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc5121_ads_init_ea=
rly,
> =A0 =A0 =A0 =A0.init_IRQ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc5121_ads_init=
_IRQ,
> =A0 =A0 =A0 =A0.get_irq =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D ipic_get_irq,
> =A0 =A0 =A0 =A0.calibrate_decr =A0 =A0 =A0 =A0 =3D generic_calibrate_decr=
,
> diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/powerpc=
/platforms/512x/mpc5121_generic.c
> index a6c0e3a..3aaa281 100644
> --- a/arch/powerpc/platforms/512x/mpc5121_generic.c
> +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
> @@ -28,6 +28,7 @@
> =A0*/
> =A0static char *board[] __initdata =3D {
> =A0 =A0 =A0 =A0"prt,prtlvt",
> + =A0 =A0 =A0 "ifm,pdm360ng",

You're adding a new board here.  This is completely unrelated.

> =A0 =A0 =A0 =A0NULL
> =A0};
>
> @@ -48,10 +49,22 @@ static int __init mpc5121_generic_probe(void)
> =A0 =A0 =A0 =A0return board[i] !=3D NULL;
> =A0}
>
> +void __init mpc512x_generic_init_early(void)
> +{
> + =A0 =A0 =A0 mpc512x_init_diu();
> +}
> +
> +void __init mpc512x_generic_setup_arch(void)
> +{
> + =A0 =A0 =A0 mpc512x_setup_diu();
> +}
> +
> =A0define_machine(mpc5121_generic) {
> =A0 =A0 =A0 =A0.name =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D "MPC5121 gen=
eric",
> =A0 =A0 =A0 =A0.probe =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D mpc5121_gene=
ric_probe,
> =A0 =A0 =A0 =A0.init =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_init=
,
> + =A0 =A0 =A0 .init_early =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_generic_ini=
t_early,
> + =A0 =A0 =A0 .setup_arch =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_generic_set=
up_arch,
> =A0 =A0 =A0 =A0.init_IRQ =A0 =A0 =A0 =A0 =A0 =A0 =A0 =3D mpc512x_init_IRQ=
,
> =A0 =A0 =A0 =A0.get_irq =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D ipic_get_irq,
> =A0 =A0 =A0 =A0.calibrate_decr =A0 =A0 =A0 =A0 =3D generic_calibrate_decr=
,
> diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platfor=
ms/512x/mpc512x.h
> index d72b2c7..1cfe9d5 100644
> --- a/arch/powerpc/platforms/512x/mpc512x.h
> +++ b/arch/powerpc/platforms/512x/mpc512x.h
> @@ -17,4 +17,7 @@ extern int __init mpc5121_clk_init(void);
> =A0void __init mpc512x_declare_of_platform_devices(void);
> =A0extern void mpc512x_restart(char *cmd);
> =A0extern void __init mpc5121_usb_init(void);
> +extern void __init mpc512x_init_diu(void);
> +extern void __init mpc512x_setup_diu(void);

__init annotations do not belong in header files.

> +extern struct fsl_diu_shared_fb diu_shared_fb;

Hmmmm.  I'm not fond of the global data structure.  Especially
considering that the struct fsl_diu_shared_fb is defined in
mpc512x_shared.c, so nothing outside of that .c file can do anything
with the structure.

> =A0#endif =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* __MPC512X_H_=
_ */
> diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerpc/=
platforms/512x/mpc512x_shared.c
> index fbdf65f..a8c50a6 100644
> --- a/arch/powerpc/platforms/512x/mpc512x_shared.c
> +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
> @@ -16,7 +16,11 @@
> =A0#include <linux/io.h>
> =A0#include <linux/irq.h>
> =A0#include <linux/of_platform.h>
> +#include <linux/fsl-diu-fb.h>
> +#include <linux/bootmem.h>
> +#include <sysdev/fsl_soc.h>
>
> +#include <asm/cacheflush.h>
> =A0#include <asm/machdep.h>
> =A0#include <asm/ipic.h>
> =A0#include <asm/prom.h>
> @@ -53,6 +57,284 @@ void mpc512x_restart(char *cmd)
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0;
> =A0}
>
> +struct fsl_diu_shared_fb {
> + =A0 =A0 =A0 char =A0 =A0 =A0 =A0 =A0 =A0gamma[0x300]; =A0 /* 32-bit ali=
gned! */
> + =A0 =A0 =A0 struct diu_ad =A0 ad0; =A0 =A0 =A0 =A0 =A0 =A0/* 32-bit ali=
gned! */
> + =A0 =A0 =A0 phys_addr_t =A0 =A0 fb_phys;
> + =A0 =A0 =A0 size_t =A0 =A0 =A0 =A0 =A0fb_len;
> + =A0 =A0 =A0 bool =A0 =A0 =A0 =A0 =A0 =A0in_use;
> +};
> +
> +unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 int monitor_port)
> +{
> + =A0 =A0 =A0 unsigned int pix_fmt;
> +
> + =A0 =A0 =A0 switch (bits_per_pixel) {
> + =A0 =A0 =A0 case 32:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pix_fmt =3D 0x88883316;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case 24:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pix_fmt =3D 0x88082219;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 case 16:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pix_fmt =3D 0x65053118;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pix_fmt =3D 0x00000400;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 return pix_fmt;
> +}
> +
> +void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base)
> +{
> +}
> +
> +void mpc512x_set_monitor_port(int monitor_port)
> +{
> +}
> +
> +#define CCM_SCFR1 =A0 =A0 =A00x0000000c
> +#define DIU_DIV_MASK =A0 0x000000ff
> +void mpc512x_set_pixel_clock(unsigned int pixclock)
> +{
> + =A0 =A0 =A0 unsigned long bestval, bestfreq, speed_ccb, busfreq;
> + =A0 =A0 =A0 unsigned long minpixclock, maxpixclock, pixval;
> + =A0 =A0 =A0 struct device_node *np;
> + =A0 =A0 =A0 void __iomem *ccm;
> + =A0 =A0 =A0 u32 temp;
> + =A0 =A0 =A0 long err;
> + =A0 =A0 =A0 int i;
> +
> + =A0 =A0 =A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clo=
ck");
> + =A0 =A0 =A0 if (!np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("Can't find clock control module.\n"=
);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 ccm =3D of_iomap(np, 0);
> + =A0 =A0 =A0 if (!ccm) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("Can't map clock control module reg.=
\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(np);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 of_node_put(np);
> +
> + =A0 =A0 =A0 busfreq =3D 200000000;

Instead of some hard coding some bogus defalt busfreq, you should
error out if the real frequency cannot be determined.  Force users to
supply a valid tree.

> + =A0 =A0 =A0 np =3D of_find_node_by_type(NULL, "cpu");
> + =A0 =A0 =A0 if (np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 unsigned int size;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 const unsigned int *prop =3D
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_get_property(np, "bus-fr=
equency", &size);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (prop)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 busfreq =3D *prop;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 of_node_put(np);
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 /* Pixel Clock configuration */
> + =A0 =A0 =A0 pr_debug("DIU: Bus Frequency =3D %lu\n", busfreq);
> + =A0 =A0 =A0 speed_ccb =3D busfreq * 4;
> +
> + =A0 =A0 =A0 /* Calculate the pixel clock with the smallest error */
> + =A0 =A0 =A0 /* calculate the following in steps to avoid overflow */
> + =A0 =A0 =A0 pr_debug("DIU pixclock in ps - %d\n", pixclock);
> + =A0 =A0 =A0 temp =3D 1;
> + =A0 =A0 =A0 temp *=3D 1000000000;
> + =A0 =A0 =A0 temp /=3D pixclock;
> + =A0 =A0 =A0 temp *=3D 1000;
> + =A0 =A0 =A0 pixclock =3D temp;

Really?  I think you can simplify this.

> + =A0 =A0 =A0 pr_debug("DIU pixclock freq - %u\n", pixclock);
> +
> + =A0 =A0 =A0 temp *=3D 5;
> + =A0 =A0 =A0 temp /=3D 100; =A0/* pixclock * 0.05 */
> + =A0 =A0 =A0 pr_debug("deviation =3D %d\n", temp);
> + =A0 =A0 =A0 minpixclock =3D pixclock - temp;
> + =A0 =A0 =A0 maxpixclock =3D pixclock + temp;
> + =A0 =A0 =A0 pr_debug("DIU minpixclock - %lu\n", minpixclock);
> + =A0 =A0 =A0 pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
> + =A0 =A0 =A0 pixval =3D speed_ccb/pixclock;
> + =A0 =A0 =A0 pr_debug("DIU pixval =3D %lu\n", pixval);
> +
> + =A0 =A0 =A0 err =3D 100000000;
> + =A0 =A0 =A0 bestval =3D pixval;
> + =A0 =A0 =A0 pr_debug("DIU bestval =3D %lu\n", bestval);
> +
> + =A0 =A0 =A0 bestfreq =3D 0;
> + =A0 =A0 =A0 for (i =3D -1; i <=3D 1; i++) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 temp =3D speed_ccb / (pixval+i);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("DIU test pixval i=3D%d, pixval=3D=
%lu, temp freq. =3D %u\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 i, pixval, temp);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if ((temp < minpixclock) || (temp > maxpixc=
lock))
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("DIU exceeds monit=
or range (%lu to %lu)\n",
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 minpixclock=
, maxpixclock);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else if (abs(temp - pixclock) < err) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("Entered the else =
if block %d\n", i);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 err =3D abs(temp - pixclock=
);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bestval =3D pixval + i;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 bestfreq =3D temp;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 pr_debug("DIU chose =3D %lx\n", bestval);
> + =A0 =A0 =A0 pr_debug("DIU error =3D %ld\n NomPixClk ", err);
> + =A0 =A0 =A0 pr_debug("DIU: Best Freq =3D %lx\n", bestfreq);
> + =A0 =A0 =A0 /* Modify DIU_DIV in CCM SCFR1 */
> + =A0 =A0 =A0 temp =3D in_be32(ccm + CCM_SCFR1);
> + =A0 =A0 =A0 pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
> + =A0 =A0 =A0 temp &=3D ~DIU_DIV_MASK;
> + =A0 =A0 =A0 temp |=3D (bestval & DIU_DIV_MASK);
> + =A0 =A0 =A0 out_be32(ccm + CCM_SCFR1, temp);
> + =A0 =A0 =A0 pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
> + =A0 =A0 =A0 iounmap(ccm);
> +}
> +
> +ssize_t mpc512x_show_monitor_port(int monitor_port, char *buf)
> +{
> + =A0 =A0 =A0 return snprintf(buf, PAGE_SIZE, "0 - 5121 LCD\n");
> +}
> +
> +int mpc512x_set_sysfs_monitor_port(int val)
> +{
> + =A0 =A0 =A0 return 0;
> +}
> +
> +struct fsl_diu_shared_fb __attribute__ ((__aligned__(8))) diu_shared_fb;
> +EXPORT_SYMBOL_GPL(diu_shared_fb);
> +
> +#if defined(CONFIG_FB_FSL_DIU) || \
> + =A0 =A0defined(CONFIG_FB_FSL_DIU_MODULE)
> +static inline void mpc512x_free_bootmem(struct page *page)
> +{
> + =A0 =A0 =A0 __ClearPageReserved(page);
> + =A0 =A0 =A0 BUG_ON(PageTail(page));
> + =A0 =A0 =A0 BUG_ON(atomic_read(&page->_count) > 1);
> + =A0 =A0 =A0 atomic_set(&page->_count, 1);
> + =A0 =A0 =A0 __free_page(page);
> + =A0 =A0 =A0 totalram_pages++;
> +}
> +
> +void mpc512x_release_bootmem(void)
> +{
> + =A0 =A0 =A0 unsigned long addr =3D diu_shared_fb.fb_phys & PAGE_MASK;
> + =A0 =A0 =A0 unsigned long size =3D diu_shared_fb.fb_len;
> + =A0 =A0 =A0 unsigned long start, end;
> +
> + =A0 =A0 =A0 if (diu_shared_fb.in_use) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 start =3D PFN_UP(addr);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 end =3D PFN_DOWN(addr + size);
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 for (; start < end; start++)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mpc512x_free_bootmem(pfn_to=
_page(start));
> +
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 diu_shared_fb.in_use =3D false;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 diu_ops.release_bootmem =3D NULL;
> +}
> +#endif
> +
> +/*
> + * Check if DIU was pre-initialized. If so, perform steps
> + * needed to continue displaying through the whole boot process.
> + * Move area descriptor and gamma table elsewhere, they are
> + * destroyed by bootmem allocator otherwise. The frame buffer
> + * address range will be reserved in setup_arch() after bootmem
> + * allocator is up.
> + */
> +void __init mpc512x_init_diu(void)
> +{
> + =A0 =A0 =A0 struct device_node *np;
> + =A0 =A0 =A0 void __iomem *diu_reg;
> + =A0 =A0 =A0 phys_addr_t desc;
> + =A0 =A0 =A0 void __iomem *vaddr;
> + =A0 =A0 =A0 unsigned long mode, pix_fmt, res, bpp;
> + =A0 =A0 =A0 unsigned long dst;
> +
> + =A0 =A0 =A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu=
");
> + =A0 =A0 =A0 if (!np) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("No DIU node\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 diu_reg =3D of_iomap(np, 0);
> + =A0 =A0 =A0 of_node_put(np);
> + =A0 =A0 =A0 if (!diu_reg) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("Can't map DIU\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 return;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 mode =3D in_be32(diu_reg + 0x1c);
> + =A0 =A0 =A0 if (mode !=3D 1) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_info("%s: DIU OFF\n", __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out;
> + =A0 =A0 =A0 }
> +
> + =A0 =A0 =A0 desc =3D in_be32(diu_reg);
> + =A0 =A0 =A0 vaddr =3D ioremap(desc, sizeof(struct diu_ad));
> + =A0 =A0 =A0 if (!vaddr) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("Can't map DIU area desc.\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 memcpy(&diu_shared_fb.ad0, vaddr, sizeof(struct diu_ad));
> + =A0 =A0 =A0 /* flush fb area descriptor */
> + =A0 =A0 =A0 dst =3D (unsigned long)&diu_shared_fb.ad0;
> + =A0 =A0 =A0 flush_dcache_range(dst, dst + sizeof(struct diu_ad) - 1);
> +
> + =A0 =A0 =A0 res =3D in_be32(diu_reg + 0x28);
> + =A0 =A0 =A0 pix_fmt =3D in_le32(vaddr);
> + =A0 =A0 =A0 bpp =3D ((pix_fmt >> 16) & 0x3) + 1;
> + =A0 =A0 =A0 diu_shared_fb.fb_phys =3D in_le32(vaddr + 4);
> + =A0 =A0 =A0 diu_shared_fb.fb_len =3D ((res & 0xfff0000) >> 16) * (res &=
 0xfff) * bpp;
> + =A0 =A0 =A0 diu_shared_fb.in_use =3D true;
> + =A0 =A0 =A0 iounmap(vaddr);
> +
> + =A0 =A0 =A0 desc =3D in_be32(diu_reg + 0xc);
> + =A0 =A0 =A0 vaddr =3D ioremap(desc, sizeof(diu_shared_fb.gamma));
> + =A0 =A0 =A0 if (!vaddr) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("Can't map DIU area desc.\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 diu_shared_fb.in_use =3D false;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 goto out;
> + =A0 =A0 =A0 }
> + =A0 =A0 =A0 memcpy(&diu_shared_fb.gamma, vaddr, sizeof(diu_shared_fb.ga=
mma));
> + =A0 =A0 =A0 /* flush gamma table */
> + =A0 =A0 =A0 dst =3D (unsigned long)&diu_shared_fb.gamma;
> + =A0 =A0 =A0 flush_dcache_range(dst, dst + sizeof(diu_shared_fb.gamma) -=
 1);
> +
> + =A0 =A0 =A0 iounmap(vaddr);
> + =A0 =A0 =A0 out_be32(diu_reg + 0xc, virt_to_phys(&diu_shared_fb.gamma))=
;
> + =A0 =A0 =A0 out_be32(diu_reg + 4, 0);
> + =A0 =A0 =A0 out_be32(diu_reg + 8, 0);
> + =A0 =A0 =A0 out_be32(diu_reg, virt_to_phys(&diu_shared_fb.ad0));
> +
> +out:
> + =A0 =A0 =A0 iounmap(diu_reg);
> +}
> +
> +void __init mpc512x_setup_diu(void)
> +{
> + =A0 =A0 =A0 int ret;
> +
> + =A0 =A0 =A0 if (diu_shared_fb.in_use) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D reserve_bootmem(diu_shared_fb.fb_ph=
ys,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 diu_shared_fb.fb_len,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
 BOOTMEM_EXCLUSIVE);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (ret) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_err("%s: reserve bootmem=
 failed\n", __func__);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 diu_shared_fb.in_use =3D fa=
lse;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> + =A0 =A0 =A0 }
> +
> +#if defined(CONFIG_FB_FSL_DIU) || \
> + =A0 =A0defined(CONFIG_FB_FSL_DIU_MODULE)
> + =A0 =A0 =A0 diu_ops.get_pixel_format =A0 =A0 =A0 =A0=3D mpc512x_get_pix=
el_format;
> + =A0 =A0 =A0 diu_ops.set_gamma_table =A0 =A0 =A0 =A0 =3D mpc512x_set_gam=
ma_table;
> + =A0 =A0 =A0 diu_ops.set_monitor_port =A0 =A0 =A0 =A0=3D mpc512x_set_mon=
itor_port;
> + =A0 =A0 =A0 diu_ops.set_pixel_clock =A0 =A0 =A0 =A0 =3D mpc512x_set_pix=
el_clock;
> + =A0 =A0 =A0 diu_ops.show_monitor_port =A0 =A0 =A0 =3D mpc512x_show_moni=
tor_port;
> + =A0 =A0 =A0 diu_ops.set_sysfs_monitor_port =A0=3D mpc512x_set_sysfs_mon=
itor_port;
> + =A0 =A0 =A0 diu_ops.release_bootmem =A0 =A0 =A0 =A0 =3D mpc512x_release=
_bootmem;
> +#endif
> +}
> +
> =A0void __init mpc512x_init_IRQ(void)
> =A0{
> =A0 =A0 =A0 =A0struct device_node *np;
> diff --git a/arch/powerpc/sysdev/fsl_soc.h b/arch/powerpc/sysdev/fsl_soc.=
h
> index 19754be..346057d 100644
> --- a/arch/powerpc/sysdev/fsl_soc.h
> +++ b/arch/powerpc/sysdev/fsl_soc.h
> @@ -30,6 +30,7 @@ struct platform_diu_data_ops {
> =A0 =A0 =A0 =A0void (*set_pixel_clock) (unsigned int pixclock);
> =A0 =A0 =A0 =A0ssize_t (*show_monitor_port) (int monitor_port, char *buf)=
;
> =A0 =A0 =A0 =A0int (*set_sysfs_monitor_port) (int val);
> + =A0 =A0 =A0 void (*release_bootmem) (void);
> =A0};
>
> =A0extern struct platform_diu_data_ops diu_ops;
> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> index 19ca1da..263f7da 100644
> --- a/drivers/video/fsl-diu-fb.c
> +++ b/drivers/video/fsl-diu-fb.c
> @@ -34,7 +34,7 @@
> =A0#include <linux/of_platform.h>
>
> =A0#include <sysdev/fsl_soc.h>
> -#include "fsl-diu-fb.h"
> +#include <linux/fsl-diu-fb.h>
>
> =A0#include "ofmode.h"
>
> @@ -331,8 +331,11 @@ static int fsl_diu_enable_panel(struct fb_info *info=
)
> =A0 =A0 =A0 =A0if (mfbi->type !=3D MFB_TYPE_OFF) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0switch (mfbi->index) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case 0: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 /* plane 0 */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hw->desc[0] !=3D ad->pa=
ddr)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (in_be32(&hw->desc[0]) !=
=3D ad->paddr) {

Unrelated bugfix?  If so, please split into separate patch.


> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&d=
r.diu_reg->diu_mode, 0);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0out_be32(&=
hw->desc[0], ad->paddr);

This line also looks like it needs fixing.

> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&d=
r.diu_reg->diu_mode, 1);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0case 1: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 /* plane 1 AOI 0 */
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0cmfbi =3D machine_data->fs=
l_diu_info[2]->par;
> @@ -391,7 +394,7 @@ static int fsl_diu_disable_panel(struct fb_info *info=
)
>
> =A0 =A0 =A0 =A0switch (mfbi->index) {
> =A0 =A0 =A0 =A0case 0: =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 /* plane 0 */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (hw->desc[0] !=3D machine_data->dummy_ad=
->paddr)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (in_be32(&hw->desc[0]) !=3D machine_data=
->dummy_ad->paddr)

Same bugfix?

> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0out_be32(&hw->desc[0],
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0machine_da=
ta->dummy_ad->paddr);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0break;
> @@ -1102,6 +1105,10 @@ static int fsl_diu_open(struct fb_info *info, int =
user)
> =A0 =A0 =A0 =A0struct mfb_info *mfbi =3D info->par;
> =A0 =A0 =A0 =A0int res =3D 0;
>
> + =A0 =A0 =A0 /* free boot splash memory on first /dev/fb0 open */
> + =A0 =A0 =A0 if (!mfbi->index && diu_ops.release_bootmem)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 diu_ops.release_bootmem();
> +
> =A0 =A0 =A0 =A0spin_lock(&diu_lock);
> =A0 =A0 =A0 =A0mfbi->count++;
> =A0 =A0 =A0 =A0if (mfbi->count =3D=3D 1) {
> @@ -1436,6 +1443,7 @@ static int __devinit fsl_diu_probe(struct of_device=
 *ofdev,
> =A0 =A0 =A0 =A0int ret, i, error =3D 0;
> =A0 =A0 =A0 =A0struct resource res;
> =A0 =A0 =A0 =A0struct fsl_diu_data *machine_data;
> + =A0 =A0 =A0 int diu_mode;
>
> =A0 =A0 =A0 =A0machine_data =3D kzalloc(sizeof(struct fsl_diu_data), GFP_=
KERNEL);
> =A0 =A0 =A0 =A0if (!machine_data)
> @@ -1472,7 +1480,9 @@ static int __devinit fsl_diu_probe(struct of_device=
 *ofdev,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0goto error2;
> =A0 =A0 =A0 =A0}
>
> - =A0 =A0 =A0 out_be32(&dr.diu_reg->diu_mode, 0); =A0 =A0 =A0 =A0 =A0 =A0=
 /* disable DIU anyway*/
> + =A0 =A0 =A0 diu_mode =3D in_be32(&dr.diu_reg->diu_mode);
> + =A0 =A0 =A0 if (diu_mode !=3D MFB_MODE1)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&dr.diu_reg->diu_mode, 0); =A0 =A0=
 /* disable DIU */

Is this the best approach?  Would it be better to make this decision
based on a property in the device tree?

>
> =A0 =A0 =A0 =A0/* Get the IRQ of the DIU */
> =A0 =A0 =A0 =A0machine_data->irq =3D irq_of_parse_and_map(np, 0);
> @@ -1520,7 +1530,12 @@ static int __devinit fsl_diu_probe(struct of_devic=
e *ofdev,
> =A0 =A0 =A0 =A0machine_data->dummy_ad->offset_xyd =3D 0;
> =A0 =A0 =A0 =A0machine_data->dummy_ad->next_ad =3D 0;
>
> - =A0 =A0 =A0 out_be32(&dr.diu_reg->desc[0], machine_data->dummy_ad->padd=
r);
> + =A0 =A0 =A0 /* Let DIU display splash screen if it was pre-initialized
> + =A0 =A0 =A0 =A0* by the bootloader, set dummy area descriptor otherwise=
.
> + =A0 =A0 =A0 =A0*/
> + =A0 =A0 =A0 if (diu_mode !=3D MFB_MODE1)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 out_be32(&dr.diu_reg->desc[0], machine_data=
->dummy_ad->paddr);
> +

Same as above.

> =A0 =A0 =A0 =A0out_be32(&dr.diu_reg->desc[1], machine_data->dummy_ad->pad=
dr);
> =A0 =A0 =A0 =A0out_be32(&dr.diu_reg->desc[2], machine_data->dummy_ad->pad=
dr);
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 2/3] fbdev: fsl-diu-fb.c: allow setting panel video mode from DT
  2010-02-27 21:58     ` [PATCH 2/3] fbdev: fsl-diu-fb.c: allow setting panel video mode from DT Anatolij Gustschin
@ 2010-02-28  6:52       ` Grant Likely
  0 siblings, 0 replies; 48+ messages in thread
From: Grant Likely @ 2010-02-28  6:52 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linux-fbdev, wd, dzu, jrigby, linuxppc-dev, yorksun

On Sat, Feb 27, 2010 at 2:58 PM, Anatolij Gustschin <agust@denx.de> wrote:
> Add support for specifying display panel data in the device
> tree. If no panel data is provided in the device tree, default
> video mode will be used as usual.
>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>

This one seems okay, but the binding in the first patch first needs to
get resolved.

g.

> ---
> =A0drivers/video/Kconfig =A0 =A0 =A0| =A0 =A01 +
> =A0drivers/video/fsl-diu-fb.c | =A0 63 +++++++++++++++++++++++++---------=
----------
> =A02 files changed, 37 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
> index dc1beb0..c805ecd 100644
> --- a/drivers/video/Kconfig
> +++ b/drivers/video/Kconfig
> @@ -1850,6 +1850,7 @@ config FB_FSL_DIU
> =A0 =A0 =A0 =A0select FB_CFB_COPYAREA
> =A0 =A0 =A0 =A0select FB_CFB_IMAGEBLIT
> =A0 =A0 =A0 =A0select PPC_LIB_RHEAP
> + =A0 =A0 =A0 select FB_OF_MODE
> =A0 =A0 =A0 =A0---help---
> =A0 =A0 =A0 =A0 =A0Framebuffer driver for the Freescale SoC DIU
>
> diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> index 4637bcb..19ca1da 100644
> --- a/drivers/video/fsl-diu-fb.c
> +++ b/drivers/video/fsl-diu-fb.c
> @@ -36,6 +36,8 @@
> =A0#include <sysdev/fsl_soc.h>
> =A0#include "fsl-diu-fb.h"
>
> +#include "ofmode.h"
> +
> =A0/*
> =A0* These parameters give default parameters
> =A0* for video output 1024x768,
> @@ -1168,7 +1170,7 @@ static int init_fbinfo(struct fb_info *info)
> =A0 =A0 =A0 =A0return 0;
> =A0}
>
> -static int __devinit install_fb(struct fb_info *info)
> +static int __devinit install_fb(struct device_node *np, struct fb_info *=
info)
> =A0{
> =A0 =A0 =A0 =A0int rc;
> =A0 =A0 =A0 =A0struct mfb_info *mfbi =3D info->par;
> @@ -1177,33 +1179,40 @@ static int __devinit install_fb(struct fb_info *i=
nfo)
> =A0 =A0 =A0 =A0if (init_fbinfo(info))
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0return -EINVAL;
>
> - =A0 =A0 =A0 if (mfbi->index =3D=3D 0) =A0 /* plane 0 */
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 aoi_mode =3D fb_mode;
> - =A0 =A0 =A0 else
> + =A0 =A0 =A0 if (mfbi->index =3D=3D 0) { /* plane 0 */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 /* use default mode for plane0 if there is =
no mode in DTB */
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (of_get_video_mode(np, info) < 0)
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 aoi_mode =3D fb_mode;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 else
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 aoi_mode =3D NULL;
> + =A0 =A0 =A0 } else
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0aoi_mode =3D init_aoi_mode;
> - =A0 =A0 =A0 pr_debug("mode used =3D %s\n", aoi_mode);
> - =A0 =A0 =A0 rc =3D fb_find_mode(&info->var, info, aoi_mode, fsl_diu_mod=
e_db,
> - =A0 =A0 =A0 =A0 =A0 =A0ARRAY_SIZE(fsl_diu_mode_db), &fsl_diu_default_mo=
de, default_bpp);
>
> - =A0 =A0 =A0 switch (rc) {
> - =A0 =A0 =A0 case 1:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode specified in @mode\n")=
;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> - =A0 =A0 =A0 case 2:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode specified in @mode "
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "with ignored refresh rate\=
n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> - =A0 =A0 =A0 case 3:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode default mode\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> - =A0 =A0 =A0 case 4:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode from list\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> - =A0 =A0 =A0 default:
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("rc =3D %d\n", rc);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("failed to find mode\n");
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 if (aoi_mode) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("mode used =3D %s\n", aoi_mode);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 rc =3D fb_find_mode(&info->var, info, aoi_m=
ode, fsl_diu_mode_db,
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ARRAY_S=
IZE(fsl_diu_mode_db),
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 &fsl_di=
u_default_mode, default_bpp);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 switch (rc) {
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 1:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode specif=
ied in @mode\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 2:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode specif=
ied in @mode "
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 "with ignor=
ed refresh rate\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 3:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode defaul=
t mode\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 case 4:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("using mode from l=
ist\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 default:
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("rc =3D %d\n", rc)=
;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 pr_debug("failed to find mo=
de\n");
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 return -EINVAL;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 break;
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 }
> =A0 =A0 =A0 =A0}
>
> =A0 =A0 =A0 =A0pr_debug("xres_virtual %d\n", info->var.xres_virtual);
> @@ -1521,7 +1530,7 @@ static int __devinit fsl_diu_probe(struct of_device=
 *ofdev,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mfbi->ad =3D (struct diu_ad *)((u32)pool.a=
d.vaddr
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0+ pool.ad.offset) + i;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0mfbi->ad->paddr =3D pool.ad.paddr + i * si=
zeof(struct diu_ad);
> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D install_fb(machine_data->fsl_diu_in=
fo[i]);
> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D install_fb(np, machine_data->fsl_di=
u_info[i]);
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0if (ret) {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0dev_err(&ofdev->dev,
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0"Failed to=
 register framebuffer %d\n",
> --
> 1.6.3.3
>
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 0/3] Rework MPC5121 DIU support (for 2.6.34)
  2010-02-27 21:58     ` [PATCH 0/3] Rework MPC5121 DIU support (for 2.6.34) Anatolij Gustschin
@ 2010-02-28  7:04       ` Grant Likely
  0 siblings, 0 replies; 48+ messages in thread
From: Grant Likely @ 2010-02-28  7:04 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: linux-fbdev, wd, dzu, jrigby, linuxppc-dev, yorksun

Hi Anatolij,

On Sat, Feb 27, 2010 at 2:58 PM, Anatolij Gustschin <agust@denx.de> wrote:
> This patch series rework DIU support patch submitted
> previously with the patch series for updating MPC5121
> support in mainline. It doesn't add new panel timing data
> to the framebuffer driver anymore. Instead we now allow
> encoding this data in the device tree. First two patches
> add this support.

Thanks for this work.  I've made specific comments on the individual
patches.  There are some details to be worked out, but I think it is
moving in the right direction.

> It is intended for inclusion in 2.6.34, since without
> DIU support patch framebuffer doesn't work on mpc5121.

It's actually late for 2.6.34.  Unless it is a bug fix, I stop picking
up new patches somewhere in the -rc7 or -rc8 timerframe, and I am
definitely in bug-fix-only mode once the merge window has opened.  I
do this to ensure all patches receive a decent amount of linux-next
exposure before I ask Linus to pull them.

I'll being picking up new patches for 2.6.35 into my -next branch
after 2.6.34-rc1 is released.

g.

-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 1/3] video: add support for getting video mode from device tree
  2010-02-28  6:30       ` Grant Likely
@ 2010-02-28  8:44         ` Mitch Bradley
  2010-02-28 14:47           ` Grant Likely
  2010-03-01  3:45           ` Benjamin Herrenschmidt
  0 siblings, 2 replies; 48+ messages in thread
From: Mitch Bradley @ 2010-02-28  8:44 UTC (permalink / raw)
  To: Grant Likely
  Cc: linux-fbdev, wd, dzu, jrigby, devicetree-discuss, linuxppc-dev,
	Anatolij Gustschin, yorksun

>
> Hi Anatolij,
>
> [added cc: to devicetree-discuss@lists.ozlabs.org]
>
> On Sat, Feb 27, 2010 at 2:58 PM, Anatolij Gustschin <agust@denx.de> wrote:
>   
>> > Framebuffer drivers may want to get panel timing info
>> > from the device tree. This patch adds appropriate support.
>> > Subsequent patch for FSL DIU frame buffer driver makes use
>> > of this functionality.
>>     
>
> I think this is moving in the right direction, but there needs to
> debate & review over the binding before committing to anything.
> Please write a patch that documents the new binding in
> Documentation/powerpc/dts-bindings.  All new bindings should be
> documented and reviewed on devicetree-discuss before merging any
> drivers that use them into mainline.
>
> From what I can tell by reading your code, I suspect that the binding
> you've designed will solve your immediate problem, but won't be able
> to handle anything slightly more complex, but it also looks like the
> binding has been designed to be generic, usable by any display device.
>
> First off, I did a tiny amount of research, and I didn't find any
> existing OpenFirmware bindings for describing video displays.
> Otherwise, I'd suggest considering that.
>
> From the little bit that I know, it seems that for most video devices
> (ie. PCs) the video card discovers the capabilities of the screen by
> reading the monitor's EDID data.  However, in your particular case
> embedded case, a fixed flat panel is attached, and there isn't any
> EDID data provided.  Therefore, you need an alternate method of
> describing the display capabilities.  Rather than designing something
> entirely new, you may want to consider using the EDID data format
> directly; or at least cover the same things that EDID describes.  The
> downside to using EDID directly is that it is a packed binary format
> that isn't parseable by mere mortals; but the data contained in it
> seems about right.  The upside is the kernel already knows what to do
> with EDID data.
>
> Otherwise you risk designing something that won't be useful for
> anything much outside of your own use case.  For example, the binding
> I see from the code cannot handle a display with multiple output
> modes.
>
> Also, since you're now in the realm of describing a video display,
> which is separate from the display controller, you should consider
> describing the display in a separate device tree node.  Maybe
> something like this...
>
> video {
>         compatible = "fsl,mpc5121-diu";
>         display {
>                 compatible = "<vendor>,<model>";
>                 edid = [edid-data];
>         };
> };
>   


As it turns out, I'm doing exactly that - exporting verbatim EDID data 
as the value of the "edid" property - for the display node on the Via 
version of the OLPC machine.  The kernel driver uses it instead of 
trying to obtain the EDID data from the monitor, because the builtin 
OLPC display cannot supply EDID data through the usual hardware interfaces.

Mitch


> Cheers,
> g.
>
>   

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 1/3] video: add support for getting video mode from device tree
  2010-02-28  8:44         ` Mitch Bradley
@ 2010-02-28 14:47           ` Grant Likely
  2010-03-01  3:45           ` Benjamin Herrenschmidt
  1 sibling, 0 replies; 48+ messages in thread
From: Grant Likely @ 2010-02-28 14:47 UTC (permalink / raw)
  To: Mitch Bradley
  Cc: linux-fbdev, wd, dzu, jrigby, devicetree-discuss, linuxppc-dev,
	Anatolij Gustschin, yorksun

On Sun, Feb 28, 2010 at 1:44 AM, Mitch Bradley <wmb@firmworks.com> wrote:
> Grant Likely Wrote:
>> On Sat, Feb 27, 2010 at 2:58 PM, Anatolij Gustschin <agust@denx.de> wrot=
e:
>> Also, since you're now in the realm of describing a video display,
>> which is separate from the display controller, you should consider
>> describing the display in a separate device tree node. =A0Maybe
>> something like this...
>>
>> video {
>> =A0 =A0 =A0 =A0compatible =3D "fsl,mpc5121-diu";
>> =A0 =A0 =A0 =A0display {
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0compatible =3D "<vendor>,<model>";
>> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0edid =3D [edid-data];
>> =A0 =A0 =A0 =A0};
>> };
>>
>
>
> As it turns out, I'm doing exactly that - exporting verbatim EDID data as
> the value of the "edid" property - for the display node on the Via versio=
n
> of the OLPC machine. =A0The kernel driver uses it instead of trying to ob=
tain
> the EDID data from the monitor, because the builtin OLPC display cannot
> supply EDID data through the usual hardware interfaces.

Cool.  That sounds sane then.  How do you go about generating the EDID
data?  Is there a tool that can do that?  Or did you hand craft it?

Cheers,
g.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 1/3] video: add support for getting video mode from device tree
  2010-02-28  8:44         ` Mitch Bradley
  2010-02-28 14:47           ` Grant Likely
@ 2010-03-01  3:45           ` Benjamin Herrenschmidt
  2010-04-28 13:43             ` Anatolij Gustschin
  1 sibling, 1 reply; 48+ messages in thread
From: Benjamin Herrenschmidt @ 2010-03-01  3:45 UTC (permalink / raw)
  To: Mitch Bradley
  Cc: linux-fbdev, wd, dzu, jrigby, devicetree-discuss, linuxppc-dev,
	Anatolij Gustschin, yorksun

At some stage, Grant wrote:

> > First off, I did a tiny amount of research, and I didn't find any
> > existing OpenFirmware bindings for describing video displays.
> > Otherwise, I'd suggest considering that.

There's a binding for framebuffers but it sucks big time :-) It doesn't
provide a reliable way for the OS to get to the physical address of the
fb, doesn't define outputs and mode setting, doesn't really deal with
>8bpp, etc....

On Sat, 2010-02-27 at 22:44 -1000, Mitch Bradley wrote:

> As it turns out, I'm doing exactly that - exporting verbatim EDID
> data 
> as the value of the "edid" property - for the display node on the Via 
> version of the OLPC machine.  The kernel driver uses it instead of 
> trying to obtain the EDID data from the monitor, because the builtin 
> OLPC display cannot supply EDID data through the usual hardware
> interfaces.

This is actually a common practice (though EDID is most often in
uppercase) on Apple hardware too. It has issues though in the sense that
it doesn't carry proper connector information and falls over in many
multi-head cases.

I think passing the EDID data, when available, is thus the right thing
to do indeed, however that doesn't solve two problems:

 - Where to put that property ? This is a complicated problem and we
might argue on a binding for weeks because video cards typically support
multiple outputs, etc. etc... I think the best for now is to stick as
closely as possible to the existing OF fb binding, and have "display"
nodes for each output, which can eventually contain an EDID. We might
also want to add a string that indicate the connector type. Specific
drivers might want to define additional properties here where it makes
sense such as binding of those outputs to CRTCs or such, up to you.

 - We -also- want a way to specify the "default" mode as set by the
firmware, at least on some devices. The EDID gives capabilities, and
often for LCDs also the "preferred" mode which is almost always the
"default" mode ... but could be different. In order to avoid "flicking",
the driver might wants to know what is the currently programmed mode.
For that, having split out properties makes sense, though I would like
to either prefix them all with "mode," or stick them in a sub-node of
the display@.

Cheers,
Ben.

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 06/11] dma: Add MPC512x DMA driver
  2010-02-05 13:42 ` [PATCH v3 06/11] dma: Add MPC512x DMA driver Anatolij Gustschin
  2010-02-10  2:44   ` Grant Likely
@ 2010-03-01 13:46   ` Anatolij Gustschin
  2010-03-02  6:00     ` Dan Williams
  1 sibling, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-03-01 13:46 UTC (permalink / raw)
  To: Dan Williams; +Cc: wd, dzu, linuxppc-dev, Piotr Ziecik

Hi Dan,

any chance this patch could be merged for 2.6.34 ?

Thanks,
Anatolij

On Fri,  5 Feb 2010 14:42:52 +0100
Anatolij Gustschin <agust@denx.de> wrote:

> From: Piotr Ziecik <kosmo@semihalf.com>
> 
> Adds initial version of MPC512x DMA driver.
> Only memory to memory transfers are currenly supported.
> 
> Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> Signed-off-by: Wolfgang Denk <wd@denx.de>
> Signed-off-by: Anatolij Gustschin <agust@denx.de>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Cc: Grant Likely <grant.likely@secretlab.ca>
> Cc: John Rigby <jcrigby@gmail.com>
> ---
> No changes since v2
> 
> Changes since v1:
>  - move content of the mpc512x.h into the drivers .c file as
>    it is only used by this DMA driver
>  - use __devinit/__devexit/__devexit_p as requested
>  - add unregistration of the dma device
>  - remove meaningless comment
> 
> Changes since patch version submitted in May 2009:
>  - don't use wildcards in compatible property, use "fsl,mpc5121-dma"
>  - don't add "fsl,mpc5121-dma" compatible to of_bus_ids[] as the
>    dma device is part of IMMR
> 
>  drivers/dma/Kconfig       |    7 +
>  drivers/dma/Makefile      |    1 +
>  drivers/dma/mpc512x_dma.c |  800 +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 808 insertions(+), 0 deletions(-)
>  create mode 100644 drivers/dma/mpc512x_dma.c

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 06/11] dma: Add MPC512x DMA driver
  2010-03-01 13:46   ` Anatolij Gustschin
@ 2010-03-02  6:00     ` Dan Williams
  0 siblings, 0 replies; 48+ messages in thread
From: Dan Williams @ 2010-03-02  6:00 UTC (permalink / raw)
  To: Anatolij Gustschin; +Cc: wd, dzu, linuxppc-dev, Piotr Ziecik

Anatolij Gustschin wrote:
> Hi Dan,
> 
> any chance this patch could be merged for 2.6.34 ?

Looks good to me, I'll include it in the dmaengine pull request.

--
Dan

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver
  2010-02-10  2:42   ` Grant Likely
@ 2010-03-30 13:15     ` Artem Bityutskiy
  0 siblings, 0 replies; 48+ messages in thread
From: Artem Bityutskiy @ 2010-03-30 13:15 UTC (permalink / raw)
  To: Grant Likely
  Cc: Piotr Ziecik, dzu, linuxppc-dev, linux-mtd, Anatolij Gustschin,
	David Woodhouse

On Tue, 2010-02-09 at 19:42 -0700, Grant Likely wrote:
> On Fri, Feb 5, 2010 at 6:42 AM, Anatolij Gustschin <agust@denx.de> wrote:
> > Adds NAND Flash Controller driver for MPC5121 Revision 2.
> > All device features, except hardware ECC and power management,
> > are supported.
> >
> > Signed-off-by: Piotr Ziecik <kosmo@semihalf.com>
> > Signed-off-by: Wolfgang Denk <wd@denx.de>
> > Signed-off-by: Anatolij Gustschin <agust@denx.de>
> > Cc: <linux-mtd@lists.infradead.org>
> > Cc: Grant Likely <grant.likely@secretlab.ca>
> > Cc: John Rigby <jcrigby@gmail.com>
> 
> On *very* brief review...
> 
> Acked-by: Grant Likely <grant.likely@secretlab.ca>
> 
> David, there are ordering issues on this patch with arch-specific
> code.  If the patch looks okay to you, then can I pick it up into my
> tree?

Because of the general large response time of the MTD community, I
suggest you to go put this stuff to your tree.

-- 
Best Regards,
Artem Bityutskiy (Артём Битюцкий)

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 1/3] video: add support for getting video mode from device tree
  2010-03-01  3:45           ` Benjamin Herrenschmidt
@ 2010-04-28 13:43             ` Anatolij Gustschin
  2010-05-19 21:19               ` Grant Likely
  0 siblings, 1 reply; 48+ messages in thread
From: Anatolij Gustschin @ 2010-04-28 13:43 UTC (permalink / raw)
  To: Benjamin Herrenschmidt
  Cc: linux-fbdev, wd, dzu, devicetree-discuss, linuxppc-dev,
	Mitch Bradley, yorksun

On Mon, 01 Mar 2010 14:45:20 +1100
Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:

> On Sat, 2010-02-27 at 22:44 -1000, Mitch Bradley wrote:
> 
> > As it turns out, I'm doing exactly that - exporting verbatim EDID
> > data 
> > as the value of the "edid" property - for the display node on the Via 
> > version of the OLPC machine.  The kernel driver uses it instead of 
> > trying to obtain the EDID data from the monitor, because the builtin 
> > OLPC display cannot supply EDID data through the usual hardware
> > interfaces.
> 
> This is actually a common practice (though EDID is most often in
> uppercase) on Apple hardware too. It has issues though in the sense that
> it doesn't carry proper connector information and falls over in many
> multi-head cases.
> 
> I think passing the EDID data, when available, is thus the right thing
> to do indeed, however that doesn't solve two problems:
> 
>  - Where to put that property ? This is a complicated problem and we
> might argue on a binding for weeks because video cards typically support
> multiple outputs, etc. etc... I think the best for now is to stick as
> closely as possible to the existing OF fb binding, and have "display"
> nodes for each output, which can eventually contain an EDID. We might
> also want to add a string that indicate the connector type. Specific
> drivers might want to define additional properties here where it makes
> sense such as binding of those outputs to CRTCs or such, up to you.

Putting EDID to display node would be really sufficient for LCDs in
our case. Other systems might define this additional connector type
property.

> 
>  - We -also- want a way to specify the "default" mode as set by the
> firmware, at least on some devices. The EDID gives capabilities, and
> often for LCDs also the "preferred" mode which is almost always the
> "default" mode ... but could be different. In order to avoid "flicking",
> the driver might wants to know what is the currently programmed mode.
> For that, having split out properties makes sense, though I would like
> to either prefix them all with "mode," or stick them in a sub-node of
> the display@.

I would propose defining following properties in the case the
programmed mode is different from "default" mode:

display@...{
	compatible = "<vendor>,<model>"
	EDID = [edid-data];

	current-mode {
		pixel_clock = <value>;
		horizontal_active = <value>;
		horizontal_blank = <value>;
		vertical_active = <value>;
		vertical_blank = <value>;
		horizontal_active = <value>;
		hsync_offset = <value>;
		hsync_pulse_width = <value>;
		vsync_offset = <value>;
		vsync_pulse_width = <value>;
		hsync_positive;
		vsync_positive;
	}
};

The firmware can set the "default" mode using the EDID's preferred
Detailed Timing Descriptor data. If on some devices it sets another
mode than the preferred mode, then the firmware can insert a
"current-mode" sub-node with currently programmed mode. The driver
can check for this sub-node and use it's data and if it isn't present,
it can use the preferred timing data from EDID. The names of the
properties here are actually what Detailed Timing Descriptor in EDID
specifies. What do you think?

Thanks,
Anatolij

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 3/3] powerpc/mpc5121: shared DIU framebuffer support
  2010-02-28  6:50       ` Grant Likely
@ 2010-04-28 20:28         ` Anatolij Gustschin
  0 siblings, 0 replies; 48+ messages in thread
From: Anatolij Gustschin @ 2010-04-28 20:28 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev, linux-fbdev, yorksun, dzu, wd

Hi Grant,

Thanks for review and comments. I'm back to this now and hope
to address your comments soon.

On Sat, 27 Feb 2010 23:50:09 -0700
Grant Likely <grant.likely@secretlab.ca> wrote:

> On Sat, Feb 27, 2010 at 2:58 PM, Anatolij Gustschin <agust@denx.de> wrote:
> > MPC5121 DIU configuration/setup as initialized by the boot
> > loader currently will get lost while booting Linux. As a
> > result displaying the boot splash is not possible through
> > the boot process.
> >
> > To prevent this we reserve configured DIU frame buffer
> > address range while booting and preserve AOI descriptor
> > and gamma table so that DIU continues displaying through
> > the whole boot process. On first open from user space
> > DIU frame buffer driver releases the reserved frame
> > buffer area and continues to operate as usual.
> >
> > The patch also moves drivers/video/fsl-diu-fb.h file to
> > include/linux as we use some DIU structures in platform
> > code.
> >
> > 'diu_ops' callbacks in platform code borrowed from John's
> > DIU code.
> >
> > Signed-off-by: John Rigby <jrigby@gmail.com>
> > Signed-off-by: Anatolij Gustschin <agust@denx.de>
> > Cc: Grant Likely <grant.likely@secretlab.ca>
>=20
> On quick glance this patch seems mostly okay, but this patch should
> probably be broken up a bit to simplify review and dissociate
> unrelated changes.  For example, the move of fsl-diu-fb.h is a
> discrete change that should be split off.  Some more comments
> below....

I will split off fsl-diu-fb.h move to separate patch.

...
> > diff --git a/arch/powerpc/platforms/512x/mpc5121_generic.c b/arch/power=
pc/platforms/512x/mpc5121_generic.c
> > index a6c0e3a..3aaa281 100644
> > --- a/arch/powerpc/platforms/512x/mpc5121_generic.c
> > +++ b/arch/powerpc/platforms/512x/mpc5121_generic.c
> > @@ -28,6 +28,7 @@
> > =C2=A0*/
> > =C2=A0static char *board[] __initdata =3D {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0"prt,prtlvt",
> > + =C2=A0 =C2=A0 =C2=A0 "ifm,pdm360ng",
>=20
> You're adding a new board here.  This is completely unrelated.

Yes, it is unrelated. This hunk sneaked in by accident, will drop it.

...
> > diff --git a/arch/powerpc/platforms/512x/mpc512x.h b/arch/powerpc/platf=
orms/512x/mpc512x.h
> > index d72b2c7..1cfe9d5 100644
> > --- a/arch/powerpc/platforms/512x/mpc512x.h
> > +++ b/arch/powerpc/platforms/512x/mpc512x.h
> > @@ -17,4 +17,7 @@ extern int __init mpc5121_clk_init(void);
> > =C2=A0void __init mpc512x_declare_of_platform_devices(void);
> > =C2=A0extern void mpc512x_restart(char *cmd);
> > =C2=A0extern void __init mpc5121_usb_init(void);
> > +extern void __init mpc512x_init_diu(void);
> > +extern void __init mpc512x_setup_diu(void);
>=20
> __init annotations do not belong in header files.

Ok, I will remove them.

> > +extern struct fsl_diu_shared_fb diu_shared_fb;
>=20
> Hmmmm.  I'm not fond of the global data structure.  Especially
> considering that the struct fsl_diu_shared_fb is defined in
> mpc512x_shared.c, so nothing outside of that .c file can do anything
> with the structure.

This is a remainder from early debugging code, will remove it.

> > =C2=A0#endif =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 /* __MPC512X_H__ */
> > diff --git a/arch/powerpc/platforms/512x/mpc512x_shared.c b/arch/powerp=
c/platforms/512x/mpc512x_shared.c
> > index fbdf65f..a8c50a6 100644
> > --- a/arch/powerpc/platforms/512x/mpc512x_shared.c
> > +++ b/arch/powerpc/platforms/512x/mpc512x_shared.c
> > @@ -16,7 +16,11 @@
> > =C2=A0#include <linux/io.h>
> > =C2=A0#include <linux/irq.h>
> > =C2=A0#include <linux/of_platform.h>
> > +#include <linux/fsl-diu-fb.h>
> > +#include <linux/bootmem.h>
> > +#include <sysdev/fsl_soc.h>
> >
> > +#include <asm/cacheflush.h>
> > =C2=A0#include <asm/machdep.h>
> > =C2=A0#include <asm/ipic.h>
> > =C2=A0#include <asm/prom.h>
> > @@ -53,6 +57,284 @@ void mpc512x_restart(char *cmd)
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0;
> > =C2=A0}
> >
> > +struct fsl_diu_shared_fb {
> > + =C2=A0 =C2=A0 =C2=A0 char =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0ga=
mma[0x300]; =C2=A0 /* 32-bit aligned! */
> > + =C2=A0 =C2=A0 =C2=A0 struct diu_ad =C2=A0 ad0; =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0/* 32-bit aligned! */
> > + =C2=A0 =C2=A0 =C2=A0 phys_addr_t =C2=A0 =C2=A0 fb_phys;
> > + =C2=A0 =C2=A0 =C2=A0 size_t =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fb_len;
> > + =C2=A0 =C2=A0 =C2=A0 bool =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0in=
_use;
> > +};
> > +
> > +unsigned int mpc512x_get_pixel_format(unsigned int bits_per_pixel,
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 int monitor_port)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 unsigned int pix_fmt;
> > +
> > + =C2=A0 =C2=A0 =C2=A0 switch (bits_per_pixel) {
> > + =C2=A0 =C2=A0 =C2=A0 case 32:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x888833=
16;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> > + =C2=A0 =C2=A0 =C2=A0 case 24:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x880822=
19;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> > + =C2=A0 =C2=A0 =C2=A0 case 16:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x650531=
18;
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> > + =C2=A0 =C2=A0 =C2=A0 default:
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pix_fmt =3D 0x000004=
00;
> > + =C2=A0 =C2=A0 =C2=A0 }
> > + =C2=A0 =C2=A0 =C2=A0 return pix_fmt;
> > +}
> > +
> > +void mpc512x_set_gamma_table(int monitor_port, char *gamma_table_base)
> > +{
> > +}
> > +
> > +void mpc512x_set_monitor_port(int monitor_port)
> > +{
> > +}
> > +
> > +#define CCM_SCFR1 =C2=A0 =C2=A0 =C2=A00x0000000c
> > +#define DIU_DIV_MASK =C2=A0 0x000000ff
> > +void mpc512x_set_pixel_clock(unsigned int pixclock)
> > +{
> > + =C2=A0 =C2=A0 =C2=A0 unsigned long bestval, bestfreq, speed_ccb, busf=
req;
> > + =C2=A0 =C2=A0 =C2=A0 unsigned long minpixclock, maxpixclock, pixval;
> > + =C2=A0 =C2=A0 =C2=A0 struct device_node *np;
> > + =C2=A0 =C2=A0 =C2=A0 void __iomem *ccm;
> > + =C2=A0 =C2=A0 =C2=A0 u32 temp;
> > + =C2=A0 =C2=A0 =C2=A0 long err;
> > + =C2=A0 =C2=A0 =C2=A0 int i;
> > +
> > + =C2=A0 =C2=A0 =C2=A0 np =3D of_find_compatible_node(NULL, NULL, "fsl,=
mpc5121-clock");
> > + =C2=A0 =C2=A0 =C2=A0 if (!np) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pr_err("Can't find c=
lock control module.\n");
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return;
> > + =C2=A0 =C2=A0 =C2=A0 }
> > +
> > + =C2=A0 =C2=A0 =C2=A0 ccm =3D of_iomap(np, 0);
> > + =C2=A0 =C2=A0 =C2=A0 if (!ccm) {
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 pr_err("Can't map cl=
ock control module reg.\n");
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 of_node_put(np);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 return;
> > + =C2=A0 =C2=A0 =C2=A0 }
> > + =C2=A0 =C2=A0 =C2=A0 of_node_put(np);
> > +
> > + =C2=A0 =C2=A0 =C2=A0 busfreq =3D 200000000;
>=20
> Instead of some hard coding some bogus defalt busfreq, you should
> error out if the real frequency cannot be determined.  Force users to
> supply a valid tree.

Ok, will fix.

...
> > +
> > + =C2=A0 =C2=A0 =C2=A0 /* Calculate the pixel clock with the smallest e=
rror */
> > + =C2=A0 =C2=A0 =C2=A0 /* calculate the following in steps to avoid ove=
rflow */
> > + =C2=A0 =C2=A0 =C2=A0 pr_debug("DIU pixclock in ps - %d\n", pixclock);
> > + =C2=A0 =C2=A0 =C2=A0 temp =3D 1;
> > + =C2=A0 =C2=A0 =C2=A0 temp *=3D 1000000000;
> > + =C2=A0 =C2=A0 =C2=A0 temp /=3D pixclock;
> > + =C2=A0 =C2=A0 =C2=A0 temp *=3D 1000;
> > + =C2=A0 =C2=A0 =C2=A0 pixclock =3D temp;
>=20
> Really?  I think you can simplify this.

Yes, will do it in the next patch.

...
> > diff --git a/drivers/video/fsl-diu-fb.c b/drivers/video/fsl-diu-fb.c
> > index 19ca1da..263f7da 100644
> > --- a/drivers/video/fsl-diu-fb.c
> > +++ b/drivers/video/fsl-diu-fb.c
> > @@ -34,7 +34,7 @@
> > =C2=A0#include <linux/of_platform.h>
> >
> > =C2=A0#include <sysdev/fsl_soc.h>
> > -#include "fsl-diu-fb.h"
> > +#include <linux/fsl-diu-fb.h>
> >
> > =C2=A0#include "ofmode.h"
> >
> > @@ -331,8 +331,11 @@ static int fsl_diu_enable_panel(struct fb_info *in=
fo)
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0if (mfbi->type !=3D MFB_TYPE_OFF) {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0switch (mfbi->in=
dex) {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 0: =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 /* plane 0 */
> > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 if (hw->desc[0] !=3D ad->paddr)
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 if (in_be32(&hw->desc[0]) !=3D ad->paddr) {
>=20
> Unrelated bugfix?  If so, please split into separate patch.
>=20
>=20
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 out_be32(&dr.diu_reg->diu_mode, 0);
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0out_be32(&hw->desc[0], ad->paddr);
>=20
> This line also looks like it needs fixing.

Will re-check it an fix.

>=20
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 out_be32(&dr.diu_reg->diu_mode, 1);
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 }
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0break;
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 1: =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 /* plane 1 AOI 0 */
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0cmfbi =3D machine_data->fsl_diu_info[2]->par;
> > @@ -391,7 +394,7 @@ static int fsl_diu_disable_panel(struct fb_info *in=
fo)
> >
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0switch (mfbi->index) {
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0case 0: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=
=A0 /* plane 0 */
> > - =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (hw->desc[0] !=3D=
 machine_data->dummy_ad->paddr)
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (in_be32(&hw->des=
c[0]) !=3D machine_data->dummy_ad->paddr)
>=20
> Same bugfix?

Will re-check it, too.

>=20
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0out_be32(&hw->desc[0],
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =
=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0machine_data->dummy_ad->paddr);
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break;
> > @@ -1102,6 +1105,10 @@ static int fsl_diu_open(struct fb_info *info, in=
t user)
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0struct mfb_info *mfbi =3D info->par;
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0int res =3D 0;
> >
> > + =C2=A0 =C2=A0 =C2=A0 /* free boot splash memory on first /dev/fb0 ope=
n */
> > + =C2=A0 =C2=A0 =C2=A0 if (!mfbi->index && diu_ops.release_bootmem)
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 diu_ops.release_boot=
mem();
> > +
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0spin_lock(&diu_lock);
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0mfbi->count++;
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0if (mfbi->count =3D=3D 1) {
> > @@ -1436,6 +1443,7 @@ static int __devinit fsl_diu_probe(struct of_devi=
ce *ofdev,
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0int ret, i, error =3D 0;
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0struct resource res;
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0struct fsl_diu_data *machine_data;
> > + =C2=A0 =C2=A0 =C2=A0 int diu_mode;
> >
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0machine_data =3D kzalloc(sizeof(struct fsl_d=
iu_data), GFP_KERNEL);
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!machine_data)
> > @@ -1472,7 +1480,9 @@ static int __devinit fsl_diu_probe(struct of_devi=
ce *ofdev,
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto error2;
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0}
> >
> > - =C2=A0 =C2=A0 =C2=A0 out_be32(&dr.diu_reg->diu_mode, 0); =C2=A0 =C2=
=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* disable DIU anyway*/
> > + =C2=A0 =C2=A0 =C2=A0 diu_mode =3D in_be32(&dr.diu_reg->diu_mode);
> > + =C2=A0 =C2=A0 =C2=A0 if (diu_mode !=3D MFB_MODE1)
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 out_be32(&dr.diu_reg=
->diu_mode, 0); =C2=A0 =C2=A0 /* disable DIU */
>=20
> Is this the best approach?  Would it be better to make this decision
> based on a property in the device tree?

I don't think it is worth it. The driver disables the DIU
regardless of it is enabled or not and enables it later
using a dummy descriptor. We just prevent this disabling
if the DIU is pre-initialized and already displaying.

> >
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Get the IRQ of the DIU */
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0machine_data->irq =3D irq_of_parse_and_map(n=
p, 0);
> > @@ -1520,7 +1530,12 @@ static int __devinit fsl_diu_probe(struct of_dev=
ice *ofdev,
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0machine_data->dummy_ad->offset_xyd =3D 0;
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0machine_data->dummy_ad->next_ad =3D 0;
> >
> > - =C2=A0 =C2=A0 =C2=A0 out_be32(&dr.diu_reg->desc[0], machine_data->dum=
my_ad->paddr);
> > + =C2=A0 =C2=A0 =C2=A0 /* Let DIU display splash screen if it was pre-i=
nitialized
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0* by the bootloader, set dummy area descri=
ptor otherwise.
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0*/
> > + =C2=A0 =C2=A0 =C2=A0 if (diu_mode !=3D MFB_MODE1)
> > + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 out_be32(&dr.diu_reg=
->desc[0], machine_data->dummy_ad->paddr);
> > +
>=20
> Same as above.
>=20
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0out_be32(&dr.diu_reg->desc[1], machine_data-=
>dummy_ad->paddr);
> > =C2=A0 =C2=A0 =C2=A0 =C2=A0out_be32(&dr.diu_reg->desc[2], machine_data-=
>dummy_ad->paddr);
> >
>=20
>=20
>=20

Thanks,
Anatolij

^ permalink raw reply	[flat|nested] 48+ messages in thread

* Re: [PATCH 1/3] video: add support for getting video mode from device tree
  2010-04-28 13:43             ` Anatolij Gustschin
@ 2010-05-19 21:19               ` Grant Likely
  0 siblings, 0 replies; 48+ messages in thread
From: Grant Likely @ 2010-05-19 21:19 UTC (permalink / raw)
  To: Anatolij Gustschin
  Cc: linux-fbdev, wd, dzu, devicetree-discuss, linuxppc-dev,
	Mitch Bradley, yorksun

On Wed, Apr 28, 2010 at 7:43 AM, Anatolij Gustschin <agust@denx.de> wrote:
> On Mon, 01 Mar 2010 14:45:20 +1100
> Benjamin Herrenschmidt <benh@kernel.crashing.org> wrote:
>
>> On Sat, 2010-02-27 at 22:44 -1000, Mitch Bradley wrote:
>>
>> > As it turns out, I'm doing exactly that - exporting verbatim EDID
>> > data
>> > as the value of the "edid" property - for the display node on the Via
>> > version of the OLPC machine. =A0The kernel driver uses it instead of
>> > trying to obtain the EDID data from the monitor, because the builtin
>> > OLPC display cannot supply EDID data through the usual hardware
>> > interfaces.
>>
>> This is actually a common practice (though EDID is most often in
>> uppercase) on Apple hardware too. It has issues though in the sense that
>> it doesn't carry proper connector information and falls over in many
>> multi-head cases.
>>
>> I think passing the EDID data, when available, is thus the right thing
>> to do indeed, however that doesn't solve two problems:
>>
>> =A0- Where to put that property ? This is a complicated problem and we
>> might argue on a binding for weeks because video cards typically support
>> multiple outputs, etc. etc... I think the best for now is to stick as
>> closely as possible to the existing OF fb binding, and have "display"
>> nodes for each output, which can eventually contain an EDID. We might
>> also want to add a string that indicate the connector type. Specific
>> drivers might want to define additional properties here where it makes
>> sense such as binding of those outputs to CRTCs or such, up to you.
>
> Putting EDID to display node would be really sufficient for LCDs in
> our case. Other systems might define this additional connector type
> property.
>
>>
>> =A0- We -also- want a way to specify the "default" mode as set by the
>> firmware, at least on some devices. The EDID gives capabilities, and
>> often for LCDs also the "preferred" mode which is almost always the
>> "default" mode ... but could be different. In order to avoid "flicking",
>> the driver might wants to know what is the currently programmed mode.
>> For that, having split out properties makes sense, though I would like
>> to either prefix them all with "mode," or stick them in a sub-node of
>> the display@.
>
> I would propose defining following properties in the case the
> programmed mode is different from "default" mode:
>
> display@...{
> =A0 =A0 =A0 =A0compatible =3D "<vendor>,<model>"
> =A0 =A0 =A0 =A0EDID =3D [edid-data];
>
> =A0 =A0 =A0 =A0current-mode {
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0pixel_clock =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0horizontal_active =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0horizontal_blank =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vertical_active =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vertical_blank =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0horizontal_active =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0hsync_offset =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0hsync_pulse_width =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vsync_offset =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vsync_pulse_width =3D <value>;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0hsync_positive;
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0vsync_positive;
> =A0 =A0 =A0 =A0}
> };
>
> The firmware can set the "default" mode using the EDID's preferred
> Detailed Timing Descriptor data. If on some devices it sets another
> mode than the preferred mode, then the firmware can insert a
> "current-mode" sub-node with currently programmed mode. The driver
> can check for this sub-node and use it's data and if it isn't present,
> it can use the preferred timing data from EDID. The names of the
> properties here are actually what Detailed Timing Descriptor in EDID
> specifies. What do you think?

If you really want to do that, then I think it is okay.  I really
don't know enough about the problem space to say whether or not that
particular description is a good binding or not, but regardless it
should be a video-controller-specific binding.  The name of the node
should probably be prefixed with "<manufacturer>," and it should be
documented along with the display controller's device tree binding.
If another controller wants/needs a different binding format (for the
current mode), then that is fine too (unless you can make a really
good argument that this current-mode binding is perfect and no other
layout should ever be required).  :-)

Cheers,
g.

>
> Thanks,
> Anatolij
>



--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2010-05-19 21:20 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-02-05 13:42 [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin
2010-02-05 13:42 ` [PATCH v3 01/11] powerpc/mpc5121: avoid using arch_initcall for clock init Anatolij Gustschin
2010-02-05 13:42 ` [PATCH v3 02/11] powerpc/mpc5121: Add machine restart support Anatolij Gustschin
2010-02-09 23:24   ` Wolfram Sang
2010-02-15 16:38     ` Anatolij Gustschin
2010-02-10  2:32   ` Grant Likely
2010-02-15 16:51     ` [PATCH v4 " Anatolij Gustschin
2010-02-15 20:58       ` Wolfram Sang
2010-02-05 13:42 ` [PATCH v3 03/11] rtc: Add MPC5121 Real time clock driver Anatolij Gustschin
2010-02-10  2:39   ` Grant Likely
2010-02-10 18:25     ` [rtc-linux] " Alessandro Zummo
2010-02-05 13:42 ` [PATCH v3 04/11] mtd: Add MPC5121 NAND Flash Controller driver Anatolij Gustschin
2010-02-10  2:42   ` Grant Likely
2010-03-30 13:15     ` Artem Bityutskiy
2010-02-15 17:35   ` [PATCH v4 " Anatolij Gustschin
2010-02-16  8:11     ` Artem Bityutskiy
2010-02-23 15:54       ` Kári Davíðsson
2010-02-05 13:42 ` [PATCH v3 05/11] powerpc/mpc5121: create and register NFC device Anatolij Gustschin
2010-02-05 13:42 ` [PATCH v3 06/11] dma: Add MPC512x DMA driver Anatolij Gustschin
2010-02-10  2:44   ` Grant Likely
2010-03-01 13:46   ` Anatolij Gustschin
2010-03-02  6:00     ` Dan Williams
2010-02-05 13:42 ` [PATCH v3 07/11] powerpc/fsl_soc.c: prepare for addition of mpc5121 USB code Anatolij Gustschin
2010-02-05 13:42 ` [PATCH v3 08/11] powerpc/mpc5121: add USB host support Anatolij Gustschin
2010-02-05 13:42 ` [PATCH v3 09/11] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
2010-02-16 18:06   ` Grant Likely
2010-02-18 16:15     ` York Sun
2010-02-27 21:58     ` [PATCH 0/3] Rework MPC5121 DIU support (for 2.6.34) Anatolij Gustschin
2010-02-28  7:04       ` Grant Likely
2010-02-27 21:58     ` [PATCH 1/3] video: add support for getting video mode from device tree Anatolij Gustschin
2010-02-28  6:30       ` Grant Likely
2010-02-28  8:44         ` Mitch Bradley
2010-02-28 14:47           ` Grant Likely
2010-03-01  3:45           ` Benjamin Herrenschmidt
2010-04-28 13:43             ` Anatolij Gustschin
2010-05-19 21:19               ` Grant Likely
2010-02-27 21:58     ` [PATCH 2/3] fbdev: fsl-diu-fb.c: allow setting panel video mode from DT Anatolij Gustschin
2010-02-28  6:52       ` Grant Likely
2010-02-27 21:58     ` [PATCH 3/3] powerpc/mpc5121: shared DIU framebuffer support Anatolij Gustschin
2010-02-28  6:50       ` Grant Likely
2010-04-28 20:28         ` Anatolij Gustschin
2010-02-27 22:09     ` [PATCH v3 09/11] " Anatolij Gustschin
2010-02-05 13:42 ` [PATCH v3 10/11] powerpc/mpc5121: update mpc5121ads DTS Anatolij Gustschin
2010-02-16 18:11   ` Grant Likely
2010-02-16 19:32     ` [PATCH] powerpc: mpc5121: correct DIU compatible property Anatolij Gustschin
2010-02-16 19:51       ` Grant Likely
2010-02-05 13:42 ` [PATCH v3 11/11] powerpc/mpc5121: Add default config for MPC5121 Anatolij Gustschin
2010-02-09  8:48 ` [PATCH v3 00/11] Update support for MPC512x Anatolij Gustschin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).