All of lore.kernel.org
 help / color / mirror / Atom feed
* [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support
@ 2013-03-29  7:06 Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 01/11] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
                   ` (18 more replies)
  0 siblings, 19 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

    http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

    https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU:

1. Download the QEMU source tree

    $ git clone -b qemu-1.3.0 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

    $ ./configure --target-list=arm-softmmu
    $ make
    $ make install

3. Launch u-boot with QEMU:

    $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2012.10/u-boot

Kuo-Jung Su (11):
  arm: add MMU/d-cache support for Faraday cores
  net/ftgmac100: add MMU/D-cache support
  net: add FTMAC110 10/100Mbps ethernet support
  usb-ehci: add Faraday USB 2.0 EHCI controller support
  usb-gadget: add FOTG210 USB gadget support
  i2c: add FTI2C010 I2C controller support
  spi: add FTSPI010 SPI controller support
  mtd/nand: add FTNANDC021 NAND flash controller support
  mtd/spi: add FTSPI020 SPI Flash controller support
  mmc: add an alternative FTSDC010 driver support
  arm: add Faraday A36x SoC platform support

 arch/arm/cpu/faraday/Makefile             |   57 ++
 arch/arm/cpu/faraday/a360/Makefile        |   49 ++
 arch/arm/cpu/faraday/a360/reset.c         |   22 +
 arch/arm/cpu/faraday/a369/Makefile        |   50 ++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   74 +++
 arch/arm/cpu/faraday/a369/reset.c         |   22 +
 arch/arm/cpu/faraday/cmd_bootfa.c         |  121 ++++
 arch/arm/cpu/faraday/config.mk            |   33 +
 arch/arm/cpu/faraday/cpu.c                |  230 +++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  165 +++++
 arch/arm/cpu/faraday/fttmr010.c           |  155 +++++
 arch/arm/cpu/faraday/fwimage.h            |   38 ++
 arch/arm/cpu/faraday/fwimage2.h           |   70 +++
 arch/arm/cpu/faraday/interrupts.c         |  169 ++++++
 arch/arm/cpu/faraday/start.S              |  535 +++++++++++++++++
 arch/arm/cpu/u-boot.lds                   |   11 +
 arch/arm/include/asm/arch-a360/hardware.h |   80 +++
 arch/arm/include/asm/arch-a369/hardware.h |  106 ++++
 arch/arm/include/asm/dma-mapping.h        |   55 +-
 arch/arm/include/asm/global_data.h        |    4 +
 arch/arm/include/asm/io.h                 |   75 +++
 arch/arm/include/asm/mach-types.h         |    1 +
 arch/arm/lib/cache-cp15.c                 |   44 ++
 board/faraday/a360evb/Makefile            |   49 ++
 board/faraday/a360evb/board.c             |   65 ++
 board/faraday/a360evb/clk.c               |   48 ++
 board/faraday/a360evb/config.mk           |   33 +
 board/faraday/a360evb/lowlevel_init.S     |   33 +
 board/faraday/a369evb/Makefile            |   49 ++
 board/faraday/a369evb/board.c             |  182 ++++++
 board/faraday/a369evb/clk.c               |   80 +++
 board/faraday/a369evb/config.mk           |   33 +
 board/faraday/a369evb/lowlevel_init.S     |  133 +++++
 boards.cfg                                |    3 +
 common/cmd_boot.c                         |    4 +
 common/usb_hub.c                          |    5 +
 drivers/i2c/Makefile                      |    1 +
 drivers/i2c/fti2c010.c                    |  360 +++++++++++
 drivers/i2c/fti2c010.h                    |   68 +++
 drivers/mmc/Makefile                      |    1 +
 drivers/mmc/ftsdc010_mci.c                |  362 +++++++++++
 drivers/mmc/ftsdc010_mci.h                |   91 +++
 drivers/mtd/nand/Makefile                 |    1 +
 drivers/mtd/nand/ftnandc021.c             |  550 +++++++++++++++++
 drivers/mtd/nand/ftnandc021.h             |  165 +++++
 drivers/mtd/spi/Makefile                  |    4 +
 drivers/mtd/spi/ftspi020.c                |  589 ++++++++++++++++++
 drivers/mtd/spi/ftspi020.h                |  118 ++++
 drivers/mtd/spi/winbond.c                 |   17 +-
 drivers/net/Makefile                      |    1 +
 drivers/net/ftgmac100.c                   |   83 ++-
 drivers/net/ftmac110.c                    |  484 +++++++++++++++
 drivers/net/ftmac110.h                    |  131 ++++
 drivers/spi/Makefile                      |    1 +
 drivers/spi/ftssp010_spi.c                |  333 +++++++++++
 drivers/spi/ftssp010_spi.h                |   85 +++
 drivers/usb/gadget/Makefile               |    1 +
 drivers/usb/gadget/fotg210.c              |  926 +++++++++++++++++++++++++++++
 drivers/usb/gadget/fotg210.h              |   99 +++
 drivers/usb/gadget/gadget_chips.h         |    8 +
 drivers/usb/host/Makefile                 |    1 +
 drivers/usb/host/ehci-faraday.c           |  157 +++++
 drivers/usb/host/ehci-hcd.c               |   11 +
 drivers/usb/host/ehci.h                   |    5 +
 include/common.h                          |   13 +
 include/configs/a360.h                    |  180 ++++++
 include/configs/a369.h                    |   40 ++
 include/configs/a369_defaults.h           |  285 +++++++++
 include/configs/a369_fa606te.h            |   32 +
 include/faraday/fttmr010.h                |   51 +-
 include/faraday/ftwdt010_wdt.h            |    8 +
 71 files changed, 8110 insertions(+), 35 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/reset.c
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/a369/reset.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h
 create mode 100644 drivers/mmc/ftsdc010_mci.c
 create mode 100644 drivers/mmc/ftsdc010_mci.h
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/mtd/nand/ftnandc021.h
 create mode 100644 drivers/mtd/spi/ftspi020.c
 create mode 100644 drivers/mtd/spi/ftspi020.h
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h
 create mode 100644 drivers/spi/ftssp010_spi.c
 create mode 100644 drivers/spi/ftssp010_spi.h
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/gadget/fotg210.h
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_defaults.h
 create mode 100644 include/configs/a369_fa606te.h

--
1.7.9.5

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

* [U-Boot] [PATCH 01/11] arm: add MMU/d-cache support for Faraday cores
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 02/11] net/ftgmac100: add MMU/D-cache support Kuo-Jung Su
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch would enable MMU for Faraday ARMv5TE cores.

Here is the abstract of the MMU design.

Assume SDRAM memory region starts at 0x10000000, and its size = 0x800000.

0x00000000 +-------------------+
           |                   |
           |     UN-CACHED     |
           |                   |
           |                   |
0x10000000 +-------------------+
           |  CACHED (SDRAM)   | <- It's where data/bss/stack lived.
           |                   |
           |                   |
0x10800000 +-------------------+
           |                   |
           |                   |
           |     UN-CACHED     |
           |                   |
           |                   |
0xFF800000 +-------------------+
           | UN-CACHED (SDRAM) | <- An un-cached shadow of the SDRAM.
           |                   |    dma_alloc_coherent() always returns
           |                   |    an address in this region.
0xFFFFFFFF +-------------------+

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 arch/arm/include/asm/dma-mapping.h |   55 ++++++++++++++++++++++++--
 arch/arm/include/asm/global_data.h |    4 ++
 arch/arm/include/asm/io.h          |   75 ++++++++++++++++++++++++++++++++++++
 arch/arm/lib/cache-cp15.c          |   44 +++++++++++++++++++++
 common/cmd_boot.c                  |    4 ++
 5 files changed, 179 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..d4f779e 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -2,6 +2,8 @@
  * (C) Copyright 2007
  * Stelian Pop <stelian@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -24,22 +26,69 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#include <asm/io.h>
+#include <malloc.h>
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };

-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	*handle = (unsigned long)malloc(len);
-	return (void *)*handle;
+	void *va = memalign(ARCH_DMA_MINALIGN, len);
+	if (va && handle)
+		*handle = virt_to_phys(va);
+
+#ifdef CONFIG_FARADAY
+# ifndef CONFIG_SYS_DCACHE_OFF
+#include <asm/u-boot.h> /* boot information for Linux kernel */
+#include <asm/global_data.h>	/* global data used for startup functions */
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->arch.cpu_mmu) {
+		/* invalidate the buffer, and change to un-cached memory address */
+		if (va != NULL) {
+			invalidate_dcache_range((ulong)va, (ulong)va + len);
+			va = __uncached(va);
+		}
+	}
+# endif
+#endif	/* CONFIG_FARADAY */
+
+	return va;
+}
+
+static inline void dma_free_coherent(void *va)
+{
+	free(__cached(va));
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/u-boot.h> /* boot information for Linux kernel */
+#include <asm/global_data.h>	/* global data used for startup functions */
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((unsigned long)vaddr, (unsigned long)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((unsigned long)vaddr, (unsigned long)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else
 	return (unsigned long)vaddr;
+#endif
 }

 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 37ac0da..bd18ff7 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -38,6 +38,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..4659439 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/io.h
  *
  *  Copyright (C) 1996-2000 Russell King
+ *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -57,9 +58,83 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)

 }

+#if defined(CONFIG_FARADAY)
+
+#include <asm/u-boot.h> /* boot information for Linux kernel */
+#include <asm/global_data.h>
+
+static inline void *__cached(void *va)
+{
+# if !defined(CONFIG_SYS_DCACHE_OFF)
+	DECLARE_GLOBAL_DATA_PTR;
+	unsigned long base = (4096 - (gd->ram_size >> 20)) << 20;	/* un-cached base address */
+
+	if (!gd->arch.cpu_mmu)
+		return va;
+
+	if ((unsigned long)va >= base &&
+		(unsigned long)va < (base + gd->ram_size))
+		va = (void *)((unsigned long)va - base + CONFIG_SYS_SDRAM_BASE);
+# endif	/* !CONFIG_SYS_DCACHE_OFF */
+
+	return va;
+}
+
+static inline void *__uncached(void *va)
+{
+# if !defined(CONFIG_SYS_DCACHE_OFF)
+	DECLARE_GLOBAL_DATA_PTR;
+	unsigned long base = (4096 - (gd->ram_size >> 20)) << 20;	/* un-cached base address */
+
+	if (!gd->arch.cpu_mmu)
+		return va;
+
+# ifdef CONFIG_USE_IRQ
+	if ((unsigned long)va < SZ_1M)
+		return (void *)(base + (unsigned long)va);
+# endif
+
+	if ((unsigned long)va >= CONFIG_SYS_SDRAM_BASE &&
+		(unsigned long)va < (CONFIG_SYS_SDRAM_BASE + gd->ram_size))
+		return (void *)(base + ((unsigned long)va - CONFIG_SYS_SDRAM_BASE));
+# endif	/* !CONFIG_SYS_DCACHE_OFF */
+
+	return va;
+}
+
+#endif	/* CONFIG_FARADAY */
+
 static inline phys_addr_t virt_to_phys(void * vaddr)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+
+	DECLARE_GLOBAL_DATA_PTR;
+	bd_t *bd = gd->bd;
+	unsigned long base = (4096 - (gd->ram_size >> 20)) << 20;	/* un-cached base address */
+	unsigned long phys = (unsigned long)(vaddr);
+
+	if (!gd->arch.cpu_mmu)
+		return (phys_addr_t)phys;
+
+	if (phys >= base) {
+		unsigned long bank;
+		unsigned long off = phys - base;
+		for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
+			if (bd->bi_dram[bank].size > off)
+				break;
+			off -= bd->bi_dram[bank].size;
+		}
+		phys = bd->bi_dram[bank].start + off;
+	}
+# ifdef CONFIG_USE_IRQ
+	else if (phys < SZ_1M && bd->bi_dram[0].start != 0)
+		phys = bd->bi_dram[0].start + phys;
+# endif
+
+	return (phys_addr_t)phys;
+#else
 	return (phys_addr_t)(vaddr);
+#endif
 }

 /*
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index b6e5e95..cf45d31 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -1,6 +1,8 @@
 /*
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -81,6 +83,10 @@ static inline void dram_bank_mmu_setup(int bank)
 {
 	bd_t *bd = gd->bd;
 	int	i;
+#ifdef CONFIG_FARADAY
+	ulong ubase, off;
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+#endif

 	debug("%s: bank: %d\n", __func__, bank);
 	for (i = bd->bi_dram[bank].start >> 20;
@@ -92,6 +98,32 @@ static inline void dram_bank_mmu_setup(int bank)
 		set_section_dcache(i, DCACHE_WRITEBACK);
 #endif
 	}
+#ifdef CONFIG_FARADAY
+# ifdef CONFIG_USE_IRQ
+	/* map the exception table to 0x00000000 if necessary */
+	if (bank == 0 && bd->bi_dram[bank].start != 0) {
+		u32 pa = bd->bi_dram[bank].start;
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
+#else
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
+#endif
+	}
+# endif
+	/* calculate address offset */
+	off  = 0;
+	for (i = 0; i < bank; ++i)
+		off += bd->bi_dram[bank].size;
+
+	/* create memory map */
+	ubase = (4096 - (gd->ram_size >> 20)) << 20;
+	for (i = 0; i < bd->bi_dram[bank].size >> 20; ++i) {
+		u32 pa = bd->bi_dram[bank].start + (i << 20);
+		/* create un-cached address map */
+		u32 va = ubase + off + (i << 20);
+		page_table[va >> 20] = pa | (3 << 10) | DCACHE_OFF;
+	}
+#endif
 }

 /* to activate the MMU we need to set up virtual memory: use 1M areas */
@@ -117,6 +149,12 @@ static inline void mmu_setup(void)
 		     : : "r" (~0));
 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#if !defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+	reg |= CR_W;
+#endif
+#ifdef CONFIG_FARADAY
+	reg |= CR_Z;	/* Branch Prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -131,9 +169,15 @@ static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;

+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
+
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | cache_bit);
diff --git a/common/cmd_boot.c b/common/cmd_boot.c
index d3836fd..b2477e8 100644
--- a/common/cmd_boot.c
+++ b/common/cmd_boot.c
@@ -50,6 +50,10 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])

 	printf ("## Starting application at 0x%08lX ...\n", addr);

+#if defined(__ARM__) && !defined(CONFIG_SYS_DCACHE_OFF)
+	cleanup_before_linux();
+#endif
+
 	/*
 	 * pass address parameter as argv[0] (aka command name),
 	 * and all remaining args
--
1.7.9.5

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

* [U-Boot] [PATCH 02/11] net/ftgmac100: add MMU/D-cache support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 01/11] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 03/11] net: add FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
                   ` (16 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/net/ftgmac100.c |   83 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 56 insertions(+), 27 deletions(-)

diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 69ba57d..0169a42 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -7,6 +7,9 @@
  * (C) Copyright 2010 Andes Technology
  * Macpaul Lin <macpaul@andestech.com>
  *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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
@@ -28,20 +31,25 @@
 #include <net.h>
 #include <asm/io.h>
 #include <linux/mii.h>
+#include <asm/dma-mapping.h>

 #include "ftgmac100.h"

-#define ETH_ZLEN	60
+#define CFG_XBUF_SIZE		1536
+
+#define ETH_ZLEN			60

 /* RBSR - hw default init value is also 0x640 */
 #define RBSR_DEFAULT_VALUE	0x640

 /* PKTBUFSTX/PKTBUFSRX must both be power of 2 */
-#define PKTBUFSTX	4	/* must be power of 2 */
+#define PKTBUFSTX			4	/* must be power of 2 */

 struct ftgmac100_data {
-	struct ftgmac100_txdes txdes[PKTBUFSTX];
-	struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+	ulong txdes_dma;
+	struct ftgmac100_txdes *txdes;
+	ulong rxdes_dma;
+	struct ftgmac100_rxdes *rxdes;
 	int tx_index;
 	int rx_index;
 	int phy_addr;
@@ -375,13 +383,32 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 {
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
-	struct ftgmac100_txdes *txdes = priv->txdes;
-	struct ftgmac100_rxdes *rxdes = priv->rxdes;
+	struct ftgmac100_txdes *txdes;
+	struct ftgmac100_rxdes *rxdes;
 	unsigned int maccr;
+	void *buf;
 	int i;

 	debug("%s()\n", __func__);

+	if (!priv->txdes) {
+		txdes = dma_alloc_coherent(sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+		if (!txdes)
+			panic("ftgmac100: out of memory\n");
+		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+		priv->txdes = txdes;
+	}
+	txdes = priv->txdes;
+
+	if (!priv->rxdes) {
+		rxdes = dma_alloc_coherent(sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+		if (!rxdes)
+			panic("ftgmac100: out of memory\n");
+		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+		priv->rxdes = rxdes;
+	}
+	rxdes = priv->rxdes;
+
 	/* set the ethernet address */
 	ftgmac100_set_mac_from_env(dev);

@@ -397,21 +424,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)

 	for (i = 0; i < PKTBUFSTX; i++) {
 		/* TXBUF_BADR */
-		txdes[i].txdes3 = 0;
+		if (!txdes[i].txdes2) {
+			buf = memalign(64, CFG_XBUF_SIZE);
+			if (!buf)
+				panic("ftgmac100: out of memory\n");
+			txdes[i].txdes3 = virt_to_phys(buf);
+			txdes[i].txdes2 = (uint)buf;
+		}
 		txdes[i].txdes1 = 0;
 	}

 	for (i = 0; i < PKTBUFSRX; i++) {
 		/* RXBUF_BADR */
-		rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i];
+		if (!rxdes[i].rxdes2) {
+			buf = NetRxPackets[i];
+			rxdes[i].rxdes3 = virt_to_phys(buf);
+			rxdes[i].rxdes2 = (uint)buf;
+		}
 		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
 	}

 	/* transmit ring */
-	writel((unsigned int)txdes, &ftgmac100->txr_badr);
+	writel(priv->txdes_dma, &ftgmac100->txr_badr);

 	/* receive ring */
-	writel((unsigned int)rxdes, &ftgmac100->rxr_badr);
+	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);

 	/* poll receive descriptor automatically */
 	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -466,8 +503,11 @@ static int ftgmac100_recv(struct eth_device *dev)
 	debug("%s(): RX buffer %d, %x received\n",
 	       __func__, priv->rx_index, rxlen);

+	/* invalidate d-cache */
+	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
 	/* pass the packet up to the protocol layers. */
-	NetReceive((void *)curr_des->rxdes3, rxlen);
+	NetReceive((void *)curr_des->rxdes2, rxlen);

 	/* release buffer to DMA */
 	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
@@ -485,7 +525,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
 	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
-	int start;

 	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
 		debug("%s(): no TX descriptor available\n", __func__);
@@ -496,28 +535,18 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)

 	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;

-	/* initiate a transmit sequence */
-	curr_des->txdes3 = (unsigned int)packet;	/* TXBUF_BADR */
+	memcpy((void *)curr_des->txdes2, (void *)packet, length);
+	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);

-	/* only one descriptor on TXBUF */
 	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
 	curr_des->txdes0 |= FTGMAC100_TXDES0_FTS |
-			    FTGMAC100_TXDES0_LTS |
-			    FTGMAC100_TXDES0_TXBUF_SIZE(length) |
-			    FTGMAC100_TXDES0_TXDMA_OWN ;
+				FTGMAC100_TXDES0_LTS |
+				FTGMAC100_TXDES0_TXBUF_SIZE(length) |
+				FTGMAC100_TXDES0_TXDMA_OWN ;

 	/* start transmit */
 	writel(1, &ftgmac100->txpd);

-	/* wait for transfer to succeed */
-	start = get_timer(0);
-	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
-		if (get_timer(0) >= 5) {
-			debug("%s(): timed out\n", __func__);
-			return -1;
-		}
-	}
-
 	debug("%s(): packet sent\n", __func__);

 	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
--
1.7.9.5

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

* [U-Boot] [PATCH 03/11] net: add FTMAC110 10/100Mbps ethernet support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 01/11] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 02/11] net/ftgmac100: add MMU/D-cache support Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support Kuo-Jung Su
                   ` (15 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTMAC110 10/100Mbps supports half-word data transfer for Linux.
However it has a weird DMA alignment issue:

(1) Tx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: O.K

(2) Rx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: Invalid!!!

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/net/Makefile   |    1 +
 drivers/net/ftmac110.c |  484 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ftmac110.h |  131 +++++++++++++
 3 files changed, 616 insertions(+)
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 786a656..0e23817 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
 COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
+COBJS-$(CONFIG_FTMAC110) += ftmac110.o
 COBJS-$(CONFIG_FTMAC100) += ftmac100.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
new file mode 100644
index 0000000..67373f5
--- /dev/null
+++ b/drivers/net/ftmac110.c
@@ -0,0 +1,484 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#ifndef EMAC_REG32
+#define EMAC_REG32(dev, off)	*(volatile uint32_t *)((dev)->iobase + (off))
+#endif
+
+#define CFG_DEBUG_DESC			0
+#define CFG_DEBUG_TX			0
+#define CFG_DEBUG_RX			0
+
+#define CFG_RXDES_NUM			8
+#define CFG_TXDES_NUM			2
+#define CFG_XBUF_SIZE			1536
+
+/*******************************************************************/
+/*               FTMAC110 DMA design issue                         */
+/*                                             Dante Su 2010.02.03 */
+/*                                                                 */
+/* The DMA engine has a weird restriction that its Rx DMA engine   */
+/* accepts only 16-bits aligned address, 32-bits aligned is not    */
+/* acceptable. However this restriction does not apply to Tx DMA.  */
+/* Conclusion:                                                     */
+/* (1) Tx DMA Buffer Address:                                      */
+/*     1 bytes aligned: Invalid                                    */
+/*     2 bytes aligned: O.K                                        */
+/*     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)       */
+/* (2) Rx DMA Buffer Address:                                      */
+/*     1 bytes aligned: Invalid                                    */
+/*     2 bytes aligned: O.K                                        */
+/*     4 bytes aligned: Invalid                                    */
+/*******************************************************************/
+
+struct ftmac110_priv {
+	uint32_t        iobase;
+	uint32_t        irqmask;
+	uint32_t        maccr;
+	uint32_t        lnkup;
+
+	struct ftmac110_rxd *rx_descs;
+	ulong           rx_descs_dma;
+	uint32_t        rx_idx;
+
+	struct ftmac110_txd *tx_descs;
+	ulong           tx_descs_dma;
+	uint32_t        tx_idx;
+
+	uint32_t        phy_addr;
+};
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static char ftmac110_mac_addr[] = {0x00, 0x41, 0x71, 0x00, 0x00, 0x52};
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev, uint8_t phyaddr, uint8_t phyreg)
+{
+	uint32_t tmp;
+
+	tmp = MIIREG_READ
+		  | (phyaddr << MIIREG_PHYADDR_SHIFT)
+		  | (phyreg  << MIIREG_PHYREG_SHIFT)
+		  | 0x30000000;
+
+	EMAC_REG32(dev, REG_PHYCR) = tmp;
+
+	do {
+		tmp = EMAC_REG32(dev, REG_PHYCR);
+	} while (tmp & MIIREG_READ);
+
+	return (uint16_t)(tmp & 0xFFFF);
+}
+
+static void mdio_write(struct eth_device *dev, uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+	unsigned int tmp;
+
+	tmp = MIIREG_WRITE
+		  | (phyaddr << MIIREG_PHYADDR_SHIFT)
+		  | (phyreg  << MIIREG_PHYREG_SHIFT)
+		  | 0x30000000;
+
+	EMAC_REG32(dev, REG_PHYDR) = phydata;
+	EMAC_REG32(dev, REG_PHYCR) = tmp;
+
+	do {
+		tmp = EMAC_REG32(dev, REG_PHYCR);
+	} while (tmp & MIIREG_WRITE);
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+	ulong ts;
+	uint32_t maccr;
+	uint16_t pa, tmp;
+	struct ftmac110_priv    *priv = dev->priv;
+
+	maccr = MACCR_100M | MACCR_FD;
+
+	/* 0. find the phy device  */
+	for (pa = 0; pa < 32; ++pa) {
+		tmp = mdio_read(dev, pa, MII_PHYSID1);
+		if (tmp == 0xFFFF || tmp == 0x0000)
+			continue;
+		break;
+	}
+	if (pa >= 32) {
+		puts("ftmac110: phy device not found!\n");
+		return maccr;
+	} else {
+		priv->phy_addr = pa;
+	}
+
+	/* 1. check link status */
+	priv->lnkup = 0;
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		if (mdio_read(dev, priv->phy_addr, MII_BMSR) & BMSR_LSTATUS) {
+			priv->lnkup = 1;
+			break;
+		}
+	}
+	if (!priv->lnkup) {
+		puts("ftmac110: link down\n");
+		goto exit;
+	}
+
+	/* 2. check A/N status */
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		if (mdio_read(dev, priv->phy_addr, MII_BMSR) & BMSR_ANEGCOMPLETE)
+			break;
+	}
+	if (get_timer(ts) >= 1000) {
+		puts("ftmac110: A/N failed\n");
+		goto exit;
+	}
+
+	/* 3. build MACCR with the PHY status */
+	tmp  = mdio_read(dev, priv->phy_addr, MII_ADVERTISE);
+	tmp &= mdio_read(dev, priv->phy_addr, MII_LPA);
+
+	/* 3-1. 10/100Mbps Detection */
+	if (tmp & LPA_100FULL)        /* 100Mbps full-duplex */
+		maccr = MACCR_100M | MACCR_FD;
+	else if (tmp & LPA_100HALF)   /* 100Mbps half-duplex */
+		maccr = MACCR_100M;
+	else if (tmp & LPA_10FULL)    /* 10Mbps full-duplex */
+		maccr = MACCR_FD;
+	else if (tmp & LPA_10HALF)    /* 10Mbps half-duplex */
+		maccr = 0;
+	else
+		maccr = MACCR_100M | MACCR_FD;
+
+	printf("ftmac110: %d Mbps, %s\n",
+		   (maccr & MACCR_100M) ? 100 : 10,
+		   (maccr & MACCR_FD) ? "Full" : "half");
+
+exit:
+	return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+	uint32_t i, tmp, maccr;
+	struct ftmac110_priv *priv = dev->priv;
+
+	/*
+	 * 1. MAC reset
+	 */
+	EMAC_REG32(priv, REG_MACCR) = MACCR_RESET;
+	do {
+		tmp = EMAC_REG32(priv, REG_MACCR);
+	} while (tmp & MACCR_RESET);
+
+	/* 1-1. tx ring */
+	for (i = 0; i < CFG_TXDES_NUM; ++i)
+		priv->tx_descs[i].owner = 0;    /* owned by SW */
+	priv->tx_idx = 0;
+
+	/* 1-2. rx ring    */
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		priv->rx_descs[i].owner = 1;    /* owned by HW */
+		priv->rx_descs[i].bufsz = CFG_XBUF_SIZE;
+	}
+	priv->rx_idx = 0;
+
+	/*
+	 * 2. PHY status query
+	 */
+	maccr = ftmac110_phyqry(dev);
+
+	/*
+	 * 3. Fix up the MACCR value
+	 */
+	priv->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+				| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+	priv->irqmask = 0;
+
+	/*
+	 * 4. MAC address setup
+	 */
+	do {
+		uint8_t *ma = dev->enetaddr;
+		EMAC_REG32(priv, REG_HMAC) = ma[1] | (ma[0] << 8);
+		EMAC_REG32(priv, REG_LMAC) = ma[5] | (ma[4] << 8) | (ma[3] << 16) | (ma[2] << 24);
+	} while (0);
+
+	/*
+	 * 5. MAC registers setup
+	 */
+	EMAC_REG32(priv, REG_RXBAR) = priv->rx_descs_dma;
+	EMAC_REG32(priv, REG_TXBAR) = priv->tx_descs_dma;
+	EMAC_REG32(priv, REG_ITC)   = 0x00001010;
+	EMAC_REG32(priv, REG_APTC)  = 0x00000001;
+	EMAC_REG32(priv, REG_DBLAC) = 0x00000390;
+	EMAC_REG32(priv, REG_ISR)   = 0x000003FF;
+	EMAC_REG32(priv, REG_IMR)   = priv->irqmask;
+	EMAC_REG32(priv, REG_MACCR) = priv->maccr;
+
+	return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+	debug("ftmac110: probe\n");
+
+	if (ftmac110_reset(dev))
+		return -1;
+
+	return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+	struct ftmac110_priv *priv = dev->priv;
+
+	EMAC_REG32(priv, REG_IMR) = 0;
+	EMAC_REG32(priv, REG_MACCR) = 0;
+
+	debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *packet, int length)
+{
+	struct ftmac110_priv *priv = dev->priv;
+	struct ftmac110_txd *cur_desc;
+
+	if (!priv->lnkup)
+		return 0;
+
+	if (length <= 0 || length > CFG_XBUF_SIZE) {
+		printf("ftmac110: bad tx packet length(%d)\n", length);
+		return 0;
+	}
+
+	if (length < 60)
+		length = 60;
+
+	cur_desc = &priv->tx_descs[priv->tx_idx];
+	if (cur_desc->owner) {
+		EMAC_REG32(priv, REG_TXPD) = 0xffffffff;    /* kick-off Tx DMA */
+		printf("ftmac110: out of txd\n");
+		return 0;
+	}
+
+	memcpy(cur_desc->vbuf, (void *)packet, length);
+	dma_map_single(cur_desc->vbuf, length, DMA_TO_DEVICE);
+
+	cur_desc->len   = length;
+	cur_desc->lts   = 1;
+	cur_desc->fts   = 1;
+	cur_desc->owner = 1;
+
+	EMAC_REG32(priv, REG_TXPD) = 0xffffffff;    /* kick-off Tx DMA */
+
+#if CFG_DEBUG_TX
+	printf("ftmac110: txd[%d]@0x%08X, buf=0x%p(pa=0x%08X)\n",
+		   priv->tx_idx, (uint32_t)cur_desc,
+		   cur_desc->vbuf, cur_desc->buf);
+#endif
+
+	priv->tx_idx = (priv->tx_idx + 1) % CFG_TXDES_NUM;
+
+	return length;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+	struct ftmac110_priv *priv = dev->priv;
+	struct ftmac110_rxd *cur_desc;
+	uint32_t rlen = 0;
+	uint8_t *buf;
+	uint16_t len;
+
+	if (!priv->lnkup)
+		return 0;
+
+	do {
+		cur_desc = &priv->rx_descs[priv->rx_idx];
+		if (cur_desc->owner == 1)
+			break;
+
+		len = cur_desc->len;
+		buf = cur_desc->vbuf;
+
+		if (cur_desc->error) {
+			printf("ftmac110: rx error\n");
+		} else {
+#if CFG_DEBUG_RX
+			printf("ftmac110: rxd[%d]@0x%p, buf=0x%08X, len=%d\n",
+				   priv->rx_idx, cur_desc,
+				   (uint32_t)buf, len);
+#endif
+			dma_map_single(buf, len, DMA_FROM_DEVICE);
+			NetReceive(buf, len);
+			rlen += len;
+		}
+
+		cur_desc->len   = 0;
+		cur_desc->owner = 1;    /* owned by hardware */
+
+		priv->rx_idx = (priv->rx_idx + 1) % CFG_RXDES_NUM;
+	} while (0);
+
+	return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read (const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		*value = mdio_read(dev, addr, reg);
+	}
+
+	return ret;
+}
+
+static int ftmac110_mdio_write (const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		mdio_write(dev, addr, reg, value);
+	}
+
+	return ret;
+}
+
+#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+	int i, card_number = 0;
+	char enetvar[32];
+	char *tmp, *end;
+	struct eth_device *dev;
+	struct ftmac110_priv *priv;
+
+	dev = malloc(sizeof(struct eth_device) + sizeof(struct ftmac110_priv));
+	if (dev == NULL) {
+		panic("ftmac110: out of memory 1\n");
+		return -1;
+	}
+	priv = (struct ftmac110_priv *)(dev + 1);
+	memset(dev, 0, sizeof(struct eth_device) + sizeof(struct ftmac110_priv));
+
+	sprintf(dev->name, "FTMAC110#%d", card_number);
+
+	dev->iobase = priv->iobase = CONFIG_FTMAC110_BASE;
+	dev->priv = priv;
+	dev->init = ftmac110_probe;
+	dev->halt = ftmac110_halt;
+	dev->send = ftmac110_send;
+	dev->recv = ftmac110_recv;
+
+	sprintf(enetvar, card_number ? "eth%daddr" : "ethaddr", card_number);
+
+	tmp = getenv(enetvar);
+	if (tmp != NULL) {
+		for (i = 0; i < 6; i++) {
+			dev->enetaddr[i] = tmp ? simple_strtoul(tmp, &end, 16) : 0;
+			if (tmp)
+				tmp = (*end) ? end + 1 : end;
+		}
+	} else {
+		memcpy(dev->enetaddr, ftmac110_mac_addr, 6);
+	}
+
+	/* allocate tx descriptors (it must be 16 bytes aligned) */
+	priv->tx_descs = dma_alloc_coherent(sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &priv->tx_descs_dma);
+	if (priv->tx_descs == NULL)
+		panic("ftmac110: out of memory 3\n");
+	memset((void *)priv->tx_descs, 0, sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+		if (!va)
+			panic("ftmac110: out of memory 4\n");
+		priv->tx_descs[i].vbuf  = va;
+		priv->tx_descs[i].buf   = virt_to_phys(va);
+		priv->tx_descs[i].len   = 0;
+		priv->tx_descs[i].end   = 0;
+		priv->tx_descs[i].owner = 0;    /* owned by SW */
+	}
+	priv->tx_descs[CFG_TXDES_NUM - 1].end = 1;
+	priv->tx_idx = 0;
+
+	/* allocate rx descriptors (it must be 16 bytes aligned) */
+	priv->rx_descs = dma_alloc_coherent(sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &priv->rx_descs_dma);
+	if (priv->rx_descs == NULL)
+		panic("ftmac110: out of memory 4\n");
+	memset((void *)priv->rx_descs, 0, sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+		if (!va)
+			panic("ftmac110: out of memory 5\n");
+		/* it needs to be exactly 2 bytes aligned */
+		va = ((uint8_t *)va + 2);
+		priv->rx_descs[i].vbuf  = va;
+		priv->rx_descs[i].buf   = (uint32_t)virt_to_phys(va);
+		priv->rx_descs[i].len   = 0;
+		priv->rx_descs[i].bufsz = CFG_XBUF_SIZE;
+		priv->rx_descs[i].end   = 0;
+		priv->rx_descs[i].owner = 1;    /* owned by HW */
+	}
+	priv->rx_descs[CFG_RXDES_NUM - 1].end = 1;
+	priv->rx_idx = 0;
+
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register (dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+#if CFG_DEBUG_DESC
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		printf("TXD[%d]: 0x%08X, 0x%08X<=0x%08x\n",
+			   i, (uint32_t)&priv->tx_descs[i],
+			   (uint32_t)priv->tx_descs[i].vbuf,
+			   (uint32_t)priv->tx_descs[i].buf);
+	}
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		printf("RXD[%d]: 0x%08X, 0x%08X<=0x%08X\n",
+			   i, (uint32_t)&priv->rx_descs[i],
+			   (uint32_t)priv->rx_descs[i].vbuf,
+			   (uint32_t)priv->rx_descs[i].buf);
+	}
+#endif
+
+	card_number++;
+
+	return card_number;
+}
diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h
new file mode 100644
index 0000000..b98bd7b
--- /dev/null
+++ b/drivers/net/ftmac110.h
@@ -0,0 +1,131 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTMAC110_H
+#define __FTMAC110_H
+
+/*
+ * FTMAC110 MAC Registers
+ */
+#define REG_ISR		0x00	/* Interrups status register */
+#define REG_IMR		0x04	/* Interrupt maks register */
+#define REG_HMAC	0x08	/* MAC address (Most significant) */
+#define REG_LMAC	0x0c	/* MAC address (Least significant) */
+#define REG_MHT0	0x10	/* Multicast Hash Table 0 register */
+#define REG_MHT1	0x14	/* Multicast Hash Table 1 register */
+#define REG_TXPD	0x18	/* Transmit Poll Demand register */
+#define REG_RXPD	0x1c	/* Receive Poll Demand register */
+#define REG_TXBAR	0x20	/* Transmit Ring Base Address register */
+#define REG_RXBAR	0x24	/* Receive Ring Base Address register */
+#define REG_ITC		0x28	/* Interrupt timer control register */
+#define REG_APTC	0x2C	/* Automatic Polling Timer control register */
+#define REG_DBLAC	0x30	/* DMA Burst Length and Arbitration control register */
+
+#define REG_MACCR	0x88	/* MAC control register */
+#define REG_MACSR	0x8C	/* MAC status register */
+#define REG_PHYCR	0x90	/* PHY control register */
+#define REG_PHYDR	0x94	/* PHY data register */
+#define REG_FCR		0x98	/* Flow Control register */
+#define REG_BPR		0x9c	/* Back pressure register */
+
+/* Interrupt status register(ISR), Interrupt mask register(IMR) bit setting */
+#define ISR_PHYSTCHG        (1 << 9)	/* phy status change */
+#define ISR_AHBERR			(1 << 8)	/* bus error */
+#define ISR_RXLOST			(1 << 7)	/* rx lost due to fifo overflow */
+#define ISR_RXFIFO			(1 << 6)	/* rx to fifo */
+#define ISR_TXLOST			(1 << 5)	/* tx lost due to collision */
+#define ISR_TXOK			(1 << 4)	/* tx to ethernet */
+#define ISR_NOTXBUF			(1 << 3)	/* out of tx buffer */
+#define ISR_TXFIFO			(1 << 2)	/* packets transmitted to fifo */
+#define ISR_NORXBUF			(1 << 1)	/* out of rx buffer */
+#define ISR_RXOK			(1 << 0)	/* packets received to buffer (ram) */
+
+/* MACC control bits */
+#define MACCR_100M			(1 << 18)	/* 100Mbps mode */
+#define MACCR_RXBCST		(1 << 17)	/* receive all broadcast packet */
+#define MACCR_RXMCST		(1 << 16)	/* receive all multicast packet */
+#define MACCR_FD			(1 << 15)	/* full duplex */
+#define MACCR_CRCAPD		(1 << 14)	/* append crc to transmit packet */
+#define MACCR_RXALL			(1 << 12)	/* not check incoming packet's destination address */
+#define MACCR_RXFTL			(1 << 11)	/* store incoming packet even its length > 1518 byte */
+#define MACCR_RXRUNT		(1 << 10)	/* store incoming packet even its length < 64 byte */
+#define MACCR_RXMCSTHT		(1 << 9)	/* receive multicast packet by matching hash table */
+#define MACCR_RXEN			(1 << 8)	/* rx enable */
+#define MACCR_RXINHDTX		(1 << 6)	/* rx in half duplex tx */
+#define MACCR_TXEN			(1 << 5)	/* tx enable */
+#define MACCR_CRCDIS		(1 << 4)	/* store incoming packet even if crc error */
+#define MACCR_LOOPBACK		(1 << 3)	/* Internal loop-back */
+#define MACCR_RESET			(1 << 2)	/* reset */
+#define MACCR_RXDMAEN		(1 << 1)	/* enable rx dma */
+#define MACCR_TXDMAEN		(1 << 0)	/* enable tx dma */
+
+/*
+ *        MII PHY Registers
+ */
+
+/*
+ * Bits related to the MII interface
+ */
+#define MIIREG_READ				(1 << 26)
+#define MIIREG_WRITE			(1 << 27)
+#define MIIREG_PHYREG_SHIFT		21
+#define MIIREG_PHYADDR_SHIFT	16
+
+/*
+ *        Receive Ring descriptor structure
+ */
+struct ftmac110_rxd {
+	/* RXDES0 */
+	uint32_t len:11;
+	uint32_t rsvd1:5;
+	uint32_t mcast:1;
+	uint32_t bcast:1;
+	uint32_t error:5;
+	uint32_t rsvd2:5;
+	uint32_t lrs:1;
+	uint32_t frs:1;
+	uint32_t rsvd3:1;
+	uint32_t owner:1;    /* BIT: 31 - 1:Hardware, 0: Software */
+
+	/* RXDES1 */
+	uint32_t bufsz:11;
+	uint32_t rsvd4:20;
+	uint32_t end:1;
+
+	/* RXDES2 */
+	uint32_t buf;
+
+	/* RXDES3 */
+	void    *vbuf;
+};
+
+struct ftmac110_txd {
+	/* TXDES0 */
+	uint32_t collision:2;
+	uint32_t rsvd1:29;
+	uint32_t owner:1;	/* BIT: 31 - 1:Hardware, 0: Software */
+
+	/* TXDES1 */
+	uint32_t len:11;
+	uint32_t rsvd2:16;
+	uint32_t lts:1;
+	uint32_t fts:1;
+	uint32_t tx2fic:1;
+	uint32_t txic:1;
+	uint32_t end:1;
+
+	/* TXDES2 */
+	uint32_t buf;
+
+	/* TXDES3 */
+	void    *vbuf;
+};
+
+#endif  /* FTMAC110_H */
--
1.7.9.5

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

* [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (2 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 03/11] net: add FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-30  6:29   ` Marek Vasut
  2013-03-29  7:06 ` [U-Boot] [PATCH 05/11] usb-gadget: add FOTG210 USB gadget support Kuo-Jung Su
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch add supports to both Faraday FUSBH200 and FOTG210,
these controllers slightly differ from standard EHCI specification.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 common/usb_hub.c                |    5 ++
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  157 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |   11 +++
 drivers/usb/host/ehci.h         |    5 ++
 5 files changed, 179 insertions(+)
 create mode 100644 drivers/usb/host/ehci-faraday.c

diff --git a/common/usb_hub.c b/common/usb_hub.c
index b5eeb62..099696e 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -375,6 +375,11 @@ static int usb_hub_configure(struct usb_device *dev)
 		return -1;
 	}

+#ifdef CONFIG_USB_EHCI_FARADAY
+	/* dante: fusbh200 requires a long long delay ... */
+	mdelay(250);
+#endif
+
 	if (usb_get_hub_status(dev, buffer) < 0) {
 		USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
 				dev->status);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 9a6f982..d5577bd 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -44,6 +44,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..a5a6394
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,157 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <usb.h>
+
+#include "ehci.h"
+
+#ifndef BIT
+#define BIT(nr)	(1UL << (nr))
+#endif
+
+/* Lower Timing for FPGA Mode */
+#define CFG_LOWER_TIMING        0
+
+struct faraday_usb_hcd {
+	uint32_t iobase;
+};
+
+static struct faraday_usb_hcd faraday_usb_hcd_info[] = {
+#ifdef CONFIG_USB_EHCI_BASE
+	{ .iobase = CONFIG_USB_EHCI_BASE, },
+#endif
+#ifdef CONFIG_USB_EHCI_BASE1
+	{ .iobase = CONFIG_USB_EHCI_BASE1, },
+#endif
+};
+
+#define HCD_REG32(chip, off) \
+    *(volatile uint32_t *)((chip)->iobase + (off))
+
+static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
+{
+	uint32_t iobase = (uint32_t)hccr;
+	return !REG32(iobase + 0x34) || REG32(iobase + 0x34) == 0xffffffff;
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct faraday_usb_hcd *hcd = &faraday_usb_hcd_info[index];
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+
+	hccr = (struct ehci_hccr *)hcd->iobase;
+	hcor = (struct ehci_hcor *)(hcd->iobase +
+		HC_LENGTH(ehci_readl(&hccr->cr_capbase)));
+
+	if (ehci_hci_fotg2xx(hccr)) {
+
+		/* A-device bus reset */
+		HCD_REG32(hcd, 0x80) |= BIT(5);
+		HCD_REG32(hcd, 0x80) &= ~BIT(4);
+		mdelay(1);
+		HCD_REG32(hcd, 0x80) &= ~BIT(5);
+		HCD_REG32(hcd, 0x80) |= BIT(4);
+		mdelay(1);
+
+		/* Reset interrupt */
+		HCD_REG32(hcd, 0xC0) = 7;
+
+		/* Disable OTG & device interrupts */
+		HCD_REG32(hcd, 0xC4) = 3;
+
+		/* Set interrupt polarity to active high */
+		HCD_REG32(hcd, 0xC4) |= BIT(3);
+
+		/* In FPGA mode (15MHz <= AHB <= 30MHz), enter half speed mode. */
+		if (clk_get_rate("AHB") <= 30000000) {
+			HCD_REG32(hcd, 0x100) |= BIT(1);
+			printf("fotg210: AHB is too slow, enter half-speed mode.\n");
+		}
+
+#ifdef CFG_LOWER_TIMING
+		HCD_REG32(hcd, 0x40) |= 0x0d;
+#endif
+
+	} else {
+
+		/* Set interrupt polarity to active high */
+		HCD_REG32(hcd, 0x40) |= BIT(3);
+
+		/* In FPGA mode (15MHz <= AHB <= 30MHz), enter half speed mode. */
+		if (clk_get_rate("AHB") <= 30000000) {
+			HCD_REG32(hcd, 0x40) |= BIT(2);
+			printf("fusbh200: AHB is too slow, enter half-speed mode.\n");
+		}
+
+#ifdef CFG_LOWER_TIMING
+		HCD_REG32(hcd, 0x34) |= (3 << 2) | (1 << 0);
+#endif
+
+		/* Turn on VBUS */
+		HCD_REG32(hcd, 0x40) &= ~BIT(4);
+
+		/* Enable over-current & vbus error interrupts */
+		HCD_REG32(hcd, 0x44) = 0x1F;
+		HCD_REG32(hcd, 0x48) |= BIT(1) | BIT(0);
+
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+int ehci_hcd_port_speed(struct ehci_hccr *hccr)
+{
+	int rc = 0;
+	int speed;
+	uint32_t iobase = (uint32_t)hccr;
+
+	if (ehci_hci_fotg2xx(hccr))
+		speed = (REG32(iobase + 0x80) >> 22) & 0x03;
+	else
+		speed = (REG32(iobase + 0x40) >>  9) & 0x03;
+
+	switch (speed) {
+	case 0:    /* full speed */
+		break;
+
+	case 1:    /* low  speed */
+		rc = USB_PORT_STAT_LOW_SPEED;
+		break;
+
+	case 2:    /* high speed */
+		rc = USB_PORT_STAT_HIGH_SPEED;
+		break;
+
+	default:
+		printf("faraday-usb: invalid device speed\n");
+		break;
+	}
+
+	return rc;
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..450d217 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -149,8 +149,10 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t tmp;
 	uint32_t *reg_ptr;
+#endif
 	int ret = 0;

 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,6 +165,7 @@ static int ehci_reset(int index)
 		goto out;
 	}

+#ifndef CONFIG_USB_EHCI_FARADAY
 	if (ehci_is_TDI()) {
 		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
 		tmp = ehci_readl(reg_ptr);
@@ -172,6 +175,7 @@ static int ehci_reset(int index)
 #endif
 		ehci_writel(reg_ptr, tmp);
 	}
+#endif	/* !CONFIG_USB_EHCI_FARADAY */

 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -711,6 +715,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;

 		if (ehci_is_TDI()) {
+#ifdef CONFIG_USB_EHCI_FARADAY
+			tmpbuf[1] |= ehci_hcd_port_speed(ctrl->hccr) >> 8;
+#else
 			switch (PORTSC_PSPD(reg)) {
 			case PORTSC_PSPD_FS:
 				break;
@@ -722,6 +729,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 				break;
 			}
+#endif
 		} else {
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 		}
@@ -950,10 +958,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index d090f0a..9309ede 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -82,6 +82,7 @@ struct ehci_hcor {
 	uint32_t or_periodiclistbase;
 	uint32_t or_asynclistaddr;
 	uint32_t _reserved_0_;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t or_burstsize;
 	uint32_t or_txfilltuning;
 #define TXFIFO_THRESH_MASK		(0x3f << 16)
@@ -89,6 +90,7 @@ struct ehci_hcor {
 	uint32_t _reserved_1_[6];
 	uint32_t or_configflag;
 #define FLAG_CF		(1 << 0)	/* true:  we'll support "high speed" */
+#endif  /* #ifndef CONFIG_USB_EHCI_FARADAY */
 	uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
 #define PORTSC_PSPD(x)		(((x) >> 26) & 0x3)
 #define PORTSC_PSPD_FS			0x0
@@ -255,5 +257,8 @@ struct QH {
 /* Low level init functions */
 int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor);
 int ehci_hcd_stop(int index);
+#ifdef CONFIG_USB_EHCI_FARADAY
+int ehci_hcd_port_speed(struct ehci_hccr *hccr);
+#endif

 #endif /* USB_EHCI_H */
--
1.7.9.5

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

* [U-Boot] [PATCH 05/11] usb-gadget: add FOTG210 USB gadget support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (3 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-30  6:27   ` Marek Vasut
  2013-03-29  7:06 ` [U-Boot] [PATCH 06/11] i2c: add FTI2C010 I2C controller support Kuo-Jung Su
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch would try to use Faraday FOTG210 to implement
a USB RNDIS Ethernet.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  926 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/fotg210.h      |   99 ++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 4 files changed, 1034 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/gadget/fotg210.h

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..640ae55
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,926 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "fotg210.h"
+
+#define CFG_HALF_SPEED			0
+#define CFG_LOW_TIMING			0
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint32_t maxpacket:16;
+	uint32_t id:4;
+	uint32_t stopped:1;
+	uint32_t rsvd:11;
+
+	struct list_head                      queue;
+	const struct usb_endpoint_descriptor *desc;
+	struct fotg210_chip                  *chip;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	uint32_t                  iobase;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType  = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes =    USB_ENDPOINT_XFER_CONTROL,
+};
+
+#define USB_REG32(chip, off)    *(volatile uint32_t *)((chip)->iobase + (off))
+
+static inline int
+fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id % 4) + 1);
+}
+
+static inline int
+ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) % 4);
+}
+
+static inline int
+ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* input */
+		USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) |= BIT(12);
+		USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) &= ~BIT(12);
+		USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) &= ~BIT(11);
+	} else {
+		/* output */
+		USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) |= BIT(12);
+		USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) &= BIT(12);
+		USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) &= BIT(11);
+	}
+
+	return 0;
+}
+
+static int
+fotg210_reset(struct fotg210_chip *chip)
+{
+	chip->state = USB_STATE_POWERED;
+
+	/* device address reset */
+	chip->addr  = 0;
+	USB_REG32(chip, REG_DCAR)   = 0;
+
+	/* enable the chip and perform a soft reset later */
+	USB_REG32(chip, REG_DCCR)   = BIT(5);
+
+	/* set idle counter */
+	USB_REG32(chip, REG_DCIDLE) = 7;
+
+	/* disable interrupts */
+	USB_REG32(chip, REG_HCIER)  = 0;
+	USB_REG32(chip, REG_DCIMR)  = 0x3;
+	USB_REG32(chip, REG_DCIMR0) = 0x3F;
+	USB_REG32(chip, REG_DCIMR1) = 0xF00FF;
+	USB_REG32(chip, REG_DCIMR2) = 0x7FF;
+
+	/* clear interrupts */
+	USB_REG32(chip, REG_HCISR)  = 0x3F;
+	USB_REG32(chip, REG_OTGISR) = 0x1FFF;
+	USB_REG32(chip, REG_DCISR)  = 0;
+	USB_REG32(chip, REG_DCISR0) = 0;
+	USB_REG32(chip, REG_DCISR1) = 0;
+	USB_REG32(chip, REG_DCISR2) = 0;
+
+	/* soft reset */
+	USB_REG32(chip, REG_DCCR) |= BIT(4);
+	while (USB_REG32(chip, REG_DCCR) & BIT(4))
+		;
+
+	/* CX FIFO reset */
+	USB_REG32(chip, REG_DCCXFIFO) |= BIT(3);
+	while (USB_REG32(chip, REG_DCCXFIFO) & BIT(3))
+		;
+
+	/* create static ep-fifo map (EP1-FIFO0, EP2-FIFO1 ...)*/
+	USB_REG32(chip, REG_EPMAP14) = 0x33221100;
+	USB_REG32(chip, REG_EPMAP58) = 0x00000000;
+	USB_REG32(chip, REG_FIFOMAP) = 0x04030201;
+	USB_REG32(chip, REG_FIFOCFG) = 0x00000000;
+	USB_REG32(chip, REG_IEP1)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_IEP2)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_IEP3)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_IEP4)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_IEP5)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_IEP6)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_IEP7)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_IEP8)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP1)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP2)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP3)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP4)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP5)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP6)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP7)    = CFG_EPX_MAX_PACKET_SIZE;
+	USB_REG32(chip, REG_OEP8)    = CFG_EPX_MAX_PACKET_SIZE;
+
+	/* reset EP FIFO */
+	USB_REG32(chip, REG_FIFO0) |= BIT(12);
+	while (USB_REG32(chip, REG_FIFO0) & BIT(12))
+		;
+	USB_REG32(chip, REG_FIFO1) |= BIT(12);
+	while (USB_REG32(chip, REG_FIFO1) & BIT(12))
+		;
+	USB_REG32(chip, REG_FIFO2) |= BIT(12);
+	while (USB_REG32(chip, REG_FIFO2) & BIT(12))
+		;
+	USB_REG32(chip, REG_FIFO3) |= BIT(12);
+	while (USB_REG32(chip, REG_FIFO3) & BIT(12))
+		;
+
+	/* disable OTG interrupts */
+	USB_REG32(chip, REG_OTGIER) = 0;
+	USB_REG32(chip, REG_ISR)    = BIT(2) | BIT(1) | BIT(0);
+	USB_REG32(chip, REG_IMR)    = BIT(3) | BIT(2) | BIT(1);    /* active high, no OTG & Host */
+
+	/* disable EP0 IN/OUT interrupt */
+	USB_REG32(chip, REG_DCIMR0) = BIT(2) | BIT(1);
+	/* disable EPX IN+SPK+OUT interrupts */
+	USB_REG32(chip, REG_DCIMR1) = 0xF00FF;
+	/* disable wakeup+idle+dma+zlp interrupts */
+	USB_REG32(chip, REG_DCIMR2) = BIT(10) | BIT(9) | BIT(8) | BIT(7) | BIT(6) | BIT(5);
+	/* enable all interrupt source group */
+	USB_REG32(chip, REG_DCIMR)  = 0;
+
+	/* suspend delay = 7 ms */
+	USB_REG32(chip, REG_DCIDLE) = 3;
+
+	/* turn-on global interrupts */
+	USB_REG32(chip, REG_DCCR) |= BIT(2);
+
+#if CFG_HALF_SPEED
+	/* half-speed */
+	USB_REG32(chip, REG_DCCR) |= BIT(1);
+#endif
+
+#if CFG_LOW_TIMING
+	/* low timing */
+	USB_REG32(chip, REG_OTGCSR) |= BIT(11) | BIT(10) | BIT(9);
+#endif
+
+	return 0;
+}
+
+static int
+fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	uint32_t tmp, timeout;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	uint32_t fifo = ep_to_fifo(chip, ep->id);
+	int rc = 0;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (timeout = 5000; timeout; --timeout) {
+		if (!(USB_REG32(chip, REG_DMAPARAM1) & BIT(0)))
+			break;
+		udelay(1);
+	}
+	if (timeout == 0) {
+		printf("fotg210: dma busy (0x%08X)\n", USB_REG32(chip, REG_DMAFIFO));
+		req->req.status = -EBUSY;
+		return -EBUSY;
+	}
+
+	/* 3. DMA target setup */
+#ifndef CONFIG_SYS_DCACHE_OFF
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+	else
+		invalidate_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+#endif
+	USB_REG32(chip, REG_DMAPARAM2) = virt_to_phys(buf);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until fifo empty */
+			while (!(USB_REG32(chip, REG_DCCXFIFO) & BIT(5)))
+				;
+			USB_REG32(chip, REG_DMAFIFO) = BIT(4);
+		} else {
+			/* Wait until fifo empty */
+			while (!(USB_REG32(chip, REG_DCCXFIFO) & (1 << (8 + fifo))))
+				;
+			USB_REG32(chip, REG_DMAFIFO) = 1 << fifo;
+		}
+		USB_REG32(chip, REG_DMAPARAM1) = len << 8 | BIT(1);
+	} else {
+		uint32_t blen;
+		if (ep->id == 0) {
+			USB_REG32(chip, REG_DMAFIFO) = BIT(4);
+			do {
+				blen = USB_REG32(chip, REG_DCCXFIFO) >> 24;
+			} while (blen < len);
+		} else {
+			USB_REG32(chip, REG_DMAFIFO) = 1 << fifo;
+			blen = USB_REG32(chip, REG_FIFO0 + (4 * fifo)) & 0x7FF;
+		}
+		len  = (len < blen) ? len : blen;
+		USB_REG32(chip, REG_DMAPARAM1) = len << 8;
+	}
+
+	/* 4. DMA kick-off */
+	USB_REG32(chip, REG_DMAPARAM1) |= BIT(0);
+
+	/* 5. DMA wait */
+	rc = -EBUSY;
+	for (timeout = 250000; timeout; --timeout) {
+		tmp = USB_REG32(chip, REG_DCISR2);
+		/* DMA complete */
+		if (tmp & BIT(7)) {
+			rc = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & BIT(8)) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & (BIT(2) | BIT(1) | BIT(0))) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+		udelay(1);
+	}
+
+	/* 7. DMA target reset */
+	if (rc)
+		USB_REG32(chip, REG_DMAPARAM1) |= BIT(3);
+	USB_REG32(chip, REG_DCISR2)  &= 0x7f;
+	USB_REG32(chip, REG_DMAFIFO)  = 0;
+
+	req->req.status = rc;
+	if (rc == 0)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, rc);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE            0
+#define CX_FINISH        1
+#define CX_STALL        2
+
+static void
+fotg210_setup(struct fotg210_chip *chip)
+{
+	int rc = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (USB_REG32(chip, REG_OTGCSR) & BIT(21)) {
+			/* Mini-B */
+			if (USB_REG32(chip, REG_DCCR) & BIT(6)) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				USB_REG32(chip, REG_DCSOFMTR) = 0x044C;
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				USB_REG32(chip, REG_DCSOFMTR) = 0x2710;
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	USB_REG32(chip, REG_DMAFIFO) = BIT(4);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = USB_REG32(chip, REG_DMAPARAM3);
+	tmp[1] = USB_REG32(chip, REG_DMAPARAM3);
+	/* release data port */
+	USB_REG32(chip, REG_DMAFIFO) = 0;
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	rc = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			printf("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if ((req->wValue & 0x00FF) == 0) {
+				chip->state = USB_STATE_ADDRESS;
+				USB_REG32(chip, REG_DCAR) = chip->addr;
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				USB_REG32(chip, REG_DCAR) = chip->addr | BIT(7);
+			}
+			rc = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			printf("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue;
+			rc = CX_FINISH;
+			USB_REG32(chip, REG_DCAR) = chip->addr;
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			printf("fotg210: clr_feature(%d, %d)\n", req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				rc = CX_FINISH;
+				break;
+
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				rc = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			printf("fotg210: set_feature(%d, %d)\n", req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				do {
+					int id = req->wIndex & 0xf;
+					USB_REG32(chip, REG_IEP1 + (id - 1) * 4) |= BIT(11);
+					USB_REG32(chip, REG_OEP1 + (id - 1) * 4) |= BIT(11);
+				} while (0);
+				rc = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				rc = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			printf("fotg210: get_status\n");
+			rc = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			printf("fotg210: set_descriptor\n");
+			rc = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			printf("fotg210: sync frame\n");
+			rc = CX_STALL;
+			break;
+		}
+	}    /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (rc == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			rc = CX_STALL;
+		else
+			rc = CX_FINISH;
+	}
+
+	switch (rc) {
+	case CX_FINISH:
+		USB_REG32(chip, REG_DCCXFIFO) |= BIT(0);
+		break;
+
+	case CX_STALL:
+		USB_REG32(chip, REG_DCCXFIFO) |= (BIT(2) | BIT(0));
+		printf("fotg210: cx_stall?\n");
+		break;
+
+	case CX_IDLE:
+		printf("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void
+fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue))
+		USB_REG32(chip, REG_DCIMR1) |= 0x03 << (ep_to_fifo(chip, ep->id) * 2);
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int
+fotg210_ep_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		USB_REG32(chip, REG_FIFOMAP) |= 0x10 << (8 * id);
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		USB_REG32(chip, REG_FIFOCFG) |= 0x21 << (8 * id);
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		USB_REG32(chip, REG_FIFOCFG) |= 0x22 << (8 * id);
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		USB_REG32(chip, REG_FIFOCFG) |= 0x23 << (8 * id);
+		break;
+	}
+
+	return 0;
+}
+
+static int
+fotg210_ep_disable (struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	USB_REG32(chip, REG_FIFOCFG) &= ~(0x23 << (8 * id));
+	USB_REG32(chip, REG_FIFOMAP) &= ~(0x30 << (8 * id));
+
+	return 0;
+}
+
+static struct usb_request *
+fotg210_ep_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags) {
+	struct fotg210_request *req = malloc(sizeof(*req));
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void
+fotg210_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int
+fotg210_ep_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_request *req = container_of(_req, struct fotg210_request, req);
+
+	if (!_req || !_req->complete || !_req->buf || !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspend!?\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			USB_REG32(chip, REG_DCIMR1) &= ~(0x03 << (ep_to_fifo(chip, ep->id) * 2));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int
+fotg210_ep_dequeue (struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep  *ep  = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		return -EINVAL;
+	}
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int
+fotg210_ep_halt (struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	int rc = -1;
+
+	printf("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until fifo empty */
+			while ((USB_REG32(chip, REG_DCCXFIFO) & 0xf00) != 0xf00)
+				;
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				USB_REG32(chip, REG_IEP1 + (ep->id - 1) * 4) |= BIT(11);
+			else
+				USB_REG32(chip, REG_OEP1 + (ep->id - 1) * 4) |= BIT(11);
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				USB_REG32(chip, REG_IEP1 + (ep->id - 1) * 4) &= ~BIT(11);
+			else
+				USB_REG32(chip, REG_OEP1 + (ep->id - 1) * 4) &= ~BIT(11);
+		}
+		rc = 0;
+	}
+
+	return rc;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void
+pullup(struct fotg210_chip *chip, int is_on)
+{
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			USB_REG32(chip, REG_DCCR) |= BIT(5);
+			/* clear unplug bit (BIT0) */
+			USB_REG32(chip, 0x114) &= (~BIT(0));
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		USB_REG32(chip, REG_DCAR) = 0;
+		/* set unplug bit (BIT0) */
+		USB_REG32(chip, 0x114) |= BIT(0);
+		/* disable the chip */
+		USB_REG32(chip, REG_DCCR) &= ~BIT(5);
+	}
+}
+
+static int
+fotg210_pullup (struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	printf("fotg210: pullup=%d\n", is_on);
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int
+fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip = container_of(_gadget, struct fotg210_chip, gadget);
+	return USB_REG32(chip, REG_DCSOFFNR) & 0x7ff;
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.iobase = CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name    = "ep0",
+			.ops    = &fotg210_ep_ops,
+		},
+		.desc       = &ep0_desc,
+		.chip        = &controller,
+		.maxpacket    = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name    = "ep1",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name    = "ep2",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name    = "ep3",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name    = "ep4",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	uint32_t isr, dcisr;
+
+	isr   = USB_REG32(chip, REG_ISR) & (~USB_REG32(chip, REG_IMR));
+	dcisr = USB_REG32(chip, REG_DCISR) & (~USB_REG32(chip, REG_DCIMR));
+	if (!(isr & BIT(0)) || dcisr == 0)
+		return 0;
+
+	USB_REG32(chip, REG_ISR) = BIT(0);
+
+	/* CX interrupts */
+	if (dcisr & BIT(0)) {
+		uint32_t st = USB_REG32(chip, REG_DCISR0);
+		USB_REG32(chip, REG_DCISR0) = 0;
+
+		if (st & BIT(4))
+			printf("fotg210: cmd error\n");
+
+		if (st & BIT(5))
+			printf("fotg210: cmd abort\n");
+
+		if (st & BIT(0))            /* setup */
+			fotg210_setup(chip);
+		else if (st & BIT(3))        /* command finish */
+			USB_REG32(chip, REG_DCCXFIFO) |= BIT(0);
+	}
+
+	/* FIFO interrupts */
+	if (dcisr & BIT(1)) {
+		uint32_t id;
+		uint32_t st = USB_REG32(chip, REG_DCISR1);
+		for (id = 0; id < 4; ++id) {
+			if (st & (3 << (id * 2)))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (dcisr & BIT(2)) {
+		uint32_t st = USB_REG32(chip, REG_DCISR2);
+		USB_REG32(chip, REG_DCISR2) = 0;
+
+		if (st & BIT(0)) {
+			printf("fotg210: reset by host\n");
+		} else if (st & BIT(1)) {
+			printf("fotg210: suspend/removed\n");
+		} else if (st & BIT(2)) {
+			printf("fotg210: resume\n");
+		}
+
+		/* Errors */
+		if (st & BIT(3))
+			printf("fotg210: iso error\n");
+		if (st & BIT(4))
+			printf("fotg210: iso abort\n");
+		if (st & BIT(8))
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, rc = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	rc = driver->bind(&chip->gadget);
+	if (rc) {
+		printf("fotg210: driver->bind() returned %d\n", rc);
+		dcache_enable();
+		return rc;
+	}
+	chip->driver = driver;
+
+	return rc;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/fotg210.h b/drivers/usb/gadget/fotg210.h
new file mode 100644
index 0000000..b5f9842
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.h
@@ -0,0 +1,99 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef FOTG210_H
+#define FOTG210_H
+
+#ifndef BIT
+#define BIT(nr)	(1UL << (nr))
+#endif
+
+#define REG_HCISR       0x014    /* Host Controller: Interupt Status Register */
+#define REG_HCIER       0x018    /* Host Controller: Interupt Enable Register */
+
+/*
+ * Global Registers
+ */
+#define REG_ISR         0x0C0    /* Interrupt Status */
+#define REG_IMR         0x0C4    /* Interrupt Control */
+
+/*
+ * OTG Registers
+ */
+#define REG_OTGCSR      0x080    /* OTG Control Status */
+#define REG_OTGISR      0x084    /* OTG Interrupt Status */
+#define REG_OTGIER      0x088    /* OTG Interrupt Enable Register */
+
+/*
+ * Device Registers
+ */
+#define REG_DCCR        0x100    /* Device Controller: Control Register */
+#define REG_DCAR        0x104    /* Device Address */
+#define REG_DCTSTR      0x108    /* Device Test */
+#define REG_DCSOFFNR    0x10C    /* Device SOF Frame Number */
+#define REG_DCSOFMTR    0x110    /* Device SOF Frame Number */
+
+#define REG_DCCXR       0x11C    /* Device CX Configuration */
+#define REG_DCCXFIFO    0x120    /* Device CX FIFO */
+#define REG_DCIDLE      0x124    /* Device Idle Counter */
+
+#define REG_DCIMR       0x130    /* Device Group Interrupt Mask */
+#define REG_DCIMR0      0x134    /* Device Group 0 Interrupt Mask */
+#define REG_DCIMR1      0x138    /* Device Group 1 Interrupt Mask */
+#define REG_DCIMR2      0x13C    /* Device Group 2 Interrupt Mask */
+#define REG_DCISR       0x140    /* Device Group Interrupt Status */
+#define REG_DCISR0      0x144    /* Device Group 0 Interrupt Status */
+#define REG_DCISR1      0x148    /* Device Group 1 Interrupt Status */
+#define REG_DCISR2      0x14C    /* Device Group 2 Interrupt Status */
+
+#define REG_DCRXZLPKT   0x150    /* Device Receive Zero-Length Packet */
+#define REG_DCTXZLPKT   0x154    /* Device Receive Zero-Length Packet */
+#define REG_DCISOERR    0x158    /* Device ISO Error/Abort */
+
+#define REG_IEP1        0x160    /* Device IN Endpoint */
+#define REG_IEP2        0x164    /* Device IN Endpoint */
+#define REG_IEP3        0x168    /* Device IN Endpoint */
+#define REG_IEP4        0x16C    /* Device IN Endpoint */
+#define REG_IEP5        0x170    /* Device IN Endpoint */
+#define REG_IEP6        0x174    /* Device IN Endpoint */
+#define REG_IEP7        0x178    /* Device IN Endpoint */
+#define REG_IEP8        0x17C    /* Device IN Endpoint */
+
+#define REG_OEP1        0x180    /* Device OUT Endpoint */
+#define REG_OEP2        0x184    /* Device OUT Endpoint */
+#define REG_OEP3        0x188    /* Device OUT Endpoint */
+#define REG_OEP4        0x18C    /* Device OUT Endpoint */
+#define REG_OEP5        0x190    /* Device OUT Endpoint */
+#define REG_OEP6        0x194    /* Device OUT Endpoint */
+#define REG_OEP7        0x198    /* Device OUT Endpoint */
+#define REG_OEP8        0x19C    /* Device OUT Endpoint */
+
+#define REG_EPMAP14     0x1A0    /* Device Endpoint Map 1 ~ 4 */
+#define REG_EPMAP58     0x1A4    /* Device Endpoint Map 5 ~ 8 */
+#define REG_FIFOMAP     0x1A8    /* Device FIFO Map */
+#define REG_FIFOCFG     0x1AC    /* Device FIFO Configuration */
+
+#define REG_FIFO0       0x1B0    /* Device FIFO 0 */
+#define REG_FIFO1       0x1B4    /* Device FIFO 1 */
+#define REG_FIFO2       0x1B8    /* Device FIFO 2 */
+#define REG_FIFO3       0x1BC    /* Device FIFO 3 */
+
+#define REG_DMAFIFO     0x1C0    /* Device DMA Target FIFO */
+#define REG_DMAPARAM1   0x1C8    /* Device DMA Parameter 1 */
+#define REG_DMAPARAM2   0x1CC    /* Device DMA Parameter 2 */
+#define REG_DMAPARAM3   0x1D0    /* Device DMA Parameter 3 */
+
+#define ERR_ISOERR      0
+#define ERR_ISOABT      1
+#define ERR_DMAERR      2
+#define ERR_CMDERR      3
+#define ERR_CMDABT      4
+
+#endif
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH 06/11] i2c: add FTI2C010 I2C controller support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (4 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 05/11] usb-gadget: add FOTG210 USB gadget support Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 07/11] spi: add FTSPI010 SPI " Kuo-Jung Su
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTI2C010 is a multi-function I2C controller
which supports both master and slave mode.
This patch simplily implements the master mode only.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/i2c/Makefile   |    1 +
 drivers/i2c/fti2c010.c |  360 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/fti2c010.h |   68 +++++++++
 3 files changed, 429 insertions(+)
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 5dbdbe3..ed2b8c0 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
 COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
 COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
 COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
+COBJS-$(CONFIG_FTI2C010) += fti2c010.o
 COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
 COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
 COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
new file mode 100644
index 0000000..be5e02c
--- /dev/null
+++ b/drivers/i2c/fti2c010.c
@@ -0,0 +1,360 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <i2c.h>
+
+#include "fti2c010.h"
+
+#define I2C_RD        1
+#define I2C_WR        0
+
+struct fti2c010_chip {
+	uint32_t bus;
+	uint32_t speed;
+	uint32_t iobase;
+};
+
+#if defined(CONFIG_HARD_I2C)
+
+static struct fti2c010_chip fti2c010_info[] = {
+#ifdef CONFIG_I2C_MULTI_BUS
+# ifdef CONFIG_FTI2C010_BASE0
+	{
+		.bus    = 0,
+		.speed  = 0,
+		.iobase = CONFIG_FTI2C010_BASE0,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE1
+	{
+		.bus    = 1,
+		.speed  = 0,
+		.iobase = CONFIG_FTI2C010_BASE1,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE2
+	{
+		.bus    = 2,
+		.speed  = 0,
+		.iobase = CONFIG_FTI2C010_BASE2,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE3
+	{
+		.bus    = 3,
+		.speed  = 0,
+		.iobase = CONFIG_FTI2C010_BASE3,
+	},
+# endif
+#else    /* #ifdef CONFIG_I2C_MULTI_BUS */
+	{
+		.bus    = 0,
+		.speed  = 0,
+		.iobase = CONFIG_FTI2C010_BASE,
+	},
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+};
+
+static struct fti2c010_chip *priv = fti2c010_info;
+
+/* Register access macros */
+#define I2C_REG32(priv, off)	\
+	*(volatile uint32_t *)((priv)->iobase + (off))
+
+static int fti2c010_wait(uint32_t mask)
+{
+	int ret = -1;
+	uint32_t stat, t;
+
+	for (t = get_timer(0); get_timer(t) < 100; ) {
+		stat = I2C_REG32(priv, REG_SR);
+		if ((stat & mask) == mask) {
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * u-boot I2C API
+ */
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+	if (speed || priv->speed == 0)
+		i2c_set_bus_speed(speed);
+}
+
+/*
+ * Probe the given I2C chip address.  Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uchar chip)
+{
+	int rc;
+
+	i2c_init(0, chip);
+
+	/* 1. Select slave device (7bits Address + 1bit R/W) */
+	I2C_REG32(priv, REG_DR) = (chip << 1) + I2C_WR;
+	I2C_REG32(priv, REG_CR) = CR_ENABLE | CR_TBEN | CR_START;
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* 2. Select device register */
+	I2C_REG32(priv, REG_DR) = 0;
+	I2C_REG32(priv, REG_CR) = CR_ENABLE | CR_TBEN;
+	rc = fti2c010_wait(SR_DT);
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	I2C_REG32(priv, REG_DR) = (chip << 1) + I2C_WR;
+	I2C_REG32(priv, REG_CR) = CR_ENABLE | CR_TBEN | CR_START;
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		I2C_REG32(priv, REG_DR) = paddr[pos];
+		I2C_REG32(priv, REG_CR) = ctrl;
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Get register data
+	 */
+
+	/* B.1 Select slave device (7bits Address + 1bit R/W) */
+	I2C_REG32(priv, REG_DR) = (chip << 1) + I2C_RD;
+	I2C_REG32(priv, REG_CR) = CR_ENABLE | CR_TBEN | CR_START;
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* B.2 Get register data */
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		uint32_t stat = SR_DR;
+		if (pos == len - 1) {
+			ctrl |= CR_NAK | CR_STOP;
+			stat |= SR_ACK;
+		}
+		I2C_REG32(priv, REG_CR) = ctrl;
+		rc = fti2c010_wait(stat);
+		if (rc)
+			break;
+		buf[pos] = (uchar)(I2C_REG32(priv, REG_DR) & 0xFF);
+	}
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	I2C_REG32(priv, REG_DR) = (chip << 1) + I2C_WR;
+	I2C_REG32(priv, REG_CR) = CR_ENABLE | CR_TBEN | CR_START;
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		I2C_REG32(priv, REG_DR) = paddr[pos];
+		I2C_REG32(priv, REG_CR) = ctrl;
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Set register data
+	 */
+
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		if (pos == len - 1)
+			ctrl |= CR_STOP;
+		I2C_REG32(priv, REG_DR) = buf[pos];
+		I2C_REG32(priv, REG_CR) = ctrl;
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
+ * Functions for setting the current I2C bus and its speed
+ */
+#ifdef CONFIG_I2C_MULTI_BUS
+
+/*
+ * i2c_set_bus_num:
+ *
+ *  Change the active I2C bus.  Subsequent read/write calls will
+ *  go to this one.
+ *
+ *    bus - bus index, zero based
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_num(unsigned int bus)
+{
+	if (bus >= sizeof(fti2c010_info) / sizeof(fti2c010_info[0]))
+		return -1;
+	priv = fti2c010_info + bus;
+	i2c_init(5000, 0);
+	return 0;
+}
+
+/*
+ * i2c_get_bus_num:
+ *
+ *  Returns index of currently active I2C bus.  Zero-based.
+ */
+
+unsigned int i2c_get_bus_num(void)
+{
+	return priv->bus;
+}
+
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+
+/*
+ * i2c_set_bus_speed:
+ *
+ *  Change the speed of the active I2C bus
+ *
+ *    speed - bus speed in Hz
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_speed(unsigned int speed)
+{
+#ifdef CONFIG_FTI2C010_SCLK
+	unsigned long apb = CONFIG_FTI2C010_SCLK;
+#else
+	unsigned long apb = clk_get_rate("I2C");
+#endif
+	unsigned long div = 0x640;
+	unsigned long gsr = 0;
+	unsigned long tsr = 0x20;
+	unsigned long t;
+
+	I2C_REG32(priv, REG_CR) = 1;
+	t = get_timer(0);
+	while (get_timer(t) < 100) {
+		if (I2C_REG32(priv, REG_CR) & 1)
+			continue;
+		break;
+	}
+
+	/* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
+	priv->speed = apb / (2 * (div + 2) + gsr);
+
+	if (speed > 0) {
+		for (div = 0; div < 0x1000000; ++div) {
+			priv->speed = apb / (2 * (div + 2) + gsr);
+			if (priv->speed < speed)
+				break;
+		}
+	}
+
+	I2C_REG32(priv, REG_TGSR) = (gsr << 10) | tsr;
+	I2C_REG32(priv, REG_CDR)  = div;
+
+	return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ *  Returns speed of currently active I2C bus in Hz
+ */
+
+unsigned int i2c_get_bus_speed(void)
+{
+	return priv->speed;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/fti2c010.h b/drivers/i2c/fti2c010.h
new file mode 100644
index 0000000..704b3a2
--- /dev/null
+++ b/drivers/i2c/fti2c010.h
@@ -0,0 +1,68 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTI2C010_H
+#define __FTI2C010_H
+
+/*
+ * FTI2C010 registers
+ */
+#define REG_CR              0x00    /* control register */
+#define REG_SR              0x04    /* status register */
+#define REG_CDR             0x08    /* clock division register */
+#define REG_DR              0x0C    /* data register */
+#define REG_SAR             0x10    /* slave address register */
+#define REG_TGSR            0x14    /* time & glitch suppression register */
+#define REG_BMR             0x18    /* bus monitor register */
+#define REG_REVR            0x30    /* revision register */
+
+/*
+ * REG_CTRL
+ */
+#define CR_ALIEN      0x2000  /* Arbitration lose */
+#define CR_SAMIEN     0x1000  /* slave address match */
+#define CR_STOPIEN    0x800   /* stop condition */
+#define CR_BERRIEN    0x400   /* non ACK response */
+#define CR_DRIEN      0x200   /* data receive */
+#define CR_DTIEN      0x100   /* data transmit */
+#define CR_TBEN       0x80    /* transfer byte enable */
+#define CR_NAK        0x40    /* with this bit set, fti2c010 will not drive ACK signal */
+#define CR_STOP       0x20    /* stop */
+#define CR_START      0x10    /* start */
+#define CR_GCEN       0x8     /* general call */
+#define CR_SCLEN      0x4     /* enable clock */
+#define CR_I2CEN      0x2     /* enable I2C */
+#define CR_I2CRST     0x1     /* reset I2C */
+#define CR_ENABLE	\
+	(CR_ALIEN | CR_SAMIEN | CR_STOPIEN | CR_BERRIEN \
+	| CR_DRIEN | CR_DTIEN | CR_SCLEN | CR_I2CEN)
+
+/*
+ * REG_STAT
+ */
+#define SR_CLRAL      0x400
+#define SR_CLRGC      0x200
+#define SR_CLRSAM     0x100
+#define SR_CLRSTOP    0x80
+#define SR_CLRBERR    0x40
+#define SR_DR         0x20     /* DR received one new data byte */
+#define SR_DT         0x10     /* DR trandmitted one new data byte */
+#define SR_BB         0x8
+#define SR_BUSY       0x4
+#define SR_ACK        0x2
+#define SR_RW         0x1
+
+/*
+ * REG_BMR
+ */
+#define BMR_SCL         0x2
+#define BMR_SDA         0x1
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH 07/11] spi: add FTSPI010 SPI controller support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (5 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 06/11] i2c: add FTI2C010 I2C controller support Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 08/11] mtd/nand: add FTNANDC021 NAND flash " Kuo-Jung Su
                   ` (11 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FTSSP010 is a multi-function controller
which supports I2S/SPI/SSP/AC97/SPDIF.
This patch simpily implements the SPI mode only.
BTW the DMA and CS/Clock control logic has been
altered since revision 1.19.0. So this patch
would 1st detects the revision id of the underlying
chip, and then switch to the corresponding control
routines.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/spi/Makefile       |    1 +
 drivers/spi/ftssp010_spi.c |  333 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/ftssp010_spi.h |   85 +++++++++++
 3 files changed, 419 insertions(+)
 create mode 100644 drivers/spi/ftssp010_spi.c
 create mode 100644 drivers/spi/ftssp010_spi.h

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 4268595..2db2a5c 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
 COBJS-$(CONFIG_CF_SPI) += cf_spi.o
 COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
 COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
+COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
 COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
 COBJS-$(CONFIG_ICH_SPI) +=  ich.o
 COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
new file mode 100644
index 0000000..fbd3601
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.c
@@ -0,0 +1,333 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <malloc.h>
+
+#include "ftssp010_spi.h"
+
+struct ftssp010_chip {
+	uint32_t fifo;
+	uint32_t rev;
+	uint32_t bus;
+	uint32_t div;
+	uint32_t mode;
+	uint32_t iobase;
+	struct {
+		uint32_t iobase;
+		uint32_t pin;
+	} gpio;
+};
+
+static struct ftssp010_chip ftssp010_info[] = {
+#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0)
+	{
+		.bus    = 0,
+		.div    = 0,
+		.mode   = 0,
+		.iobase = CONFIG_FTSSP010_BASE,
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		.gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN },
+#endif
+	},
+#endif
+#ifdef CONFIG_FTSSP010_BASE1
+	{
+		.bus    = 1,
+		.div    = 0,
+		.mode   = 0,
+		.iobase = CONFIG_FTSSP010_BASE1,
+	},
+#endif
+#ifdef CONFIG_FTSSP010_BASE2
+	{
+		.bus    = 2,
+		.div    = 0,
+		.mode   = 0,
+		.iobase = CONFIG_FTSSP010_BASE2,
+	},
+#endif
+#ifdef CONFIG_FTSSP010_BASE3
+	{
+		.bus    = 3,
+		.div    = 0,
+		.mode   = 0,
+		.iobase = CONFIG_FTSSP010_BASE3,
+	},
+#endif
+};
+
+static struct ftssp010_chip *priv = ftssp010_info;
+
+/* Register access macros */
+#define SPI_REG32(priv, off)	\
+	*(volatile uint32_t *)((priv)->iobase + (off))
+
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+#define GPIO_REG32(priv, off)	\
+	*(volatile uint32_t *)((priv)->gpio.iobase + (off))
+#endif
+
+static int ftssp010_spi_work_transfer_v1_19(const void *tx_buf, void *rx_buf,
+	int len, unsigned int flags)
+{
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+	uint32_t      tmp;
+	uint8_t       *p8 = (uint8_t *)&tmp;
+
+	while (len > 0) {
+		int i, depth = min(priv->fifo >> 2, len);
+		uint32_t xmsk = 0;
+
+		if (tx_buf) {
+			for (i = 0; i < depth; ++i) {
+				while (!(SPI_REG32(priv, REG_SR) & SR_TFNF))
+					;
+				tmp = 0;
+				p8[0] = *txb++;
+				SPI_REG32(priv, REG_DR) = tmp;
+			}
+			xmsk |= CR2_TXEN | CR2_TXDOE;
+			if ((SPI_REG32(priv, REG_CR2) & xmsk) != xmsk)
+				SPI_REG32(priv, REG_CR2) |= xmsk;
+
+		}
+		if (rx_buf) {
+			xmsk |= CR2_RXEN;
+			if ((SPI_REG32(priv, REG_CR2) & xmsk) != xmsk)
+				SPI_REG32(priv, REG_CR2) |= xmsk;
+			for (i = 0; i < depth; ++i) {
+				while (!SR_RFVE(SPI_REG32(priv, REG_SR)))
+					;
+				tmp = SPI_REG32(priv, REG_DR);
+				*rxb++ = p8[0];
+			}
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static int ftssp010_spi_work_transfer(const void *tx_buf, void *rx_buf,
+	int len, unsigned int flags)
+{
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+	uint32_t      tmp;
+	uint8_t       *p8 = (uint8_t *)&tmp;
+
+	while (len > 0) {
+		int i, depth = min(priv->fifo >> 2, len);
+
+		for (i = 0; i < depth; ++i) {
+			while (!(SPI_REG32(priv, REG_SR) & SR_TFNF))
+				;
+			tmp = 0;
+			if (txb)
+				p8[0] = *txb++;
+			SPI_REG32(priv, REG_DR) = tmp;
+		}
+
+		for (i = 0; i < depth; ++i) {
+			while (!SR_RFVE(SPI_REG32(priv, REG_SR)))
+				;
+			tmp = SPI_REG32(priv, REG_DR);
+			if (rxb)
+				*rxb++ = p8[0];
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+/*=====================================================================*/
+/*                         Public Functions                            */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Determine if a SPI chipselect is valid.
+ * This function is provided by the board if the low-level SPI driver
+ * needs it to determine if a given chipselect is actually valid.
+ *
+ * Returns: 1 if bus:cs identifies a valid chip on this board, 0
+ * otherwise.
+ */
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	uint32_t txfifo, rxfifo;
+
+	if (bus >= ARRAY_SIZE(ftssp010_info))
+		return 0;
+
+	priv = ftssp010_info + bus;
+	priv->rev = SPI_REG32(priv, REG_REVR);
+	txfifo = FEAR_TXFIFO(SPI_REG32(priv, REG_FEAR));
+	rxfifo = FEAR_RXFIFO(SPI_REG32(priv, REG_FEAR));
+	priv->fifo = min(txfifo, rxfifo);
+
+	printf("ftssp010: rev.=0x%08X, fifo=%d\n", priv->rev, priv->fifo);
+
+	if (priv->rev >= 0x00011900) {
+		if (cs > 3)
+			return 0;
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		if (cs > 0)
+			return 0;
+		/* setup gpio pin as an output pin */
+		GPIO_REG32(priv, 0x08) |= (1 << priv->gpio.pin);
+#else
+		return 0;
+#endif
+	}
+
+	return 1;
+}
+
+/*-----------------------------------------------------------------------
+ * Activate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should activate the chip select
+ * to the device identified by "slave".
+ */
+void spi_cs_activate(struct spi_slave *slave)
+{
+	priv = ftssp010_info + slave->bus;
+	/* cs pull low */
+	if (priv->rev >= 0x00011900) {
+		SPI_REG32(priv, REG_CR2) = (slave->cs << 10)
+			| CR2_SSPEN | CR2_TXFCLR | CR2_RXFCLR;
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		GPIO_REG32(priv, 0x14) |= (1 << priv->gpio.pin);
+#endif
+	}
+	udelay_masked(1);
+}
+
+/*-----------------------------------------------------------------------
+ * Deactivate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should deactivate the chip
+ * select to the device identified by "slave".
+ */
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	priv = ftssp010_info + slave->bus;
+
+	/* wait until device idle */
+	while (SPI_REG32(priv, REG_SR) & SR_BUSY)
+		;
+
+	/* cs pull high */
+	if (priv->rev >= 0x00011900) {
+		SPI_REG32(priv, REG_CR2) = (slave->cs << 10) | CR2_FS;
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		GPIO_REG32(priv, 0x10) |= (1 << priv->gpio.pin);
+#endif
+	}
+	udelay_masked(1);
+}
+
+void spi_init(void)
+{
+}
+
+struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
+								  unsigned int max_hz, unsigned int mode) {
+	uint32_t div = 1;
+#ifdef CONFIG_FTSSP010_SCLK
+	uint32_t clk = CONFIG_FTSSP010_SCLK;
+#else
+	uint32_t clk = clk_get_rate("SSP");
+#endif
+	struct spi_slave *ss;
+
+	if (!spi_cs_is_valid(bus, cs))
+		return NULL;
+
+	ss = malloc(sizeof(struct spi_slave));
+	if (!ss)
+		return NULL;
+
+	ss->bus = bus;
+	ss->cs  = cs;
+
+	if (max_hz > 0) {
+		for (div = 0; div < 0xFFFF; ++div) {
+			if ((clk / (2 * (div + 1))) <= max_hz)
+				break;
+		}
+	}
+
+	priv = ftssp010_info + bus;
+	priv->div  = div;
+	priv->mode = mode;
+
+	printf("ftssp010: bus=%d, hz=%u\n", priv->bus, (clk / (2 * (div + 1))));
+
+	return ss;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	SPI_REG32(priv, REG_CR1) = CR1_SDL(8) | CR1_CLKDIV(priv->div);
+
+	if (priv->rev >= 0x00011900) {
+		SPI_REG32(priv, REG_CR0) = CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO
+			| CR0_FLASH;
+		SPI_REG32(priv, REG_CR2) = CR2_TXFCLR | CR2_RXFCLR;
+	} else {
+		SPI_REG32(priv, REG_CR0) = CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO;
+		SPI_REG32(priv, REG_CR2) = CR2_TXFCLR | CR2_RXFCLR
+			| CR2_SSPEN | CR2_TXDOE;
+	}
+
+	spi_cs_deactivate(slave);
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	SPI_REG32(priv, REG_CR2) = 0;
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+			 const void *dout, void *din, unsigned long flags)
+{
+	u32 len = bitlen >> 3;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(slave);
+
+	if (priv->rev >= 0x00011900)
+		ftssp010_spi_work_transfer_v1_19(dout, din, len, flags);
+	else
+		ftssp010_spi_work_transfer(dout, din, len, flags);
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(slave);
+
+	return 0;
+}
diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
new file mode 100644
index 0000000..9e33bdd
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.h
@@ -0,0 +1,85 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTSSP010_H
+#define __FTSSP010_H
+
+/* FTSSP010 HW Registers */
+#define REG_CR0		0x00	/* control register */
+#define REG_CR1		0x04	/* control register */
+#define REG_CR2		0x08	/* control register */
+#define REG_SR		0x0C	/* status register */
+#define REG_ICR		0x10	/* interrupt control register */
+#define REG_ISR		0x14	/* interrupt status register */
+#define REG_DR		0x18	/* data register */
+#define REG_REVR	0x60	/* revision register */
+#define REG_FEAR	0x64	/* feature register */
+
+/* Control register 0  */
+#define CR0_FFMT_MASK       (7 << 12)
+#define CR0_FFMT_SSP        (0 << 12)
+#define CR0_FFMT_SPI        (1 << 12)
+#define CR0_FFMT_MICROWIRE  (2 << 12)
+#define CR0_FFMT_I2S        (3 << 12)
+#define CR0_FFMT_AC97       (4 << 12)
+#define CR0_FLASH           (1 << 11)
+#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
+#define CR0_LBM             (1 << 7)  /* Loopback mode */
+#define CR0_LSB             (1 << 6)  /* LSB first */
+#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
+#define CR0_FSJUSTIFY       (1 << 4)
+#define CR0_OPM_SLAVE       (0 << 2)
+#define CR0_OPM_MASTER      (3 << 2)
+#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
+#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
+#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
+#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
+#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
+#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
+
+/* Control Register 1 */
+
+#define CR1_PDL(x)          (((x) & 0xff) << 24)		/* padding length */
+#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16)	/* data length */
+#define CR1_CLKDIV(x)       ((x) & 0xffff)				/*  clk divider */
+
+/* Control Register 2 */
+#define CR2_FSOS(x)         (((x) & 0x03) << 10)	/* FS/CS Select */
+#define CR2_FS              (1 << 9)	/* FS/CS Signal Level */
+#define CR2_TXEN            (1 << 8)	/* Tx Enable */
+#define CR2_RXEN            (1 << 7)	/* Rx Enable */
+#define CR2_SSPRST          (1 << 6)	/* SSP reset */
+#define CR2_TXFCLR          (1 << 3)	/* TX FIFO Clear */
+#define CR2_RXFCLR          (1 << 2)	/* RX FIFO Clear */
+#define CR2_TXDOE           (1 << 1)	/* TX Data Output Enable */
+#define CR2_SSPEN           (1 << 0)	/* SSP Enable */
+
+/*
+ * Status Register
+ */
+#define SR_RFF				(1 << 0)        /* receive FIFO full */
+#define SR_TFNF				(1 << 1)        /* transmit FIFO not full */
+#define SR_BUSY				(1 << 2)        /* bus is busy */
+#define SR_RFVE(reg)		(((reg) >> 4) & 0x1f)   /* receive  FIFO valid entries */
+#define SR_TFVE(reg)		(((reg) >> 12) & 0x1f)  /* transmit FIFO valid entries */
+
+/*
+ * Feature Register
+ */
+#define FEAR_WIDTH(reg)		((((reg) >>  0) & 0xff) + 1)
+#define FEAR_RXFIFO(reg)	((((reg) >>  8) & 0xff) + 1)
+#define FEAR_TXFIFO(reg)	((((reg) >> 16) & 0xff) + 1)
+#define FEAR_AC97			(1 << 24)
+#define FEAR_I2S			(1 << 25)
+#define FEAR_SPI_MWR		(1 << 26)
+#define FEAR_SSP			(1 << 27)
+#define FEAR_SPDIF			(1 << 28)
+
+#endif
-- 
1.7.9.5

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

* [U-Boot] [PATCH 08/11] mtd/nand: add FTNANDC021 NAND flash controller support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (6 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 07/11] spi: add FTSPI010 SPI " Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 09/11] mtd/spi: add FTSPI020 SPI Flash " Kuo-Jung Su
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is a integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  550 +++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/ftnandc021.h |  165 +++++++++++++
 3 files changed, 716 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/mtd/nand/ftnandc021.h

diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index c77c0c4..16b5016 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -63,6 +63,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..095206a
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,550 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <nand.h>
+#include <malloc.h>
+
+#include "ftnandc021.h"
+
+/* common bitmask of nand flash status register */
+#define NAND_IOSTATUS_ERROR		BIT(0)
+#define NAND_IOSTATUS_READY		BIT(6)
+#define NAND_IOSTATUS_UNPROTCT	BIT(7)
+
+struct ftnandc021_chip {
+	void         *iobase;
+	unsigned int  cmd;
+
+	unsigned int  pgidx;
+
+	unsigned int  off;
+	uint8_t       buf[256];
+
+	unsigned int  adrc;	/* address cycle */
+	unsigned int  pgsz;	/* page size */
+	unsigned int  bksz;	/* block size */
+};
+
+/* Register access macros */
+#define NAND_REG32(priv, off) \
+	*(volatile uint32_t *)((uint32_t)((priv)->iobase) + (off))
+
+static struct nand_ecclayout ftnandc021_oob_2k = {
+	.eccbytes = 24,
+	.eccpos = {
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63
+	},
+	.oobfree = {
+		{
+			.offset = 9,
+			.length = 3
+		}
+	}
+};
+
+static int
+ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	uint32_t bk = 2;	/* 64 pages */
+	uint32_t pg = 1;	/* 2k */
+	uint32_t ac = 2;	/* 5 */
+	uint32_t mask = NANDC_NANDC_SW_RESET | NANDC_BMC_SW_RESET | NANDC_ECC_SW_RESET;
+
+#ifdef CONFIG_FTNANDC021_ACTIMING_1
+	NAND_REG32(priv, REG_AC1_CONTROL)   = CONFIG_FTNANDC021_ACTIMING_1;
+#endif
+#ifdef CONFIG_FTNANDC021_ACTIMING_2
+	NAND_REG32(priv, REG_AC2_CONTROL)   = CONFIG_FTNANDC021_ACTIMING_2;
+#endif
+
+	NAND_REG32(priv, REG_INT_EN)        = 0;
+	NAND_REG32(priv, REG_PAGE_INDEX)    = 0;
+	NAND_REG32(priv, REG_WRITE_BI)      = 0xff;
+	NAND_REG32(priv, REG_WRITE_LSN_CRC) = 0xffffffff;
+	if (chip->options & NAND_BUSWIDTH_16)
+		NAND_REG32(priv, REG_FLOW_CONTROL) = BIT(8) | BIT(7) | NANDC_IO_WIDTH_16BIT;
+	else
+		NAND_REG32(priv, REG_FLOW_CONTROL) = BIT(8) | BIT(7) | NANDC_IO_WIDTH_8BIT;
+
+	/* chip reset */
+	NAND_REG32(priv, REG_MLC_SW_RESET)  = mask;
+
+	/* wait until chip ready */
+	while (NAND_REG32(priv, REG_MLC_SW_RESET) & BIT(0))
+		;
+
+	switch (priv->bksz / priv->pgsz) {
+	case 16:
+		bk = 0;
+		break;
+	case 32:
+		bk = 1;
+		break;
+	case 64:
+		bk = 2;
+		break;
+	case 128:
+		bk = 3;
+		break;
+	}
+
+	switch (priv->pgsz) {
+	case 512:
+		pg = 0;
+		break;
+	case 2048:
+		pg = 1;
+		break;
+	case 4096:
+		pg = 2;
+		break;
+	}
+
+	switch (priv->adrc) {
+	case 3:
+		ac = 0;
+		break;
+	case 4:
+		ac = 1;
+		break;
+	case 5:
+		ac = 2;
+		break;
+	}
+
+	NAND_REG32(priv, REG_MEMORY_CONFIG) = NANDC_MS_32GB | NANDC_MOD0_ENABLE
+										| (bk << 16) | (pg << 8) | (ac << 10);
+
+	/* PIO mode */
+	NAND_REG32(priv, REG_BMC_PIO_MODE_READY) = 0;
+
+	return 0;
+}
+
+static inline int
+ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	uint32_t st = NAND_REG32(priv, REG_DEV_ID_BYTE47);
+
+	if (st & NAND_IOSTATUS_ERROR)
+		return -NAND_IOSTATUS_ERROR;
+
+	if (!(st & NAND_IOSTATUS_READY))
+		return -NAND_IOSTATUS_READY;
+
+	if (!(st & NAND_IOSTATUS_UNPROTCT))
+		return -NAND_IOSTATUS_UNPROTCT;
+
+	return 0;
+}
+
+static inline int
+ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	uint32_t t;
+	int rc = -1;
+
+	for (t = get_timer(0); get_timer(t) < 200; ) {
+		if (!(NAND_REG32(priv, REG_ACCESS_CONTROL) & NANDC_CMD_LAUNCH)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int
+ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	int rc = 0;
+
+	NAND_REG32(priv, REG_ACCESS_CONTROL) = NANDC_CMD_LAUNCH | (cmd << NANDC_CMD_OFFSET);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : nand_ckst (We have queued data@the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case NANDC_CMD_PAGE_READ:
+		break;
+	case NANDC_CMD_PAGE_WRITE_RS:
+		rc = ftnandc021_ckst(priv);
+		break;
+	case NANDC_CMD_BLK_ERASE_RS:
+	case NANDC_CMD_SPARE_WRITE_RS:
+		rc = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		rc = ftnandc021_wait(priv);
+	}
+
+	return rc;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int
+ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip  *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	int rc = 1;
+
+	if (ftnandc021_wait(priv) || ftnandc021_ckst(priv))
+		rc = 0;
+
+	return rc;
+}
+
+static void
+ftnandc021_read_oob(struct mtd_info *mtd, uint8_t * buf, int len)
+{
+	struct nand_chip  *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	uint32_t tmp;
+
+	/*
+	 * Bad Block Information:
+	 * 1. Large Page(2048, 4096): off=0, len=2
+	 * 2. Small Page(512): off=5, len=1
+	 */
+	buf[0]  = NAND_REG32(priv, REG_READ_BI) & 0xFF;
+	buf[1]  = 0xFF;
+
+	tmp     = NAND_REG32(priv, REG_READ_LSN_CRC);
+	buf[8]  = (tmp >>  0) & 0xFF;
+	buf[9]  = (tmp >>  8) & 0xFF;
+	if (mtd->writesize >=  4096) {
+		buf[12] = (tmp >> 16) & 0xFF;
+		buf[13] = (tmp >> 24) & 0xFF;
+	}
+
+	tmp     = NAND_REG32(priv, REG_READ_LSN);
+	buf[10] = (tmp >>  0) & 0xFF;
+	buf[11] = (tmp >>  8) & 0xFF;
+	if (mtd->writesize >=  4096) {
+		buf[14] = (tmp >> 16) & 0xFF;
+		buf[15] = (tmp >> 24) & 0xFF;
+	}
+}
+
+static void
+ftnandc021_write_oob(struct mtd_info *mtd, const uint8_t * buf, int len)
+{
+	struct nand_chip  *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	uint32_t tmp;
+
+	NAND_REG32(priv, REG_WRITE_BI) = buf[0];
+
+	tmp = buf[8] | (buf[9] << 8);
+	if (mtd->writesize >=  4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	NAND_REG32(priv, REG_WRITE_LSN_CRC) = tmp;
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >=  4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	NAND_REG32(priv, REG_LSN_CONTROL)   = tmp;
+}
+
+static uint8_t
+ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip  *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	uint8_t rc = 0xFF;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+	case NAND_CMD_READOOB:
+		rc = priv->buf[priv->off % 256];
+		priv->off += 1;
+		break;
+	case NAND_CMD_STATUS:
+		rc = (uint8_t)(NAND_REG32(priv, REG_DEV_ID_BYTE47) & 0xFF);
+		break;
+	default:
+		printf("ftnandc021_read_byte...not supported cmd(0x%02X)!?\n", priv->cmd);
+		break;
+	}
+
+	return rc;
+}
+
+static uint16_t
+ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t rc = 0xFFFF;
+	uint8_t *buf = (uint8_t *)&rc;
+
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return rc;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void
+ftnandc021_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip  *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	uint32_t off;
+
+	if ((uint32_t)buf & 0x03) {
+		printf("ftnandc021_read_buf: buf at 0x%08X is not aligned\n", (uint32_t)buf);
+		return;
+	}
+
+	/* oob read */
+	if (len <= mtd->oobsize) {
+		ftnandc021_read_oob(mtd, buf, len);
+		return;
+	}
+
+	/* page read */
+	for (off = 0; len > 0; len -= 4, off += 4) {
+		ulong ts = get_timer(0);
+		do {
+			if (NAND_REG32(priv, 0x208) & BIT(0))
+				break;
+		} while (get_timer(ts) < CONFIG_SYS_HZ);
+
+		if (!(NAND_REG32(priv, 0x208) & BIT(0))) {
+			printf("ftnandc021_read_buf: data timeout (cmd=0x%02X)\n", priv->cmd);
+			return;
+		}
+		*(uint32_t *)(buf + off) = NAND_REG32(priv, REG_BMC_DATA_PORT);
+	}
+
+	if (ftnandc021_wait(priv))
+		printf("ftnandc021_read_buf: command timeout (cmd=0x%02X)\n", priv->cmd);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void
+ftnandc021_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip  *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	uint32_t off;
+
+	if ((uint32_t)buf & 0x03) {
+		printf("ftnandc021_write_buf: buf at 0x%08X is not aligned\n", (uint32_t)buf);
+		return;
+	}
+
+	/* 1. oob write */
+	if (len <= mtd->oobsize)
+		return;
+
+	/* 2. page write */
+	for (off = 0; len > 0; len -= 4, off += 4) {
+		while (!(NAND_REG32(priv, 0x208) & BIT(0)))
+			;
+		NAND_REG32(priv, REG_BMC_DATA_PORT) = *(uint32_t *)(buf + off);
+	}
+
+	/* 3. wait until command finish */
+	if (ftnandc021_wait(priv))
+		printf("ftnandc021_write_buf: write fail\n");
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int
+ftnandc021_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	int rc = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (tmp == NULL) {
+		printf("ftnandc021_verify_buf: out of memory\n");
+		return -1;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			rc = -2;
+	}
+
+	free(tmp);
+
+	if (rc)
+		printf("ftnandc021_verify_buf...failed (buf@%p, len=%d)\n", buf, len);
+
+	return rc;
+}
+
+static void
+ftnandc021_cmdfunc(struct mtd_info *mtd, unsigned cmd, int column, int pgidx)
+{
+	struct nand_chip  *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+
+	priv->cmd   = cmd;
+	priv->pgidx = pgidx;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		if (ftnandc021_command(priv, NANDC_CMD_READ_ID)) {
+			printf("ftnandc021_cmdfunc: RDID failed.\n");
+		} else {
+			uint32_t tmp;
+			tmp = NAND_REG32(priv, REG_DEV_ID_BYTE03);
+			memcpy(priv->buf + 0, &tmp, 4);
+			tmp = NAND_REG32(priv, REG_DEV_ID_BYTE47);
+			memcpy(priv->buf + 4, &tmp, 4);
+			priv->off = 0;
+		}
+		break;
+
+	case NAND_CMD_READ0:	/* 0x00 */
+		NAND_REG32(priv, REG_PAGE_INDEX) = pgidx;
+		NAND_REG32(priv, REG_PAGE_COUNT) = 1;
+		if (ftnandc021_command(priv, NANDC_CMD_PAGE_READ))
+			printf("ftnandc021_cmdfunc: PGREAD failed.\n");
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		NAND_REG32(priv, REG_PAGE_INDEX) = pgidx;
+		NAND_REG32(priv, REG_PAGE_COUNT) = 1;
+		if (ftnandc021_command(priv, NANDC_CMD_SPARE_READ)) {
+			printf("ftnandc021_cmdfunc: OOBREAD failed.\n");
+		} else {
+			ftnandc021_read_oob(mtd, priv->buf, mtd->oobsize);
+			priv->off = 0;
+		}
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		NAND_REG32(priv, REG_PAGE_INDEX) = pgidx;
+		NAND_REG32(priv, REG_PAGE_COUNT) = 1;
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, NANDC_CMD_BLK_ERASE_RS))
+			printf("ftnandc021_cmdfunc: ERASE failed, pgidx=%d\n", pgidx);
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, NANDC_CMD_READ_STS))
+			printf("ftnandc021_cmdfunc: STREAD failed.\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->writesize);
+
+		NAND_REG32(priv, REG_PAGE_INDEX) = pgidx;
+		NAND_REG32(priv, REG_PAGE_COUNT) = 1;
+		if (column >= mtd->writesize) {
+			if (ftnandc021_command(priv, NANDC_CMD_SPARE_WRITE_RS))
+				printf("ftnandc021_cmdfunc: oob write failed..\n");
+		} else {
+			if (ftnandc021_command(priv, NANDC_CMD_PAGE_WRITE_RS))
+				printf("ftnandc021_cmdfunc: page write failed..\n");
+		}
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, NANDC_CMD_RESET))
+			printf("ftnandc021_cmdfunc: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021_cmdfunc: error, unsupported command (0x%x).\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void
+ftnandc021_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+}
+
+int
+ftnandc021_probe(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv;
+
+	priv = malloc(sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -1;
+
+	memset(priv, 0, sizeof(*priv));
+	priv->iobase = (void *)CONFIG_NAND_FTNANDC021_BASE;
+	priv->adrc   = (unsigned int)chip->priv;
+	priv->pgsz   = 1 << chip->page_shift;
+	priv->bksz   = 1 << chip->phys_erase_shift;
+
+	chip->priv       = priv;
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	chip->ecc.mode   = NAND_ECC_NONE;
+	chip->ecc.layout = &ftnandc021_oob_2k;
+
+	chip->options    |= NAND_NO_AUTOINCR;
+
+	ftnandc021_reset(chip);
+
+	debug("ftnandc021: pg=%dK, bk=%dK, adrc=%d\n",
+		   priv->pgsz >> 10, priv->bksz >> 10, priv->adrc);
+
+	return 0;
+}
diff --git a/drivers/mtd/nand/ftnandc021.h b/drivers/mtd/nand/ftnandc021.h
new file mode 100644
index 0000000..cf5d955
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.h
@@ -0,0 +1,165 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTNANDC021_H
+#define __FTNANDC021_H
+
+#ifndef BIT
+#define BIT(nr)		(1UL << (nr))
+#endif
+
+/* SMC Register Offset Definitions */
+/** ECC control register **/
+#define REG_ECC_PARITY0           0x00
+#define REG_ECC_PARITY1           0x04
+#define REG_ECC_PARITY2           0x08
+#define REG_ECC_PARITY3           0x0C
+#define REG_ECC_STATUS            0x10
+
+/** NANDC control register **/
+#define REG_HOST_STATUS           0x100
+#define REG_ACCESS_CONTROL        0x104
+#define REG_FLOW_CONTROL          0x108
+#define REG_PAGE_INDEX            0x10C
+#define REG_MEMORY_CONFIG         0x110
+#define REG_AC1_CONTROL           0x114
+#define REG_AC2_CONTROL           0x118
+#define REG_TARGET_PAGE_INDEX     0x11C
+#define REG_DEV_ID_BYTE03         0x120
+#define REG_DEV_ID_BYTE47         0x124
+#define REG_INT_EN                0x128
+#define REG_INT_STS_CLEAR         0x12C
+#define REG_FLASH0_BLK_OFFSET     0x130
+#define REG_FLASH1_BLK_OFFSET     0x134
+#define REG_FLASH2_BLK_OFFSET     0x138
+#define REG_FLASH3_BLK_OFFSET     0x13C
+#define REG_WRITE_BI              0x140
+#define REG_WRITE_LSN             0x144
+#define REG_WRITE_LSN_CRC         0x148
+#define REG_LSN_CONTROL           0x14C
+#define REG_READ_BI               0x150
+#define REG_READ_LSN              0x154
+#define REG_READ_LSN_CRC          0x158
+
+#define REG_F0_CB_TGT_BLK_OFFSET  0x160
+#define REG_F1_CB_TGT_BLK_OFFSET  0x164
+#define REG_F2_CB_TGT_BLK_OFFSET  0x168
+#define REG_F3_CB_TGT_BLK_OFFSET  0x16c
+
+#define REG_F0_LSN_INIT           0x170
+#define REG_F1_LSN_INIT           0x174
+#define REG_F2_LSN_INIT           0x178
+#define REG_F3_LSN_INIT           0x17C
+
+/** BMC control register **/
+#define REG_BMC_INT               0x204
+#define REG_BMC_BURST_TX_MODE     0x208
+#define REG_BMC_PIO_MODE_READY    0x20C
+
+/** MISC register **/
+#define REG_BMC_DATA_PORT         0x300
+#define REG_MLC_INT_CONTROL       0x304
+#define REG_PAGE_COUNT            0x308
+#define REG_MLC_SW_RESET          0x30C
+#define REG_REVISION              0x3F8
+#define REG_CONFIGURATION         0x3FC
+
+
+#define NANDC_MLC_ECC_EN          BIT(8)
+#define NANDC_NANDC_SW_RESET      BIT(2)
+#define NANDC_BMC_SW_RESET        BIT(1)
+#define NANDC_ECC_SW_RESET        BIT(0)
+
+/* 0x10: ECC status register */
+#define NANDC_ECC_CORR_FAIL       BIT(3)
+#define NANDC_ECC_ERR_OCCUR       BIT(2)
+#define NANDC_ECC_DEC_CP          BIT(1)
+#define NANDC_ECC_ENC_CP          BIT(0)
+
+/* 0x100: NAND flash host controller status register */
+#define NANDC_BLANK_CHECK_FAIL    BIT(7)
+#define NANDC_ECC_FAIL_TIMEOUT    BIT(5)
+#define NANDC_STS_FAIL            BIT(4)
+#define NANDC_LSN_CRC_FAIL        BIT(3)
+#define NANDC_CMD_CP              BIT(2)
+#define NANDC_BUSY                BIT(1)
+#define NANDC_CHIP_ENABLE         BIT(0)
+
+/* 0x104: Access control register */
+#define NANDC_CMD_READ_ID			1
+#define NANDC_CMD_RESET				2
+#define NANDC_CMD_READ_STS			4
+#define NANDC_CMD_READ_EDC_STS		11
+#define NANDC_CMD_PAGE_READ			5
+#define NANDC_CMD_SPARE_READ		6
+#define NANDC_CMD_BLANK_CHK			28
+#define NANDC_CMD_PAGE_WRITE_RS		16
+#define NANDC_CMD_BLK_ERASE_RS		17
+#define NANDC_CMD_COPY_BACK_RS		18
+#define NANDC_CMD_SPARE_WRITE_RS	19
+#define NANDC_CMD_2P_PAGE_WRITE_RS	24
+#define NANDC_CMD_2P_BLK_ERASE_RS	25
+#define NANDC_CMD_2P_COPY_BACK_RS	26
+#ifdef FLASH_PAGE_4K
+#define NANDC_CMD_SPARE_READALL		14
+#endif
+
+#define NANDC_CMD_OFFSET			8
+
+#define NANDC_CMD_LAUNCH			BIT(7)
+
+/* 0x108: Flow control register */
+#define NANDC_IO_WIDTH_16BIT        BIT(4)
+#define NANDC_WP                    BIT(3)
+#define NANDC_PASS_STATUS_CHK_FAIL  BIT(2)
+#define NANDC_MICRON_CMD            BIT(1)
+#define NANDC_SKIP_ZERO_BLANK_CHK   BIT(0)
+#define NANDC_IO_WIDTH_8BIT         0
+
+/* 0x110: Memory module configuration register */
+#define NANDC_BS_16P                0
+#define NANDC_BS_32P                (1 << 16)
+#define NANDC_BS_64P                (2 << 16)
+#define NANDC_BS_128P               (3 << 16)
+
+#define NANDC_MA_SINGLE             0
+#define NANDC_MA_TWO_PLANE          (1 << 14)
+
+#define NANDC_IT_NI                 0
+#define NANDC_IT_TWO                (1 << 12)
+#define NANDC_IT_FOUR               (2 << 12)
+
+#define NANDC_AP_3C                 0
+#define NANDC_AP_4C                 (1 << 10)
+#define NANDC_AP_5C                 (2 << 10)
+
+#define NANDC_PS_512                0
+#define NANDC_PS_2K                 (1 << 8)
+#define NANDC_PS_4K                 (2 << 8)
+
+#define NANDC_MS_16MB               0
+#define NANDC_MS_32MB               (1 << 4)
+#define NANDC_MS_64MB               (2 << 4)
+#define NANDC_MS_128MB              (3 << 4)
+#define NANDC_MS_256MB              (4 << 4)
+#define NANDC_MS_512MB              (5 << 4)
+#define NANDC_MS_1GB                (6 << 4)
+#define NANDC_MS_2GB                (7 << 4)
+#define NANDC_MS_4GB                (8 << 4)
+#define NANDC_MS_8GB                (9 << 4)
+#define NANDC_MS_16GB               (10 << 4)
+#define NANDC_MS_32GB               (11 << 4)
+
+#define NANDC_MOD0_ENABLE           BIT(0)
+#define NANDC_MOD1_ENABLE           BIT(1)
+#define NANDC_MOD2_ENABLE           BIT(2)
+#define NANDC_MOD3_ENABLE           BIT(3)
+
+#endif    /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH 09/11] mtd/spi: add FTSPI020 SPI Flash controller support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (7 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 08/11] mtd/nand: add FTNANDC021 NAND flash " Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 10/11] mmc: add an alternative FTSDC010 driver support Kuo-Jung Su
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTSPI020 is dedicated SPI bus designed for
SPI Flash chips. It supports Fast-Read-Dual,
Fast-Read-Dual-IO, Fast-Read-Quad and Fast-Read-Quad-IO.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/mtd/spi/Makefile   |    4 +
 drivers/mtd/spi/ftspi020.c |  589 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/ftspi020.h |  118 +++++++++
 drivers/mtd/spi/winbond.c  |   17 +-
 4 files changed, 727 insertions(+), 1 deletion(-)
 create mode 100644 drivers/mtd/spi/ftspi020.c
 create mode 100644 drivers/mtd/spi/ftspi020.h

diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 90f8392..ce60e1b 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -29,6 +29,9 @@ ifdef CONFIG_SPL_BUILD
 COBJS-$(CONFIG_SPL_SPI_LOAD)	+= spi_spl_load.o
 endif
 
+ifeq ($(CONFIG_FTSPI020),y)
+COBJS-$(CONFIG_FTSPI020) += ftspi020.o
+else
 COBJS-$(CONFIG_SPI_FLASH)	+= spi_flash.o
 COBJS-$(CONFIG_SPI_FLASH_ATMEL)	+= atmel.o
 COBJS-$(CONFIG_SPI_FLASH_EON)	+= eon.o
@@ -39,6 +42,7 @@ COBJS-$(CONFIG_SPI_FLASH_STMICRO)	+= stmicro.o
 COBJS-$(CONFIG_SPI_FLASH_WINBOND)	+= winbond.o
 COBJS-$(CONFIG_SPI_FRAM_RAMTRON)	+= ramtron.o
 COBJS-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
+endif
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/mtd/spi/ftspi020.c b/drivers/mtd/spi/ftspi020.c
new file mode 100644
index 0000000..5c85203
--- /dev/null
+++ b/drivers/mtd/spi/ftspi020.c
@@ -0,0 +1,589 @@
+/*
+ * Faraday SPI Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include "ftspi020.h"
+
+#define CFG_USE_FASTRD          1
+#define CFG_USE_FASTRD_QUAD     1 /* Fast Read Quad */
+#define CFG_SHOW_PROGRESS		1 /* print a '.' at the end of each action */
+
+/* Register access macros */
+#define SPI_REG32(reg)          *(volatile uint32_t *)(CONFIG_FTSPI020_BASE + (reg))
+
+/* Flash opcodes. */
+#define OPCODE_WREN                 0x06    /* Write enable */
+#define OPCODE_RDSR                 0x05    /* Read status register */
+#define OPCODE_WRSR                 0x01    /* Write status register 1 byte */
+#define OPCODE_NORM_READ            0x03    /* Read data bytes (low frequency) */
+#define OPCODE_NORM_READ4           0x13    /* Read data bytes (low frequency, 4 bytes address) */
+#define OPCODE_FAST_READ            0x0b    /* Read data bytes (high frequency) */
+#define OPCODE_FAST_READ4           0x0c    /* Read data bytes (high frequency, 4 bytes address) */
+#define OPCODE_FAST_READ_DUAL       0x3b    /* Read data bytes (high frequency) */
+#define OPCODE_FAST_READ4_DUAL      0x3c    /* Read data bytes (high frequency, 4 bytes address) */
+#define OPCODE_FAST_READ_QUAD       0x6b    /* Read data bytes (high frequency) */
+#define OPCODE_FAST_READ4_QUAD      0x6c    /* Read data bytes (high frequency, 4 bytes address) */
+#define OPCODE_PP                   0x02    /* Page program (up to 256 bytes) */
+#define OPCODE_PP4                  0x12    /* Page program (up to 256 bytes, 4 bytes address) */
+#define OPCODE_BE_4K                0x20    /* Erase 4KiB block */
+#define OPCODE_BE_32K               0x52    /* Erase 32KiB block */
+#define OPCODE_CHIP_ERASE           0xc7    /* Erase whole flash chip */
+#define OPCODE_SE                   0xd8    /* Sector erase (usually 64KiB) */
+#define OPCODE_SE4                  0xdc    /* Sector erase (usually 64KiB, 4 bytes address) */
+#define OPCODE_RDID                 0x9f    /* Read JEDEC ID */
+
+/* Status Register bits. */
+#define SR_WIP                      BIT(0)  /* Write in progress */
+#define SR_WEL                      BIT(1)  /* Write enable latch */
+
+struct spi_flash_param {
+	const char *name;
+	uint32_t    id;
+	uint32_t    ext_id;
+	uint32_t    sz_sector;
+	uint32_t    nr_sector;
+
+	uint32_t    flags;
+#define SECT_4K            BIT(0)          /* OPCODE_BE_4K works uniformly */
+#define FASTRD_DUAL        BIT(8)
+#if CFG_USE_FASTRD_QUAD
+#define FASTRD_QUAD        BIT(9)
+#else
+#define FASTRD_QUAD        0
+#endif
+};
+
+/* spi_flash needs to be first so upper layers can free() it */
+struct spi_flash_info {
+	struct spi_flash flash;
+	const struct spi_flash_param *param;
+
+	unsigned fastrd_dual:1;
+	unsigned fastrd_quad:1;
+};
+
+static inline const struct spi_flash_param *flash_to_param(struct spi_flash *flash)
+{
+	struct spi_flash_info *fl = (struct spi_flash_info *)flash;
+	return fl->param;
+}
+
+static const struct spi_flash_param fl_list[] = {
+
+	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
+	{ "at25fs010",  0x1f6601, 0, 32 * 1024,   4 },
+	{ "at25fs040",  0x1f6604, 0, 64 * 1024,   8 },
+
+	{ "at25df041a", 0x1f4401, 0, 64 * 1024,   8 },
+	{ "at25df321a", 0x1f4701, 0, 64 * 1024,  64 },
+	{ "at25df641",  0x1f4800, 0, 64 * 1024, 128 },
+
+	{ "at26f004",   0x1f0400, 0, 64 * 1024,  8 },
+	{ "at26df081a", 0x1f4501, 0, 64 * 1024, 16 },
+	{ "at26df161a", 0x1f4601, 0, 64 * 1024, 32 },
+	{ "at26df321",  0x1f4700, 0, 64 * 1024, 64 },
+
+	/* EON -- en25xxx */
+	{ "en25f32",   0x1c3116, 0, 64 * 1024,  64 },
+	{ "en25p32",   0x1c2016, 0, 64 * 1024,  64 },
+	{ "en25q32b",  0x1c3016, 0, 64 * 1024,  64 },
+	{ "en25p64",   0x1c2017, 0, 64 * 1024, 128 },
+	{ "en25qh256", 0x1c7019, 0, 64 * 1024, 512 },
+
+	/* GD -- GD25xxx */
+	{ "gd25q16",   0xc84015, 0, 64 * 1024,  32 },
+	{ "gd25q32",   0xc84016, 0, 64 * 1024,  64 },
+	{ "gd25q64",   0xc84017, 0, 64 * 1024, 128 },
+
+	/* Intel/Numonyx -- xxxs33b */
+	{ "160s33b",  0x898911, 0, 64 * 1024,  32 },
+	{ "320s33b",  0x898912, 0, 64 * 1024,  64 },
+	{ "640s33b",  0x898913, 0, 64 * 1024, 128 },
+
+	/* Macronix */
+	{ "mx25l4005a",  0xc22013, 0, 64 * 1024,   8 },
+	{ "mx25l8005",   0xc22014, 0, 64 * 1024,  16 },
+	{ "mx25l1606e",  0xc22015, 0, 64 * 1024,  32 },
+	{ "mx25l3205d",  0xc22016, 0, 64 * 1024,  64 },
+	{ "mx25l6405d",  0xc22017, 0, 64 * 1024, 128 },
+	{ "mx25l12805d", 0xc22018, 0, 64 * 1024, 256 },
+	{ "mx25l12855e", 0xc22618, 0, 64 * 1024, 256 },
+	{ "mx25l25635e", 0xc22019, 0, 64 * 1024, 512 },
+	{ "mx25l25655e", 0xc22619, 0, 64 * 1024, 512 },
+
+	/* Spansion -- single (large) sector size only, at least
+	 * for the chips listed here (without boot sectors).
+	 */
+	{ "s25sl004a",  0x010212,      0,  64 * 1024,   8 },
+	{ "s25sl008a",  0x010213,      0,  64 * 1024,  16 },
+	{ "s25sl016a",  0x010214,      0,  64 * 1024,  32 },
+	{ "s25sl032a",  0x010215,      0,  64 * 1024,  64 },
+	{ "s25sl032p",  0x010215, 0x4d00,  64 * 1024,  64 },
+	{ "s25sl064a",  0x010216,      0,  64 * 1024, 128 },
+	{ "s25fl128s0", 0x010218, 0x4d00, 256 * 1024,  64, FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl128s1", 0x010218, 0x4d01,  64 * 1024, 256, FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128, FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl256s1", 0x010219, 0x4d01,  64 * 1024, 512, FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl512s",  0x010220, 0x4d00, 256 * 1024, 256, FASTRD_DUAL | FASTRD_QUAD },
+	{ "s70fl01gs",  0x010221, 0x4d00, 256 * 1024, 256 },
+	{ "s25sl12800", 0x012018, 0x0300, 256 * 1024,  64 },
+	{ "s25sl12801", 0x012018, 0x0301,  64 * 1024, 256 },
+	{ "s25fl129p0", 0x012018, 0x4d00, 256 * 1024,  64, FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl129p1", 0x012018, 0x4d01,  64 * 1024, 256, FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl016k",  0xef4015,      0,  64 * 1024,  32 },
+	{ "s25fl064k",  0xef4017,      0,  64 * 1024, 128 },
+
+	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
+	{ "sst25vf040b", 0xbf258d, 0, 64 * 1024,  8 },
+	{ "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16 },
+	{ "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32 },
+	{ "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64 },
+	{ "sst25vf064c", 0xbf254b, 0, 64 * 1024, 128, FASTRD_DUAL },
+	{ "sst25wf512",  0xbf2501, 0, 64 * 1024,  1 },
+	{ "sst25wf010",  0xbf2502, 0, 64 * 1024,  2 },
+	{ "sst25wf020",  0xbf2503, 0, 64 * 1024,  4 },
+	{ "sst25wf040",  0xbf2504, 0, 64 * 1024,  8 },
+
+	/* Micron -- newer production may have feature updates */
+	{ "m25p05",  0x202010,  0,  32 * 1024,   2 },
+	{ "m25p10",  0x202011,  0,  32 * 1024,   4 },
+	{ "m25p20",  0x202012,  0,  64 * 1024,   4 },
+	{ "m25p40",  0x202013,  0,  64 * 1024,   8 },
+	{ "m25p80",  0x202014,  0,  64 * 1024,  16 },
+	{ "m25p16",  0x202015,  0,  64 * 1024,  32 },
+	{ "m25p32",  0x202016,  0,  64 * 1024,  64 },
+	{ "m25p64",  0x202017,  0,  64 * 1024, 128 },
+	{ "m25p128", 0x202018,  0, 256 * 1024,  64 },
+
+	{ "m45pe10", 0x204011,  0, 64 * 1024,    2 },
+	{ "m45pe80", 0x204014,  0, 64 * 1024,   16 },
+	{ "m45pe16", 0x204015,  0, 64 * 1024,   32 },
+
+	{ "m25pe80", 0x208014,  0, 64 * 1024, 16 },
+	{ "m25pe16", 0x208015,  0, 64 * 1024, 32 },
+
+	{ "m25px32",    0x207116,  0, 64 * 1024, 64 },
+	{ "m25px32-s0", 0x207316,  0, 64 * 1024, 64 },
+	{ "m25px32-s1", 0x206316,  0, 64 * 1024, 64 },
+	{ "m25px64",    0x207117,  0, 64 * 1024, 128 },
+
+	{ "n25q032a13e", 0x20ba16, 0, 64 * 1024,  64, },
+	{ "n25q064a13e", 0x20ba17, 0, 64 * 1024, 128, },
+	{ "n25q128a13e", 0x20ba18, 0, 64 * 1024, 256, },
+	{ "n25q256a13e", 0x20ba19, 0, 64 * 1024, 512, },
+	{ "n25qax3g",    0x20ba20, 0, 64 * 1024, 1024, },
+	{ "n25q00aa13g", 0x20ba21, 0, 64 * 1024, 2048, },
+
+	/* Winbond */
+	{ "w25x10", 0xef3011, 0, 64 * 1024, 2, },
+	{ "w25x20", 0xef3012, 0, 64 * 1024, 4, },
+	{ "w25x40", 0xef3013, 0, 64 * 1024, 8, },
+	{ "w25p80", 0xef2014, 0, 64 * 1024, 16, },
+	{ "w25x80", 0xef3014, 0, 64 * 1024, 16, },
+	{ "w25p16", 0xef2015, 0, 64 * 1024, 32, },
+	{ "w25x16", 0xef3015, 0, 64 * 1024, 32, },
+	{ "w25x32", 0xef3016, 0, 64 * 1024, 64, },
+	{ "w25q32", 0xef4016, 0, 64 * 1024, 64, },
+	{ "w25x64", 0xef3017, 0, 64 * 1024, 128, },
+	{ "w25q64", 0xef4017, 0, 64 * 1024, 128, },
+	{ "w25q128", 0xef4018, 0, 64 * 1024, 256, FASTRD_DUAL | FASTRD_QUAD },
+
+	/* generic */
+	{ "unknown",       0, 0, 64 * 1024, 256, },
+};
+
+static int ftspi020_rdid(struct spi_flash *flash, void *buf)
+{
+	uint32_t id32[2];
+	uint8_t *id = buf;
+	int i;
+
+	/* clear isr */
+	SPI_REG32(REG_ISR)  = BIT(0);
+
+	/* issue command */
+	SPI_REG32(REG_CMD0) = 0;
+	SPI_REG32(REG_CMD1) = (1 << 24);
+	SPI_REG32(REG_CMD2) = sizeof(id32);
+	SPI_REG32(REG_CMD3) = (OPCODE_RDID << 24) | (flash->spi->cs << 8) | BIT(0);
+
+	for (i = 0; i < sizeof(id32) / sizeof(id32[0]); ++i) {
+		/* wait until rx ready */
+		while (!(SPI_REG32(REG_SR) & BIT(1)))
+			;
+		id32[i] = SPI_REG32(REG_DR);
+	}
+
+	/* wait until command finish */
+	while (!(SPI_REG32(REG_ISR) & BIT(0)))
+		;
+	SPI_REG32(REG_ISR) = BIT(0);
+
+	memcpy(id, id32, 5);
+
+	return 0;
+}
+
+static int ftspi020_rdsr(struct spi_flash *flash)
+{
+	int st;
+
+	/* clear isr */
+	SPI_REG32(REG_ISR)  = BIT(0);
+
+	/* issue command */
+	SPI_REG32(REG_CMD0) = 0;
+	SPI_REG32(REG_CMD1) = (1 << 24);
+	SPI_REG32(REG_CMD2) = 1;
+	SPI_REG32(REG_CMD3) = (OPCODE_RDSR << 24) | (flash->spi->cs << 8) | BIT(0);
+
+	/* wait until rx ready */
+	while (!(SPI_REG32(REG_SR) & BIT(1)))
+		;
+	st = SPI_REG32(REG_DR);
+
+	/* wait until command finish */
+	while (!(SPI_REG32(REG_ISR) & BIT(0)))
+		;
+	SPI_REG32(REG_ISR) = BIT(0);
+
+	return st & 0xff;
+}
+
+/*
+ * Write status register
+ * Returns negative if error occurred.
+ */
+static int ftspi020_wrsr(struct spi_flash *flash, uint32_t val, uint8_t len)
+{
+	/* clear isr */
+	SPI_REG32(REG_ISR)  = BIT(0);
+
+	/* issue command */
+	SPI_REG32(REG_CMD0) = 0;
+	SPI_REG32(REG_CMD1) = (1 << 24);
+	SPI_REG32(REG_CMD2) = len;
+	SPI_REG32(REG_CMD3) = (OPCODE_WRSR << 24) | (flash->spi->cs << 8) | BIT(1) | BIT(0);
+
+	/* wait until tx ready */
+	while (!(SPI_REG32(REG_SR) & BIT(0)))
+		;
+	SPI_REG32(REG_DR) = cpu_to_le32(val);
+
+	/* wait until command finish */
+	while (!(SPI_REG32(REG_ISR) & BIT(0)))
+		;
+	SPI_REG32(REG_ISR) = BIT(0);
+
+	/* wait until device ready */
+	while (ftspi020_rdsr(flash) & SR_WEL)
+		;
+
+	return 0;
+}
+
+static int ftspi020_read(struct spi_flash *flash, u32 offset, size_t len, void *buf)
+{
+	struct spi_flash_info *fl = (struct spi_flash_info *)flash;
+	uint32_t i, v;
+
+	if (((uint32_t)buf) & 0x03) {
+		printf("ftspi020: read buffer is not 32-bits aligned!?\n");
+		return -1;
+	}
+
+	/* 1. wait until device ready */
+	while (ftspi020_rdsr(flash) & SR_WIP)
+		;
+
+	/* 2. issue command (Rd) */
+	SPI_REG32(REG_ISR)  = BIT(0);
+	SPI_REG32(REG_CMD0) = offset;
+	SPI_REG32(REG_CMD2) = len;
+
+	if (offset < 0x1000000) {
+#if CFG_USE_FASTRD
+		if (fl->fastrd_quad) {
+			SPI_REG32(REG_CMD1) = (1 << 24) | (8 << 16) | 3;
+			SPI_REG32(REG_CMD3) = (OPCODE_FAST_READ_QUAD << 24) | (flash->spi->cs << 8) | (2 << 5) | BIT(0);
+		} else if (fl->fastrd_dual) {
+			SPI_REG32(REG_CMD1) = (1 << 24) | (8 << 16) | 3;
+			SPI_REG32(REG_CMD3) = (OPCODE_FAST_READ_DUAL << 24) | (flash->spi->cs << 8) | (1 << 5) | BIT(0);
+		} else {
+			SPI_REG32(REG_CMD1) = (1 << 24) | (8 << 16) | 3;
+			SPI_REG32(REG_CMD3) = (OPCODE_FAST_READ << 24) | (flash->spi->cs << 8) | BIT(0);
+		}
+#else
+		SPI_REG32(REG_CMD1) = (1 << 24) | 3;
+		SPI_REG32(REG_CMD3) = (OPCODE_NORM_READ << 24) | (flash->spi->cs << 8) | BIT(0);
+#endif
+	} else {
+#if CFG_USE_FASTRD
+		if (fl->fastrd_quad) {
+			SPI_REG32(REG_CMD1) = (1 << 24) | (8 << 16) | 4;
+			SPI_REG32(REG_CMD3) = (OPCODE_FAST_READ4_QUAD << 24) | (flash->spi->cs << 8) | (2 << 5) | BIT(0);
+		} else if (fl->fastrd_dual) {
+			SPI_REG32(REG_CMD1) = (1 << 24) | (8 << 16) | 4;
+			SPI_REG32(REG_CMD3) = (OPCODE_FAST_READ4_DUAL << 24) | (flash->spi->cs << 8) | (1 << 5) | BIT(0);
+		} else {
+			SPI_REG32(REG_CMD1) = (1 << 24) | (8 << 16) | 4;
+			SPI_REG32(REG_CMD3) = (OPCODE_FAST_READ4 << 24) | (flash->spi->cs << 8) | BIT(0);
+		}
+#else
+		SPI_REG32(REG_CMD1) = (1 << 24) | 4;
+		SPI_REG32(REG_CMD3) = (OPCODE_NORM_READ4 << 24) | (flash->spi->cs << 8) | BIT(0);
+#endif
+	}
+
+	/* 3. data phase */
+	for (i = 0; i < (len & 0xFFFFFFFC); ) {
+		/* wait until rx ready */
+		while (!(SPI_REG32(REG_SR) & BIT(1)))
+			;
+
+		*((uint32_t *)buf) = SPI_REG32(REG_DR);
+
+		buf = (void *)((uint32_t)buf + 4);
+		i += 4;
+	}
+
+	if (len & 0x03) {
+		/* wait until rx ready */
+		while (!(SPI_REG32(REG_SR) & BIT(1)))
+			;
+
+		v = SPI_REG32(REG_DR);
+
+		for (i = 0; i < (len & 0x03); ++i)
+			((uint8_t *)buf)[i] = ((uint8_t *)&v)[i];
+	}
+
+	/* 4. wait until command finish */
+	while (!(SPI_REG32(REG_ISR) & BIT(0)))
+		;
+	SPI_REG32(REG_ISR) = BIT(0);
+
+	return 0;
+}
+
+static int ftspi020_wren(struct spi_flash *flash)
+{
+	/* issue command (WE) */
+	SPI_REG32(REG_CMD0) = 0;
+	SPI_REG32(REG_CMD1) = (1 << 24);
+	SPI_REG32(REG_CMD2) = 0;
+	SPI_REG32(REG_CMD3) = (OPCODE_WREN << 24) | (flash->spi->cs << 8) | BIT(1) | BIT(0);
+
+	/* wait until command finish */
+	while (!(SPI_REG32(REG_ISR) & BIT(0)))
+		;
+	SPI_REG32(REG_ISR) = BIT(0);
+
+	return 0;
+}
+
+static int ftspi020_write(struct spi_flash *flash, u32 offset, size_t len, const void *buf)
+{
+	if (offset & 0x03) {
+		printf("ftspi020: offset is not 32-bits aligned!?\n");
+		return -1;
+	}
+
+	if (((uint32_t)buf) & 0x03) {
+		printf("ftspi020: write buffer is not 32-bits aligned!?\n");
+		return -1;
+	}
+
+	/* 256 bytes page write */
+	while (len > 0) {
+		int i;
+		int wl = min(256, len);
+
+#if CFG_SHOW_PROGRESS
+		/* output a '.' on each 64KB boundary */
+		if ((offset & 0x0000ffff) == 0)
+			puts(".");
+#endif
+
+		/* 1. wait until device ready */
+		while (ftspi020_rdsr(flash) & SR_WIP)
+			;
+
+		/* 2. write enable */
+		while (!(ftspi020_rdsr(flash) & SR_WEL))
+			ftspi020_wren(flash);
+
+		/* issue command (PP) */
+		SPI_REG32(REG_CMD0) = offset;
+		SPI_REG32(REG_CMD2) = wl;
+		if (offset < 0x1000000) {
+			SPI_REG32(REG_CMD1) = (1 << 24) | 3;
+			SPI_REG32(REG_CMD3) = (OPCODE_PP << 24) | (flash->spi->cs << 8) | BIT(1) | BIT(0);
+		} else {
+			SPI_REG32(REG_CMD1) = (1 << 24) | 4;
+			SPI_REG32(REG_CMD3) = (OPCODE_PP4 << 24) | (flash->spi->cs << 8) | BIT(1) | BIT(0);
+		}
+		/* data phase */
+		for (i = 0; i < wl; i += 4) {
+			/* wait until tx ready */
+			while (!(SPI_REG32(REG_SR) & BIT(0)))
+				;
+			SPI_REG32(REG_DR) = *(uint32_t *)buf;
+			buf = (void *)(((uint32_t)buf) + 4);
+		}
+		offset += wl;
+		len -= wl;
+
+		/* wait until command finish */
+		while (!(SPI_REG32(REG_ISR) & BIT(0)))
+			;
+		SPI_REG32(REG_ISR) = BIT(0);
+	}
+
+	return 0;
+}
+
+static int ftspi020_erase(struct spi_flash *flash, u32 offset, size_t len)
+{
+	u32 addr = 0;
+	const struct spi_flash_param *param = flash_to_param(flash);
+
+	for (addr = offset & ~(param->sz_sector - 1); addr < offset + len; addr += param->sz_sector) {
+
+#if CFG_SHOW_PROGRESS
+		puts(".");
+#endif
+
+		/* 1. wait until device ready */
+		while (ftspi020_rdsr(flash) & SR_WIP)
+			;
+
+		/* 2. write enable */
+		while (!(ftspi020_rdsr(flash) & SR_WEL))
+			ftspi020_wren(flash);
+
+		/* 3. sector erase */
+		/* issue command (SE) */
+		SPI_REG32(REG_CMD0) = addr;
+		SPI_REG32(REG_CMD2) = 0;
+		if (addr < 0x1000000) {
+			SPI_REG32(REG_CMD1) = (1 << 24) | 3;
+			SPI_REG32(REG_CMD3) = (OPCODE_SE << 24) | (flash->spi->cs << 8) | BIT(1) | BIT(0);
+		} else {
+			SPI_REG32(REG_CMD1) = (1 << 24) | 4;
+			SPI_REG32(REG_CMD3) = (OPCODE_SE4 << 24) | (flash->spi->cs << 8) | BIT(1) | BIT(0);
+		}
+
+		/* 4. wait until command finish */
+		while (!(SPI_REG32(REG_ISR) & BIT(0)))
+			;
+		SPI_REG32(REG_ISR) = BIT(0);
+
+	}
+
+	return 0;
+}
+
+struct spi_flash *spi_flash_probe(uint bus, uint cs, uint max_hz, uint spi_mode)
+{
+	struct spi_slave *spi = NULL;
+	struct spi_flash_info *flash = NULL;
+	u32 i, id, ext_id, div = 8;
+	u8  idcode[5];
+
+	if (bus > 0 || cs >= 4)
+		return NULL;
+
+	spi = malloc(sizeof(struct spi_slave));
+	if (spi == NULL)
+		return NULL;
+	spi->bus = bus;
+	spi->cs  = cs;
+
+	flash = malloc(sizeof(struct spi_flash_info));
+	if (flash == NULL)
+		return NULL;
+	flash->flash.spi   = spi;
+	flash->flash.read  = ftspi020_read;
+	flash->flash.write = ftspi020_write;
+	flash->flash.erase = ftspi020_erase;
+
+	/* reset */
+	SPI_REG32(REG_CR) = BIT(8);
+	while (SPI_REG32(REG_CR) & BIT(8))
+		;
+
+	/* clock speed */
+	if (max_hz > 0) {
+		ulong clk = clk_get_rate("SPI");
+		for (div = 2; div < 8; div += 2) {
+			if (clk / div <= max_hz)
+				break;
+		}
+	}
+
+	/* mode + clock */
+	if (spi_mode == SPI_MODE_3)
+		SPI_REG32(REG_CR) = BIT(4) | ((div >> 1) - 1);
+	else
+		SPI_REG32(REG_CR) = ((div >> 1) - 1);
+
+	/* AC timing: trace delay, cs delay */
+	SPI_REG32(REG_ATR) = 0xFF;
+
+	printf("ftspi020: div=%d\n", div);
+
+	ftspi020_rdid((struct spi_flash *)flash, idcode);
+
+	id     = (idcode[0] << 16) | (idcode[1] << 8) | (idcode[2]);
+	ext_id = (idcode[3] <<  8) | (idcode[4]);
+
+	printf("ftspi020: id=%06x.%04x\n", id, ext_id);
+
+	for (i = 0; i < ARRAY_SIZE(fl_list) - 1; ++i) {
+		if (id == fl_list[i].id) {
+			if (fl_list[i].ext_id == 0 || fl_list[i].ext_id == ext_id)
+				break;
+		}
+	}
+
+	/*
+	 * Atmel, SST and Intel/Numonyx serial flash tend to power
+	 * up with the software protection bits set
+	 */
+	ftspi020_wren((struct spi_flash *)flash);
+	ftspi020_wrsr((struct spi_flash *)flash, 0, 1);
+
+	flash->param       = fl_list + i;
+	flash->flash.name  = fl_list[i].name;
+	flash->flash.size  = fl_list[i].sz_sector * fl_list[i].nr_sector;
+
+	if (flash->param->flags & FASTRD_QUAD) {
+		printf("ftspi020: enable fast read quad\n");
+		ftspi020_wren((struct spi_flash *)flash);
+		ftspi020_wrsr((struct spi_flash *)flash, 0x0200, 2);
+		flash->fastrd_quad = 1;
+	} else if (flash->param->flags & FASTRD_DUAL) {
+		printf("ftspi020: enable fast read dual\n");
+		flash->fastrd_dual = 1;
+	}
+
+	return (struct spi_flash *)flash;
+}
+
+void spi_flash_free(struct spi_flash *flash)
+{
+	if (flash)
+		free(flash);
+}
diff --git a/drivers/mtd/spi/ftspi020.h b/drivers/mtd/spi/ftspi020.h
new file mode 100644
index 0000000..80d98f2
--- /dev/null
+++ b/drivers/mtd/spi/ftspi020.h
@@ -0,0 +1,118 @@
+/*
+ * Faraday SPI Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTSPI020_H
+#define __FTSPI020_H
+
+#ifndef BIT
+#define BIT(nr)		(1UL << (nr))
+#endif
+
+/*
+ * FTSPI020 Registers
+ */
+#define REG_CMD0    0x00 /* Command Register */
+#define REG_CMD1    0x04
+#define REG_CMD2    0x08
+#define REG_CMD3    0x0c
+#define REG_CR      0x10 /* Control Register */
+#define REG_ATR     0x14 /* AC Timing Register */
+#define REG_SR      0x18 /* Status Register */
+#define REG_ICR     0x20 /* Interrupt Enable Register */
+#define REG_ISR     0x24 /* Interrupt Status Register */
+#define REG_RDST    0x28 /* Read Status Register */
+#define REG_REVR    0x50 /* Revision Register */
+#define REG_FEAR    0x54 /* Feature Register */
+#define REG_DR      0x100/* Data Register */
+
+/*
+ * Control Register offset 0x10
+ */
+#define CR_READY_LOC_MASK   ~(0x7 << 16)
+#define CR_READY_LOC(x)     (((x) & 0x7) << 16)
+#define CR_ABORT            BIT(8)
+#define CR_CLK_MODE_MASK    ~BIT(4)
+#define CR_CLK_MODE_0       0
+#define CR_CLK_MODE_3       BIT(4)
+#define CR_CLK_DIVIDER_MASK ~(3 << 0)
+#define CR_CLK_DIVIDER_2    (0 << 0)
+#define CR_CLK_DIVIDER_4    (1 << 0)
+#define CR_CLK_DIVIDER_6    (2 << 0)
+#define CR_CLK_DIVIDER_8    (3 << 0)
+
+/*
+ * Status Register offset 0x18
+ */
+#define SR_RFR              BIT(1) /* RX FIFO ready */
+#define SR_TFR              BIT(0) /* TX FIFO ready */
+
+/*
+ * Interrupt Control Register
+ */
+#define ICR_RFTH(x)         (((x) & 0x3) << 12) /* RX FIFO threshold interrupt */
+#define ICR_TFTH(x)         (((x) & 0x3) << 8)  /* TX FIFO threshold interrupt */
+#define ICR_DMA             BIT(0) /* DMA handshake enable */
+
+/*
+ * Interrupt Status Register
+ */
+#define ISR_CMD_CMPL        BIT(0) /* Command complete interrupt  */
+
+/*
+ * Feature Register
+ */
+#define FEAR_CLK_MODE(reg)       (((reg) >> 25) & 0x1)
+#define FEAR_DTR_MODE(reg)       (((reg) >> 24) & 0x1)
+#define FEAR_CMDQ_DEPTH(reg)     (((reg) >> 16) & 0xff)
+#define FEAR_RXFIFO_DEPTH(reg)   (((reg) >>  8) & 0xff)
+#define FEAR_TXFIFO_DEPTH(reg)   (((reg) >>  0) & 0xff)
+
+/*
+ * CMD1 Register offset 4: Command Queue Second Word
+ */
+#define CMD1_CONT_READ_MODE_EN   BIT(28)
+
+#define CMD1_OP_CODE_0_BYTE      (0 << 24)
+#define CMD1_OP_CODE_1_BYTE      (1 << 24)
+#define CMD1_OP_CODE_2_BYTE      (2 << 24)
+
+#define CMD1_DUMMY_CYCLE(x)      (((x) & 0xff) << 16)
+
+#define CMD1_NO_ADDR             (0 << 0)
+#define CMD1_ADDR_1BYTE          (1 << 0)
+#define CMD1_ADDR_2BYTE          (2 << 0)
+#define CMD1_ADDR_3BYTE          (3 << 0)
+#define CMD1_ADDR_4BYTE          (4 << 0)
+
+/*
+ * CMD3 Register offset 0xc: Command Queue Fourth Word
+ */
+#define CMD3_INSTR_CODE(x)       (((x) & 0xff) << 24)
+#define CMD3_CONT_READ_CODE(x)   (((x) & 0xff) << 16)
+#define CMD3_CE(x)               (((x) & 0x3) << 8)
+#define CMD3_SERIAL_MODE         (0 << 5)
+#define CMD3_DUAL_MODE           (1 << 5)
+#define CMD3_QUAD_MODE           (2 << 5)
+#define CMD3_DUAL_IO_MODE        (3 << 5)
+#define CMD3_QUAD_IO_MODE        (4 << 5)
+
+#define CMD3_DTR_MODE_EN         BIT(4)
+
+#define CMD3_RDST_SW             BIT(3)
+#define CMD3_RDST_HW             0
+
+#define CMD3_RDST                BIT(2)
+
+#define CMD3_WRITE               BIT(1)
+#define CMD3_READ                0
+
+#define CMD3_CMD_COMPL_INTR      BIT(0)
+
+#endif
diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c
index 05dc644..7c354ce 100644
--- a/drivers/mtd/spi/winbond.c
+++ b/drivers/mtd/spi/winbond.c
@@ -18,6 +18,21 @@ struct winbond_spi_flash_params {
 
 static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {
 	{
+		.id			= 0x2014,
+		.nr_blocks		= 16,
+		.name			= "W25P80",
+	},
+	{
+		.id			= 0x2015,
+		.nr_blocks		= 32,
+		.name			= "W25P16",
+	},
+	{
+		.id			= 0x2016,
+		.nr_blocks		= 64,
+		.name			= "W25P32",
+	},
+	{
 		.id			= 0x3013,
 		.nr_blocks		= 8,
 		.name			= "W25X40",
@@ -99,7 +114,7 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
 	}
 
 	flash->page_size = 256;
-	flash->sector_size = 4096;
+	flash->sector_size = (idcode[1] == 0x20) ? 65536 : 4096;
 	flash->size = 4096 * 16 * params->nr_blocks;
 
 	return flash;
-- 
1.7.9.5

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

* [U-Boot] [PATCH 10/11] mmc: add an alternative FTSDC010 driver support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (8 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 09/11] mtd/spi: add FTSPI020 SPI Flash " Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-03-29  7:06 ` [U-Boot] [PATCH 11/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (8 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTSDC010 is a MMC/SD host controller.
There is already a driver in u-boot, which is
modified from eSHDC and contributed by Andes Tech.

However it works extreamly slow in Faraday A36x SoC
Platforms, so I turn to implement this new version
of driver with 10 times faster speed, and improved
stability.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/mmc/Makefile       |    1 +
 drivers/mmc/ftsdc010_mci.c |  362 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/mmc/ftsdc010_mci.h |   91 +++++++++++
 3 files changed, 454 insertions(+)
 create mode 100644 drivers/mmc/ftsdc010_mci.c
 create mode 100644 drivers/mmc/ftsdc010_mci.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 65791aa..dfe1b8c 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -33,6 +33,7 @@ COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
 COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 COBJS-$(CONFIG_FTSDC010) += ftsdc010_esdhc.o
+COBJS-$(CONFIG_FTSDC010_MCI) += ftsdc010_mci.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
 COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
new file mode 100644
index 0000000..d07e4ff
--- /dev/null
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -0,0 +1,362 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+
+#include "ftsdc010_mci.h"
+
+#define SD_REG32(chip, off) \
+	*(volatile uint32_t *)((uint8_t *)(chip)->iobase + (off))
+
+struct ftsdc010_chip {
+	uint32_t iobase;
+	uint32_t wprot;   /* write protected (locked) */
+	uint32_t rate;    /* actual SD clock in Hz */
+	uint32_t sclk;    /* FTSDC010 source clock in Hz */
+	uint32_t fifo;    /* fifo depth in bytes */
+	uint32_t acmd;
+};
+
+static inline int
+ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	uint32_t timeout;
+
+	uint32_t cmd   = mmc_cmd->cmdidx;
+	uint32_t arg   = mmc_cmd->cmdarg;
+	uint32_t flags = mmc_cmd->resp_type;
+
+	cmd |= CMD_EN;
+
+	if (chip->acmd) {
+		cmd |= CMD_APP;
+		chip->acmd = 0;
+	}
+
+	if (flags & MMC_RSP_PRESENT)
+		cmd |= CMD_WAIT_RSP;
+
+	if (flags & MMC_RSP_136)
+		cmd |= CMD_LONG_RSP;
+
+	SD_REG32(chip, REG_SCR) = SR_RSP_ERR | SR_RSP | SR_CMD;
+
+	SD_REG32(chip, REG_ARG) = arg;
+
+	SD_REG32(chip, REG_CMD) = cmd;
+
+	if ((flags & (MMC_RSP_PRESENT | MMC_RSP_136)) == 0) {
+		for (timeout = 250000; timeout > 0; --timeout) {
+			if (SD_REG32(chip, REG_SR) & SR_CMD) {
+				SD_REG32(chip, REG_SCR) = SR_CMD;
+				break;
+			}
+			udelay(1);
+		}
+	} else {
+		for (timeout = 250000; timeout > 0; --timeout) {
+			uint32_t st = SD_REG32(chip, REG_SR);
+			if (st & SR_RSP) {
+				SD_REG32(chip, REG_SCR) = SR_RSP;
+				if (flags & MMC_RSP_136) {
+					mmc_cmd->response[0] = SD_REG32(chip, REG_RSP3);
+					mmc_cmd->response[1] = SD_REG32(chip, REG_RSP2);
+					mmc_cmd->response[2] = SD_REG32(chip, REG_RSP1);
+					mmc_cmd->response[3] = SD_REG32(chip, REG_RSP0);
+				} else {
+					mmc_cmd->response[0] = SD_REG32(chip, REG_RSP0);
+				}
+				break;
+			} else if (st & SR_RSP_ERR) {
+				SD_REG32(chip, REG_SCR) = SR_RSP_ERR;
+				debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n", mmc_cmd->cmdidx, st);
+				return TIMEOUT;
+			}
+			udelay(1);
+		}
+	}
+
+	if (timeout == 0) {
+		debug("ftsdc010: cmd timeout (op code=%d)\n", mmc_cmd->cmdidx);
+		return TIMEOUT;
+	}
+
+	if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD)
+		chip->acmd = 1;
+
+	return 0;
+}
+
+static int
+ftsdc010_wait(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	uint32_t mask = SR_DAT | SR_DAT_END | SR_DAT_ERR;
+	uint32_t timeout;
+
+	for (timeout = 250000; timeout; --timeout) {
+		uint32_t st = SD_REG32(chip, REG_SR);
+		SD_REG32(chip, REG_SCR) = (st & mask);
+
+		if (st & SR_DAT_ERR) {
+			printf("ftsdc010: data error!(st=0x%x)\n", st);
+			return TIMEOUT;
+		} else if (st & SR_DAT_END) {
+			break;
+		}
+		udelay(1);
+	}
+
+	if (timeout == 0) {
+		debug("ftsdc010: wait timeout\n");
+		return TIMEOUT;
+	}
+
+	return 0;
+}
+
+static void
+ftsdc010_clkset(struct ftsdc010_chip *chip, uint32_t rate)
+{
+	uint32_t div;
+	uint32_t clk = chip->sclk;
+
+	for (div = 0; div < 0x7F; ++div) {
+		if (rate >= clk / (2 * (div + 1)))
+			break;
+	}
+	SD_REG32(chip, REG_CLK) = CLK_SD | div;
+
+	chip->rate = clk / (2 * (div + 1));
+}
+
+static inline int
+ftsdc010_is_ro(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	const uint8_t *csd = (const uint8_t *)mmc->csd;
+
+	if (chip->wprot || (csd[1] & 0x30))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * u-boot mmc api
+ */
+
+static int ftsdc010_request(struct mmc *mmc,
+							struct mmc_cmd *cmd,
+							struct mmc_data *data)
+{
+	int rc;
+	uint32_t len = 0;
+	struct ftsdc010_chip *chip = mmc->priv;
+
+	if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
+		printf("ftsdc010: the card is write protected!\n");
+		return UNUSABLE_ERR;
+	}
+
+	if (data) {
+		uint32_t dcr;
+
+		len = data->blocksize * data->blocks;
+
+		/* 1. data disable + fifo reset */
+		SD_REG32(chip, REG_DCR) = DCR_FIFO_RESET;
+
+		/* 2. clear status register */
+		SD_REG32(chip, REG_SCR) = SR_DAT_END | SR_DAT | SR_DAT_ERR | SR_TXRDY | SR_RXRDY;
+
+		/* 3. data timeout (1 sec) */
+		SD_REG32(chip, REG_DTR) = chip->rate;
+
+		/* 4. data length (bytes) */
+		SD_REG32(chip, REG_DLR) = len;
+
+		/* 5. data enable */
+		dcr = (ffs(data->blocksize) - 1) | DCR_EN;
+		if (data->flags & MMC_DATA_WRITE)
+			dcr |= DCR_WR;
+		SD_REG32(chip, REG_DCR) = dcr;
+	}
+
+	rc = ftsdc010_send_cmd(mmc, cmd);
+	if (rc) {
+		printf("ftsdc010: sending CMD%d failed\n", cmd->cmdidx);
+		return rc;
+	}
+
+	if (!data)
+		return rc;
+
+	if (data->flags & MMC_DATA_WRITE) {
+		const uint8_t *buf = (const uint8_t *)data->src;
+
+		while (len > 0) {
+			int wlen;
+
+			/* wait data ready */
+			while (!(SD_REG32(chip, REG_SR) & SR_TXRDY))
+				;
+			SD_REG32(chip, REG_SCR) = SR_TXRDY;
+
+			/* write bytes to ftsdc010 */
+			for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
+				SD_REG32(chip, REG_DR) = *(uint32_t *)buf;
+				buf  += 4;
+				wlen += 4;
+			}
+
+			len -= wlen;
+		}
+
+	} else {
+		uint8_t *buf = (uint8_t *)data->dest;
+
+		while (len > 0) {
+			int rlen;
+
+			/* wait data ready */
+			while (!(SD_REG32(chip, REG_SR) & SR_RXRDY))
+				;
+			SD_REG32(chip, REG_SCR) = SR_RXRDY;
+
+			/* fetch bytes from ftsdc010 */
+			for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
+				*(uint32_t *)buf = SD_REG32(chip, REG_DR);
+				buf  += 4;
+				rlen += 4;
+			}
+
+			len -= rlen;
+		}
+
+	}
+
+	rc = ftsdc010_wait(mmc);
+	return rc;
+}
+
+static void ftsdc010_set_ios(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+
+	ftsdc010_clkset(chip, mmc->clock);
+
+	if (mmc->clock > 25000000)
+		SD_REG32(chip, REG_CLK) |= CLK_HISPD;
+	else
+		SD_REG32(chip, REG_CLK) &= ~CLK_HISPD;
+
+	SD_REG32(chip, REG_BUS) &= 0xFFFFFFF8;
+	switch (mmc->bus_width) {
+	case 4:
+		SD_REG32(chip, REG_BUS) |= 0x04;
+		break;
+	case 8:
+		SD_REG32(chip, REG_BUS) |= 0x02;
+		break;
+	default:
+		SD_REG32(chip, REG_BUS) |= 0x01;
+		break;
+	}
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+
+	if (SD_REG32(chip, REG_SR) & SR_CARD_REMOVED)
+		return NO_CARD_ERR;
+
+	if (SD_REG32(chip, REG_SR) & SR_WPROT) {
+		printf("ftsdc010: write protected\n");
+		chip->wprot = 1;
+	}
+
+	chip->fifo = (SD_REG32(chip, REG_FEAR) & 0xFF) << 2;
+
+	/* 1. chip reset */
+	SD_REG32(chip, REG_CMD) = CMD_RST;
+	while (SD_REG32(chip, REG_CMD) & CMD_RST)
+		;
+
+	/* 2. enter low speed mode (400k card detection) */
+	ftsdc010_clkset(chip, 400000);
+
+	/* 3. interrupt disabled */
+	SD_REG32(chip, REG_IER) = 0;
+
+	return 0;
+}
+
+int ftsdc010_mmc_init(int devid)
+{
+	struct mmc *mmc = NULL;
+	struct ftsdc010_chip *chip = NULL;
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		return -ENOMEM;
+	memset(mmc, 0, sizeof(struct mmc));
+
+	chip = malloc(sizeof(struct ftsdc010_chip));
+	if (!chip) {
+		free(mmc);
+		return -ENOMEM;
+	}
+	memset(chip, 0, sizeof(struct ftsdc010_chip));
+
+	chip->iobase = CONFIG_FTSDC010_BASE + (devid << 20);
+	mmc->priv    = chip;
+
+	sprintf(mmc->name, "ftsdc010");
+	mmc->send_cmd = ftsdc010_request;
+	mmc->set_ios  = ftsdc010_set_ios;
+	mmc->init     = ftsdc010_init;
+
+	switch ((SD_REG32(chip, REG_BUS) >> 3) & 3) {
+	case 1:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT;
+		break;
+	case 2:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz | MMC_MODE_4BIT | MMC_MODE_8BIT;
+		break;
+	default:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+		break;
+	}
+
+#ifdef CONFIG_SYS_CLK_FREQ
+	chip->sclk = CONFIG_SYS_CLK_FREQ;
+#else
+	chip->sclk = clk_get_rate("SDC");
+#endif
+
+	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->f_max     = chip->sclk / 2;
+	mmc->f_min     = chip->sclk / 0x100;
+	mmc->block_dev.part_type = PART_TYPE_DOS;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/drivers/mmc/ftsdc010_mci.h b/drivers/mmc/ftsdc010_mci.h
new file mode 100644
index 0000000..86d8c9f
--- /dev/null
+++ b/drivers/mmc/ftsdc010_mci.h
@@ -0,0 +1,91 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTSDC010_MCI_H
+#define __FTSDC010_MCI_H
+
+#include <faraday/ftsdc010.h>
+
+/* sd controller register */
+#define REG_CMD                0x0000
+#define REG_ARG                0x0004
+#define REG_RSP0               0x0008    /* response */
+#define REG_RSP1               0x000C
+#define REG_RSP2               0x0010
+#define REG_RSP3               0x0014
+#define REG_RSPCMD             0x0018    /* responsed command */
+#define REG_DCR                0x001C    /* data control */
+#define REG_DTR                0x0020    /* data timeout */
+#define REG_DLR                0x0024    /* data length */
+#define REG_SR                 0x0028    /* status register */
+#define REG_SCR                0x002C    /* status clear register */
+#define REG_IER                0x0030    /* interrupt mask/enable register */
+#define REG_PWR                0x0034    /* power control */
+#define REG_CLK                0x0038    /* clock control */
+#define REG_BUS                0x003C    /* bus width */
+#define REG_DR                 0x0040    /* data register */
+#define REG_GPOR               0x0048    /* general purpose output register */
+#define REG_FEAR               0x009C    /* feature register */
+#define REG_REVR               0x00A0    /* revision register */
+
+/* bit mapping of command register */
+#define CMD_IDX                0x0000003F
+#define CMD_WAIT_RSP           0x00000040
+#define CMD_LONG_RSP           0x00000080
+#define CMD_APP                0x00000100
+#define CMD_EN                 0x00000200
+#define CMD_RST                0x00000400
+
+/* bit mapping of response command register */
+#define RSP_CMDIDX             0x0000003F
+#define RSP_CMDAPP             0x00000040
+
+/* bit mapping of data control register */
+#define DCR_BKSZ               0x0000000F
+#define DCR_WR                 0x00000010
+#define DCR_RD                 0x00000000
+#define DCR_DMA                0x00000020
+#define DCR_EN                 0x00000040
+#define DCR_THRES              0x00000080
+#define DCR_BURST1             0x00000000
+#define DCR_BURST4             0x00000100
+#define DCR_BURST8             0x00000200
+#define DCR_FIFO_RESET         0x00000400
+
+/* bit mapping of status register */
+#define SR_RSP_CRC            0x00000001
+#define SR_DAT_CRC            0x00000002
+#define SR_RSP_TIMEOUT        0x00000004
+#define SR_DAT_TIMEOUT        0x00000008
+#define SR_RSP_ERR            (SR_RSP_CRC | SR_RSP_TIMEOUT)
+#define SR_DAT_ERR            (SR_DAT_CRC | SR_DAT_TIMEOUT)
+#define SR_RSP                0x00000010
+#define SR_DAT                0x00000020
+#define SR_CMD                0x00000040
+#define SR_DAT_END            0x00000080
+#define SR_TXRDY              0x00000100
+#define SR_RXRDY              0x00000200
+#define SR_CARD_CHANGE        0x00000400
+#define SR_CARD_REMOVED       0x00000800
+#define SR_WPROT              0x00001000
+#define SR_SDIO               0x00010000
+#define SR_DAT0               0x00020000
+
+/* bit mapping of clock register */
+#define CLK_HISPD              0x00000200
+#define CLK_OFF                0x00000100
+#define CLK_SD                 0x00000080
+
+/* bit mapping of bus register */
+#define BUS_CARD_DATA3         0x00000020
+#define BUS_4BITS_SUPP         0x00000008
+#define BUS_8BITS_SUPP         0x00000010
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH 11/11] arm: add Faraday A36x SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (9 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 10/11] mmc: add an alternative FTSDC010 driver support Kuo-Jung Su
@ 2013-03-29  7:06 ` Kuo-Jung Su
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                   ` (7 subsequent siblings)
  18 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-03-29  7:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday A36x EVB is a Faraday SoC platform evalution board used for
Faraday IP functional verification based on the well-known ARM AMBA 2.0
architecture.

Faraday A360 EVB:
   CPU: FA626TE
   NET: FTMAC110
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC010
   WDT: FTWDT010
   TMR: FTTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC020

Faraday A369 EVB:
   CPU: FA626TE(Master)/FA606TE(Slave)
   NET: FTGMAC100
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC011
   WDT: FTWDT010
   TMR: FTPWMTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC021

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 arch/arm/cpu/faraday/Makefile             |   57 +++
 arch/arm/cpu/faraday/a360/Makefile        |   49 +++
 arch/arm/cpu/faraday/a360/reset.c         |   22 ++
 arch/arm/cpu/faraday/a369/Makefile        |   50 +++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   74 ++++
 arch/arm/cpu/faraday/a369/reset.c         |   22 ++
 arch/arm/cpu/faraday/cmd_bootfa.c         |  121 +++++++
 arch/arm/cpu/faraday/config.mk            |   33 ++
 arch/arm/cpu/faraday/cpu.c                |  230 +++++++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  165 +++++++++
 arch/arm/cpu/faraday/fttmr010.c           |  155 +++++++++
 arch/arm/cpu/faraday/fwimage.h            |   38 ++
 arch/arm/cpu/faraday/fwimage2.h           |   70 ++++
 arch/arm/cpu/faraday/interrupts.c         |  169 +++++++++
 arch/arm/cpu/faraday/start.S              |  535 +++++++++++++++++++++++++++++
 arch/arm/cpu/u-boot.lds                   |   11 +
 arch/arm/include/asm/arch-a360/hardware.h |   80 +++++
 arch/arm/include/asm/arch-a369/hardware.h |  106 ++++++
 arch/arm/include/asm/mach-types.h         |    1 +
 board/faraday/a360evb/Makefile            |   49 +++
 board/faraday/a360evb/board.c             |   65 ++++
 board/faraday/a360evb/clk.c               |   48 +++
 board/faraday/a360evb/config.mk           |   33 ++
 board/faraday/a360evb/lowlevel_init.S     |   33 ++
 board/faraday/a369evb/Makefile            |   49 +++
 board/faraday/a369evb/board.c             |  182 ++++++++++
 board/faraday/a369evb/clk.c               |   80 +++++
 board/faraday/a369evb/config.mk           |   33 ++
 board/faraday/a369evb/lowlevel_init.S     |  133 +++++++
 boards.cfg                                |    3 +
 include/common.h                          |   13 +
 include/configs/a360.h                    |  180 ++++++++++
 include/configs/a369.h                    |   40 +++
 include/configs/a369_defaults.h           |  285 +++++++++++++++
 include/configs/a369_fa606te.h            |   32 ++
 include/faraday/fttmr010.h                |   51 ++-
 include/faraday/ftwdt010_wdt.h            |    8 +
 37 files changed, 3301 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/reset.c
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/a369/reset.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_defaults.h
 create mode 100644 include/configs/a369_fa606te.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..fb712a1
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,57 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+src-y						:= interrupts.o
+src-$(CONFIG_FTPWMTMR010)	+= ftpwmtmr010.o
+src-$(CONFIG_FTTMR010)		+= fttmr010.o
+
+START	= start.o
+COBJS	= cpu.o cmd_bootfa.o $(src-y)
+
+ifdef	CONFIG_SPL_BUILD
+ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE
+START	:=
+endif
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..ccd55fa
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   := reset.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a360/reset.c b/arch/arm/cpu/faraday/a360/reset.c
new file mode 100644
index 0000000..3a1b607
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/reset.c
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/cpu/faraday/a360/reset.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <faraday/ftwdt010_wdt.h>
+
+#define WDT_REG32(off)		REG32(CONFIG_FTWDT010_BASE + (off))
+
+void reset_cpu(unsigned long ignored)
+{
+	WDT_REG32(REG_CR)      = 0;
+	WDT_REG32(REG_LOAD)    = 1000;
+	WDT_REG32(REG_CR)      = FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST;
+	WDT_REG32(REG_RESTART) = FTWDT010_WDRESTART_MAGIC;
+}
diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..5c68d2d
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y                   := reset.o
+obj-$(CONFIG_CMD_FA606) += cmd_fa606.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/cmd_fa606.c b/arch/arm/cpu/faraday/a369/cmd_fa606.c
new file mode 100644
index 0000000..bc1f3b6
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/cmd_fa606.c
@@ -0,0 +1,74 @@
+/*
+ * arch/arm/cpu/faraday/a369/cmd_fa606.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would start the A369 slave cpu - FA606TE, and also immediately
+ * halt the master cpu - FA626TE.
+ */
+
+#include <common.h>
+#include <command.h>
+
+static int do_fa606(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int addr = CONFIG_SYS_LOAD_ADDR;
+
+	if (argc >= 2)
+		addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("FA606 Image at 0x%08X\n", addr);
+	printf("FA626 is going to enter IDLE state, and never wake-up......\n");
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+	cleanup_before_linux();
+#endif
+
+	/* 1. FA606TE address offset */
+#if 1    /* No address shift */
+	printf("FA606 address shift disable.\n");
+	REG32(CONFIG_AHBC2_BASE + 0x90) = 0;
+	REG32(0x20) = addr;
+	REG32(0x00) = 0xEA00000A;        /* b    0x30 */
+	REG32(0x30) = 0xE3A00020;        /* mov    r0, #32    ; 0x20 */
+	REG32(0x34) = 0xE590F000;        /* ldr    pc, [r0] */
+#else    /* Enable address shift */
+	printf("FA606 address shift =0x%08X\n", addr);
+	REG32(CONFIG_AHBC2_BASE + 0x90) = addr;
+#endif
+
+	/* 2. ICE + LCD    */
+	REG32(CONFIG_SCU_BASE + 0x200) = 0x00001078;
+	REG32(CONFIG_SCU_BASE + 0x228) = 0x26877330;
+	REG32(CONFIG_SCU_BASE + 0x22C) = 0x000A0A0A;
+	REG32(CONFIG_SCU_BASE + 0x230) = 0x00003FFF;
+	REG32(CONFIG_SCU_BASE + 0x238) = 0x00000065;
+	REG32(CONFIG_SCU_BASE + 0x23C) = 0x00000080;
+	udelay(5000);
+
+	/* 3. FA606 clock enable & reset */
+	REG32(CONFIG_SCU_BASE + 0x028) = 0;
+	udelay(5000);
+	REG32(CONFIG_SCU_BASE + 0x200) = 0x00001878;
+
+	/* 4. FA626 is going to enter IDLE state, and never wake-up */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15,0,r3,c7,c0,4\n"
+		:
+		:
+		: "r3"    /* clobber list */
+	);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	fa606, 2, 0, do_fa606,
+	"launch firmware with A369's built-in fa606te\n",
+	"fa606 [address] - mov pc of fa606te to the specified address.\n"
+);
diff --git a/arch/arm/cpu/faraday/a369/reset.c b/arch/arm/cpu/faraday/a369/reset.c
new file mode 100644
index 0000000..74211cf
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/reset.c
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/cpu/faraday/a369/reset.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <faraday/ftwdt010_wdt.h>
+
+#define WDT_REG32(off)		REG32(CONFIG_FTWDT010_BASE + (off))
+
+void reset_cpu(unsigned long ignored)
+{
+	WDT_REG32(REG_CR)      = 0;
+	WDT_REG32(REG_LOAD)    = 1000;
+	WDT_REG32(REG_CR)      = FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST;
+	WDT_REG32(REG_RESTART) = FTWDT010_WDRESTART_MAGIC;
+}
diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..f491e9c
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,121 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would try to boot faraday image from MMC/SD/USB/SPI/NAND/NOR
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *part = hdr->part;
+
+	for (i = 0; part[i].length > 0 && i < 10; ++i) {
+		if (strcmp(name, part[i].name) == 0) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				part[i].name, part[i].offset, part[i].length);
+			return part + i;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s", CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s", CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400", CONFIG_SYS_FLASH_BASE, CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((struct fwimage2 *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x", CONFIG_SYS_FLASH_BASE + part->offset, CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((struct fwimage2 *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x", CONFIG_SYS_LOAD_ADDR, part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((struct fwimage2 *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x", CONFIG_SYS_LOAD_ADDR, part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..ffb2e6c
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
+
+PLATFORM_CPPFLAGS += -march=armv5te
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..50fc77c
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,230 @@
+/*
+ * arch/arm/cpu/faraday/cpu.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/system.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+
+	disable_interrupts();
+
+	/* turn off D-cache */
+	dcache_disable();
+
+	/* flush I-cache */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15, 0, r3, c7, c5, 0\n" /* invalidate i-cache all */
+		:      /* output */
+		:      /* input */
+		: "r3" /* clobber list */
+	);
+
+	return 0;
+}
+
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#else
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c14,0\n"    /* clean & invalidate d-cache all */
+		"mcr p15,0,r3,c7,c10,4\n"    /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n"    /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c10,4\n"    /* drain write buffer */
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)    /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n"    /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)    /* input */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c6,0\n"    /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c5,0\n"    /* invalidate i-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
+
+void enable_caches(void)
+{
+	icache_enable();
+
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		puts("MMU:   on\n");
+		dcache_enable();
+	} else
+#endif
+		puts("MMU:   off\n");
+}
+
+#ifdef CONFIG_ARCH_CPU_INIT
+
+int arch_cpu_init(void)
+{
+	unsigned int id, ctr;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		"mrc p15, 0, %1, c0, c0, 1\n"
+		: "=r"(id), "=r"(ctr) /* output */
+		: /* input */
+	);
+
+	gd->arch.cpu_id = id;
+
+	/* MMU/D-Cache */
+	switch (gd->arch.cpu_id >> 4) {
+	case 0x6604526:    /* FA526 */
+	case 0x6604626:    /* FA626 */
+	case 0x6605606:    /* FA606TE */
+		/* Disable MMU/D-Cache */
+		gd->arch.cpu_mmu = 0;
+		break;
+	default:
+		/* Enable MMU/D-Cache */
+		gd->arch.cpu_mmu = 1;
+		break;
+	}
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+
+	/* build cpu name */
+	if ((gd->arch.cpu_id >> 24) == 0x66) {
+		switch (gd->arch.cpu_id >> 16) {
+		case 0x6605:
+			sprintf(cpu_name, "FA%xTE",
+				(unsigned int)(gd->arch.cpu_id >> 4)  & 0xFFF);
+			break;
+
+		case 0x6601:
+		default:
+			sprintf(cpu_name, "FA%x",
+				(unsigned int)(gd->arch.cpu_id >> 4)  & 0xFFF);
+			break;
+		}
+	} else {
+		sprintf(cpu_name, "ARM%x",
+			(unsigned int)(gd->arch.cpu_id >> 4)  & 0xFFF);
+	}
+
+	/* print cpuinfo */
+	printf("CPU:   %s %u MHz\n",
+		cpu_name, (unsigned int)(clk_get_rate("CPU") / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("AHB") / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("APB") / 1000000));
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_DISPLAY_CPUINFO */
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..fe57077
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,165 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+
+#define TMR_REG32(off)			REG32(CONFIG_TIMER_BASE + (off))
+
+#define REG_TMR_STAT(id)		(0x00)
+#define REG_TMR_BASE(id)		((id) << 4)
+#define REG_TMR_CTRL(id)		(REG_TMR_BASE(id) + 0x00)
+#define REG_TMR_CNTB(id)		(REG_TMR_BASE(id) + 0x04)
+#define REG_TMR_CMPB(id)		(REG_TMR_BASE(id) + 0x08)
+#define REG_TMR_CNTO(id)		(REG_TMR_BASE(id) + 0x0C)
+
+#define TMR_STAT_MASK(id)		(1 << ((id) - 1))
+
+#define TMR_CTRL_START			(1 << 1)
+#define TMR_CTRL_UPDATE			(1 << 2)
+#define TMR_CTRL_AUTORELOAD		(1 << 4)
+#define TMR_CTRL_INTEN			(1 << 5)
+
+#ifdef CONFIG_A369_FA606TE_PLATFORM
+#define ID_BASE    4
+#else
+#define ID_BASE    0
+#endif
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+
+void udelay_masked(unsigned long usec)
+{
+	int id = ID_BASE + 2;
+
+	/* timer disable */
+	TMR_REG32(REG_TMR_STAT(id)) = TMR_STAT_MASK(id);
+
+	/* timer start */
+	TMR_REG32(REG_TMR_CTRL(id)) = 0;
+	TMR_REG32(REG_TMR_CMPB(id)) = 0;
+	TMR_REG32(REG_TMR_CNTB(id)) = (sclk / 1000000) * usec;
+	TMR_REG32(REG_TMR_CTRL(id)) = TMR_CTRL_INTEN | TMR_CTRL_START | TMR_CTRL_UPDATE;
+
+	/* wait for timer interrupt status */
+	while (!(TMR_REG32(REG_TMR_STAT(id)) & TMR_STAT_MASK(id)))
+		;
+
+	/* timer disable */
+	TMR_REG32(REG_TMR_STAT(id)) = TMR_STAT_MASK(id);
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	int id = ID_BASE + 1;
+	++ticks;
+	TMR_REG32(REG_TMR_STAT(id)) = TMR_STAT_MASK(id);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	int id = ID_BASE + 1;
+
+	/* hardware reset */
+	TMR_REG32(REG_TMR_STAT(id)) = TMR_STAT_MASK(id);
+
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	TMR_REG32(REG_TMR_CTRL(id)) = 0;
+	TMR_REG32(REG_TMR_CMPB(id)) = 0;
+	TMR_REG32(REG_TMR_CNTB(id)) = sclk / CONFIG_SYS_HZ;
+	TMR_REG32(REG_TMR_CTRL(id)) = TMR_CTRL_AUTORELOAD
+								  | TMR_CTRL_INTEN
+								  | TMR_CTRL_START
+								  | TMR_CTRL_UPDATE;
+
+	irq_install_handler(CONFIG_TIMER_IRQ, (interrupt_handler_t *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+#else
+	/* setup a 30 sec one-shot timer */
+	TMR_REG32(REG_TMR_CTRL(id)) = 0;
+	TMR_REG32(REG_TMR_CMPB(id)) = 0;
+	TMR_REG32(REG_TMR_CNTB(id)) = 30 * sclk;
+	TMR_REG32(REG_TMR_CTRL(id)) = TMR_CTRL_INTEN | TMR_CTRL_START | TMR_CTRL_UPDATE;
+#endif    /* #ifdef CONFIG_USE_IRQ */
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = (30 * sclk - TMR_REG32(REG_TMR_CNTO(ID_BASE + 1))) / s;
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+	sclk  = clk_get_rate("APB");
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (TMR_REG32(REG_TMR_CNTO(ID_BASE + 1)) == 0) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..9add1f6
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,155 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <faraday/fttmr010.h>
+
+#define TMR_REG32(off)			REG32(CONFIG_TIMER_BASE + (off))
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+
+void udelay_masked(unsigned long usec)
+{
+	/* Disable Timer2 */
+	TMR_REG32(REG_CR) &= ~FTTMR010_TM2_CRMASK;
+	TMR_REG32(REG_IMR) = FTTMR010_TM2_ISRMASK;	/* disable timer2 interrupts */
+	TMR_REG32(REG_ISR) = FTTMR010_TM2_ISRMASK;	/* clear timer2 interrupts */
+
+	/* Init Timer2 */
+	TMR_REG32(REG_TMR2_COUNTER) = (sclk / 1000000) * usec;
+	TMR_REG32(REG_TMR2_RELOAD)  = 0;
+	TMR_REG32(REG_TMR2_MATCH1)  = 0;
+	TMR_REG32(REG_TMR2_MATCH2)  = 0;
+
+	/* Enable Timer2 */
+	TMR_REG32(REG_CR) |= FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE;
+
+	/* Wait until timeout */
+	while (!(TMR_REG32(REG_ISR) & FTTMR010_TM2_ISRMASK))
+		;
+
+	/* Disable Timer2 */
+	TMR_REG32(REG_CR) &= ~FTTMR010_TM2_CRMASK;
+	TMR_REG32(REG_IMR) = FTTMR010_TM2_ISRMASK;
+	TMR_REG32(REG_ISR) = FTTMR010_TM2_ISRMASK;
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	++ticks;
+	TMR_REG32(REG_ISR) = FTTMR010_TM1_ISRMASK;
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	/* timer1 reset */
+	TMR_REG32(REG_CR) &= ~FTTMR010_TM1_CRMASK;
+	TMR_REG32(REG_IMR) = FTTMR010_TM1_MATCH1;	/* disable timer1 interrupts */
+	TMR_REG32(REG_ISR) = FTTMR010_TM1_ISRMASK;	/* clear timer1 interrupts */
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt init */
+	irq_set_trigger(CONFIG_TIMER_IRQ, 1, 0);
+	irq_install_handler(CONFIG_TIMER_IRQ, (interrupt_handler_t *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+#endif
+
+	/* timer1 setup */
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	TMR_REG32(REG_TMR1_COUNTER) = sclk / CONFIG_SYS_HZ; /* counter */
+	TMR_REG32(REG_TMR1_RELOAD)  = sclk / CONFIG_SYS_HZ; /* reload */
+#else
+	/* setup a 30 sec one-shot timer */
+	TMR_REG32(REG_TMR1_COUNTER) = 30 * sclk;            /* counter */
+	TMR_REG32(REG_TMR1_RELOAD)  = 0;                    /* reload */
+#endif
+	TMR_REG32(REG_TMR1_MATCH1)  = 0;                     /* match1 */
+	TMR_REG32(REG_TMR1_MATCH2)  = 0;                     /* match2 */
+
+	/* timer1 enable overflow interrupt */
+	TMR_REG32(REG_IMR) = FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2;
+
+	/* timer1 start */
+	TMR_REG32(REG_CR) |= FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE;
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = ((30 * sclk) - TMR_REG32(REG_TMR1_COUNTER)) / s;
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+	sclk  = clk_get_rate("APB");
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (TMR_REG32(REG_TMR1_COUNTER) == 0) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..dd1a453
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/cpu/faraday/fwimage.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t	count;
+	uint32_t	version; /* ycmo100525: for firmware image version */
+	uint32_t	addr[31];
+	uint32_t	data[31];
+};
+
+struct fwfile {
+	char		name[64];
+	uint32_t	size;
+	/* uint32_t	block[1]; */
+};
+
+struct fwimage {
+	/* 8 bytes */
+	uint32_t		magic;	/* The magic number for the specific platform */
+	uint32_t		length;	/* It shall not be greater than 2048 */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam	param;
+
+	struct fwfile	file[1];
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..d6da7da
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/cpu/faraday/fwimage2.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+
+#include <image.h>
+#include "fwimage.h"
+
+/* 8 bytes struct for generic 32-bit memory write */
+struct fwmw32 {
+	uint32_t    addr;
+	uint32_t    data;
+};
+
+/* 72 bytes */
+struct fwpart {
+	/* offset: 0 ~ 63 */
+	char		name[32];
+
+	uint32_t	offset;
+	uint32_t	length;
+
+	uint32_t	load;
+	uint32_t	qcrc;		/* Quick CRC32 against 256KB of both TOP and BOTTOM */
+
+	uint32_t	flag;
+#define FWIMAGE2_FLAG_UIMAGE		0x00000001		/* Is a uImage ? */
+#define FWIMAGE2_FLAG_FILESYSTEM	0x00000010		/* Is a filesystem ? */
+
+	uint8_t		rsvd[12];
+
+	/* offset: 64 ~ 71 */
+	uint32_t	magic1000;		/* It should always be 0x00001000 */
+	uint32_t	magic0001;		/* It should always be 0x00000001 */
+};
+
+struct fwimage2 {
+	/*   4 bytes, magic */
+	uint32_t		magic;			/* Image Header Magic Number */
+#define FWIMAGE2_MAGIC			0x00484946		/* "FIH\0" */
+
+	/*   4 bytes, header length */
+	uint32_t	hlen;			/* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwmw32	mw32[32];
+
+	/* 720 bytes, firmware partition table */
+	struct fwpart	part[10];
+
+	/*   4 bytes */
+	uint32_t		hcrc;			/* Image Header Checksum (CRC32) */
+
+	/*   4 bytes, revision */
+	uint32_t		revision;		/* Image Header Revision Code */
+#define FWIMAGE2_REVISION		0x00000201		/* v2.1 */
+
+	/*  32 bytes */
+	char			build[32];		/* Build Date (yyyy/mm/dd HH:MM:SS) */
+};	/* Total 1024 bytes */
+
+#endif
diff --git a/arch/arm/cpu/faraday/interrupts.c b/arch/arm/cpu/faraday/interrupts.c
new file mode 100644
index 0000000..8a5d942
--- /dev/null
+++ b/arch/arm/cpu/faraday/interrupts.c
@@ -0,0 +1,169 @@
+/*
+ * arch/arm/cpu/faraday/interrupts.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USE_IRQ
+
+#define PIC_REG32(off)	REG32(CONFIG_PIC_BASE + (off))
+
+/* IRQ/FIQ: 0 ~ 31 */
+#define REG_IRQ32SRC    0x00    /* IRQ source register */
+#define REG_IRQ32ENA    0x04    /* IRQ enable register */
+#define REG_IRQ32SCR    0x08    /* IRQ status clear register */
+#define REG_IRQ32MDR    0x0C    /* IRQ trigger mode register */
+#define REG_IRQ32LVR    0x10    /* IRQ trigger level register */
+#define REG_IRQ32SR     0x14    /* IRQ status register */
+
+#define REG_FIQ32SRC    0x20    /* FIQ source register */
+#define REG_FIQ32ENA    0x24    /* FIQ enable register */
+#define REG_FIQ32SCR    0x28    /* FIQ status clear register */
+#define REG_FIQ32MDR    0x2C    /* FIQ trigger mode register */
+#define REG_FIQ32LVR    0x30    /* FIQ trigger level register */
+#define REG_FIQ32SR     0x34    /* FIQ status register */
+
+/* Extended IRQ/FIQ: 32 ~ 63 */
+#define REG_IRQ64SRC    0x60    /* Extended IRQ source register */
+#define REG_IRQ64ENA    0x64    /* Extended IRQ enable register */
+#define REG_IRQ64SCR    0x68    /* Extended IRQ status clear register */
+#define REG_IRQ64MDR    0x6C    /* Extended IRQ trigger mode register */
+#define REG_IRQ64LVR    0x70    /* Extended IRQ trigger level register */
+#define REG_IRQ64SR     0x74    /* Extended IRQ status register */
+
+#define REG_FIQ64SRC    0x80    /* Extended FIQ source register */
+#define REG_FIQ64ENA    0x84    /* Extended FIQ enable register */
+#define REG_FIQ64SCR    0x88    /* Extended FIQ status clear register */
+#define REG_FIQ64MDR    0x8C    /* Extended FIQ trigger mode register */
+#define REG_FIQ64LVR    0x90    /* Extended FIQ trigger level register */
+#define REG_FIQ64SR     0x94    /* Extended FIQ status register */
+
+struct _irq_handler {
+	void  *data;
+	void (*func)(void *data);
+};
+
+static struct _irq_handler IRQ_HANDLER[64];
+
+static inline void irq_acknowledge(int irq)
+{
+	if (irq < 32)
+		PIC_REG32(REG_IRQ32SCR) = 1 << irq;
+	else
+		PIC_REG32(REG_IRQ64SCR) = 1 << (irq & 0x1f);
+}
+
+void irq_enable(int irq)
+{
+	if (irq < 32)
+		PIC_REG32(REG_IRQ32ENA) |= (1 << irq);
+	else
+		PIC_REG32(REG_IRQ64ENA) |= (1 << (irq & 0x1f));
+}
+
+void irq_disable(int irq)
+{
+	if (irq < 32)
+		PIC_REG32(REG_IRQ32ENA) &= ~(1 << irq);
+	else
+		PIC_REG32(REG_IRQ64ENA) &= ~(1 << (irq & 0x1f));
+}
+
+void irq_set_trigger(int irq, int edge, int low)
+{
+	if (edge) {
+		if (irq < 32)
+			PIC_REG32(REG_IRQ32MDR) |= (1 << irq);
+		else
+			PIC_REG32(REG_IRQ64MDR) |= (1 << (irq & 0x1f));
+	} else {
+		if (irq < 32)
+			PIC_REG32(REG_IRQ32MDR) &= ~(1 << irq);
+		else
+			PIC_REG32(REG_IRQ64MDR) &= ~(1 << (irq & 0x1f));
+	}
+
+	if (low) {
+		if (irq < 32)
+			PIC_REG32(REG_IRQ32LVR) |= (1 << irq);
+		else
+			PIC_REG32(REG_IRQ64LVR) |= (1 << (irq & 0x1f));
+	} else {
+		if (irq < 32)
+			PIC_REG32(REG_IRQ32LVR) &= ~(1 << irq);
+		else
+			PIC_REG32(REG_IRQ64LVR) &= ~(1 << (irq & 0x1f));
+	}
+}
+
+void do_irq(struct pt_regs *pt_regs)
+{
+	int irq;
+	uint32_t stat;
+
+	irq  = 32;
+	stat = PIC_REG32(REG_IRQ64SR);        /* IRQ 32 ~ 63 */
+	if (!stat) {
+		irq  = 0;
+		stat = PIC_REG32(REG_IRQ32SR);    /* IRQ  0 ~ 31 */
+	}
+	irq += ffs(stat) - 1;
+
+	if (irq < 0) {
+		printf("interrupts: no irq!?\n");
+	} else {
+		irq_acknowledge(irq);
+		IRQ_HANDLER[irq].func(IRQ_HANDLER[irq].data);
+	}
+}
+
+static void default_isr(void *data)
+{
+	printf("default_isr():  called for IRQ %d\n", (int)data);
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *hndl, void *data)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = hndl;
+		IRQ_HANDLER[irq].data = data;
+	}
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = default_isr;
+		IRQ_HANDLER[irq].data = (void *)irq;
+		irq_disable(irq);
+	}
+}
+
+int arch_interrupt_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(IRQ_HANDLER); ++i)
+		irq_free_handler(i);
+
+	/* Interrupt Reset */
+	PIC_REG32(REG_IRQ32ENA) = 0;
+	PIC_REG32(REG_IRQ32SCR) = 0xFFFFFFFF;
+	PIC_REG32(REG_IRQ32MDR) = 0;
+	PIC_REG32(REG_IRQ32LVR) = 0;
+
+	PIC_REG32(REG_IRQ64ENA) = 0;
+	PIC_REG32(REG_IRQ64SCR) = 0xFFFFFFFF;
+	PIC_REG32(REG_IRQ64MDR) = 0;
+	PIC_REG32(REG_IRQ64LVR) = 0;
+
+	return 0;
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..c893423
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,535 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#ifdef CONFIG_NAND_SPL /* deprecated, use instead CONFIG_SPL_BUILD */
+	.word	CONFIG_SYS_TEXT_BASE
+#else
+#ifdef CONFIG_SPL_BUILD
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_NAND_U_BOOT
+.globl _end
+_end:
+	.word __bss_end
+#endif
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * Relocate U-Boot to RAM
+	 * It's copied from the old u-boot release.
+	 */
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+	adr	r0, _start          /* r0 <- current position of code   */
+	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
+	teq     r0, r1          /* don't reloc during debug         */
+	bleq    rr_exit
+	ldr	r2, _end_ofs        /* r2 <- size of u-boot             */
+	add	r2, r0, r2          /* r2 <- source end address         */
+
+rr_loop:
+	ldmia r0!, {r3-r10}	/* copy from source address [r0]    */
+	stmia r1!, {r3-r10}	/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end addreee [r2]    */
+	blo	rr_loop
+
+	/* Adjust the pc to use the correct text address */
+	adr	r0, _start
+	ldr	r1, _TEXT_BASE
+	sub r2, pc, r0
+	add r2, r2, #4
+	add pc, r1, r2
+
+rr_exit:
+#endif  /* #if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD) */
+
+	bl	_main
+
+/*------------------------------------------------------------------------------*/
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_NAND_SPL)
+/*
+ * void relocate_code (addr_sp, gd, addr_moni)
+ *
+ * This "function" does not return, instead it continues in RAM
+ * after relocating the monitor code.
+ *
+ */
+	.globl	relocate_code
+relocate_code:
+	mov	r4, r0	/* save addr_sp */
+	mov	r5, r1	/* save addr of gd */
+	mov	r6, r2	/* save addr of destination */
+
+	adr	r0, _start
+	sub	r9, r6, r0		/* r9 <- relocation offset */
+	cmp	r0, r6
+	moveq	r9, #0			/* no relocation. offset(r9) = 0 */
+	beq	relocate_done		/* skip relocation */
+	mov	r1, r6			/* r1 <- scratch for copy loop */
+	ldr	r3, _bss_start_ofs
+	add	r2, r0, r3		/* r2 <- source end address	    */
+
+copy_loop:
+	ldmia	r0!, {r9-r10}		/* copy from source address [r0]    */
+	stmia	r1!, {r9-r10}		/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end address [r2]    */
+	blo	copy_loop
+
+#ifndef CONFIG_SPL_BUILD
+	/*
+	 * fix .rel.dyn relocations
+	 */
+	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
+	sub	r9, r6, r0		/* r9 <- relocation offset */
+	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
+	add	r10, r10, r0		/* r10 <- sym table in FLASH */
+	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
+	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
+	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
+	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
+fixloop:
+	ldr	r0, [r2]		/* r0 <- location to fix up, IN FLASH! */
+	add	r0, r0, r9		/* r0 <- location to fix up in RAM */
+	ldr	r1, [r2, #4]
+	and	r7, r1, #0xff
+	cmp	r7, #23			/* relative fixup? */
+	beq	fixrel
+	cmp	r7, #2			/* absolute fixup? */
+	beq	fixabs
+	/* ignore unknown type of fixup */
+	b	fixnext
+fixabs:
+	/* absolute fix: set location to (offset) symbol value */
+	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
+	add	r1, r10, r1		/* r1 <- address of symbol in table */
+	ldr	r1, [r1, #4]		/* r1 <- symbol value */
+	add	r1, r1, r9		/* r1 <- relocated sym addr */
+	b	fixnext
+fixrel:
+	/* relative fix: increase location by offset */
+	ldr	r1, [r0]
+	add	r1, r1, r9
+fixnext:
+	str	r1, [r0]
+	add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */
+	cmp	r2, r3
+	blo	fixloop
+#endif
+
+relocate_done:
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ)
+	/* adjust exception table */
+	adr r0, _undefined_instruction
+	adr r2, _TEXT_BASE
+	ldr r1, [r2]
+adjustex:
+	ldr r3, [r0]
+	sub r3, r3, r1
+	add r3, r6, r3      /* r6 -> relocaddr */
+	str r3, [r0], #4
+	cmp r0, r2
+	blo adjustex
+
+	/* relocate exception table */
+	adr r0, _start
+	ldr	r1, =CONFIG_SYS_SDRAM_BASE
+	adr r2, _TEXT_BASE
+copyex:
+	ldr r3, [r0], #4 /* copy from source address [r0] */
+	str r3, [r1], #4 /* copy to   target address [r1] */
+	cmp	r0, r2       /* until source end addreee [r2] */
+	blo	copyex
+#endif	/* #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ) */
+	bx	lr
+
+_rel_dyn_start_ofs:
+	.word __rel_dyn_start - _start
+_rel_dyn_end_ofs:
+	.word __rel_dyn_end - _start
+_dynsym_start_ofs:
+	.word __dynsym_start - _start
+
+#endif
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index 3a1083d..fceea9c 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -23,6 +23,8 @@
  * MA 02111-1307 USA
  */

+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -35,6 +37,15 @@ SECTIONS
 	{
 		__image_copy_start = .;
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}

diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..47183bd
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,80 @@
+/*
+ * arch/arm/include/asm/arch-a360/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ASM_ARCH_HW_H
+#define ASM_ARCH_HW_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_NAND_FTNANDC020_BASE	0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+#define CONFIG_FTSSP010_GPIO_BASE	0x98700000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+
+#ifndef __ASSEMBLY__
+
+#define REG32(off)                 *(volatile unsigned long *)(off)
+#define REG16(off)                 *(volatile unsigned short *)(off)
+#define REG8(off)                  *(volatile unsigned char *)(off)
+
+#endif /* __ASSEMBLY__ */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..27f4dfe
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,106 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ASM_ARCH_HW_H
+#define ASM_ARCH_HW_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDR_BASE             0x93100000
+#define CONFIG_AHB_BASE             0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+#define CONFIG_FTSSP010_GPIO_BASE   0x92600000    /* GPIO 1 */
+
+/*
+ * NAND
+ */
+#define CONFIG_NAND_FTNANDC021_BASE 0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE1       0x90600000
+#define CONFIG_FTSDC010_BASE0       0x90500000
+#define CONFIG_FTSDC010_BASE        CONFIG_FTSDC010_BASE1
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+
+/*
+ * Ext. AHB
+ */
+#define CONFIG_EXTAHB_BASE          0xC0000000
+#define CONFIG_FTSPI020_BASE        CONFIG_EXTAHB_BASE
+
+#ifndef __ASSEMBLY__
+
+#define REG32(off)                  *(volatile unsigned long *)(off)
+#define REG16(off)                  *(volatile unsigned short *)(off)
+#define REG8(off)                   *(volatile unsigned char *)(off)
+
+#endif /* __ASSEMBLY__ */
+
+#endif
diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
index a676b6d..64fc68b 100644
--- a/arch/arm/include/asm/mach-types.h
+++ b/arch/arm/include/asm/mach-types.h
@@ -144,6 +144,7 @@ extern unsigned int __machine_arch_type;
 #define MACH_TYPE_AKITA                744
 #define MACH_TYPE_E330                 753
 #define MACH_TYPE_NOKIA770             755
+#define MACH_TYPE_FARADAY              758
 #define MACH_TYPE_CARMEVA              769
 #define MACH_TYPE_EDB9315A             772
 #define MACH_TYPE_STARGATE2            774
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..6c49619
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,65 @@
+/*
+ * board/faraday/a360evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SCU_REG32(off)			REG32(CONFIG_SCU_BASE + (off))
+
+/*
+ * pinmux
+ */
+static void scu_init(void)
+{
+	SCU_REG32(0x24)  = 0x00555500;
+	SCU_REG32(0x18) |= 0x800002AA;
+	SCU_REG32(0x1C) |= 0x82AAAAAA;
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	scu_init();
+
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	extern int ftmac110_initialize(bd_t *bd);
+
+	return ftmac110_initialize(bd);
+}
diff --git a/board/faraday/a360evb/clk.c b/board/faraday/a360evb/clk.c
new file mode 100644
index 0000000..b03c0fc
--- /dev/null
+++ b/board/faraday/a360evb/clk.c
@@ -0,0 +1,48 @@
+/*
+ * board/faraday/a360evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+
+static ulong clk_get_rate_ahb(void)
+{
+	return CONFIG_MAIN_CLK * ((REG32(CONFIG_PMU_BASE + 0x30) >> 3) & 0x3f) / 8;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (REG32(CONFIG_SCU_BASE + 0x14) & 0x200) ? 2 : 4;
+	return (REG32(CONFIG_PMU_BASE + 0x0C) & 0x02) ? (clk * mul) : clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a360evb/config.mk b/board/faraday/a360evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a360evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..1ead608
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,33 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..057ad3d
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,182 @@
+/*
+ * board/faraday/a369evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SCU_REG32(off)			REG32(CONFIG_SCU_BASE + (off))
+#define SMC_REG32(off)			REG32(CONFIG_SMC_BASE + (off))
+#define LCD_REG32(off)			REG32(CONFIG_FTLCDC200_BASE + (off))
+
+/*
+ * pinmux
+ */
+static void scu_init(void)
+{
+	/* If it's external CPU mode */
+	if (SCU_REG32(0x204) & (1 << 2)) {
+		SCU_REG32(0x028) = 0xC0008000;	/* [not yet verified] Make internal CPU and ISP gated */
+		SCU_REG32(0x200) |= (1 << 14);
+	} else {
+#if CONFIG_SUPP_EXTAHB
+		/* Enable external AHB */
+		SCU_REG32(0x028) = 0x40000000;
+		SCU_REG32(0x200) = 0x1078;
+		SCU_REG32(0x228) = SCU_REG32(0x228) & (~0xF0) | 0x80;
+#else
+		/* Enable SD1 */
+		SCU_REG32(0x238) = 0x00000241;
+#endif
+	}
+
+	/* Clock Setup: SD = 133MHz, SSP = APB (SPI mode) */
+	SCU_REG32(0x22C) = 0x000A0A0A;
+
+	/* Enable LCD for I2C/TVEncode work-around */
+	LCD_REG32(0x10C) = 0x1F00;	/* clock div = (31+1) */
+	LCD_REG32(0x000) = 0x0003;
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	/* 1. NOR Flash Setup */
+	SMC_REG32(0x00) = (1 << 28)  /* Enable */
+					  | (0 << 15) /* Offset */
+					  | (6 << 4)  /* 64 MB */
+					  | (1);      /* 16 Bits */
+	SMC_REG32(0x04) = 0x0f1ff3ff;
+
+	/* 2. Unused Area */
+	SMC_REG32(0x08) = 0;
+	SMC_REG32(0x0C) = 0x0f1ff3ff;
+	SMC_REG32(0x10) = 0;
+	SMC_REG32(0x14) = 0x0f1ff3ff;
+	SMC_REG32(0x18) = 0;
+	SMC_REG32(0x1C) = 0x0f1ff3ff;
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	scu_init();
+	smc_init();
+
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	extern int usb_eth_initialize(bd_t *bi);
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	extern int ftgmac100_initialize(bd_t *bd);
+	return ftgmac100_initialize(bd);
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC010_MCI)
+	extern int ftsdc010_mmc_init(int devid);
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
+
+int board_nand_init(struct nand_chip *chip)
+{
+	int ret = 0;
+#ifdef CONFIG_NAND_FTNANDC021
+	extern int ftnandc021_probe(struct nand_chip *chip);
+	uint32_t reg = SCU_REG32(0x204);
+
+#if 0
+	chip->options = NAND_BUSWIDTH_16;
+#endif
+
+	/* page shift */
+	switch ((reg & 0x180) >> 7) {
+	case 0:
+		chip->page_shift = 9;	/* 512 */
+		break;
+	case 1:
+		chip->page_shift = 11;	/* 2048 */
+		break;
+	case 2:
+	case 3:
+		chip->page_shift = 12;	/* 4096 */
+		break;
+	}
+
+	/* block shift */
+	switch ((reg & 0x600) >> 9) {
+	case 0: /* 16 pages */
+		chip->phys_erase_shift = chip->page_shift + 4;
+		break;
+	case 1: /* 32 pages */
+		chip->phys_erase_shift = chip->page_shift + 5;
+		break;
+	case 2: /* 64 pages */
+		chip->phys_erase_shift = chip->page_shift + 6;
+		break;
+	case 3: /* 128 pages */
+		chip->phys_erase_shift = chip->page_shift + 7;
+		break;
+	}
+
+	/* address cycle */
+	switch ((reg & 0x60) >> 5) {
+	case 0: /* NANDC_AP_3C: */
+		chip->priv = (void *)3;
+		break;
+	case 1: /* NANDC_AP_4C: */
+		chip->priv = (void *)4;
+		break;
+	case 2: /* NANDC_AP_5C: */
+	case 3:
+		chip->priv = (void *)5;
+		break;
+	}
+
+	ret = ftnandc021_probe(chip);
+#endif
+	return ret;
+}
diff --git a/board/faraday/a369evb/clk.c b/board/faraday/a369evb/clk.c
new file mode 100644
index 0000000..1dad123
--- /dev/null
+++ b/board/faraday/a369evb/clk.c
@@ -0,0 +1,80 @@
+/*
+ * board/faraday/a369evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+
+static ulong clk_get_rate_ahb(void)
+{
+	ulong mul = 4, clk;
+
+	/* PLL1 Enabled */
+	if (REG32(CONFIG_SCU_BASE + 0x20) & (1 << 0)) {
+		int retry = 0x1FFFF;
+		/* wait until PLL1 become stable */
+		while (--retry > 0 && !(REG32(CONFIG_SCU_BASE + 0x20) & (1 << 1)))
+			;
+		mul = (REG32(CONFIG_SCU_BASE + 0x20) >> 24) & 0x3F;
+	}
+
+	clk = (CONFIG_MAIN_CLK * mul) >> 3;
+	return clk;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+#ifndef CONFIG_A369_FA606TE_PLATFORM
+	if (!(REG32(CONFIG_SCU_BASE + 0x204) & (1 << 2))) {
+
+		switch ((REG32(CONFIG_SCU_BASE + 0x08) >> 3) & 0x03) {
+		case 0:
+			clk = clk << 0;
+			break;
+
+		case 1:
+			clk = clk << 1;
+			break;
+
+		default:
+			clk = clk << 2;
+			break;
+		}
+
+	}
+#endif
+
+	return clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a369evb/config.mk b/board/faraday/a369evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a369evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..78e1f70
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,133 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+	.macro	_v3_mw32
+
+	ldr r0, =0x1008
+	ldr r3, =0x1108
+_v3_mw32_loop:
+	cmp   r0, r3
+	movhs r1, #0
+	ldrlo r1, [r0, #0]
+	ldrlo r2, [r0, #4]
+	teq   r1, #0
+	strne r2, [r1, #0]
+	addne r0, #8
+	bne   _v3_mw32_loop
+
+	.endm	/* _v3_mw32 */
+
+	.macro	_sdram_enable
+
+	/* Clear SDRAM CKE, GPIO Hold, READ Hold */
+	ldr r0, =CONFIG_SCU_BASE
+	mov r1, #7
+	str r1, [r0, #0x14]
+
+	/* Wait until sdram ready */
+	ldr r0, =CONFIG_DDR_BASE
+_sdram_wait:
+	ldr r1, [r0, #0x04]
+	teq r1, #0x100
+	bne _sdram_wait
+
+	.endm	/* _sdram_enable */
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	/* Check image header */
+	ldr   r1, =0x1000
+	ldr   r0, [r1, #0]
+	ldr   r1, =0x00484946	/* "FIH\0" */
+	ldr   r2, =0x33333639	/* "3369" */
+	teq   r0, r1
+	teqne r0, r2
+	bne _exit
+	_v3_mw32
+	_sdram_enable
+
+#if 1
+	/* Create a shadow copy onto SDRAM (limited to 512K) */
+	mov	r0, #0						/* r0 <- start of source   */
+	ldr	r1, =CONFIG_AHB_BASE
+	ldr r2, [r1,#0x18]
+	bic r1, r2, #0x000f0000			/* r1 <- SDRAM base */
+	mov	r2, #0x80000				/* r2 <- source end address (512KB) */
+
+_copy_loop:
+	ldmia	r0!, {r3-r10}			/* copy from source address [r0]    */
+	stmia	r1!, {r3-r10}			/* copy to   target address [r1]    */
+	cmp	r0, r2						/* until source end addreee [r2]    */
+	ble	_copy_loop
+#else
+	/* Adjust lr(r14) to the remapped address */
+	ldr r0, =CONFIG_AHB_BASE
+	ldr r1, [r0,#0x18]				/* r1 = AHB slave 6 */
+	bic r1, r1, #0xff000000
+	bic r1, r1, #0x00f00000
+	lsr r1, r1, #16
+	add r1, r1, #20
+	mov r2, #1
+	lsl r2, r2, r1
+	add lr, lr, r2
+#endif
+
+	/* AHB remap */
+	mov r0, #0
+	ldr r1, =CONFIG_AHB_BASE
+	ldr r2, =CONFIG_DDR_BASE
+	ldr r5, [r0, #0]
+	ldr r3, =0xffffffff
+	eor r5, r5, r3		/* magic (r5) = REG32(0x00) XOR 0xFFFFFFFF */
+	ldr r3, [r2, #0x10]
+	bic r3, #0xff000000	/* r3 = REG32(CONFIG_IOBASE_DDR + 0x10) & 0x00FFFFFF */
+	ldr r4, =0x00100f01	/* r4 = 0x00100f01 */
+
+	/*
+	 * invalidate i-cache all to make sure the codes bellow
+	 * to be fetched into a single 32-bytes cache line
+	 */
+	mcr p15, 0, r0, c7, c5, 0
+
+	.align 5
+
+	str r3, [r2, #0x10]	/* REG32(CONFIG_IOBASE_DDR + 0x10) &= 0x00FFFFFF */
+	str r4, [r1, #0x88]	/* REG32(CONFIG_IOBASE_AHB + 0x88)  = 0x00100F01 */
+
+_remap_wait:
+	str r5, [r0, #0]
+	ldr r1, [r0, #0]
+	teq r1, r5
+	bne _remap_wait		/* while(magic != REG32(addr)) */
+
+_exit:
+	mov	pc, lr
diff --git a/boards.cfg b/boards.cfg
index ee68fdd..fbf76a9 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -73,6 +73,9 @@ mini2440                     arm         arm920t     mini2440            friendl
 VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
 smdk2410                     arm         arm920t     -                   samsung        s3c24x0
 omap1510inn                  arm         arm925t     -                   ti
+a360                         arm         faraday     a360evb             faraday        a360
+a369                         arm         faraday     a369evb             faraday        a369
+a369_fa606te                 arm         faraday     a369evb             faraday        a369
 integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap:CM926EJ_S
 integratorcp_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorcp:CM924EJ_S
 aspenite                     arm         arm926ejs   -                   Marvell        armada100
diff --git a/include/common.h b/include/common.h
index d41aeb4..6324806 100644
--- a/include/common.h
+++ b/include/common.h
@@ -112,6 +112,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_FARADAY
+#include <asm/arch/hardware.h>
+#endif

 #include <part.h>
 #include <flash.h>
@@ -257,6 +260,16 @@ typedef void (interrupt_handler_t)(void *);
 	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
 	(type *)( (char *)__mptr - offsetof(type,member) );})

+#ifdef CONFIG_FARADAY
+/* board/faraday/xxx/clk.c */
+extern ulong clk_get_rate(char *id);
+
+/* arch/arm/cpu/faraday/xxx/interrupt.c */
+extern void irq_set_trigger(int irq, int edge, int low);
+extern void irq_enable(int irq);
+extern void irq_disable(int irq);
+#endif
+
 /*
  * Function Prototypes
  */
diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..e9a085f
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,180 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * Hardware Resources (i.e. iobase, irq)
+ */
+#include <asm/arch/hardware.h>
+
+#define CONFIG_A360_PLATFORM        1
+#define CONFIG_SYS_NO_FLASH         1
+/* #define CONFIG_USE_IRQ				1 */	/* Enable interrupt */
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+/* #define CONFIG_BOARD_EARLY_INIT_F   1 */
+#define CONFIG_BOARD_LATE_INIT      1
+
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_256M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to (CONFIG_SYS_INIT_SP_ADDR) & ~0x07)
+ * and then relocated to DRAM while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR     (CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_4M
+
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+/*
+ * CPU
+ */
+#define CONFIG_ARCH_CPU_INIT		1
+#define CONFIG_DISPLAY_CPUINFO		1
+#define CONFIG_FARADAY				1
+#define CONFIG_SYS_CACHELINE_SIZE	32
+
+/*
+ * Interrupt
+ */
+#if CONFIG_USE_IRQ
+#define CONFIG_FTINTC020			1
+#define CONFIG_PIC_BASE				CONFIG_FTINTC020_BASE
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010				1
+#define CONFIG_TIMER_BASE			CONFIG_FTTMR010_BASE
+#define CONFIG_TIMER_IRQ			CONFIG_FTTMR010_IRQ
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010				1
+
+/*
+ * Clock
+ */
+#define CONFIG_MAIN_CLK				40000000
+#define CONFIG_SYS_HZ				1000
+#define	CONFIG_SYS_MONITOR_LEN		SZ_256K	/* 256 kB for U-Boot */
+
+/*
+ * U-Boot general commands
+ */
+#define CONFIG_CMD_AUTOSCRIPT		1		/* Autoscript Support		*/
+#define CONFIG_CMD_BDI				1		/* bdinfo			*/
+#define CONFIG_CMD_BOOTD			1		/* bootd			*/
+#define CONFIG_CMD_ECHO				1		/* echo arguments		*/
+#define CONFIG_CMD_ENV				1		/* saveenv			*/
+#define CONFIG_CMD_IMI				1		/* iminfo			*/
+#define CONFIG_CMD_MEMORY			1		/* md mm nm mw cp cmp crc base loop mtest */
+#define CONFIG_CMD_NET				1		/* bootp, tftpboot, rarpboot	*/
+#define CONFIG_CMD_RUN				1		/* run command in env variable	*/
+#define CONFIG_CMD_CACHE			1		/* cache enable/disable command */
+#define CONFIG_CMD_ELF				1
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_CMDLINE_TAG			1			/* enable passing of ATAGs	*/
+#define CONFIG_SETUP_MEMORY_TAGS	1
+#define CONFIG_INITRD_TAG			1
+
+/*
+ * Serial Info
+ */
+#define CONFIG_SYS_NS16550			1
+#define CONFIG_SYS_NS16550_SERIAL	1
+#define CONFIG_SYS_NS16550_CLK		18432000
+#define CONFIG_SYS_NS16550_COM1		CONFIG_FTUART010_BASE
+#define CONFIG_SYS_NS16550_MEM32	1
+#define CONFIG_SYS_NS16550_REG_SIZE	-4
+#define CONFIG_CONS_INDEX			1
+#define CONFIG_BAUDRATE				38400
+#undef  CONFIG_HWFLOW				/* don't include RTS/CTS flow control support	*/
+#undef  CONFIG_MODEM_SUPPORT		/* disable modem initialization stuff */
+
+/*
+ * NIC driver
+ */
+#define CONFIG_FTMAC110             1
+#define CONFIG_ETHADDR				00:84:14:72:61:69  /* used by common/env_common.c */
+#define CONFIG_NETMASK				255.255.255.0
+#define CONFIG_IPADDR				10.0.0.123
+#define CONFIG_SERVERIP				10.0.0.128
+#define CONFIG_MII					1
+#define CONFIG_NET_MULTI			1
+#define CONFIG_NET_RETRY_COUNT		20
+#define CONFIG_DRIVER_ETHER			1
+#define CONFIG_CMD_MII				1
+#define CONFIG_CMD_PING				1
+
+/*
+ * Shell
+ */
+#define	CONFIG_SYS_HUSH_PARSER		1
+#define	CONFIG_SYS_PROMPT_HUSH_PS2	"> "
+#define CONFIG_SYS_PROMPT			"=> "	/* Monitor Command Prompt */
+#define CONFIG_AUTO_COMPLETE		1
+#define CONFIG_CMDLINE_EDITING		1
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_NOWHERE		1
+#define CONFIG_ENV_OFFSET			0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND	0x07FE0000
+#define CONFIG_ENV_SIZE				0x00020000
+
+/*
+ * System
+ */
+#define CONFIG_SYS_LOAD_ADDR		0x01000000  /* default load address */
+#define CONFIG_SYS_BAUDRATE_TABLE	{ 115200, 57600, 38400, 19200, 9600 }
+#define CONFIG_SYS_CBSIZE			256		/* Console I/O Buffer Size */
+#define CONFIG_SYS_MAXARGS			32		/* max number of command args */
+#define CONFIG_SYS_PBSIZE			(CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16) /* Print Buffer Size */
+#define CONFIG_LZMA					1
+#define CONFIG_TIMESTAMP			1
+#define CONFIG_SYS_LONGHELP			1		/* still about 20 kB free with this defined */
+#define CONFIG_VERSION_VARIABLE		1       /* include version env variable */
+
+/*
+ * FAT (USB & MMC)
+ */
+#define CONFIG_DOS_PARTITION        1
+#define CONFIG_CMD_FAT              1
+#define CONFIG_PARTITIONS           1
+
+/*
+ * USB
+ */
+#define CONFIG_USB_EHCI_FUSBH200            1
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS  1
+#define CONFIG_USB_EHCI						1
+#define CONFIG_USB_EHCI_FARADAY				1
+#define CONFIG_EHCI_IS_TDI                  1
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+#define CONFIG_EHCI_DCACHE                  1
+#endif
+#define CONFIG_CMD_USB                      1
+#define CONFIG_USB_STORAGE                  1
+
+#endif
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..e37ea9d
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,40 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_PLATFORM        1
+
+/* Support external AHB */
+#if 0
+#define CONFIG_SUPP_EXTAHB          1
+#endif
+
+/* Support USB RNDIS Ethernet */
+#if 0
+#define CONFIG_SUPP_USB_RNDIS       1
+#endif
+
+/* Disable NOR flash support */
+#define CONFIG_SYS_NO_FLASH         1
+
+/* Support interrupt */
+#if 0
+#define CONFIG_USE_IRQ              1
+#endif
+
+#if 1
+/* Enable MMU/D-CACHE */
+#define CONFIG_SYS_ARM_CACHE_WRITETHROUGH 1
+#else
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF       1
+#endif
+
+/* Transfer the control to the built-in slave cpu: FA606TE */
+#define CONFIG_CMD_FA606            1
+
+/* Hardware Resources (i.e. iobase, irq) */
+#include <asm/arch/hardware.h>
+
+#include "a369_defaults.h"
+
+#endif
diff --git a/include/configs/a369_defaults.h b/include/configs/a369_defaults.h
new file mode 100644
index 0000000..55c4535
--- /dev/null
+++ b/include/configs/a369_defaults.h
@@ -0,0 +1,285 @@
+#ifndef __CONFIG_A369_DEFAULTS_H
+#define __CONFIG_A369_DEFAULTS_H
+
+/*
+ * Autoboot
+ */
+#define CONFIG_BOOTDELAY			3
+#define CONFIG_BOOTCOMMAND			"bootfa nand linux"
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+/* #define CONFIG_BOARD_EARLY_INIT_F   1 */
+#define CONFIG_BOARD_LATE_INIT      1
+
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_512M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to (CONFIG_SYS_INIT_SP_ADDR) & ~0x07)
+ * and then relocated to DRAM while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR     (CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_8M
+
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+/*
+ * CPU
+ */
+#define CONFIG_ARCH_CPU_INIT        1
+#define CONFIG_DISPLAY_CPUINFO      1
+#define CONFIG_FARADAY              1
+#define CONFIG_SYS_CACHELINE_SIZE	32
+
+/*
+ * Interrupt
+ */
+#if CONFIG_USE_IRQ
+#define CONFIG_FTINTC020            1
+# ifdef CONFIG_A369_PLATFORM
+#define CONFIG_PIC_BASE             CONFIG_FTINTC020_BASE
+# else
+#define CONFIG_PIC_BASE             CONFIG_FTINTC020_BASE1
+# endif
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010          1
+#define CONFIG_TIMER_BASE           CONFIG_FTPWMTMR010_BASE
+#define CONFIG_TIMER_IRQ            CONFIG_FTPWMTMR010_IRQ
+
+/*
+ * Clock
+ */
+#define CONFIG_MAIN_CLK             33000000
+#define CONFIG_SYS_HZ               1000
+#define CONFIG_SYS_MONITOR_LEN      SZ_256K    /* 256 kB for U-Boot */
+
+/*
+ * U-Boot general commands
+ */
+#define CONFIG_CMD_AUTOSCRIPT       1        /* Autoscript Support        */
+#define CONFIG_CMD_BDI              1        /* bdinfo            */
+#define CONFIG_CMD_BOOTD            1        /* bootd            */
+#define CONFIG_CMD_ECHO             1        /* echo arguments        */
+#define CONFIG_CMD_ENV              1        /* saveenv            */
+#define CONFIG_CMD_IMI              1        /* iminfo            */
+#define CONFIG_CMD_MEMORY           1        /* md mm nm mw cp cmp crc base loop mtest */
+#define CONFIG_CMD_NET              1        /* bootp, tftpboot, rarpboot    */
+#define CONFIG_CMD_RUN              1        /* run command in env variable    */
+#define CONFIG_CMD_CACHE            1        /* cache enable/disable command */
+#define CONFIG_CMD_ELF              1
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_CMDLINE_TAG          1            /* enable passing of ATAGs    */
+#define CONFIG_SETUP_MEMORY_TAGS    1
+#define CONFIG_INITRD_TAG           1
+
+/*
+ * Serial Info
+ */
+#define CONFIG_SYS_NS16550          1
+#define CONFIG_SYS_NS16550_SERIAL   1
+#define CONFIG_SYS_NS16550_CLK      18432000
+#define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+#define CONFIG_SYS_NS16550_MEM32    1
+#define CONFIG_SYS_NS16550_REG_SIZE -4
+#define CONFIG_CONS_INDEX           1
+#define CONFIG_BAUDRATE             38400
+#undef  CONFIG_HWFLOW               /* don't include RTS/CTS flow control support    */
+#undef  CONFIG_MODEM_SUPPORT        /* disable modem initialization stuff */
+
+/*
+ * NIC driver
+ */
+#define CONFIG_FTGMAC100            1
+#define CONFIG_PHY_MAX_ADDR			32	/* used by Ratbert's ftgmac100 only */
+#define CONFIG_FTGMAC100_EGIGA		1	/* used by Ratbert's ftgmac100 only */
+#define CONFIG_ETHADDR              00:84:14:72:61:69  /* used by common/env_common.c */
+#define CONFIG_NETMASK              255.255.255.0
+#define CONFIG_IPADDR               10.0.0.123
+#define CONFIG_SERVERIP             10.0.0.128
+#define CONFIG_MII                  1
+#define CONFIG_NET_MULTI            1
+#define CONFIG_NET_RETRY_COUNT      20
+#define CONFIG_DRIVER_ETHER         1
+#define CONFIG_CMD_MII              1
+#define CONFIG_CMD_PING             1
+
+/*
+ * I2C Controller
+ */
+#define CONFIG_FTI2C010             1
+#define CONFIG_HARD_I2C             1        /* Always defined for hardware I2C support */
+#define CONFIG_SYS_I2C_SPEED        5000    /* default speed (in HZ) */
+#define CONFIG_SYS_I2C_SLAVE        0
+#define CONFIG_CMD_I2C              1
+#define CONFIG_I2C_CMD_TREE         1
+#define CONFIG_I2C_MULTI_BUS        1
+#define CONFIG_SYS_MAX_I2C_BUS      2
+
+/*
+ * EEPROM
+ */
+#define CONFIG_CMD_EEPROM                       1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS       3
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS   5
+#define CONFIG_SYS_I2C_MULTI_EEPROMS            1
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN          1
+#define CONFIG_ENV_EEPROM_IS_ON_I2C             1
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_SPI         1
+#define CONFIG_FTSSP010_GPIO_PIN    27
+#define CONFIG_SPI                  1
+#define CONFIG_HARD_SPI             1
+#define CONFIG_CMD_SPI              1
+#define CONFIG_ENV_SPI_BUS          0
+#define CONFIG_ENV_SPI_CS           0
+#define CONFIG_ENV_SPI_MAX_HZ       25000000
+#define CONFIG_DEFAULT_SPI_MODE     0
+
+/*
+ * SPI Flash
+ */
+#define CONFIG_FTSSP010_SPI         1
+#if 0
+#define CONFIG_FTSPI020             1
+#else
+#define CONFIG_SPI_FLASH            1
+#define CONFIG_SPI_FLASH_MACRONIX   1
+#define CONFIG_SPI_FLASH_WINBOND    1
+#endif
+#define CONFIG_CMD_SF               1        /* serial flash command */
+
+/*
+ * NOR Flash
+ */
+#ifndef CONFIG_SYS_NO_FLASH
+#define CONFIG_SYS_FLASH_CFI_WIDTH  FLASH_CFI_16BIT
+#define CONFIG_SYS_FLASH_BASE       0x20000000
+#define PHYS_FLASH_SIZE             SZ_64M
+#define CONFIG_SYS_FLASH_CFI        1
+#define CONFIG_FLASH_CFI_DRIVER     1
+#define CONFIG_SYS_MAX_FLASH_BANKS  1
+#define CONFIG_SYS_MAX_FLASH_SECT   1024            /* max. sector number */
+#define CFG_FLASH_EMPTY_INFO        /* print 'E' for empty sector on flinfo */
+#define CONFIG_CMD_IMLS             1
+#define CONFIG_CMD_FLASH            1
+#endif    /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * NAND Flash
+ */
+#define CONFIG_NAND_FTNANDC021          1
+#define CONFIG_FTNANDC021_ACTIMING_1    0x02240264
+#define CONFIG_FTNANDC021_ACTIMING_2    0x42054209
+#define CONFIG_CMD_NAND                 1
+#define CONFIG_SYS_MAX_NAND_DEVICE      1    /* Max number of NAND devices */
+#define CONFIG_SYS_NAND_BASE            CONFIG_NAND_FTNANDC021_BASE
+#define CONFIG_SYS_NAND_BASE_LIST       { CONFIG_NAND_FTNANDC021_BASE }
+#define CONFIG_MTD_NAND_VERIFY_WRITE
+
+/*
+ * Shell
+ */
+#define    CONFIG_SYS_HUSH_PARSER       1
+#define    CONFIG_SYS_PROMPT_HUSH_PS2   "> "
+#define CONFIG_SYS_PROMPT               "=> "    /* Monitor Command Prompt */
+#define CONFIG_AUTO_COMPLETE            1
+#define CONFIG_CMDLINE_EDITING          1
+
+/*
+ * Environment
+ */
+#define CONFIG_CMD_SAVEENV              1
+#define CONFIG_ENV_IS_IN_NAND           1
+#define CONFIG_ENV_OFFSET               0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND        0x07FE0000
+#define CONFIG_ENV_SIZE                 0x00020000
+
+/*
+ * System
+ */
+#define CONFIG_SYS_LOAD_ADDR            0x01000000  /* default load address */
+#define CONFIG_SYS_BAUDRATE_TABLE       { 115200, 57600, 38400, 19200, 9600 }
+#define CONFIG_SYS_CBSIZE               256        /* Console I/O Buffer Size */
+#define CONFIG_SYS_MAXARGS              32        /* max number of command args */
+#define CONFIG_SYS_PBSIZE               (CONFIG_SYS_CBSIZE+sizeof(CONFIG_SYS_PROMPT)+16) /* Print Buffer Size */
+#define CONFIG_LZMA                     1
+#define CONFIG_TIMESTAMP                1
+#define CONFIG_SYS_LONGHELP             1        /* still about 20 kB free with this defined */
+#define CONFIG_VERSION_VARIABLE         1       /* include version env variable */
+
+/*
+ * FAT (USB & MMC)
+ */
+#define CONFIG_DOS_PARTITION        1
+#define CONFIG_CMD_FAT              1
+#define CONFIG_PARTITIONS           1
+
+/*
+ * MMC  (FTSDC010)
+ */
+#if 1
+#define CONFIG_FTSDC010_MCI         1
+#else
+#define CONFIG_FTSDC010             1
+#define CONFIG_FTSDC010_NUMBER      1
+#define CONFIG_SYS_CLK_FREQ         133000000	/* AHB clock */
+#endif
+#define CONFIG_MMC                  1
+#define CONFIG_CMD_MMC              1
+#define CONFIG_GENERIC_MMC          1
+
+/*
+ * USB EHCI Host
+ */
+#define CONFIG_USB_EHCI_BASE                CONFIG_FUSBH200_BASE
+#if CONFIG_SUPP_USB_RNDIS
+#define CONFIG_USB_MAX_CONTROLLER_COUNT		1
+#else
+#define CONFIG_USB_EHCI_BASE1               CONFIG_FOTG210_BASE
+#define CONFIG_USB_MAX_CONTROLLER_COUNT		2
+#endif
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS  1
+#define CONFIG_USB_EHCI                     1
+#define CONFIG_USB_EHCI_FARADAY             1
+#define CONFIG_EHCI_IS_TDI                  1
+#define CONFIG_CMD_USB                      1
+#define CONFIG_USB_STORAGE                  1
+
+/*
+ * USB Gadget
+ */
+#if CONFIG_SUPP_USB_RNDIS
+#define CONFIG_USB_GADGET					1
+#define CONFIG_USB_GADGET_FOTG210           1
+#define CONFIG_USB_GADGET_DUALSPEED         1
+#define CONFIG_USB_ETHER                    1
+#define CONFIG_USB_ETH_RNDIS                1
+#define CONFIG_USBNET_DEV_ADDR              "00:41:71:00:00:55"    /* U-Boot mac address */
+#define CONFIG_USBNET_HOST_ADDR             "00:41:71:00:00:54"    /* PC mac address */
+#endif
+
+#endif
diff --git a/include/configs/a369_fa606te.h b/include/configs/a369_fa606te.h
new file mode 100644
index 0000000..c69962c
--- /dev/null
+++ b/include/configs/a369_fa606te.h
@@ -0,0 +1,32 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_FA606TE_PLATFORM 1
+
+/* Support external AHB */
+#if 0
+#define CONFIG_SUPP_EXTAHB           1
+#endif
+
+/* Support USB RNDIS Ethernet */
+#if 0
+#define CONFIG_SUPP_USB_RNDIS        1
+#endif
+
+/* Disable NOR flash support */
+#define CONFIG_SYS_NO_FLASH          1
+
+/* Support interrupt */
+#if 0
+#define CONFIG_USE_IRQ               1
+#endif
+
+/* Disable CPU MMU support */
+#define CONFIG_SYS_DCACHE_OFF        1    /* Disable MMU/D-CACHE */
+
+/* Hardware Resources (i.e. iobase, irq) */
+#include <asm/arch/hardware.h>
+
+#include "a369_defaults.h"
+
+#endif
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 72abcb3..5e17b1f 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -41,15 +41,41 @@ struct fttmr010 {
 	unsigned int	interrupt_mask;		/* 0x38 */
 };

+#define REG_TMR1_COUNTER	0x00    /* timer1 counter register */
+#define REG_TMR1_RELOAD		0x04    /* timer1 reload register */
+#define REG_TMR1_MATCH1		0x08    /* timer1 match1 register */
+#define REG_TMR1_MATCH2		0x0C    /* timer1 match2 register */
+
+#define REG_TMR2_COUNTER	0x10    /* timer2 counter register */
+#define REG_TMR2_RELOAD		0x14    /* timer2 reload register */
+#define REG_TMR2_MATCH1		0x18    /* timer2 match1 register */
+#define REG_TMR2_MATCH2		0x1C    /* timer2 match2 register */
+
+#define REG_TMR3_COUNTER	0x20    /* timer3 counter register */
+#define REG_TMR3_RELOAD		0x24    /* timer3 reload register */
+#define REG_TMR3_MATCH1		0x28    /* timer3 match1 register */
+#define REG_TMR3_MATCH2		0x2C    /* timer3 match2 register */
+
+#define REG_CR				0x30    /* control register */
+#define REG_ISR				0x34    /* interrupt status register */
+#define REG_IMR				0x38    /* interrupt mask register */
+#define REG_REVR			0x3C    /* revision register */
+
+#define REG_TMR_BASE(id)	(0x00 + ((id) << 4))
+#define REG_TMR_COUNTER		0x00
+#define REG_TMR_RELOAD		0x04
+#define REG_TMR_MATCH1		0x08
+#define REG_TMR_MATCH2		0x0C
+
 /*
  * Timer Control Register
  */
-#define FTTMR010_TM3_UPDOWN	(1 << 11)
+#define FTTMR010_TM3_UPDOWN	(1 << 11)		/* 0=count down; 1=count up */
 #define FTTMR010_TM2_UPDOWN	(1 << 10)
 #define FTTMR010_TM1_UPDOWN	(1 << 9)
-#define FTTMR010_TM3_OFENABLE	(1 << 8)
-#define FTTMR010_TM3_CLOCK	(1 << 7)
-#define FTTMR010_TM3_ENABLE	(1 << 6)
+#define FTTMR010_TM3_OFENABLE	(1 << 8)	/* overflow interrupt enabled */
+#define FTTMR010_TM3_CLOCK	(1 << 7)		/* clock source=(0:APB/1:External) */
+#define FTTMR010_TM3_ENABLE	(1 << 6)		/* timer enabled */
 #define FTTMR010_TM2_OFENABLE	(1 << 5)
 #define FTTMR010_TM2_CLOCK	(1 << 4)
 #define FTTMR010_TM2_ENABLE	(1 << 3)
@@ -57,6 +83,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_ENABLE | FTTMR010_TM1_CLOCK \
+	| FTTMR010_TM1_OFENABLE | FTTMR010_TM1_UPDOWN)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_ENABLE | FTTMR010_TM2_CLOCK \
+	| FTTMR010_TM2_OFENABLE | FTTMR010_TM2_UPDOWN)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_ENABLE | FTTMR010_TM3_CLOCK \
+	| FTTMR010_TM3_OFENABLE | FTTMR010_TM3_UPDOWN)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -70,4 +106,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_OVERFLOW)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_MATCH1 | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_OVERFLOW)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_MATCH1 | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_OVERFLOW)
+
 #endif	/* __FTTMR010_H */
diff --git a/include/faraday/ftwdt010_wdt.h b/include/faraday/ftwdt010_wdt.h
index 31ca768..98fa956 100644
--- a/include/faraday/ftwdt010_wdt.h
+++ b/include/faraday/ftwdt010_wdt.h
@@ -39,6 +39,14 @@ struct ftwdt010_wdt {
 	unsigned int	wdintrlen;	/* Interrupt Length	- 0x18 */
 };

+#define REG_COUNTER	0x00		/* Counter Register */
+#define REG_LOAD	0x04		/* Load Register */
+#define REG_RESTART	0x08		/* Restart Register */
+#define REG_CR		0x0c		/* Control Register */
+#define REG_SR		0x10		/* Status Register */
+#define REG_SCR		0x14		/* Status Clear Register */
+#define REG_ILR		0x18		/* Interrupt Length Register */
+
 /*
  * WDLOAD - Counter Auto Reload Register
  *   The Auto Reload Register is set to 0x03EF1480 (66Mhz) by default.
--
1.7.9.5

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

* [U-Boot] [PATCH 05/11] usb-gadget: add FOTG210 USB gadget support
  2013-03-29  7:06 ` [U-Boot] [PATCH 05/11] usb-gadget: add FOTG210 USB gadget support Kuo-Jung Su
@ 2013-03-30  6:27   ` Marek Vasut
  2013-04-01  1:20     ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-03-30  6:27 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch would try to use Faraday FOTG210 to implement
> a USB RNDIS Ethernet.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>

[...]

> +static inline int
> +ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
> +{
> +	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
> +
> +	if (ep_addr & USB_DIR_IN) {
> +		/* input */
> +		USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) |= BIT(12);
> +		USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) &= ~BIT(12);
> +		USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) &= ~BIT(11);
> +	} else {
> +		/* output */
> +		USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) |= BIT(12);
> +		USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) &= BIT(12);
> +		USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) &= BIT(11);
> +	}

Use readl(), writel(), clrsetbits_le32() etc.

For example see drivers/i2c/mxs_i2c.c

[...]

> +/*
> + * Global Registers
> + */
> +#define REG_ISR         0x0C0    /* Interrupt Status */
> +#define REG_IMR         0x0C4    /* Interrupt Control */

Use structure based access, ie.

arch/arm/include/asm/arch-mxs/regs-i2c.h

struct regs {
	uint32_t reg1;
	uint32_t reg2;
...
};

writel(val, &regs->reg1);

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

* [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support
  2013-03-29  7:06 ` [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support Kuo-Jung Su
@ 2013-03-30  6:29   ` Marek Vasut
  2013-04-01  1:21     ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-03-30  6:29 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch add supports to both Faraday FUSBH200 and FOTG210,
> these controllers slightly differ from standard EHCI specification.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>

You want to fix the magic values here, use readl()/writel() to operate 
registers, kill the BIT() macro and review comments in common files.

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH 05/11] usb-gadget: add FOTG210 USB gadget support
  2013-03-30  6:27   ` Marek Vasut
@ 2013-04-01  1:20     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-01  1:20 UTC (permalink / raw)
  To: u-boot

2013/3/30 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch would try to use Faraday FOTG210 to implement
>> a USB RNDIS Ethernet.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> [...]
>
>> +static inline int
>> +ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
>> +{
>> +     int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
>> +
>> +     if (ep_addr & USB_DIR_IN) {
>> +             /* input */
>> +             USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) |= BIT(12);
>> +             USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) &= ~BIT(12);
>> +             USB_REG32(chip, REG_IEP1 + (ep - 1) * 4) &= ~BIT(11);
>> +     } else {
>> +             /* output */
>> +             USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) |= BIT(12);
>> +             USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) &= BIT(12);
>> +             USB_REG32(chip, REG_OEP1 + (ep - 1) * 4) &= BIT(11);
>> +     }
>
> Use readl(), writel(), clrsetbits_le32() etc.
>
> For example see drivers/i2c/mxs_i2c.c
>

Got it, thanks

> [...]
>
>> +/*
>> + * Global Registers
>> + */
>> +#define REG_ISR         0x0C0    /* Interrupt Status */
>> +#define REG_IMR         0x0C4    /* Interrupt Control */
>
> Use structure based access, ie.
>
> arch/arm/include/asm/arch-mxs/regs-i2c.h
>
> struct regs {
>         uint32_t reg1;
>         uint32_t reg2;
> ...
> };
>
> writel(val, &regs->reg1);

Got it, thanks

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support
  2013-03-30  6:29   ` Marek Vasut
@ 2013-04-01  1:21     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-01  1:21 UTC (permalink / raw)
  To: u-boot

2013/3/30 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch add supports to both Faraday FUSBH200 and FOTG210,
>> these controllers slightly differ from standard EHCI specification.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> You want to fix the magic values here, use readl()/writel() to operate
> registers, kill the BIT() macro and review comments in common files.
>
> Best regards,
> Marek Vasut

Got it, thanks

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support
  2013-03-29  7:06 ` [U-Boot] [PATCH 01/11] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
@ 2013-04-18  9:25   ` Kuo-Jung Su
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 01/12] mtd: spi: winbond: add W25PXX support Kuo-Jung Su
                       ` (12 more replies)
  0 siblings, 13 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

    http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

    https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU:

1. Download the QEMU source tree

    $ git clone -b qemu-1.3.0 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

    $ ./configure --target-list=arm-softmmu
    $ make
    $ make install

3. Launch u-boot with QEMU:

    $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-devel/u-boot


Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (12):
  mtd: spi: winbond: add W25PXX support
  net: ftgmac100: add MMU/D-cache support
  net: add Faraday FTMAC110 10/100Mbps ethernet support
  i2c: add Faraday FTI2C010 I2C controller support
  spi: add Faraday FTSPI010 SPI controller support
  mmc: add an alternative driver to Faraday FTSDC010
  mtd: nand: add Faraday FTNANDC021 NAND controller support
  mtd: spi: add FTSPI020 SPI Flash controller support
  usb: ehci: add Faraday USB 2.0 EHCI controller support
  usb: gadget: add Faraday FOTG210 USB gadget support
  arm: add MMU/d-cache support for Faraday cores
  arm: add Faraday A36x SoC platform support

 arch/arm/cpu/faraday/Makefile             |   57 ++
 arch/arm/cpu/faraday/a360/Makefile        |   49 ++
 arch/arm/cpu/faraday/a360/reset.c         |   26 +
 arch/arm/cpu/faraday/a369/Makefile        |   50 ++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   75 +++
 arch/arm/cpu/faraday/a369/reset.c         |   26 +
 arch/arm/cpu/faraday/cmd_bootfa.c         |  132 +++++
 arch/arm/cpu/faraday/config.mk            |   33 ++
 arch/arm/cpu/faraday/cpu.c                |  238 ++++++++
 arch/arm/cpu/faraday/ftintc020.h          |   37 ++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  156 +++++
 arch/arm/cpu/faraday/ftpwmtmr010.h        |   41 ++
 arch/arm/cpu/faraday/fttmr010.c           |  159 +++++
 arch/arm/cpu/faraday/fwimage.h            |   38 ++
 arch/arm/cpu/faraday/fwimage2.h           |   70 +++
 arch/arm/cpu/faraday/interrupts.c         |  155 +++++
 arch/arm/cpu/faraday/start.S              |  523 ++++++++++++++++
 arch/arm/cpu/u-boot.lds                   |   11 +
 arch/arm/include/asm/arch-a360/hardware.h |   72 +++
 arch/arm/include/asm/arch-a369/hardware.h |   98 +++
 arch/arm/include/asm/dma-mapping.h        |   56 +-
 arch/arm/include/asm/global_data.h        |    4 +
 arch/arm/include/asm/io.h                 |   84 ++-
 arch/arm/include/asm/mach-types.h         |    1 +
 arch/arm/lib/cache-cp15.c                 |   42 ++
 board/faraday/a360evb/Makefile            |   49 ++
 board/faraday/a360evb/board.c             |   67 +++
 board/faraday/a360evb/clk.c               |   52 ++
 board/faraday/a360evb/config.mk           |   33 ++
 board/faraday/a360evb/lowlevel_init.S     |   33 ++
 board/faraday/a369evb/Makefile            |   49 ++
 board/faraday/a369evb/board.c             |  178 ++++++
 board/faraday/a369evb/clk.c               |   81 +++
 board/faraday/a369evb/config.mk           |   33 ++
 board/faraday/a369evb/lowlevel_init.S     |  136 +++++
 boards.cfg                                |    3 +
 common/cmd_boot.c                         |    4 +
 common/usb_hub.c                          |    5 +
 drivers/i2c/Makefile                      |    1 +
 drivers/i2c/fti2c010.c                    |  363 ++++++++++++
 drivers/i2c/fti2c010.h                    |   71 +++
 drivers/mmc/Makefile                      |    1 +
 drivers/mmc/ftsdc010_mci.c                |  373 ++++++++++++
 drivers/mtd/nand/Makefile                 |    1 +
 drivers/mtd/nand/ftnandc021.c             |  544 +++++++++++++++++
 drivers/mtd/nand/ftnandc021.h             |  132 +++++
 drivers/mtd/spi/Makefile                  |    4 +
 drivers/mtd/spi/ftspi020.c                |  691 +++++++++++++++++++++
 drivers/mtd/spi/ftspi020.h                |  109 ++++
 drivers/mtd/spi/winbond.c                 |   17 +-
 drivers/net/Makefile                      |    1 +
 drivers/net/ftgmac100.c                   |   70 ++-
 drivers/net/ftmac110.c                    |  452 ++++++++++++++
 drivers/net/ftmac110.h                    |  159 +++++
 drivers/spi/Makefile                      |    1 +
 drivers/spi/ftssp010_spi.c                |  337 +++++++++++
 drivers/spi/ftssp010_spi.h                |   86 +++
 drivers/usb/gadget/Makefile               |    1 +
 drivers/usb/gadget/fotg210.c              |  922 +++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h         |    8 +
 drivers/usb/host/Makefile                 |    1 +
 drivers/usb/host/ehci-faraday.c           |  139 +++++
 drivers/usb/host/ehci-hcd.c               |   11 +
 drivers/usb/host/ehci.h                   |    5 +
 include/common.h                          |   13 +
 include/configs/a360.h                    |  185 ++++++
 include/configs/a369.h                    |   41 ++
 include/configs/a369_defaults.h           |  295 +++++++++
 include/configs/a369_fa606te.h            |   32 +
 include/faraday/ftsdc010.h                |   16 +-
 include/faraday/fttmr010.h                |   17 +
 include/faraday/mmc.h                     |   16 +
 include/faraday/nand.h                    |   16 +
 include/netdev.h                          |    1 +
 include/usb/fotg210.h                     |   71 +++
 include/usb/fusbh200.h                    |   28 +
 76 files changed, 8158 insertions(+), 29 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/reset.c
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/a369/reset.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftintc020.h
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.h
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h
 create mode 100644 drivers/mmc/ftsdc010_mci.c
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/mtd/nand/ftnandc021.h
 create mode 100644 drivers/mtd/spi/ftspi020.c
 create mode 100644 drivers/mtd/spi/ftspi020.h
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h
 create mode 100644 drivers/spi/ftssp010_spi.c
 create mode 100644 drivers/spi/ftssp010_spi.h
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_defaults.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/faraday/mmc.h
 create mode 100644 include/faraday/nand.h
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v2 01/12] mtd: spi: winbond: add W25PXX support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 02/12] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
                       ` (11 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/mtd/spi/winbond.c |   17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/mtd/spi/winbond.c b/drivers/mtd/spi/winbond.c
index 2716209..2a27837 100644
--- a/drivers/mtd/spi/winbond.c
+++ b/drivers/mtd/spi/winbond.c
@@ -18,6 +18,21 @@ struct winbond_spi_flash_params {
 
 static const struct winbond_spi_flash_params winbond_spi_flash_table[] = {
 	{
+		.id			= 0x2014,
+		.nr_blocks		= 16,
+		.name			= "W25P80",
+	},
+	{
+		.id			= 0x2015,
+		.nr_blocks		= 32,
+		.name			= "W25P16",
+	},
+	{
+		.id			= 0x2016,
+		.nr_blocks		= 64,
+		.name			= "W25P32",
+	},
+	{
 		.id			= 0x3013,
 		.nr_blocks		= 8,
 		.name			= "W25X40",
@@ -104,7 +119,7 @@ struct spi_flash *spi_flash_probe_winbond(struct spi_slave *spi, u8 *idcode)
 	}
 
 	flash->page_size = 256;
-	flash->sector_size = 4096;
+	flash->sector_size = (idcode[1] == 0x20) ? 65536 : 4096;
 	flash->size = 4096 * 16 * params->nr_blocks;
 
 	return flash;
-- 
1.7.9.5

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

* [U-Boot] [PATCH v2 02/12] net: ftgmac100: add MMU/D-cache support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 01/12] mtd: spi: winbond: add W25PXX support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 03/12] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
                       ` (10 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Joe Hershberger <joe.hershberger@gmail.com>
---
 drivers/net/ftgmac100.c |   70 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 69ba57d..2dbb328 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -27,11 +27,13 @@
 #include <malloc.h>
 #include <net.h>
 #include <asm/io.h>
+#include <asm/dma-mapping.h>
 #include <linux/mii.h>

 #include "ftgmac100.h"

 #define ETH_ZLEN	60
+#define CFG_XBUF_SIZE	1536

 /* RBSR - hw default init value is also 0x640 */
 #define RBSR_DEFAULT_VALUE	0x640
@@ -40,8 +42,10 @@
 #define PKTBUFSTX	4	/* must be power of 2 */

 struct ftgmac100_data {
-	struct ftgmac100_txdes txdes[PKTBUFSTX];
-	struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+	ulong txdes_dma;
+	struct ftgmac100_txdes *txdes;
+	ulong rxdes_dma;
+	struct ftgmac100_rxdes *rxdes;
 	int tx_index;
 	int rx_index;
 	int phy_addr;
@@ -375,13 +379,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 {
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
-	struct ftgmac100_txdes *txdes = priv->txdes;
-	struct ftgmac100_rxdes *rxdes = priv->rxdes;
+	struct ftgmac100_txdes *txdes;
+	struct ftgmac100_rxdes *rxdes;
 	unsigned int maccr;
+	void *buf;
 	int i;

 	debug("%s()\n", __func__);

+	if (!priv->txdes) {
+		txdes = dma_alloc_coherent(
+			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+		if (!txdes)
+			panic("ftgmac100: out of memory\n");
+		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+		priv->txdes = txdes;
+	}
+	txdes = priv->txdes;
+
+	if (!priv->rxdes) {
+		rxdes = dma_alloc_coherent(
+			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+		if (!rxdes)
+			panic("ftgmac100: out of memory\n");
+		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+		priv->rxdes = rxdes;
+	}
+	rxdes = priv->rxdes;
+
 	/* set the ethernet address */
 	ftgmac100_set_mac_from_env(dev);

@@ -397,21 +422,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)

 	for (i = 0; i < PKTBUFSTX; i++) {
 		/* TXBUF_BADR */
-		txdes[i].txdes3 = 0;
+		if (!txdes[i].txdes2) {
+			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+			if (!buf)
+				panic("ftgmac100: out of memory\n");
+			txdes[i].txdes3 = virt_to_phys(buf);
+			txdes[i].txdes2 = (uint)buf;
+		}
 		txdes[i].txdes1 = 0;
 	}

 	for (i = 0; i < PKTBUFSRX; i++) {
 		/* RXBUF_BADR */
-		rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i];
+		if (!rxdes[i].rxdes2) {
+			buf = NetRxPackets[i];
+			rxdes[i].rxdes3 = virt_to_phys(buf);
+			rxdes[i].rxdes2 = (uint)buf;
+		}
 		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
 	}

 	/* transmit ring */
-	writel((unsigned int)txdes, &ftgmac100->txr_badr);
+	writel(priv->txdes_dma, &ftgmac100->txr_badr);

 	/* receive ring */
-	writel((unsigned int)rxdes, &ftgmac100->rxr_badr);
+	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);

 	/* poll receive descriptor automatically */
 	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -466,8 +501,11 @@ static int ftgmac100_recv(struct eth_device *dev)
 	debug("%s(): RX buffer %d, %x received\n",
 	       __func__, priv->rx_index, rxlen);

+	/* invalidate d-cache */
+	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
 	/* pass the packet up to the protocol layers. */
-	NetReceive((void *)curr_des->rxdes3, rxlen);
+	NetReceive((void *)curr_des->rxdes2, rxlen);

 	/* release buffer to DMA */
 	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
@@ -485,7 +523,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
 	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
-	int start;

 	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
 		debug("%s(): no TX descriptor available\n", __func__);
@@ -496,8 +533,8 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)

 	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;

-	/* initiate a transmit sequence */
-	curr_des->txdes3 = (unsigned int)packet;	/* TXBUF_BADR */
+	memcpy((void *)curr_des->txdes2, (void *)packet, length);
+	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);

 	/* only one descriptor on TXBUF */
 	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
@@ -509,15 +546,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	/* start transmit */
 	writel(1, &ftgmac100->txpd);

-	/* wait for transfer to succeed */
-	start = get_timer(0);
-	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
-		if (get_timer(0) >= 5) {
-			debug("%s(): timed out\n", __func__);
-			return -1;
-		}
-	}
-
 	debug("%s(): packet sent\n", __func__);

 	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
--
1.7.9.5

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

* [U-Boot] [PATCH v2 03/12] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 01/12] mtd: spi: winbond: add W25PXX support Kuo-Jung Su
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 02/12] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 10:52       ` Wolfgang Denk
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 04/12] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
                       ` (9 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTMAC110 10/100Mbps supports half-word data transfer for Linux.
However it has a weird DMA alignment issue:

(1) Tx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: O.K

(2) Rx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: Invalid!!!

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Joe Hershberger <joe.hershberger@gmail.com>
---
 drivers/net/Makefile   |    1 +
 drivers/net/ftmac110.c |  452 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ftmac110.h |  159 +++++++++++++++++
 include/netdev.h       |    1 +
 4 files changed, 613 insertions(+)
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 786a656..0e23817 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
 COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
+COBJS-$(CONFIG_FTMAC110) += ftmac110.o
 COBJS-$(CONFIG_FTMAC100) += ftmac100.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
new file mode 100644
index 0000000..f7b5385
--- /dev/null
+++ b/drivers/net/ftmac110.c
@@ -0,0 +1,452 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#define CFG_RXDES_NUM			8
+#define CFG_TXDES_NUM			2
+#define CFG_XBUF_SIZE			1536
+
+/*******************************************************************/
+/*               FTMAC110 DMA design issue                         */
+/*                                             Dante Su 2010.02.03 */
+/*                                                                 */
+/* The DMA engine has a weird restriction that its Rx DMA engine   */
+/* accepts only 16-bits aligned address, 32-bits aligned is not    */
+/* acceptable. However this restriction does not apply to Tx DMA.  */
+/* Conclusion:                                                     */
+/* (1) Tx DMA Buffer Address:                                      */
+/*     1 bytes aligned: Invalid                                    */
+/*     2 bytes aligned: O.K                                        */
+/*     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)       */
+/* (2) Rx DMA Buffer Address:                                      */
+/*     1 bytes aligned: Invalid                                    */
+/*     2 bytes aligned: O.K                                        */
+/*     4 bytes aligned: Invalid                                    */
+/*******************************************************************/
+
+struct ftmac110_chip {
+	void    *regs;
+	uint32_t imr;
+	uint32_t maccr;
+	uint32_t lnkup;
+	uint32_t phy_addr;
+
+	struct ftmac110_rxd *rxd;
+	ulong                rxd_dma;
+	uint32_t             rxd_idx;
+
+	struct ftmac110_txd *txd;
+	ulong                txd_dma;
+	uint32_t             txd_idx;
+};
+
+/* Register access macros */
+#define MAC_READ(r)			le32_to_cpu(readl(r))
+#define MAC_WRITE(v, r)		writel(cpu_to_le32(v), r)
+
+static char ftmac110_mac_addr[] = { 0x00, 0x41, 0x71, 0x00, 0x00, 0x52 };
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+	uint32_t tmp;
+
+	tmp = PHYCR_READ
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT)
+		| 0x30000000;
+
+	MAC_WRITE(tmp, &regs->phycr);
+
+	do {
+		tmp = MAC_READ(&regs->phycr);
+	} while (tmp & PHYCR_READ);
+
+	return (uint16_t)(tmp & 0xFFFF);
+}
+
+static void mdio_write(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+	unsigned int tmp;
+
+	tmp = PHYCR_WRITE
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT)
+		| 0x30000000;
+
+	MAC_WRITE(phydata, &regs->phydr);
+	MAC_WRITE(tmp, &regs->phycr);
+
+	do {
+		tmp = MAC_READ(&regs->phycr);
+	} while (tmp & PHYCR_WRITE);
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+	ulong ts;
+	uint32_t maccr;
+	uint16_t pa, tmp;
+	struct ftmac110_chip *chip = dev->priv;
+
+	maccr = MACCR_100M | MACCR_FD;
+
+	/* 0. find the phy device  */
+	for (pa = 0; pa < 32; ++pa) {
+		tmp = mdio_read(dev, pa, MII_PHYSID1);
+		if (tmp == 0xFFFF || tmp == 0x0000)
+			continue;
+		break;
+	}
+	if (pa >= 32) {
+		puts("ftmac110: phy device not found!\n");
+		return maccr;
+	} else {
+		chip->phy_addr = pa;
+	}
+
+	/* 1. check link status */
+	chip->lnkup = 0;
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		if (mdio_read(dev, chip->phy_addr, MII_BMSR)
+			& BMSR_LSTATUS) {
+			chip->lnkup = 1;
+			break;
+		}
+	}
+	if (!chip->lnkup) {
+		puts("ftmac110: link down\n");
+		goto exit;
+	}
+
+	/* 2. check A/N status */
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		if (mdio_read(dev, chip->phy_addr, MII_BMSR)
+			& BMSR_ANEGCOMPLETE)
+			break;
+	}
+	if (get_timer(ts) >= 1000) {
+		puts("ftmac110: A/N failed\n");
+		goto exit;
+	}
+
+	/* 3. build MACCR with the PHY status */
+	tmp  = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
+	tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
+
+	/* 3-1. 10/100Mbps Detection */
+	if (tmp & LPA_100FULL)        /* 100Mbps full-duplex */
+		maccr = MACCR_100M | MACCR_FD;
+	else if (tmp & LPA_100HALF)   /* 100Mbps half-duplex */
+		maccr = MACCR_100M;
+	else if (tmp & LPA_10FULL)    /* 10Mbps full-duplex */
+		maccr = MACCR_FD;
+	else if (tmp & LPA_10HALF)    /* 10Mbps half-duplex */
+		maccr = 0;
+	else
+		maccr = MACCR_100M | MACCR_FD;
+
+	printf("ftmac110: %d Mbps, %s\n",
+		   (maccr & MACCR_100M) ? 100 : 10,
+		   (maccr & MACCR_FD) ? "Full" : "half");
+
+exit:
+	return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+	uint8_t *a;
+	uint32_t i, maccr;
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+
+	/* 1. MAC reset */
+	MAC_WRITE(MACCR_RESET, &regs->maccr);
+	while (MAC_READ(&regs->maccr) & MACCR_RESET)
+		;
+
+	/* 1-1. Init tx ring */
+	for (i = 0; i < CFG_TXDES_NUM; ++i)
+		chip->txd[i].owner = 0;    /* owned by SW */
+	chip->txd_idx = 0;
+
+	/* 1-2. Init rx ring */
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		chip->rxd[i].owner = 1;    /* owned by HW */
+		chip->rxd[i].bufsz = cpu_to_le16(CFG_XBUF_SIZE);
+	}
+	chip->rxd_idx = 0;
+
+	/* 2. PHY status query */
+	maccr = ftmac110_phyqry(dev);
+
+	/* 3. Fix up the MACCR value */
+	chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+		| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+	chip->imr = 0;
+
+	/* 4. MAC address setup */
+	a = dev->enetaddr;
+	MAC_WRITE(a[1] | (a[0] << 8), &regs->mac[0]);
+	MAC_WRITE(a[5] | (a[4] << 8) | (a[3] << 16)
+		| (a[2] << 24), &regs->mac[1]);
+
+	/* 5. MAC registers setup */
+	MAC_WRITE(chip->rxd_dma, &regs->rxbar);
+	MAC_WRITE(chip->txd_dma, &regs->txbar);
+	MAC_WRITE(0x00001010, &regs->itc);
+	MAC_WRITE(0x00000001, &regs->aptc);
+	MAC_WRITE(0x00000390, &regs->dblac);
+	MAC_WRITE(0x000003FF, &regs->isr);
+	MAC_WRITE(chip->imr, &regs->imr);
+	MAC_WRITE(chip->maccr, &regs->maccr);
+
+	return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+	debug("ftmac110: probe\n");
+
+	if (ftmac110_reset(dev))
+		return -1;
+
+	return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+
+	MAC_WRITE(0, &regs->imr);
+	MAC_WRITE(0, &regs->maccr);
+
+	debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *packet, int length)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+	struct ftmac110_txd *cur_desc;
+
+	if (!chip->lnkup)
+		return 0;
+
+	if (length <= 0 || length > CFG_XBUF_SIZE) {
+		printf("ftmac110: bad tx packet length(%d)\n", length);
+		return 0;
+	}
+
+	if (length < 60)
+		length = 60;
+
+	cur_desc = &chip->txd[chip->txd_idx];
+	if (cur_desc->owner) {
+		/* kick-off Tx DMA */
+		MAC_WRITE(0xffffffff, &regs->txpd);
+		printf("ftmac110: out of txd\n");
+		return 0;
+	}
+
+	memcpy(cur_desc->vbuf, (void *)packet, length);
+	dma_map_single(cur_desc->vbuf, length, DMA_TO_DEVICE);
+
+	cur_desc->len   = cpu_to_le16(length);
+	cur_desc->lts   = 1;
+	cur_desc->fts   = 1;
+	cur_desc->owner = 1;
+
+	/* kick-off Tx DMA */
+	MAC_WRITE(0xffffffff, &regs->txpd);
+
+	chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
+
+	return length;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_rxd *cur_desc;
+	uint32_t rlen = 0;
+	uint8_t *buf;
+	uint16_t len;
+
+	if (!chip->lnkup)
+		return 0;
+
+	do {
+		cur_desc = &chip->rxd[chip->rxd_idx];
+		if (cur_desc->owner == 1)
+			break;
+
+		len = le16_to_cpu(cur_desc->len);
+		buf = cur_desc->vbuf;
+
+		if (cur_desc->error) {
+			printf("ftmac110: rx error\n");
+		} else {
+			dma_map_single(buf, len, DMA_FROM_DEVICE);
+			NetReceive(buf, len);
+			rlen += len;
+		}
+
+		cur_desc->len   = 0;
+		cur_desc->owner = 1;    /* owned by hardware */
+
+		chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
+	} while (0);
+
+	return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		*value = mdio_read(dev, addr, reg);
+	}
+
+	return ret;
+}
+
+static int ftmac110_mdio_write(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		mdio_write(dev, addr, reg, value);
+	}
+
+	return ret;
+}
+
+#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+	int i, card_number = 0;
+	char enetvar[32];
+	struct eth_device *dev;
+	struct ftmac110_chip *chip;
+
+	dev = malloc(sizeof(*dev) + sizeof(*chip));
+	if (dev == NULL) {
+		panic("ftmac110: out of memory 1\n");
+		return -1;
+	}
+	chip = (struct ftmac110_chip *)(dev + 1);
+	memset(dev, 0, sizeof(*dev) + sizeof(*chip));
+
+	sprintf(dev->name, "FTMAC110#%d", card_number);
+
+	dev->iobase = CONFIG_FTMAC110_BASE;
+	chip->regs = (void *)dev->iobase;
+	dev->priv = chip;
+	dev->init = ftmac110_probe;
+	dev->halt = ftmac110_halt;
+	dev->send = ftmac110_send;
+	dev->recv = ftmac110_recv;
+
+	sprintf(enetvar, card_number ? "eth%daddr" : "ethaddr", card_number);
+
+	if (!eth_getenv_enetaddr(enetvar, dev->enetaddr))
+		memcpy(dev->enetaddr, ftmac110_mac_addr, 6);
+
+	/* allocate tx descriptors (it must be 16 bytes aligned) */
+	chip->txd = dma_alloc_coherent(
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
+	if (chip->txd == NULL)
+		panic("ftmac110: out of memory 3\n");
+	memset((void *)chip->txd, 0,
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+		if (!va)
+			panic("ftmac110: out of memory 4\n");
+		chip->txd[i].vbuf  = va;
+		chip->txd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->txd[i].len   = 0;
+		chip->txd[i].end   = 0;
+		chip->txd[i].owner = 0;    /* owned by SW */
+	}
+	chip->txd[CFG_TXDES_NUM - 1].end = 1;
+	chip->txd_idx = 0;
+
+	/* allocate rx descriptors (it must be 16 bytes aligned) */
+	chip->rxd = dma_alloc_coherent(
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
+	if (!chip->rxd)
+		panic("ftmac110: out of memory 4\n");
+	memset((void *)chip->rxd, 0,
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+		if (!va)
+			panic("ftmac110: out of memory 5\n");
+		/* it needs to be exactly 2 bytes aligned */
+		va = ((uint8_t *)va + 2);
+		chip->rxd[i].vbuf  = va;
+		chip->rxd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->rxd[i].len   = 0;
+		chip->rxd[i].bufsz = cpu_to_le16(CFG_XBUF_SIZE);
+		chip->rxd[i].end   = 0;
+		chip->rxd[i].owner = 1;    /* owned by HW */
+	}
+	chip->rxd[CFG_RXDES_NUM - 1].end = 1;
+	chip->rxd_idx = 0;
+
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+	card_number++;
+
+	return card_number;
+}
diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h
new file mode 100644
index 0000000..2cf435b
--- /dev/null
+++ b/drivers/net/ftmac110.h
@@ -0,0 +1,159 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTMAC110_H
+#define _FTMAC110_H
+
+struct ftmac110_regs {
+	uint32_t isr;    /* 0x00: Interrups Status Register */
+	uint32_t imr;    /* 0x04: Interrupt Mask Register */
+	uint32_t mac[2]; /* 0x08: MAC Address */
+	uint32_t mht[2]; /* 0x10: Multicast Hash Table 0 Register */
+	uint32_t txpd;   /* 0x18: Transmit Poll Demand Register */
+	uint32_t rxpd;   /* 0x1c: Receive Poll Demand register */
+	uint32_t txbar;  /* 0x20: Tx Ring Base Address Register */
+	uint32_t rxbar;  /* 0x24: Rx Ring Base Address Register */
+	uint32_t itc;    /* 0x28: Interrupt Timer Control Register */
+	uint32_t aptc;   /* 0x2C: Automatic Polling Timer Control Register */
+	uint32_t dblac;  /* 0x30: DMA Burst Length&Arbitration Control */
+	uint32_t revr;   /* 0x34: Revision Register */
+	uint32_t fear;   /* 0x38: Feature Register */
+	uint32_t rsvd[19];
+	uint32_t maccr;  /* 0x88: MAC Control Register */
+	uint32_t macsr;  /* 0x8C: MAC Status Register */
+	uint32_t phycr;  /* 0x90: PHY Control Register */
+	uint32_t phydr;  /* 0x94: PHY Data Register */
+	uint32_t fcr;    /* 0x98: Flow Control Register */
+	uint32_t bpr;    /* 0x9C: Back Pressure Register */
+};
+
+/* Interrupt status/mask register(ISR/IMR) bits */
+#define ISR_PHYSTCHG     (1 << 9) /* phy status change */
+#define ISR_AHBERR       (1 << 8) /* bus error */
+#define ISR_RXLOST       (1 << 7) /* rx lost due to fifo overflow */
+#define ISR_RXFIFO       (1 << 6) /* rx to fifo */
+#define ISR_TXLOST       (1 << 5) /* tx lost due to collision */
+#define ISR_TXOK         (1 << 4) /* tx to ethernet */
+#define ISR_NOTXBUF      (1 << 3) /* out of tx buffer */
+#define ISR_TXFIFO       (1 << 2) /* packets transmitted to fifo */
+#define ISR_NORXBUF      (1 << 1) /* out of rx buffer */
+#define ISR_RXOK         (1 << 0) /* packets received to buffer (ram) */
+
+/* MACC control bits */
+#define MACCR_100M       (1 << 18) /* 100Mbps mode */
+#define MACCR_RXBCST     (1 << 17) /* receive all broadcast packet */
+#define MACCR_RXMCST     (1 << 16) /* receive all multicast packet */
+#define MACCR_FD         (1 << 15) /* full duplex */
+#define MACCR_CRCAPD     (1 << 14) /* append crc to transmit packet */
+#define MACCR_RXALL      (1 << 12) /* ignore dst address */
+#define MACCR_RXFTL      (1 << 11) /* rx packet even it's > 1518 byte */
+#define MACCR_RXRUNT     (1 << 10) /* rx packet even it's < 64 byte */
+#define MACCR_RXMCSTHT   (1 << 9)  /* rx multicast per hash table */
+#define MACCR_RXEN       (1 << 8)  /* rx enable */
+#define MACCR_RXINHDTX   (1 << 6)  /* rx in half duplex tx */
+#define MACCR_TXEN       (1 << 5)  /* tx enable */
+#define MACCR_CRCDIS     (1 << 4)  /* rx packet even it's crc error */
+#define MACCR_LOOPBACK   (1 << 3)  /* Internal loop-back */
+#define MACCR_RESET      (1 << 2)  /* reset */
+#define MACCR_RXDMAEN    (1 << 1)  /* enable rx dma */
+#define MACCR_TXDMAEN    (1 << 0)  /* enable tx dma */
+
+/* MDIO PHY bits */
+#define PHYCR_READ       (1 << 26)
+#define PHYCR_WRITE      (1 << 27)
+#define PHYCR_REG_SHIFT  21
+#define PHYCR_ADDR_SHIFT 16
+
+/*
+ * descriptor structure
+ */
+struct ftmac110_rxd {
+	/* RXDES0 */
+#ifdef __ARMEB__
+	uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
+	uint32_t rsvd3:1;
+	uint32_t frs:1;
+	uint32_t lrs:1;
+	uint32_t rsvd2:5;
+	uint32_t error:5;
+	uint32_t bcast:1;
+	uint32_t mcast:1;
+	uint32_t rsvd1:5;
+	uint32_t len:11;
+#else
+	uint32_t len:11;
+	uint32_t rsvd1:5;
+	uint32_t mcast:1;
+	uint32_t bcast:1;
+	uint32_t error:5;
+	uint32_t rsvd2:5;
+	uint32_t lrs:1;
+	uint32_t frs:1;
+	uint32_t rsvd3:1;
+	uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
+#endif
+
+	/* RXDES1 */
+#ifdef __ARMEB__
+	uint32_t end:1;
+	uint32_t rsvd4:20;
+	uint32_t bufsz:11;
+#else
+	uint32_t bufsz:11;
+	uint32_t rsvd4:20;
+	uint32_t end:1;
+#endif
+
+	/* RXDES2 */
+	uint32_t buf;
+
+	/* RXDES3 */
+	void    *vbuf;    /* It's not used in HW */
+};
+
+struct ftmac110_txd {
+	/* TXDES0 */
+#ifdef __ARMEB__
+	uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
+	uint32_t rsvd1:29;
+	uint32_t collision:2;
+#else
+	uint32_t collision:2;
+	uint32_t rsvd1:29;
+	uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
+#endif
+
+	/* TXDES1 */
+#ifdef __ARMEB__
+	uint32_t end:1;
+	uint32_t txic:1;
+	uint32_t tx2fic:1;
+	uint32_t fts:1;
+	uint32_t lts:1;
+	uint32_t rsvd2:16;
+	uint32_t len:11;
+#else
+	uint32_t len:11;
+	uint32_t rsvd2:16;
+	uint32_t lts:1;
+	uint32_t fts:1;
+	uint32_t tx2fic:1;
+	uint32_t txic:1;
+	uint32_t end:1;
+#endif
+
+	/* TXDES2 */
+	uint32_t buf;
+
+	/* TXDES3 */
+	void    *vbuf; /* It's not used in HW */
+};
+
+#endif  /* FTMAC110_H */
diff --git a/include/netdev.h b/include/netdev.h
index fd3e243..48c2fe5 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -67,6 +67,7 @@ int fecmxc_initialize(bd_t *bis);
 int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
 int ftgmac100_initialize(bd_t *bits);
 int ftmac100_initialize(bd_t *bits);
+int ftmac110_initialize(bd_t *bits);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
--
1.7.9.5

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

* [U-Boot] [PATCH v2 04/12] i2c: add Faraday FTI2C010 I2C controller support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (2 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 03/12] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 10:54       ` Wolfgang Denk
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
                       ` (8 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTI2C010 is a multi-function I2C controller
which supports both master and slave mode.
This patch simplily implements the master mode only.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Heiko Schocher <hs@denx.de>
---
 drivers/i2c/Makefile   |    1 +
 drivers/i2c/fti2c010.c |  363 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/fti2c010.h |   71 ++++++++++
 3 files changed, 435 insertions(+)
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 5dbdbe3..ed2b8c0 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
 COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
 COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
 COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
+COBJS-$(CONFIG_FTI2C010) += fti2c010.o
 COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
 COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
 COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
new file mode 100644
index 0000000..dbcab0d
--- /dev/null
+++ b/drivers/i2c/fti2c010.c
@@ -0,0 +1,363 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+
+#include "fti2c010.h"
+
+#define I2C_RD        1
+#define I2C_WR        0
+
+struct fti2c010_chip {
+	void    *regs;
+	uint32_t bus;
+	uint32_t speed;
+};
+
+#define I2C_READ(r)		le32_to_cpu(readl(r))
+#define I2C_WRITE(v, r)	writel(cpu_to_le32(v), r)
+
+#if defined(CONFIG_HARD_I2C)
+
+static struct fti2c010_chip fti2c010_info[] = {
+#ifdef CONFIG_I2C_MULTI_BUS
+# ifdef CONFIG_FTI2C010_BASE0
+	{
+		.bus   = 0,
+		.speed = 0,
+		.regs  = (void *)CONFIG_FTI2C010_BASE0,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE1
+	{
+		.bus   = 1,
+		.speed = 0,
+		.regs  = (void *)CONFIG_FTI2C010_BASE1,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE2
+	{
+		.bus   = 2,
+		.speed = 0,
+		.regs  = (void *)CONFIG_FTI2C010_BASE2,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE3
+	{
+		.bus   = 3,
+		.speed = 0,
+		.regs  = (void *)CONFIG_FTI2C010_BASE3,
+	},
+# endif
+#else    /* #ifdef CONFIG_I2C_MULTI_BUS */
+	{
+		.bus   = 0,
+		.speed = 0,
+		.regs  = (void *)CONFIG_FTI2C010_BASE,
+	},
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+};
+
+static struct fti2c010_chip *priv = fti2c010_info;
+
+static int fti2c010_wait(uint32_t mask)
+{
+	int ret = -1;
+	uint32_t stat, t;
+	struct fti2c010_regs *regs = priv->regs;
+
+	for (t = get_timer(0); get_timer(t) < 100; ) {
+		stat = I2C_READ(&regs->sr);
+		if ((stat & mask) == mask) {
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * u-boot I2C API
+ */
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+	if (speed || priv->speed == 0)
+		i2c_set_bus_speed(speed);
+}
+
+/*
+ * Probe the given I2C chip address.  Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uchar chip)
+{
+	int rc;
+	struct fti2c010_regs *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	/* 1. Select slave device (7bits Address + 1bit R/W) */
+	I2C_WRITE((chip << 1) + I2C_WR, &regs->dr);
+	I2C_WRITE(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* 2. Select device register */
+	I2C_WRITE(0, &regs->dr);
+	I2C_WRITE(CR_ENABLE | CR_TBEN, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+	struct fti2c010_regs *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	I2C_WRITE((chip << 1) + I2C_WR, &regs->dr);
+	I2C_WRITE(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		I2C_WRITE(paddr[pos], &regs->dr);
+		I2C_WRITE(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Get register data
+	 */
+
+	/* B.1 Select slave device (7bits Address + 1bit R/W) */
+	I2C_WRITE((chip << 1) + I2C_RD, &regs->dr);
+	I2C_WRITE(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* B.2 Get register data */
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		uint32_t stat = SR_DR;
+		if (pos == len - 1) {
+			ctrl |= CR_NAK | CR_STOP;
+			stat |= SR_ACK;
+		}
+		I2C_WRITE(ctrl, &regs->cr);
+		rc = fti2c010_wait(stat);
+		if (rc)
+			break;
+		buf[pos] = (uchar)(I2C_READ(&regs->dr) & 0xFF);
+	}
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+	struct fti2c010_regs *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	I2C_WRITE((chip << 1) + I2C_WR, &regs->dr);
+	I2C_WRITE(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		I2C_WRITE(paddr[pos], &regs->dr);
+		I2C_WRITE(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Set register data
+	 */
+
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		if (pos == len - 1)
+			ctrl |= CR_STOP;
+		I2C_WRITE(buf[pos], &regs->dr);
+		I2C_WRITE(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
+ * Functions for setting the current I2C bus and its speed
+ */
+#ifdef CONFIG_I2C_MULTI_BUS
+
+/*
+ * i2c_set_bus_num:
+ *
+ *  Change the active I2C bus.  Subsequent read/write calls will
+ *  go to this one.
+ *
+ *    bus - bus index, zero based
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_num(unsigned int bus)
+{
+	if (bus >= sizeof(fti2c010_info) / sizeof(fti2c010_info[0]))
+		return -1;
+	priv = fti2c010_info + bus;
+	i2c_init(5000, 0);
+	return 0;
+}
+
+/*
+ * i2c_get_bus_num:
+ *
+ *  Returns index of currently active I2C bus.  Zero-based.
+ */
+
+unsigned int i2c_get_bus_num(void)
+{
+	return priv->bus;
+}
+
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+
+/*
+ * i2c_set_bus_speed:
+ *
+ *  Change the speed of the active I2C bus
+ *
+ *    speed - bus speed in Hz
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_speed(unsigned int speed)
+{
+	struct fti2c010_regs *regs = priv->regs;
+#ifdef CONFIG_FTI2C010_SCLK
+	ulong apb = CONFIG_FTI2C010_SCLK;
+#else
+	ulong apb = clk_get_rate("I2C");
+#endif
+	ulong div = 0x640;
+	ulong gsr = 0;
+	ulong tsr = 0x20;
+	ulong ts;
+
+	I2C_WRITE(BIT_MASK(0), &regs->cr);
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		if (!(I2C_READ(&regs->cr) & BIT_MASK(0)))
+			break;
+	}
+
+	/* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
+	priv->speed = apb / (2 * (div + 2) + gsr);
+
+	if (speed > 0) {
+		for (div = 0; div < 0x1000000; ++div) {
+			priv->speed = apb / (2 * (div + 2) + gsr);
+			if (priv->speed < speed)
+				break;
+		}
+	}
+
+	I2C_WRITE((gsr << 10) | tsr, &regs->tgsr);
+	I2C_WRITE(div, &regs->cdr);
+
+	return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ *  Returns speed of currently active I2C bus in Hz
+ */
+
+unsigned int i2c_get_bus_speed(void)
+{
+	return priv->speed;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/fti2c010.h b/drivers/i2c/fti2c010.h
new file mode 100644
index 0000000..214f55a
--- /dev/null
+++ b/drivers/i2c/fti2c010.h
@@ -0,0 +1,71 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTI2C010_H
+#define _FTI2C010_H
+
+/*
+ * FTI2C010 registers
+ */
+struct fti2c010_regs {
+	uint32_t cr;  /* 0x00: control register */
+	uint32_t sr;  /* 0x04: status register */
+	uint32_t cdr; /* 0x08: clock division register */
+	uint32_t dr;  /* 0x0c: data register */
+	uint32_t sar; /* 0x10: slave address register */
+	uint32_t tgsr;/* 0x14: time & glitch suppression register */
+	uint32_t bmr; /* 0x18: bus monitor register */
+	uint32_t rsvd[5];
+	uint32_t revr;/* 0x30: revision register */
+};
+
+/*
+ * REG_CTRL
+ */
+#define CR_ALIEN      0x2000  /* Arbitration lose */
+#define CR_SAMIEN     0x1000  /* slave address match */
+#define CR_STOPIEN    0x800   /* stop condition */
+#define CR_BERRIEN    0x400   /* non ACK response */
+#define CR_DRIEN      0x200   /* data receive */
+#define CR_DTIEN      0x100   /* data transmit */
+#define CR_TBEN       0x80    /* transfer byte enable */
+#define CR_NAK        0x40    /* NACK */
+#define CR_STOP       0x20    /* stop */
+#define CR_START      0x10    /* start */
+#define CR_GCEN       0x8     /* general call */
+#define CR_SCLEN      0x4     /* enable clock */
+#define CR_I2CEN      0x2     /* enable I2C */
+#define CR_I2CRST     0x1     /* reset I2C */
+#define CR_ENABLE	\
+	(CR_ALIEN | CR_SAMIEN | CR_STOPIEN | CR_BERRIEN \
+	| CR_DRIEN | CR_DTIEN | CR_SCLEN | CR_I2CEN)
+
+/*
+ * REG_STAT
+ */
+#define SR_CLRAL      0x400
+#define SR_CLRGC      0x200
+#define SR_CLRSAM     0x100
+#define SR_CLRSTOP    0x80
+#define SR_CLRBERR    0x40
+#define SR_DR         0x20     /* DR received one new data byte */
+#define SR_DT         0x10     /* DR trandmitted one new data byte */
+#define SR_BB         0x8
+#define SR_BUSY       0x4
+#define SR_ACK        0x2
+#define SR_RW         0x1
+
+/*
+ * REG_BMR
+ */
+#define BMR_SCL         0x2
+#define BMR_SDA         0x1
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (3 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 04/12] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 10:56       ` Wolfgang Denk
  2013-08-08 13:38       ` Jagan Teki
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 06/12] mmc: add an alternative driver to Faraday FTSDC010 Kuo-Jung Su
                       ` (7 subsequent siblings)
  12 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FTSSP010 is a multi-function controller
which supports I2S/SPI/SSP/AC97/SPDIF.
This patch simpily implements the SPI mode only.
BTW the DMA and CS/Clock control logic has been
altered since revision 1.19.0. So this patch
would 1st detects the revision id of the underlying
chip, and then switch to the corresponding control
routines.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/spi/Makefile       |    1 +
 drivers/spi/ftssp010_spi.c |  337 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/ftssp010_spi.h |   86 +++++++++++
 3 files changed, 424 insertions(+)
 create mode 100644 drivers/spi/ftssp010_spi.c
 create mode 100644 drivers/spi/ftssp010_spi.h

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d08609e..947d60e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
 COBJS-$(CONFIG_CF_SPI) += cf_spi.o
 COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
 COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
+COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
 COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
 COBJS-$(CONFIG_ICH_SPI) +=  ich.o
 COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
new file mode 100644
index 0000000..4247c8c
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.c
@@ -0,0 +1,337 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <malloc.h>
+
+#include "ftssp010_spi.h"
+
+struct ftssp010_chip {
+	void    *iobase;
+	uint32_t fifo;
+	uint32_t rev;
+	uint32_t div;
+	uint32_t mode;
+
+	struct {
+		uint32_t iobase;
+		uint32_t pin;
+	} gpio;
+};
+
+static struct ftssp010_chip chip_list[] = {
+#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0)
+	{
+		.iobase = (void *)CONFIG_FTSSP010_BASE,
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		.gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN },
+#endif
+	},
+#endif
+#ifdef CONFIG_FTSSP010_BASE1
+	{ .iobase = (void *)CONFIG_FTSSP010_BASE1, },
+#endif
+#ifdef CONFIG_FTSSP010_BASE2
+	{ .iobase = (void *)CONFIG_FTSSP010_BASE2, },
+#endif
+#ifdef CONFIG_FTSSP010_BASE3
+	{ .iobase = (void *)CONFIG_FTSSP010_BASE3, },
+#endif
+};
+
+/* Register access macros */
+#define SPI_READ(r)			le32_to_cpu(readl(r))
+#define SPI_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define SPI_SETBITS(m, r)	setbits_le32(r, m)
+#define SPI_CLRBITS(m, r)	clrbits_le32(r, m)
+
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+#define SPI_GPIO_READ(p, r)	\
+	le32_to_cpu(readl((p)->gpio.iobase + (r)))
+#define SPI_GPIO_WRITE(p, v, r)	\
+	writel(cpu_to_le32(v), (p)->gpio.iobase + (r))
+#define SPI_GPIO_SETBITS(p, m, r)	\
+	setbits_le32((p)->gpio.iobase + (r), m)
+#define SPI_GPIO_CLRBITS(p, m, r)	\
+	clrbits_le32((p)->gpio.iobase + (r), m)
+#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */
+
+static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs *regs = chip->iobase;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t xmsk = 0;
+
+		if (tx_buf) {
+			for (i = 0; i < depth; ++i) {
+				while (!(SPI_READ(&regs->sr) & SR_TFNF))
+					;
+				SPI_WRITE(*txb++, &regs->dr);
+			}
+			xmsk |= CR2_TXEN | CR2_TXDOE;
+			if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
+				SPI_SETBITS(xmsk, &regs->cr[2]);
+		}
+		if (rx_buf) {
+			xmsk |= CR2_RXEN;
+			if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
+				SPI_SETBITS(xmsk, &regs->cr[2]);
+			for (i = 0; i < depth; ++i) {
+				while (!SR_RFVE(SPI_READ(&regs->sr)))
+					;
+				*rxb++ = (uint8_t)SPI_READ(&regs->dr);
+			}
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs *regs = chip->iobase;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t tmp;
+
+		for (i = 0; i < depth; ++i) {
+			while (!(SPI_READ(&regs->sr) & SR_TFNF))
+				;
+			SPI_WRITE(txb ? (*txb++) : 0, &regs->dr);
+		}
+		for (i = 0; i < depth; ++i) {
+			while (!SR_RFVE(SPI_READ(&regs->sr)))
+				;
+			tmp = SPI_READ(&regs->dr);
+			if (rxb)
+				*rxb++ = (uint8_t)tmp;
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+/*=====================================================================*/
+/*                         Public Functions                            */
+/*=====================================================================*/
+
+/*-----------------------------------------------------------------------
+ * Determine if a SPI chipselect is valid.
+ * This function is provided by the board if the low-level SPI driver
+ * needs it to determine if a given chipselect is actually valid.
+ *
+ * Returns: 1 if bus:cs identifies a valid chip on this board, 0
+ * otherwise.
+ */
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	struct ftssp010_chip *chip;
+	struct ftssp010_regs *regs;
+	uint32_t txfifo, rxfifo;
+
+	if (bus >= ARRAY_SIZE(chip_list))
+		return 0;
+
+	chip = chip_list + bus;
+	regs = chip->iobase;
+	chip->rev = SPI_READ(&regs->revr);
+	txfifo = FEAR_TXFIFO(SPI_READ(&regs->fear));
+	rxfifo = FEAR_RXFIFO(SPI_READ(&regs->fear));
+	chip->fifo = min(txfifo, rxfifo);
+
+	printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
+
+	if (chip->rev >= 0x00011900) {
+		if (cs > 3)
+			return 0;
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		if (cs > 0)
+			return 0;
+		/* setup gpio pin as an output pin */
+		SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08);
+#else
+		return 0;
+#endif
+	}
+
+	return 1;
+}
+
+/*-----------------------------------------------------------------------
+ * Activate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should activate the chip select
+ * to the device identified by "slave".
+ */
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs *regs = chip->iobase;
+
+	/* cs pull low */
+	if (chip->rev >= 0x00011900) {
+		SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
+			| CR2_RXFCLR, &regs->cr[2]);
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14);
+#endif
+	}
+	udelay_masked(1);
+}
+
+/*-----------------------------------------------------------------------
+ * Deactivate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should deactivate the chip
+ * select to the device identified by "slave".
+ */
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs *regs = chip->iobase;
+
+	/* wait until device idle */
+	while (SPI_READ(&regs->sr) & SR_BUSY)
+		;
+
+	/* cs pull high */
+	if (chip->rev >= 0x00011900) {
+		SPI_WRITE((slave->cs << 10) | CR2_FS, &regs->cr[2]);
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10);
+#endif
+	}
+	udelay_masked(1);
+}
+
+void spi_init(void)
+{
+}
+
+struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
+{
+	uint32_t clk, div;
+	struct spi_slave *ss;
+	struct ftssp010_chip *chip;
+
+	if (!spi_cs_is_valid(bus, cs))
+		return NULL;
+
+	if (mode != SPI_MODE_0) {
+		printf("ftssp010: MODE%d is not supported\n", mode);
+		return NULL;
+	}
+
+	ss = malloc(sizeof(struct spi_slave));
+	if (!ss)
+		return NULL;
+
+	ss->bus = bus;
+	ss->cs  = cs;
+
+#ifdef CONFIG_FTSSP010_SCLK
+	clk = CONFIG_FTSSP010_SCLK;
+#else
+	clk = clk_get_rate("SSP");
+#endif
+	if (max_hz > 0) {
+		for (div = 0; div < 0xFFFF; ++div) {
+			if ((clk / (2 * (div + 1))) <= max_hz)
+				break;
+		}
+	} else {
+		div = 7;
+	}
+
+	chip = chip_list + bus;
+	chip->div  = div;
+	chip->mode = mode;
+
+	printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
+
+	return ss;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs *regs = chip->iobase;
+
+	SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
+
+	if (chip->rev >= 0x00011900) {
+		SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
+			&regs->cr[0]);
+		SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR,
+			&regs->cr[2]);
+	} else {
+		SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
+			&regs->cr[0]);
+		SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
+			&regs->cr[2]);
+	}
+
+	spi_cs_deactivate(slave);
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs *regs = chip->iobase;
+
+	SPI_WRITE(0, &regs->cr[2]);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+			 const void *dout, void *din, unsigned long flags)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	uint32_t len = bitlen >> 3;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(slave);
+
+	if (chip->rev >= 0x00011900)
+		ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags);
+	else
+		ftssp010_spi_work_transfer(chip, dout, din, len, flags);
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(slave);
+
+	return 0;
+}
diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
new file mode 100644
index 0000000..5ad7c47
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.h
@@ -0,0 +1,86 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTSSP010_H
+#define _FTSSP010_H
+
+/* FTSSP010 HW Registers */
+struct ftssp010_regs {
+	uint32_t cr[3];/* control register */
+	uint32_t sr;   /* status register */
+	uint32_t icr;  /* interrupt control register */
+	uint32_t isr;  /* interrupt status register */
+	uint32_t dr;   /* data register */
+	uint32_t rsvd[17];
+	uint32_t revr; /* revision register */
+	uint32_t fear; /* feature register */
+};
+
+/* Control register 0  */
+#define CR0_FFMT_MASK       (7 << 12)
+#define CR0_FFMT_SSP        (0 << 12)
+#define CR0_FFMT_SPI        (1 << 12)
+#define CR0_FFMT_MICROWIRE  (2 << 12)
+#define CR0_FFMT_I2S        (3 << 12)
+#define CR0_FFMT_AC97       (4 << 12)
+#define CR0_FLASH           (1 << 11)
+#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
+#define CR0_LBM             (1 << 7)  /* Loopback mode */
+#define CR0_LSB             (1 << 6)  /* LSB first */
+#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
+#define CR0_FSJUSTIFY       (1 << 4)
+#define CR0_OPM_SLAVE       (0 << 2)
+#define CR0_OPM_MASTER      (3 << 2)
+#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
+#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
+#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
+#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
+#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
+#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
+
+/* Control Register 1 */
+
+#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
+#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
+#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
+
+/* Control Register 2 */
+#define CR2_FSOS(x)         (((x) & 0x03) << 10)	/* FS/CS Select */
+#define CR2_FS              (1 << 9)	/* FS/CS Signal Level */
+#define CR2_TXEN            (1 << 8)	/* Tx Enable */
+#define CR2_RXEN            (1 << 7)	/* Rx Enable */
+#define CR2_SSPRST          (1 << 6)	/* SSP reset */
+#define CR2_TXFCLR          (1 << 3)	/* TX FIFO Clear */
+#define CR2_RXFCLR          (1 << 2)	/* RX FIFO Clear */
+#define CR2_TXDOE           (1 << 1)	/* TX Data Output Enable */
+#define CR2_SSPEN           (1 << 0)	/* SSP Enable */
+
+/*
+ * Status Register
+ */
+#define SR_RFF       (1 << 0) /* receive FIFO full */
+#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
+#define SR_BUSY      (1 << 2) /* bus is busy */
+#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid entries */
+#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */
+
+/*
+ * Feature Register
+ */
+#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
+#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
+#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
+#define FEAR_AC97        (1 << 24)
+#define FEAR_I2S         (1 << 25)
+#define FEAR_SPI_MWR     (1 << 26)
+#define FEAR_SSP         (1 << 27)
+#define FEAR_SPDIF       (1 << 28)
+
+#endif
-- 
1.7.9.5

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

* [U-Boot] [PATCH v2 06/12] mmc: add an alternative driver to Faraday FTSDC010
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (4 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 10:57       ` Wolfgang Denk
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
                       ` (6 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTSDC010 is a MMC/SD host controller.
Although there is already a driver in current u-boot release,
which is modified from eSHDC and contributed by Andes Tech.
Its performance is too terrible on Faraday A36x SoC platforms,
so I turn to implement this new version of driver which is
10+ times faster than the old one.

If the hardware platform is avaiable, you may modify the
'include/configs/a369_defaults.h' for performance evaluation.

Here is the code snapshot of the 'a369_defaults.h'

#if 1
#define CONFIG_FTSDC010_MCI    1
#define CONFIG_FTSDC010_SDIO   1 /* The hardware core supports SDIO */
#else
#define CONFIG_FTSDC010        1
#define CONFIG_FTSDC010_SDIO   1 /* The hardware core supports SDIO */
#define CONFIG_FTSDC010_NUMBER 1
#define CONFIG_SYS_CLK_FREQ    133000000 /* AHB clock */
#endif
#define CONFIG_MMC             1
#define CONFIG_CMD_MMC         1
#define CONFIG_GENERIC_MMC     1

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Andy Fleming <afleming@gmail.com>
---
 drivers/mmc/Makefile       |    1 +
 drivers/mmc/ftsdc010_mci.c |  373 ++++++++++++++++++++++++++++++++++++++++++++
 include/faraday/ftsdc010.h |   16 +-
 include/faraday/mmc.h      |   16 ++
 4 files changed, 403 insertions(+), 3 deletions(-)
 create mode 100644 drivers/mmc/ftsdc010_mci.c
 create mode 100644 include/faraday/mmc.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 1d6faa2..52908bd 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -33,6 +33,7 @@ COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
 COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
 COBJS-$(CONFIG_FTSDC010) += ftsdc010_esdhc.o
+COBJS-$(CONFIG_FTSDC010_MCI) += ftsdc010_mci.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
 COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
new file mode 100644
index 0000000..52c5a71
--- /dev/null
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -0,0 +1,373 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <faraday/ftsdc010.h>
+
+#define SD_READ(r)			le32_to_cpu(readl(r))
+#define SD_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define SD_SETBITS(m, r)	setbits_le32(r, m)
+#define SD_CLRBITS(m, r)	clrbits_le32(r, m)
+
+struct ftsdc010_chip {
+	void    *iobase;
+	uint32_t wprot;   /* write protected (locked) */
+	uint32_t rate;    /* actual SD clock in Hz */
+	uint32_t sclk;    /* FTSDC010 source clock in Hz */
+	uint32_t fifo;    /* fifo depth in bytes */
+	uint32_t acmd;
+};
+
+static inline int
+ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc *regs = chip->iobase;
+	int ret = -TIMEOUT;
+	uint32_t ts, st;
+	uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
+	uint32_t arg   = mmc_cmd->cmdarg;
+	uint32_t flags = mmc_cmd->resp_type;
+
+	cmd |= FTSDC010_CMD_CMD_EN;
+
+	if (chip->acmd) {
+		cmd |= FTSDC010_CMD_APP_CMD;
+		chip->acmd = 0;
+	}
+
+	if (flags & MMC_RSP_PRESENT)
+		cmd |= FTSDC010_CMD_NEED_RSP;
+
+	if (flags & MMC_RSP_136)
+		cmd |= FTSDC010_CMD_LONG_RSP;
+
+	SD_WRITE(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
+		&regs->clr);
+	SD_WRITE(arg, &regs->argu);
+	SD_WRITE(cmd, &regs->cmd);
+
+	if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
+		for (ts = get_timer(0); get_timer(ts) < 100; ) {
+			if (SD_READ(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
+				SD_WRITE(FTSDC010_STATUS_CMD_SEND, &regs->clr);
+				ret = 0;
+				break;
+			}
+		}
+	} else {
+		st = 0;
+		for (ts = get_timer(0); get_timer(ts) < 100; ) {
+			st = SD_READ(&regs->status);
+			SD_WRITE(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
+			if (st & FTSDC010_STATUS_RSP_MASK)
+				break;
+		}
+		if (st & FTSDC010_STATUS_RSP_CRC_OK) {
+			if (flags & MMC_RSP_136) {
+				mmc_cmd->response[0] = SD_READ(&regs->rsp3);
+				mmc_cmd->response[1] = SD_READ(&regs->rsp2);
+				mmc_cmd->response[2] = SD_READ(&regs->rsp1);
+				mmc_cmd->response[3] = SD_READ(&regs->rsp0);
+			} else {
+				mmc_cmd->response[0] = SD_READ(&regs->rsp0);
+			}
+			ret = 0;
+		} else {
+			debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
+				mmc_cmd->cmdidx, st);
+		}
+	}
+
+	if (ret) {
+		debug("ftsdc010: cmd timeout (op code=%d)\n",
+			mmc_cmd->cmdidx);
+	} else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
+		chip->acmd = 1;
+	}
+
+	return ret;
+}
+
+static int
+ftsdc010_wait(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc *regs = chip->iobase;
+	int ret = -TIMEOUT;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		uint32_t st = SD_READ(&regs->status);
+		SD_WRITE(st & FTSDC010_STATUS_DATA_MASK, &regs->clr);
+
+		if (st & FTSDC010_STATUS_DATA_ERROR) {
+			debug("ftsdc010: data error!(st=0x%x)\n", st);
+			break;
+		} else if (st & FTSDC010_STATUS_DATA_END) {
+			ret = 0;
+			break;
+		}
+	}
+
+	if (ret)
+		debug("ftsdc010: wait timeout\n");
+
+	return ret;
+}
+
+static void
+ftsdc010_clkset(struct ftsdc010_chip *chip, uint32_t rate)
+{
+	uint32_t div;
+	uint32_t clk = chip->sclk;
+	struct ftsdc010_mmc *regs = chip->iobase;
+
+	for (div = 0; div < 0x7f; ++div) {
+		if (rate >= clk / (2 * (div + 1)))
+			break;
+	}
+	SD_WRITE(FTSDC010_CCR_CLK_SD | FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
+
+	chip->rate = clk / (2 * (div + 1));
+}
+
+static inline int
+ftsdc010_is_ro(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	const uint8_t *csd = (const uint8_t *)mmc->csd;
+
+	if (chip->wprot || (csd[1] & 0x30))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * u-boot mmc api
+ */
+
+static int ftsdc010_request(struct mmc *mmc,
+							struct mmc_cmd *cmd,
+							struct mmc_data *data)
+{
+	int ret = -UNUSABLE_ERR;
+	uint32_t len = 0;
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc *regs = chip->iobase;
+
+	if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
+		printf("ftsdc010: the card is write protected!\n");
+		return ret;
+	}
+
+	if (data) {
+		uint32_t dcr;
+
+		len = data->blocksize * data->blocks;
+
+		/* 1. data disable + fifo reset */
+		SD_WRITE(FTSDC010_DCR_FIFO_RST, &regs->dcr);
+
+		/* 2. clear status register */
+		SD_WRITE(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
+			| FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
+
+		/* 3. data timeout (1 sec) */
+		SD_WRITE(chip->rate, &regs->dtr);
+
+		/* 4. data length (bytes) */
+		SD_WRITE(len, &regs->dlr);
+
+		/* 5. data enable */
+		dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
+		if (data->flags & MMC_DATA_WRITE)
+			dcr |= FTSDC010_DCR_DATA_WRITE;
+		SD_WRITE(dcr, &regs->dcr);
+	}
+
+	ret = ftsdc010_send_cmd(mmc, cmd);
+	if (ret) {
+		printf("ftsdc010: sending CMD%d failed\n", cmd->cmdidx);
+		return ret;
+	}
+
+	if (!data)
+		return ret;
+
+	if (data->flags & MMC_DATA_WRITE) {
+		const uint8_t *buf = (const uint8_t *)data->src;
+
+		while (len > 0) {
+			int wlen;
+			uint32_t mask = FTSDC010_STATUS_FIFO_URUN;
+
+			/* wait data ready */
+			while (!(SD_READ(&regs->status) & mask))
+				;
+			SD_WRITE(mask, &regs->clr);
+
+			/* write bytes to ftsdc010 */
+			for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
+				SD_WRITE(*(uint32_t *)buf, &regs->dwr);
+				buf  += 4;
+				wlen += 4;
+			}
+
+			len -= wlen;
+		}
+
+	} else {
+		uint8_t *buf = (uint8_t *)data->dest;
+
+		while (len > 0) {
+			int rlen;
+			uint32_t mask = FTSDC010_STATUS_FIFO_ORUN;
+
+			/* wait data ready */
+			while (!(SD_READ(&regs->status) & mask))
+				;
+			SD_WRITE(mask, &regs->clr);
+
+			/* fetch bytes from ftsdc010 */
+			for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
+				*(uint32_t *)buf = SD_READ(&regs->dwr);
+				buf  += 4;
+				rlen += 4;
+			}
+
+			len -= rlen;
+		}
+
+	}
+
+	return ftsdc010_wait(mmc);
+}
+
+static void ftsdc010_set_ios(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc *regs = chip->iobase;
+
+	ftsdc010_clkset(chip, mmc->clock);
+
+	if (mmc->clock > 25000000)
+		SD_SETBITS(FTSDC010_CCR_CLK_HISPD, &regs->ccr);
+	else
+		SD_CLRBITS(FTSDC010_CCR_CLK_HISPD, &regs->ccr);
+
+	SD_CLRBITS(0x07, &regs->bwr);
+	switch (mmc->bus_width) {
+	case 4:
+		SD_SETBITS(FTSDC010_BWR_WIDE_4_BUS, &regs->bwr);
+		break;
+	case 8:
+		SD_SETBITS(FTSDC010_BWR_WIDE_8_BUS, &regs->bwr);
+		break;
+	default:
+		SD_SETBITS(FTSDC010_BWR_SINGLE_BUS, &regs->bwr);
+		break;
+	}
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc *regs = chip->iobase;
+
+	if (SD_READ(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
+		return NO_CARD_ERR;
+
+	if (SD_READ(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
+		printf("ftsdc010: write protected\n");
+		chip->wprot = 1;
+	}
+
+	chip->fifo = (SD_READ(&regs->feature) & 0xff) << 2;
+
+	/* 1. chip reset */
+	SD_WRITE(FTSDC010_CMD_SDC_RST, &regs->cmd);
+	while (SD_READ(&regs->cmd) & FTSDC010_CMD_SDC_RST)
+		;
+
+	/* 2. enter low speed mode (400k card detection) */
+	ftsdc010_clkset(chip, 400000);
+
+	/* 3. interrupt disabled */
+	SD_WRITE(0, &regs->int_mask);
+
+	return 0;
+}
+
+int ftsdc010_mmc_init(int devid)
+{
+	struct mmc *mmc = NULL;
+	struct ftsdc010_chip *chip = NULL;
+	struct ftsdc010_mmc *regs = NULL;
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		return -ENOMEM;
+	memset(mmc, 0, sizeof(struct mmc));
+
+	chip = malloc(sizeof(struct ftsdc010_chip));
+	if (!chip) {
+		free(mmc);
+		return -ENOMEM;
+	}
+	memset(chip, 0, sizeof(struct ftsdc010_chip));
+
+	chip->iobase = (void *)(CONFIG_FTSDC010_BASE + (devid << 20));
+	mmc->priv    = chip;
+
+	regs = chip->iobase;
+
+	sprintf(mmc->name, "ftsdc010");
+	mmc->send_cmd = ftsdc010_request;
+	mmc->set_ios  = ftsdc010_set_ios;
+	mmc->init     = ftsdc010_init;
+
+	switch ((SD_READ(&regs->bwr) >> 3) & 3) {
+	case 1:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz
+			| MMC_MODE_4BIT;
+		break;
+	case 2:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz
+			| MMC_MODE_4BIT | MMC_MODE_8BIT;
+		break;
+	default:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+		break;
+	}
+
+#ifdef CONFIG_SYS_CLK_FREQ
+	chip->sclk = CONFIG_SYS_CLK_FREQ;
+#else
+	chip->sclk = clk_get_rate("SDC");
+#endif
+
+	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->f_max     = chip->sclk / 2;
+	mmc->f_min     = chip->sclk / 0x100;
+	mmc->block_dev.part_type = PART_TYPE_DOS;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/include/faraday/ftsdc010.h b/include/faraday/ftsdc010.h
index c34dde7..d8c289c 100644
--- a/include/faraday/ftsdc010.h
+++ b/include/faraday/ftsdc010.h
@@ -23,6 +23,9 @@
 #define __FTSDC010_H

 #ifndef __ASSEMBLY__
+
+#include "mmc.h"
+
 /* sd controller register */
 struct ftsdc010_mmc {
 	unsigned int	cmd;		/* 0x00 - command reg		*/
@@ -67,9 +70,6 @@ struct mmc_host {
 	unsigned int card_type;		/* Card type */
 };

-/* functions */
-int ftsdc010_mmc_init(int dev_index);
-
 #endif	/* __ASSEMBLY__ */

 /* global defines */
@@ -143,6 +143,15 @@ int ftsdc010_mmc_init(int dev_index);
 #define FTSDC010_STATUS_SDIO_IRPT		(1 << 16) /* SDIO card intr */
 #define FTSDC010_STATUS_DATA0_STATUS		(1 << 17)
 #endif /* CONFIG_FTSDC010_SDIO */
+#define FTSDC010_STATUS_RSP_ERROR	\
+	(FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_RSP_TIMEOUT)
+#define FTSDC010_STATUS_RSP_MASK	\
+	(FTSDC010_STATUS_RSP_ERROR | FTSDC010_STATUS_RSP_CRC_OK)
+#define FTSDC010_STATUS_DATA_ERROR	\
+	(FTSDC010_STATUS_DATA_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT)
+#define FTSDC010_STATUS_DATA_MASK	\
+	(FTSDC010_STATUS_DATA_ERROR | FTSDC010_STATUS_DATA_CRC_OK \
+	| FTSDC010_STATUS_DATA_END)

 /* 0x2c - clear register */
 #define FTSDC010_CLR_RSP_CRC_FAIL		(1 << 0)
@@ -192,6 +201,7 @@ int ftsdc010_mmc_init(int dev_index);
 #define FTSDC010_CCR_CLK_DIV(x)			(((x) & 0x7f) << 0)
 #define FTSDC010_CCR_CLK_SD			(1 << 7) /* 0: MMC, 1: SD */
 #define FTSDC010_CCR_CLK_DIS			(1 << 8)
+#define FTSDC010_CCR_CLK_HISPD			(1 << 9) /* high speed */

 /* card type */
 #define FTSDC010_CARD_TYPE_SD			FTSDC010_CLOCK_REG_CARD_TYPE
diff --git a/include/faraday/mmc.h b/include/faraday/mmc.h
new file mode 100644
index 0000000..ed09292
--- /dev/null
+++ b/include/faraday/mmc.h
@@ -0,0 +1,16 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FARADAY_MMC_H
+#define _FARADAY_MMC_H
+
+int ftsdc010_mmc_init(int dev_index);
+
+#endif /* _FARADAY_MMC_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (5 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 06/12] mmc: add an alternative driver to Faraday FTSDC010 Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 11:04       ` Wolfgang Denk
  2013-04-18 19:44       ` Scott Wood
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 08/12] mtd: spi: add FTSPI020 SPI Flash " Kuo-Jung Su
                       ` (5 subsequent siblings)
  12 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is a integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Scott Wood <scottwood@freescale.com>
---
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  544 +++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/ftnandc021.h |  132 ++++++++++
 include/faraday/nand.h        |   16 ++
 4 files changed, 693 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/mtd/nand/ftnandc021.h
 create mode 100644 include/faraday/nand.h

diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 35769c5..f6f89f0 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -63,6 +63,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..58863dc
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,544 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <nand.h>
+#include <malloc.h>
+
+#include "ftnandc021.h"
+
+/* common bitmask of nand flash status register */
+#define NAND_IOSTATUS_ERROR		BIT_MASK(0)
+#define NAND_IOSTATUS_READY		BIT_MASK(6)
+#define NAND_IOSTATUS_UNPROTCT	BIT_MASK(7)
+
+struct ftnandc021_chip {
+	void    *iobase;
+	uint32_t cmd;
+
+	uint32_t pgidx;
+
+	uint32_t off;
+	uint8_t  buf[256];
+
+	uint32_t adrc;	/* address cycle */
+	uint32_t pgsz;	/* page size */
+	uint32_t bksz;	/* block size */
+};
+
+/* Register access macros */
+#define NAND_READ(r)		le32_to_cpu(readl(r))
+#define NAND_WRITE(v, r)	writel(cpu_to_le32(v), r)
+#define NAND_SETBITS(m, r)	setbits_le32(r, m)
+#define NAND_CLRBITS(m, r)	clrbits_le32(r, m)
+
+static struct nand_ecclayout ftnandc021_oob_2k = {
+	.eccbytes = 24,
+	.eccpos = {
+		40, 41, 42, 43, 44, 45, 46, 47,
+		48, 49, 50, 51, 52, 53, 54, 55,
+		56, 57, 58, 59, 60, 61, 62, 63
+	},
+	.oobfree = {
+		{
+			.offset = 9,
+			.length = 3
+		}
+	}
+};
+
+static int
+ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->iobase;
+	uint32_t bk = 2;	/* 64 pages */
+	uint32_t pg = 1;	/* 2k */
+	uint32_t ac = 2;	/* 5 */
+
+#ifdef CONFIG_FTNANDC021_ACTIMING_1
+	NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_1, &regs->atr[0]);
+#endif
+#ifdef CONFIG_FTNANDC021_ACTIMING_2
+	NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_2, &regs->atr[1]);
+#endif
+
+	NAND_WRITE(0, &regs->ier);
+	NAND_WRITE(0, &regs->pir);
+	NAND_WRITE(0xff, &regs->bbiwr);
+	NAND_WRITE(0xffffffff, &regs->lsnwr);
+	NAND_WRITE(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		NAND_WRITE(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		NAND_WRITE(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	NAND_WRITE(SRR_CHIP_RESET, &regs->srr);
+
+	/* wait until chip ready */
+	while (NAND_READ(&regs->srr) & SRR_CHIP_RESET)
+		;
+
+	switch (priv->bksz / priv->pgsz) {
+	case 16:
+		bk = 0;
+		break;
+	case 32:
+		bk = 1;
+		break;
+	case 64:
+		bk = 2;
+		break;
+	case 128:
+		bk = 3;
+		break;
+	}
+
+	switch (priv->pgsz) {
+	case 512:
+		pg = 0;
+		break;
+	case 2048:
+		pg = 1;
+		break;
+	case 4096:
+		pg = 2;
+		break;
+	}
+
+	switch (priv->adrc) {
+	case 3:
+		ac = 0;
+		break;
+	case 4:
+		ac = 1;
+		break;
+	case 5:
+		ac = 2;
+		break;
+	}
+
+	NAND_WRITE(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* PIO mode */
+	NAND_WRITE(0, &regs->ior);
+
+	return 0;
+}
+
+static inline int
+ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->iobase;
+	uint32_t st = NAND_READ(&regs->idr[1]);
+
+	if (st & NAND_IOSTATUS_ERROR)
+		return -NAND_IOSTATUS_ERROR;
+
+	if (!(st & NAND_IOSTATUS_READY))
+		return -NAND_IOSTATUS_READY;
+
+	if (!(st & NAND_IOSTATUS_UNPROTCT))
+		return -NAND_IOSTATUS_UNPROTCT;
+
+	return 0;
+}
+
+static inline int
+ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->iobase;
+	ulong ts;
+	int rc = -1;
+
+	for (ts = get_timer(0); get_timer(ts) < 200; ) {
+		if (!(NAND_READ(&regs->acr) & ACR_START)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	return rc;
+}
+
+static int
+ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs *regs = priv->iobase;
+	int ret = 0;
+
+	NAND_WRITE(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : nand_ckst (We have queued data at the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+		break;
+	case FTNANDC021_CMD_WRPG:
+		ret = ftnandc021_ckst(priv);
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int
+ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv) || ftnandc021_ckst(priv))
+		ret = 0;
+
+	return ret;
+}
+
+static void
+ftnandc021_read_oob(struct mtd_info *mtd, uint8_t * buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->iobase;
+	uint32_t tmp;
+
+	/*
+	 * Bad Block Information:
+	 * 1. Large Page(2048, 4096): off=0, len=2
+	 * 2. Small Page(512): off=5, len=1
+	 */
+	buf[0]  = NAND_READ(&regs->bbird) & 0xFF;
+	buf[1]  = 0xFF;
+
+	tmp     = NAND_READ(&regs->crcrd);
+	buf[8]  = (tmp >>  0) & 0xFF;
+	buf[9]  = (tmp >>  8) & 0xFF;
+	if (mtd->writesize >=  4096) {
+		buf[12] = (tmp >> 16) & 0xFF;
+		buf[13] = (tmp >> 24) & 0xFF;
+	}
+
+	tmp     = NAND_READ(&regs->lsnrd);
+	buf[10] = (tmp >>  0) & 0xFF;
+	buf[11] = (tmp >>  8) & 0xFF;
+	if (mtd->writesize >=  4096) {
+		buf[14] = (tmp >> 16) & 0xFF;
+		buf[15] = (tmp >> 24) & 0xFF;
+	}
+}
+
+static void
+ftnandc021_write_oob(struct mtd_info *mtd, const uint8_t * buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->iobase;
+	uint32_t tmp;
+
+	tmp = buf[0];
+	NAND_WRITE(tmp, &regs->bbiwr);
+
+	tmp = buf[8] | (buf[9] << 8);
+	if (mtd->writesize >=  4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	NAND_WRITE(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >=  4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	NAND_WRITE(tmp, &regs->lsnwr);
+}
+
+static uint8_t
+ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->iobase;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+	case NAND_CMD_READOOB:
+		ret = priv->buf[priv->off % 256];
+		priv->off += 1;
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint8_t)(NAND_READ(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		debug("ftnandc021_read_byte: unknown cmd(0x%02X)\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t
+ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t ret = 0xffff;
+	uint8_t *buf = (uint8_t *)&ret;
+
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return ret;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void
+ftnandc021_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->iobase;
+	ulong off;
+
+	/* oob read */
+	if (len <= mtd->oobsize) {
+		ftnandc021_read_oob(mtd, buf, len);
+		return;
+	}
+
+	/* page read */
+	for (off = 0; len > 0; len -= 4, off += 4) {
+		while (!(NAND_READ(&regs->ior) & IOR_READY))
+			;
+		*(uint32_t *)(buf + off) = NAND_READ(&regs->dr);
+	}
+
+	if (ftnandc021_wait(priv))
+		printf("ftnandc021_read_buf: cmd(0x%x) timeout\n", priv->cmd);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void
+ftnandc021_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->iobase;
+	ulong off;
+
+	/* 1. oob write */
+	if (len <= mtd->oobsize)
+		return;
+
+	/* 2. page write */
+	for (off = 0; len > 0; len -= 4, off += 4) {
+		while (!(NAND_READ(&regs->ior) & IOR_READY))
+			;
+		NAND_WRITE(*(uint32_t *)(buf + off), &regs->dr);
+	}
+
+	/* 3. wait until command finish */
+	if (ftnandc021_wait(priv))
+		printf("ftnandc021_write_buf: write fail\n");
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int
+ftnandc021_verify_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	int rc = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021_verify_buf: out of memory\n");
+		return -1;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			rc = -2;
+	}
+
+	free(tmp);
+	return rc;
+}
+
+static void
+ftnandc021_cmdfunc(struct mtd_info *mtd, unsigned cmd, int column, int pgidx)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->iobase;
+
+	priv->cmd   = cmd;
+	priv->pgidx = pgidx;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID)) {
+			printf("ftnandc021: RDID failed.\n");
+		} else {
+			put_unaligned_le32(NAND_READ(&regs->idr[0]),
+				priv->buf);
+			put_unaligned_le32(NAND_READ(&regs->idr[1]),
+				priv->buf + 4);
+			priv->off = 0;
+		}
+		break;
+
+	case NAND_CMD_READ0:	/* 0x00 */
+		NAND_WRITE(pgidx, &regs->pir);
+		NAND_WRITE(1, &regs->pcr);
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG))
+			printf("ftnandc021: RDPG failed.\n");
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		NAND_WRITE(pgidx, &regs->pir);
+		NAND_WRITE(1, &regs->pcr);
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+		} else {
+			ftnandc021_read_oob(mtd, priv->buf, mtd->oobsize);
+			priv->off = 0;
+		}
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		NAND_WRITE(pgidx, &regs->pir);
+		NAND_WRITE(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK))
+			printf("ftnandc021: ERBLK failed\n");
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDST))
+			printf("ftnandc021: RDST failed\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		NAND_WRITE(pgidx, &regs->pir);
+		NAND_WRITE(1, &regs->pcr);
+
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->writesize);
+		if (column >= mtd->writesize) {
+			if (ftnandc021_command(priv, FTNANDC021_CMD_WROOB))
+				printf("ftnandc021: WROOB failed\n");
+		} else {
+			if (ftnandc021_command(priv, FTNANDC021_CMD_WRPG))
+				printf("ftnandc021: WRPG failed\n");
+		}
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+			printf("ftnandc021: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021: Unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void
+ftnandc021_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+}
+
+int
+ftnandc021_probe(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv;
+
+	priv = malloc(sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -1;
+
+	memset(priv, 0, sizeof(*priv));
+	priv->iobase = (void *)CONFIG_NAND_FTNANDC021_BASE;
+	priv->adrc   = (unsigned int)chip->priv;
+	priv->pgsz   = 1 << chip->page_shift;
+	priv->bksz   = 1 << chip->phys_erase_shift;
+
+	chip->priv       = priv;
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	chip->ecc.mode   = NAND_ECC_NONE;
+	chip->ecc.layout = &ftnandc021_oob_2k;
+
+	chip->options    |= NAND_NO_AUTOINCR;
+
+	ftnandc021_reset(chip);
+
+	debug("ftnandc021: pg=%dK, bk=%dK, adrc=%d\n",
+		   priv->pgsz >> 10, priv->bksz >> 10, priv->adrc);
+
+	return 0;
+}
diff --git a/drivers/mtd/nand/ftnandc021.h b/drivers/mtd/nand/ftnandc021.h
new file mode 100644
index 0000000..b8274c8
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.h
@@ -0,0 +1,132 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTNANDC021_H
+#define _FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+ /* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4]; /* ECC Parity Register */
+	uint32_t ecc_sr; /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+ /* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsni;	 /* LSN Initialize */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+ /* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+ /* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* bit mask */
+#define SR_BLANK         BIT_MASK(7)  /* blanking check failed */
+#define SR_ECC           BIT_MASK(6)  /* ecc failed */
+#define SR_STS           BIT_MASK(4)  /* status error */
+#define SR_CRC           BIT_MASK(3)  /* crc error */
+#define SR_CMD           BIT_MASK(2)  /* command finished */
+#define SR_BUSY          BIT_MASK(1)  /* chip busy */
+#define SR_ENA           BIT_MASK(0)  /* chip enabled */
+
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        BIT_MASK(7)  /* command start */
+
+#define FCR_SWCRC        BIT_MASK(8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       BIT_MASK(7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        BIT_MASK(4)  /* 16 bit data bus */
+#define FCR_WPROT        BIT_MASK(3)  /* write protected */
+#define FCR_NOSC         BIT_MASK(2)  /* bypass status check error */
+#define FCR_MICRON       BIT_MASK(1)  /* Micron 2-plane command */
+#define FCR_NOBC         BIT_MASK(0)  /* skip blanking check error */
+
+#define IER_ENA          BIT_MASK(7)  /* interrupt enabled */
+#define IER_ECC          BIT_MASK(3)  /* ecc error timeout */
+#define IER_STS          BIT_MASK(2)  /* status error */
+#define IER_CRC          BIT_MASK(1)  /* crc error */
+#define IER_CMD          BIT_MASK(0)  /* command finished */
+
+#define IOR_READY        BIT_MASK(0)  /* PIO ready */
+
+#define SRR_ECC_ENABLED  BIT_MASK(8)  /* ECC enabled */
+#define SRR_NANDC_RESET  BIT_MASK(2)  /* NANDC reset */
+#define SRR_BMC_RESET    BIT_MASK(1)  /* BMC reset */
+#define SRR_ECC_RESET    BIT_MASK(0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* FTNANDC021 integrated command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+#endif
diff --git a/include/faraday/nand.h b/include/faraday/nand.h
new file mode 100644
index 0000000..6d8efb2
--- /dev/null
+++ b/include/faraday/nand.h
@@ -0,0 +1,16 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FARADAY_NAND_H
+#define _FARADAY_NAND_H
+
+int ftnandc021_probe(struct nand_chip *chip);
+
+#endif /* _FARADAY_NAND_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v2 08/12] mtd: spi: add FTSPI020 SPI Flash controller support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (6 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 11:08       ` Wolfgang Denk
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 09/12] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
                       ` (4 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTSPI020 is dedicated SPI bus designed for SPI Flashes.

It supports Fast-Read-Dual, Fast-Read-Dual-IO, Fast-Read-Quad
and Fast-Read-Quad-IO.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/mtd/spi/Makefile   |    4 +
 drivers/mtd/spi/ftspi020.c |  691 ++++++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/spi/ftspi020.h |  109 +++++++
 3 files changed, 804 insertions(+)
 create mode 100644 drivers/mtd/spi/ftspi020.c
 create mode 100644 drivers/mtd/spi/ftspi020.h

diff --git a/drivers/mtd/spi/Makefile b/drivers/mtd/spi/Makefile
index 90f8392..ce60e1b 100644
--- a/drivers/mtd/spi/Makefile
+++ b/drivers/mtd/spi/Makefile
@@ -29,6 +29,9 @@ ifdef CONFIG_SPL_BUILD
 COBJS-$(CONFIG_SPL_SPI_LOAD)	+= spi_spl_load.o
 endif
 
+ifeq ($(CONFIG_FTSPI020),y)
+COBJS-$(CONFIG_FTSPI020) += ftspi020.o
+else
 COBJS-$(CONFIG_SPI_FLASH)	+= spi_flash.o
 COBJS-$(CONFIG_SPI_FLASH_ATMEL)	+= atmel.o
 COBJS-$(CONFIG_SPI_FLASH_EON)	+= eon.o
@@ -39,6 +42,7 @@ COBJS-$(CONFIG_SPI_FLASH_STMICRO)	+= stmicro.o
 COBJS-$(CONFIG_SPI_FLASH_WINBOND)	+= winbond.o
 COBJS-$(CONFIG_SPI_FRAM_RAMTRON)	+= ramtron.o
 COBJS-$(CONFIG_SPI_M95XXX) += eeprom_m95xxx.o
+endif
 
 COBJS	:= $(COBJS-y)
 SRCS	:= $(COBJS:.o=.c)
diff --git a/drivers/mtd/spi/ftspi020.c b/drivers/mtd/spi/ftspi020.c
new file mode 100644
index 0000000..3d8a62a
--- /dev/null
+++ b/drivers/mtd/spi/ftspi020.c
@@ -0,0 +1,691 @@
+/*
+ * Faraday SPI Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+#include <spi_flash.h>
+
+#include "ftspi020.h"
+
+#define CFG_SUPP_FASTRD         1
+#define CFG_SUPP_FASTRD_DUAL    1 /* Support fast read dual(2x) */
+#define CFG_SUPP_FASTRD_QUAD    0 /* Support fast read quad(4x) */
+#define CFG_SHOW_PROGRESS       1 /* print a '.' at the end of each action */
+
+/* Flash opcodes. */
+#define OPCODE_WREN             0x06 /* Write enable */
+#define OPCODE_RDSR             0x05 /* Read status register */
+#define OPCODE_WRSR             0x01 /* Write status register 1 byte */
+#define OPCODE_NORM_READ        0x03 /* Read (low freq.) */
+#define OPCODE_NORM_READ4       0x13 /* Read (low freq., 4 bytes addr) */
+#define OPCODE_FAST_READ        0x0b /* Read (high freq.) */
+#define OPCODE_FAST_READ4       0x0c /* Read (high freq., 4 bytes addr) */
+#define OPCODE_FAST_READ_DUAL   0x3b /* Read (high freq.) */
+#define OPCODE_FAST_READ4_DUAL  0x3c /* Read (high freq., 4 bytes addr) */
+#define OPCODE_FAST_READ_QUAD   0x6b /* Read (high freq.) */
+#define OPCODE_FAST_READ4_QUAD  0x6c /* Read (high freq. 4 bytes addr) */
+#define OPCODE_PP               0x02 /* Page program */
+#define OPCODE_PP4              0x12 /* Page program (4 bytes addr) */
+#define OPCODE_BE_4K            0x20 /* Erase 4KiB block */
+#define OPCODE_BE_32K           0x52 /* Erase 32KiB block */
+#define OPCODE_CHIP_ERASE       0xc7 /* Erase whole flash chip */
+#define OPCODE_SE               0xd8 /* Sector erase */
+#define OPCODE_SE4              0xdc /* Sector erase (4 bytes addr) */
+#define OPCODE_RDID             0x9f /* Read JEDEC ID */
+
+/* Status Register bits. */
+#define SR_WIP                  BIT_MASK(0) /* Write in progress */
+#define SR_WEL                  BIT_MASK(1) /* Write enable latch */
+
+struct ftspi020_chip;
+
+struct spi_flash_param {
+	const char *name;
+	uint32_t    id;
+	uint32_t    ext_id;
+	uint32_t    sz_sector;
+	uint32_t    nr_sector;
+
+	uint32_t    flags;
+#define SECT_4K            BIT_MASK(0) /* OPCODE_BE_4K works uniformly */
+#if CFG_SUPP_FASTRD_DUAL
+# define FASTRD_DUAL       BIT_MASK(8)
+#else
+# define FASTRD_DUAL       0
+#endif
+#if CFG_SUPP_FASTRD_QUAD
+# define FASTRD_QUAD       BIT_MASK(9)
+#else
+# define FASTRD_QUAD       0
+#endif
+};
+
+/* spi_flash needs to be first so upper layers can free() it */
+struct spi_flash_info {
+	struct spi_flash flash;
+	struct ftspi020_chip *chip;
+	const struct spi_flash_param *param;
+
+	unsigned fastrd_dual:1;
+	unsigned fastrd_quad:1;
+};
+
+struct ftspi020_chip {
+	void *iobase;
+	uint32_t cs;
+	struct spi_slave *spi;
+	struct spi_flash_info *sfi;
+};
+
+/* Register access macros */
+#define SPI_READ(r)			le32_to_cpu(readl(r))
+#define SPI_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define SPI_SETBITS(m, r)	setbits_le32(r, m)
+#define SPI_CLRBITS(m, r)	clrbits_le32(r, m)
+
+static inline struct ftspi020_chip *
+flash_to_chip(struct spi_flash *flash)
+{
+	struct spi_flash_info *fl = (struct spi_flash_info *)flash;
+	return fl->chip;
+}
+
+static inline const struct spi_flash_param *
+flash_to_param(struct spi_flash *flash)
+{
+	struct spi_flash_info *fl = (struct spi_flash_info *)flash;
+	return fl->param;
+}
+
+static const struct spi_flash_param sf_list[] = {
+
+	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
+	{ "at25fs010",  0x1f6601, 0, 32 * 1024,   4 },
+	{ "at25fs040",  0x1f6604, 0, 64 * 1024,   8 },
+
+	{ "at25df041a", 0x1f4401, 0, 64 * 1024,   8 },
+	{ "at25df321a", 0x1f4701, 0, 64 * 1024,  64 },
+	{ "at25df641",  0x1f4800, 0, 64 * 1024, 128 },
+
+	{ "at26f004",   0x1f0400, 0, 64 * 1024,  8 },
+	{ "at26df081a", 0x1f4501, 0, 64 * 1024, 16 },
+	{ "at26df161a", 0x1f4601, 0, 64 * 1024, 32 },
+	{ "at26df321",  0x1f4700, 0, 64 * 1024, 64 },
+
+	/* EON -- en25xxx */
+	{ "en25f32",   0x1c3116, 0, 64 * 1024,  64 },
+	{ "en25p32",   0x1c2016, 0, 64 * 1024,  64 },
+	{ "en25q32b",  0x1c3016, 0, 64 * 1024,  64 },
+	{ "en25p64",   0x1c2017, 0, 64 * 1024, 128 },
+	{ "en25qh256", 0x1c7019, 0, 64 * 1024, 512 },
+
+	/* GD -- GD25xxx */
+	{ "gd25q16",   0xc84015, 0, 64 * 1024,  32 },
+	{ "gd25q32",   0xc84016, 0, 64 * 1024,  64 },
+	{ "gd25q64",   0xc84017, 0, 64 * 1024, 128 },
+
+	/* Intel/Numonyx -- xxxs33b */
+	{ "160s33b",  0x898911, 0, 64 * 1024,  32 },
+	{ "320s33b",  0x898912, 0, 64 * 1024,  64 },
+	{ "640s33b",  0x898913, 0, 64 * 1024, 128 },
+
+	/* Macronix */
+	{ "mx25l4005a",  0xc22013, 0, 64 * 1024,   8 },
+	{ "mx25l8005",   0xc22014, 0, 64 * 1024,  16 },
+	{ "mx25l1606e",  0xc22015, 0, 64 * 1024,  32 },
+	{ "mx25l3205d",  0xc22016, 0, 64 * 1024,  64 },
+	{ "mx25l6405d",  0xc22017, 0, 64 * 1024, 128 },
+	{ "mx25l12805d", 0xc22018, 0, 64 * 1024, 256 },
+	{ "mx25l12855e", 0xc22618, 0, 64 * 1024, 256 },
+	{ "mx25l25635e", 0xc22019, 0, 64 * 1024, 512 },
+	{ "mx25l25655e", 0xc22619, 0, 64 * 1024, 512 },
+
+	/* Spansion -- single (large) sector size only, at least
+	 * for the chips listed here (without boot sectors).
+	 */
+	{ "s25sl004a",  0x010212,      0,  64 * 1024,   8 },
+	{ "s25sl008a",  0x010213,      0,  64 * 1024,  16 },
+	{ "s25sl016a",  0x010214,      0,  64 * 1024,  32 },
+	{ "s25sl032a",  0x010215,      0,  64 * 1024,  64 },
+	{ "s25sl032p",  0x010215, 0x4d00,  64 * 1024,  64 },
+	{ "s25sl064a",  0x010216,      0,  64 * 1024, 128 },
+	{ "s25fl128s0", 0x010218, 0x4d00, 256 * 1024,  64,
+		FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl128s1", 0x010218, 0x4d01,  64 * 1024, 256,
+		FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl256s0", 0x010219, 0x4d00, 256 * 1024, 128,
+		FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl256s1", 0x010219, 0x4d01,  64 * 1024, 512,
+		FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl512s",  0x010220, 0x4d00, 256 * 1024, 256,
+		FASTRD_DUAL | FASTRD_QUAD },
+	{ "s70fl01gs",  0x010221, 0x4d00, 256 * 1024, 256 },
+	{ "s25sl12800", 0x012018, 0x0300, 256 * 1024,  64 },
+	{ "s25sl12801", 0x012018, 0x0301,  64 * 1024, 256 },
+	{ "s25fl129p0", 0x012018, 0x4d00, 256 * 1024,  64,
+		FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl129p1", 0x012018, 0x4d01,  64 * 1024, 256,
+		FASTRD_DUAL | FASTRD_QUAD },
+	{ "s25fl016k",  0xef4015,      0,  64 * 1024,  32 },
+	{ "s25fl064k",  0xef4017,      0,  64 * 1024, 128 },
+
+	/* SST -- large erase sizes are "overlays", "sectors" are 4K */
+	{ "sst25vf040b", 0xbf258d, 0, 64 * 1024,  8 },
+	{ "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16 },
+	{ "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32 },
+	{ "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64 },
+	{ "sst25vf064c", 0xbf254b, 0, 64 * 1024, 128,
+		FASTRD_DUAL },
+	{ "sst25wf512",  0xbf2501, 0, 64 * 1024,  1 },
+	{ "sst25wf010",  0xbf2502, 0, 64 * 1024,  2 },
+	{ "sst25wf020",  0xbf2503, 0, 64 * 1024,  4 },
+	{ "sst25wf040",  0xbf2504, 0, 64 * 1024,  8 },
+
+	/* Micron -- newer production may have feature updates */
+	{ "m25p05",  0x202010,  0,  32 * 1024,   2 },
+	{ "m25p10",  0x202011,  0,  32 * 1024,   4 },
+	{ "m25p20",  0x202012,  0,  64 * 1024,   4 },
+	{ "m25p40",  0x202013,  0,  64 * 1024,   8 },
+	{ "m25p80",  0x202014,  0,  64 * 1024,  16 },
+	{ "m25p16",  0x202015,  0,  64 * 1024,  32 },
+	{ "m25p32",  0x202016,  0,  64 * 1024,  64 },
+	{ "m25p64",  0x202017,  0,  64 * 1024, 128 },
+	{ "m25p128", 0x202018,  0, 256 * 1024,  64 },
+
+	{ "m45pe10", 0x204011,  0, 64 * 1024,    2 },
+	{ "m45pe80", 0x204014,  0, 64 * 1024,   16 },
+	{ "m45pe16", 0x204015,  0, 64 * 1024,   32 },
+
+	{ "m25pe80", 0x208014,  0, 64 * 1024, 16 },
+	{ "m25pe16", 0x208015,  0, 64 * 1024, 32 },
+
+	{ "m25px32",    0x207116,  0, 64 * 1024, 64 },
+	{ "m25px32-s0", 0x207316,  0, 64 * 1024, 64 },
+	{ "m25px32-s1", 0x206316,  0, 64 * 1024, 64 },
+	{ "m25px64",    0x207117,  0, 64 * 1024, 128 },
+
+	{ "n25q032a13e", 0x20ba16, 0, 64 * 1024,  64, },
+	{ "n25q064a13e", 0x20ba17, 0, 64 * 1024, 128, },
+	{ "n25q128a13e", 0x20ba18, 0, 64 * 1024, 256, },
+	{ "n25q256a13e", 0x20ba19, 0, 64 * 1024, 512, },
+	{ "n25qax3g",    0x20ba20, 0, 64 * 1024, 1024, },
+	{ "n25q00aa13g", 0x20ba21, 0, 64 * 1024, 2048, },
+
+	/* Winbond */
+	{ "w25x10", 0xef3011, 0, 64 * 1024, 2, },
+	{ "w25x20", 0xef3012, 0, 64 * 1024, 4, },
+	{ "w25x40", 0xef3013, 0, 64 * 1024, 8, },
+	{ "w25p80", 0xef2014, 0, 64 * 1024, 16, },
+	{ "w25x80", 0xef3014, 0, 64 * 1024, 16, },
+	{ "w25p16", 0xef2015, 0, 64 * 1024, 32, },
+	{ "w25x16", 0xef3015, 0, 64 * 1024, 32, },
+	{ "w25x32", 0xef3016, 0, 64 * 1024, 64, },
+	{ "w25q32", 0xef4016, 0, 64 * 1024, 64, },
+	{ "w25x64", 0xef3017, 0, 64 * 1024, 128, },
+	{ "w25q64", 0xef4017, 0, 64 * 1024, 128, },
+	{ "w25q128", 0xef4018, 0, 64 * 1024, 256,
+		FASTRD_DUAL | FASTRD_QUAD },
+
+	/* generic */
+	{ "unknown",       0, 0, 64 * 1024, 256, },
+};
+
+static int ftspi020_rdid(struct ftspi020_chip *chip, void *buf)
+{
+	struct ftspi020_regs *regs = chip->iobase;
+	uint32_t id32[2];
+	uint8_t *id = buf;
+	int i;
+
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	/* issue command */
+	SPI_WRITE(0, &regs->cmd[0]);
+	SPI_WRITE(CMD1_ILEN(1), &regs->cmd[1]);
+	SPI_WRITE(sizeof(id32), &regs->cmd[2]);
+	SPI_WRITE(CMD3_OPC(OPCODE_RDID) | CMD3_CS(chip->cs) | CMD3_CMDIRQ,
+		&regs->cmd[3]);
+
+	for (i = 0; i < ARRAY_SIZE(id32); ++i) {
+		/* wait until rx ready */
+		while (!(SPI_READ(&regs->sr) & SR_RFR))
+			;
+		id32[i] = SPI_READ(&regs->dr);
+	}
+
+	/* wait until command finish */
+	while (!(SPI_READ(&regs->isr) & ISR_CMD))
+		;
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	memcpy(id, id32, 5);
+
+	return 0;
+}
+
+static int ftspi020_rdsr(struct ftspi020_chip *chip)
+{
+	struct ftspi020_regs *regs = chip->iobase;
+	int st;
+
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	/* issue command */
+	SPI_WRITE(0, &regs->cmd[0]);
+	SPI_WRITE(CMD1_ILEN(1), &regs->cmd[1]);
+	SPI_WRITE(1, &regs->cmd[2]);
+	SPI_WRITE(CMD3_OPC(OPCODE_RDSR) | CMD3_CS(chip->cs)
+		| CMD3_CMDIRQ, &regs->cmd[3]);
+
+	/* wait until rx ready */
+	while (!(SPI_READ(&regs->sr) & SR_RFR))
+		;
+	st = SPI_READ(&regs->dr);
+
+	/* wait until command finish */
+	while (!(SPI_READ(&regs->isr) & ISR_CMD))
+		;
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	return st & 0xff;
+}
+
+/*
+ * Write status register
+ * Returns negative if error occurred.
+ */
+static int ftspi020_wrsr(struct ftspi020_chip *chip, uint32_t val, uint8_t len)
+{
+	struct ftspi020_regs *regs = chip->iobase;
+
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	/* issue command */
+	SPI_WRITE(0, &regs->cmd[0]);
+	SPI_WRITE(CMD1_ILEN(1), &regs->cmd[1]);
+	SPI_WRITE(len, &regs->cmd[2]);
+	SPI_WRITE(CMD3_OPC(OPCODE_WRSR) | CMD3_CS(chip->cs)
+		| CMD3_WRITE | CMD3_CMDIRQ, &regs->cmd[3]);
+
+	/* wait until tx ready */
+	while (!(SPI_READ(&regs->sr) & SR_TFR))
+		;
+	SPI_WRITE(val, &regs->dr);
+
+	/* wait until command finish */
+	while (!(SPI_READ(&regs->isr) & ISR_CMD))
+		;
+
+	/* wait until device ready */
+	while (ftspi020_rdsr(chip) & SR_WEL)
+		;
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	return 0;
+}
+
+static int ftspi020_read(struct spi_flash *flash,
+	u32 off, size_t len, void *buf)
+{
+	struct ftspi020_chip *chip = flash_to_chip(flash);
+	struct ftspi020_regs *regs = chip->iobase;
+	struct spi_flash_info *fl = (struct spi_flash_info *)flash;
+	uint32_t i, v;
+
+	/* wait until device ready */
+	while (ftspi020_rdsr(chip) & SR_WIP)
+		;
+
+	/* issue command (Rd) */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+	SPI_WRITE(off, &regs->cmd[0]);
+	SPI_WRITE(len, &regs->cmd[2]);
+
+	if (off < 0x1000000) {
+#if CFG_SUPP_FASTRD
+		SPI_WRITE(CMD1_ILEN(1) | CMD1_DCYC(8) | CMD1_ALEN(3),
+			&regs->cmd[1]);
+		if (fl->fastrd_quad) {
+			SPI_WRITE(CMD3_OPC(OPCODE_FAST_READ_QUAD)
+				| CMD3_CS(chip->cs) | CMD3_QUAD | CMD3_CMDIRQ,
+				&regs->cmd[3]);
+		} else if (fl->fastrd_dual) {
+			SPI_WRITE(CMD3_OPC(OPCODE_FAST_READ_DUAL)
+				| CMD3_CS(chip->cs) | CMD3_DUAL | CMD3_CMDIRQ,
+				&regs->cmd[3]);
+		} else {
+			SPI_WRITE(CMD3_OPC(OPCODE_FAST_READ) | CMD3_CS(chip->cs)
+				| CMD3_CMDIRQ, &regs->cmd[3]);
+		}
+#else
+		SPI_WRITE(CMD1_ILEN(1) | CMD1_ALEN(3), &regs->cmd[1]);
+		SPI_WRITE(CMD3_OPC(OPCODE_NORM_READ) | CMD3_CS(chip->cs)
+			| CMD3_CMDIRQ, &regs->cmd[3]);
+#endif
+	} else {
+#if CFG_SUPP_FASTRD
+		SPI_WRITE(CMD1_ILEN(1) | CMD1_DCYC(8) | CMD1_ALEN(4),
+			&regs->cmd[1]);
+		if (fl->fastrd_quad) {
+			SPI_WRITE(CMD3_OPC(OPCODE_FAST_READ4_QUAD)
+				| CMD3_CS(chip->cs) | CMD3_QUAD | CMD3_CMDIRQ,
+				&regs->cmd[3]);
+		} else if (fl->fastrd_dual) {
+			SPI_WRITE(CMD3_OPC(OPCODE_FAST_READ4_DUAL)
+				| CMD3_CS(chip->cs) | CMD3_DUAL | CMD3_CMDIRQ,
+				&regs->cmd[3]);
+		} else {
+			SPI_WRITE(CMD3_OPC(OPCODE_FAST_READ4)
+				| CMD3_CS(chip->cs) | CMD3_CMDIRQ,
+				&regs->cmd[3]);
+		}
+#else
+		SPI_WRITE(CMD1_ILEN(1) | CMD1_ALEN(4), &regs->cmd[1]);
+		SPI_WRITE(CMD3_OPC(OPCODE_NORM_READ4) | CMD3_CS(chip->cs)
+			| CMD3_CMDIRQ, &regs->cmd[3]);
+#endif
+	}
+
+	/* data phase */
+	for (i = 0; i < (len & 0xFFFFFFFC); ) {
+		/* wait until rx ready */
+		while (!(SPI_READ(&regs->sr) & SR_RFR))
+			;
+
+		*((uint32_t *)buf) = SPI_READ(&regs->dr);
+
+		buf = (void *)((uint32_t)buf + 4);
+		i += 4;
+	}
+
+	if (len & 0x03) {
+		/* wait until rx ready */
+		while (!(SPI_READ(&regs->sr) & SR_RFR))
+			;
+
+		v = SPI_READ(&regs->dr);
+
+		for (i = 0; i < (len & 0x03); ++i)
+			((uint8_t *)buf)[i] = ((uint8_t *)&v)[i];
+	}
+
+	/* wait until command finish */
+	while (!(SPI_READ(&regs->isr) & ISR_CMD))
+		;
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	return 0;
+}
+
+static int ftspi020_wren(struct ftspi020_chip *chip)
+{
+	struct ftspi020_regs *regs = chip->iobase;
+
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	/* issue command (WE) */
+	SPI_WRITE(0, &regs->cmd[0]);
+	SPI_WRITE(CMD1_ILEN(1), &regs->cmd[1]);
+	SPI_WRITE(0, &regs->cmd[2]);
+	SPI_WRITE(CMD3_OPC(OPCODE_WREN) | CMD3_CS(chip->cs)
+		| CMD3_WRITE | CMD3_CMDIRQ, &regs->cmd[3]);
+
+	/* wait until command finish */
+	while (!(SPI_READ(&regs->isr) & ISR_CMD))
+		;
+	/* clear isr */
+	SPI_WRITE(ISR_CMD, &regs->isr);
+
+	return 0;
+}
+
+static int ftspi020_write(struct spi_flash *flash,
+	u32 off, size_t len, const void *buf)
+{
+	int i, wl;
+	struct ftspi020_chip *chip = flash_to_chip(flash);
+	struct ftspi020_regs *regs = chip->iobase;
+
+	/* page write */
+	while (len > 0) {
+		wl = min(flash->page_size, len);
+
+#if CFG_SHOW_PROGRESS
+		/* output a '.' on each 64KB boundary */
+		if (!(off & 0x0000ffff))
+			puts(".");
+#endif
+		/* wait until device ready */
+		while (ftspi020_rdsr(chip) & SR_WIP)
+			;
+
+		/* write enable */
+		while (!(ftspi020_rdsr(chip) & SR_WEL))
+			ftspi020_wren(chip);
+
+		/* issue command (PP) */
+		SPI_WRITE(off, &regs->cmd[0]);
+		SPI_WRITE(wl, &regs->cmd[2]);
+		if (off < 0x1000000) {
+			SPI_WRITE(CMD1_ILEN(1) | CMD1_ALEN(3), &regs->cmd[1]);
+			SPI_WRITE(CMD3_OPC(OPCODE_PP) | CMD3_CS(chip->cs)
+				| CMD3_WRITE | CMD3_CMDIRQ, &regs->cmd[3]);
+		} else {
+			SPI_WRITE(CMD1_ILEN(1) | CMD1_ALEN(4), &regs->cmd[1]);
+			SPI_WRITE(CMD3_OPC(OPCODE_PP4) | CMD3_CS(chip->cs)
+				| CMD3_WRITE | CMD3_CMDIRQ, &regs->cmd[3]);
+		}
+
+		/* data phase */
+		for (i = 0; i < wl; i += 4) {
+			/* wait until tx ready */
+			while (!(SPI_READ(&regs->sr) & SR_TFR))
+				;
+			SPI_WRITE(*(uint32_t *)buf, &regs->dr);
+			buf = (void *)(((uint32_t)buf) + 4);
+		}
+		off += wl;
+		len -= wl;
+
+		/* wait until command finish */
+		while (!(SPI_READ(&regs->isr) & ISR_CMD))
+			;
+		/* clear isr */
+		SPI_WRITE(ISR_CMD, &regs->isr);
+	}
+
+	return 0;
+}
+
+static int ftspi020_erase(struct spi_flash *flash, u32 offset, size_t len)
+{
+	u32 addr = 0;
+	struct ftspi020_chip *chip = flash_to_chip(flash);
+	struct ftspi020_regs *regs = chip->iobase;
+	const struct spi_flash_param *param = flash_to_param(flash);
+
+	for (addr = offset & ~(param->sz_sector - 1);
+		addr < offset + len; addr += param->sz_sector) {
+
+		/* wait until device ready */
+		while (ftspi020_rdsr(chip) & SR_WIP)
+			;
+
+		/* write enable */
+		while (!(ftspi020_rdsr(chip) & SR_WEL))
+			ftspi020_wren(chip);
+
+		/* issue command (SE) */
+		SPI_WRITE(addr, &regs->cmd[0]);
+		SPI_WRITE(0x00, &regs->cmd[2]);
+		if (addr < 0x1000000) {
+			SPI_WRITE(CMD1_ILEN(1) | CMD1_ALEN(3), &regs->cmd[1]);
+			SPI_WRITE(CMD3_OPC(OPCODE_SE) | CMD3_CS(chip->cs)
+				| CMD3_WRITE | CMD3_CMDIRQ, &regs->cmd[3]);
+		} else {
+			SPI_WRITE(CMD1_ILEN(1) | CMD1_ALEN(4), &regs->cmd[1]);
+			SPI_WRITE(CMD3_OPC(OPCODE_SE4) | CMD3_CS(chip->cs)
+				| CMD3_WRITE | CMD3_CMDIRQ, &regs->cmd[3]);
+		}
+
+		/* wait until command finish */
+		while (!(SPI_READ(&regs->isr) & ISR_CMD))
+			;
+		/* clear isr */
+		SPI_WRITE(ISR_CMD, &regs->isr);
+
+#if CFG_SHOW_PROGRESS
+		puts(".");
+#endif
+	}
+
+	return 0;
+}
+
+static struct ftspi020_chip chip_list[] = {
+	{ .iobase = (void *)CONFIG_FTSPI020_BASE, },
+#ifdef CONFIG_FTSPI020_BASE1
+	{ .iobase = (void *)CONFIG_FTSPI020_BASE1, },
+#endif
+#ifdef CONFIG_FTSPI020_BASE2
+	{ .iobase = (void *)CONFIG_FTSPI020_BASE2, },
+#endif
+#ifdef CONFIG_FTSPI020_BASE3
+	{ .iobase = (void *)CONFIG_FTSPI020_BASE3, },
+#endif
+};
+
+struct spi_flash *
+spi_flash_probe(uint bus, uint cs, uint max_hz, uint spi_mode)
+{
+	struct ftspi020_chip *chip;
+	struct ftspi020_regs *regs;
+	u32 i, id, ext_id, div = 8;
+	u8  idcode[5];
+
+	if (bus > ARRAY_SIZE(chip_list) || cs > 3)
+		return NULL;
+
+	chip = &chip_list[bus];
+	regs = chip->iobase;
+	chip->cs = cs;
+
+	chip->spi = malloc(sizeof(struct spi_slave));
+	if (!chip->spi)
+		return NULL;
+	chip->spi->bus = bus;
+	chip->spi->cs  = cs;
+
+	chip->sfi = malloc(sizeof(struct spi_flash_info));
+	if (!chip->sfi)
+		return NULL;
+	chip->sfi->chip        = chip;
+	chip->sfi->flash.spi   = chip->spi;
+	chip->sfi->flash.read  = ftspi020_read;
+	chip->sfi->flash.write = ftspi020_write;
+	chip->sfi->flash.erase = ftspi020_erase;
+
+	/* reset */
+	SPI_WRITE(CR_ABORT, &regs->cr);
+	while (SPI_READ(&regs->cr) & CR_ABORT)
+		;
+
+	/* clock speed */
+	if (max_hz > 0) {
+		ulong clk = clk_get_rate("SPI");
+		for (div = 2; div < 8; div += 2) {
+			if (clk / div <= max_hz)
+				break;
+		}
+	}
+
+	/* mode + clock */
+	switch (spi_mode) {
+	case SPI_MODE_0:
+		SPI_WRITE((div >> 1) - 1, &regs->cr);
+		break;
+	case SPI_MODE_3:
+		SPI_WRITE(CR_CLK_MODE_3 | ((div >> 1) - 1), &regs->cr);
+		break;
+	default:
+		printf("ftspi020: MODE%d is not supported.\n", spi_mode);
+		free(chip->spi);
+		free(chip->sfi);
+		return NULL;
+	}
+
+	/* AC timing: worst trace delay and cs delay */
+	SPI_WRITE(0xff, &regs->atr);
+
+	debug("ftspi020: div=%d\n", div);
+
+	ftspi020_rdid(chip, idcode);
+
+	id     = (idcode[0] << 16) | (idcode[1] << 8) | (idcode[2]);
+	ext_id = (idcode[3] <<  8) | (idcode[4]);
+
+	printf("ftspi020: id=%06x.%04x\n", id, ext_id);
+
+	for (i = 0; i < ARRAY_SIZE(sf_list) - 1; ++i) {
+		if (id == sf_list[i].id && (!sf_list[i].ext_id
+			|| sf_list[i].ext_id == ext_id))
+			break;
+	}
+
+	/*
+	 * Atmel, SST and Intel/Numonyx serial flash tend to power
+	 * up with the software protection bits set
+	 */
+	ftspi020_wren(chip);
+	ftspi020_wrsr(chip, 0, 1);
+
+	chip->sfi->param = sf_list + i;
+	chip->sfi->flash.name = sf_list[i].name;
+	chip->sfi->flash.size = sf_list[i].sz_sector * sf_list[i].nr_sector;
+	chip->sfi->flash.page_size = 256;
+	chip->sfi->flash.sector_size = sf_list[i].sz_sector;
+	chip->sfi->flash.memory_map = NULL;
+
+	printf("ftspi020: %s (%u MB)\n",
+		chip->sfi->flash.name, chip->sfi->flash.size >> 20);
+
+	if (chip->sfi->param->flags & FASTRD_QUAD) {
+		printf("ftspi020: use fast read quad(4x)\n");
+		ftspi020_wren(chip);
+		ftspi020_wrsr(chip, 0x0200, 2);
+		chip->sfi->fastrd_quad = 1;
+	} else if (chip->sfi->param->flags & FASTRD_DUAL) {
+		printf("ftspi020: use fast read dual(2x)\n");
+		chip->sfi->fastrd_dual = 1;
+	}
+
+	return &chip->sfi->flash;
+}
+
+void spi_flash_free(struct spi_flash *flash)
+{
+	struct ftspi020_chip *chip;
+
+	if (flash) {
+		chip = flash_to_chip(flash);
+		free(chip->spi);
+		free(chip->sfi);
+	}
+}
diff --git a/drivers/mtd/spi/ftspi020.h b/drivers/mtd/spi/ftspi020.h
new file mode 100644
index 0000000..6138e9b
--- /dev/null
+++ b/drivers/mtd/spi/ftspi020.h
@@ -0,0 +1,109 @@
+/*
+ * Faraday SPI Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTSPI020_H
+#define _FTSPI020_H
+
+/*
+ * FTSPI020 Registers
+ */
+struct ftspi020_regs {
+	/* 0x000 ~ 0x0fc */
+	uint32_t	cmd[4];	/* Command Register */
+	uint32_t	cr;		/* Control Register */
+	uint32_t	atr;	/* AC Timing Register */
+	uint32_t	sr;		/* Status Register */
+	uint32_t	rsvd0[1];
+	uint32_t	ier;	/* Interrupt Enable Register */
+	uint32_t	isr;	/* Interrupt Status Register */
+	uint32_t	rdsr;	/* Read Status Register */
+	uint32_t	rsvd1[9];
+	uint32_t	revr;	/* Revision Register */
+	uint32_t	fear;	/* Feature Register */
+	uint32_t	rsvd2[42];
+
+	/* 0x100 ~ 0x1fc */
+	uint32_t	dr;		/* Data Register */
+};
+
+/*
+ * Control Register offset 0x10
+ */
+#define CR_READY_LOC_MASK   ~(0x7 << 16)
+#define CR_READY_LOC(x)     (((x) & 0x7) << 16)
+#define CR_ABORT            BIT_MASK(8)
+#define CR_CLK_MODE_0       0
+#define CR_CLK_MODE_3       BIT_MASK(4)
+#define CR_CLK_DIVIDER_MASK ~(3 << 0)
+#define CR_CLK_DIVIDER_2    (0 << 0)
+#define CR_CLK_DIVIDER_4    (1 << 0)
+#define CR_CLK_DIVIDER_6    (2 << 0)
+#define CR_CLK_DIVIDER_8    (3 << 0)
+
+/*
+ * Status Register offset 0x18
+ */
+#define SR_RFR              BIT_MASK(1) /* RX FIFO Ready */
+#define SR_TFR              BIT_MASK(0) /* TX FIFO Ready */
+
+/*
+ * Interrupt Control Register
+ */
+#define ICR_RFTH(x)         (((x) & 0x3) << 12) /* RX FIFO Threshold */
+#define ICR_TFTH(x)         (((x) & 0x3) << 8)  /* TX FIFO Threshold */
+#define ICR_DMA             BIT_MASK(0) /* DMA HW Handshake Enable */
+
+/*
+ * Interrupt Status Register
+ */
+#define ISR_CMD             BIT_MASK(0) /* Command Complete/Finish  */
+
+/*
+ * Feature Register
+ */
+#define FEAR_CLK_MODE(reg)       (((reg) >> 25) & 0x1)
+#define FEAR_DTR_MODE(reg)       (((reg) >> 24) & 0x1)
+#define FEAR_CMDQ_DEPTH(reg)     (((reg) >> 16) & 0xff)
+#define FEAR_RXFIFO_DEPTH(reg)   (((reg) >>  8) & 0xff)
+#define FEAR_TXFIFO_DEPTH(reg)   (((reg) >>  0) & 0xff)
+
+/*
+ * CMD1 Register offset 4: Command Queue Second Word
+ */
+#define CMD1_CREAD               BIT_MASK(28)
+#define CMD1_ILEN(x)             (((x) & 0x03) << 24)
+#define CMD1_DCYC(x)             (((x) & 0xff) << 16)
+#define CMD1_ALEN(x)             ((x) & 0x07)
+
+/*
+ * CMD3 Register offset 0xc: Command Queue Fourth Word
+ */
+#define CMD3_OPC(x)              (((x) & 0xff) << 24)
+#define CMD3_OPC_CREAD(x)        (((x) & 0xff) << 16)
+#define CMD3_CS(x)               (((x) & 0x3) << 8)
+#define CMD3_SERIAL              (0 << 5)
+#define CMD3_DUAL                (1 << 5)
+#define CMD3_QUAD                (2 << 5)
+#define CMD3_DUAL_IO             (3 << 5)
+#define CMD3_QUAD_IO             (4 << 5)
+
+#define CMD3_DTR                 BIT_MASK(4)
+
+#define CMD3_RDST_SW             BIT_MASK(3)
+#define CMD3_RDST_HW             0
+
+#define CMD3_RDST                BIT_MASK(2)
+
+#define CMD3_WRITE               BIT_MASK(1)
+#define CMD3_READ                0
+
+#define CMD3_CMDIRQ              BIT_MASK(0)
+
+#endif
-- 
1.7.9.5

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

* [U-Boot] [PATCH v2 09/12] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (7 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 08/12] mtd: spi: add FTSPI020 SPI Flash " Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 11:09       ` Wolfgang Denk
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 10/12] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
                       ` (3 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch add supports to both Faraday FUSBH200 and FOTG210,
these controllers slightly differ from standard EHCI specification.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
 common/usb_hub.c                |    5 ++
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  139 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |   11 ++++
 drivers/usb/host/ehci.h         |    5 ++
 include/usb/fotg210.h           |   71 ++++++++++++++++++++
 include/usb/fusbh200.h          |   28 ++++++++
 7 files changed, 260 insertions(+)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index b5eeb62..26d66b8 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -375,6 +375,11 @@ static int usb_hub_configure(struct usb_device *dev)
 		return -1;
 	}

+#ifdef CONFIG_USB_EHCI_FARADAY
+	/* Faraday USB 2.0 EHCI chips need a long long delay here */
+	mdelay(250);
+#endif
+
 	if (usb_get_hub_status(dev, buffer) < 0) {
 		USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
 				dev->status);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..804e058
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,139 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+struct ehci_faraday_chip {
+	union ehci_faraday_regs *iobase;
+};
+
+static struct ehci_faraday_chip hcd_list[] = {
+#ifdef CONFIG_USB_EHCI_BASE
+	{ .iobase = (union ehci_faraday_regs *)CONFIG_USB_EHCI_BASE, },
+#endif
+#ifdef CONFIG_USB_EHCI_BASE1
+	{ .iobase = (union ehci_faraday_regs *)CONFIG_USB_EHCI_BASE1, },
+#endif
+#ifdef CONFIG_USB_EHCI_BASE2
+	{ .iobase = (union ehci_faraday_regs *)CONFIG_USB_EHCI_BASE2, },
+#endif
+#ifdef CONFIG_USB_EHCI_BASE3
+	{ .iobase = (union ehci_faraday_regs *)CONFIG_USB_EHCI_BASE3, },
+#endif
+};
+
+#define HCD_READ(r)			le32_to_cpu(readl(r))
+#define HCD_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define HCD_SETBITS(m, r)	setbits_le32(r, m)
+#define HCD_CLRBITS(m, r)	clrbits_le32(r, m)
+
+static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
+{
+	union ehci_faraday_regs *regs = (void *)hccr;
+	return !HCD_READ(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_faraday_chip *hcd = &hcd_list[index];
+	union ehci_faraday_regs *regs = hcd->iobase;
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_hci_fotg2xx(hccr)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		HCD_SETBITS(BIT_MASK(5), &regs->otg.otgcsr);
+		/* ... Drop vbus and bus traffic */
+		HCD_CLRBITS(BIT_MASK(4), &regs->otg.otgcsr);
+		mdelay(1);
+		/* ... Power on A-device */
+		HCD_CLRBITS(BIT_MASK(5), &regs->otg.otgcsr);
+		/* ... Drive vbus and bus traffic */
+		HCD_SETBITS(BIT_MASK(4), &regs->otg.otgcsr);
+		mdelay(1);
+		/* Disable OTG & device interrupts, interrupt=level-high */
+		HCD_WRITE(0x0b, &regs->otg.imr);
+		/* Clear all interrupt status */
+		HCD_WRITE(0x07, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		HCD_SETBITS(BIT_MASK(3), &regs->usb.bmcsr);
+		/* VBUS on */
+		HCD_CLRBITS(BIT_MASK(4), &regs->usb.bmcsr);
+		/* Disable all interrupts */
+		HCD_WRITE(0x00, &regs->usb.bmier);
+		HCD_WRITE(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+int ehci_hcd_port_speed(struct ehci_hccr *hccr)
+{
+	int ret = 0;
+	int speed;
+	union ehci_faraday_regs *regs = (void *)hccr;
+
+	if (ehci_hci_fotg2xx(hccr))
+		speed = (HCD_READ(&regs->otg.otgcsr) >> 22) & 0x03;
+	else
+		speed = (HCD_READ(&regs->usb.bmcsr) >>  9) & 0x03;
+
+	switch (speed) {
+	case 0:    /* full speed */
+		break;
+
+	case 1:    /* low  speed */
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+
+	case 2:    /* high speed */
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..450d217 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -149,8 +149,10 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t tmp;
 	uint32_t *reg_ptr;
+#endif
 	int ret = 0;

 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,6 +165,7 @@ static int ehci_reset(int index)
 		goto out;
 	}

+#ifndef CONFIG_USB_EHCI_FARADAY
 	if (ehci_is_TDI()) {
 		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
 		tmp = ehci_readl(reg_ptr);
@@ -172,6 +175,7 @@ static int ehci_reset(int index)
 #endif
 		ehci_writel(reg_ptr, tmp);
 	}
+#endif	/* !CONFIG_USB_EHCI_FARADAY */

 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -711,6 +715,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;

 		if (ehci_is_TDI()) {
+#ifdef CONFIG_USB_EHCI_FARADAY
+			tmpbuf[1] |= ehci_hcd_port_speed(ctrl->hccr) >> 8;
+#else
 			switch (PORTSC_PSPD(reg)) {
 			case PORTSC_PSPD_FS:
 				break;
@@ -722,6 +729,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 				break;
 			}
+#endif
 		} else {
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 		}
@@ -950,10 +958,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index d090f0a..9309ede 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -82,6 +82,7 @@ struct ehci_hcor {
 	uint32_t or_periodiclistbase;
 	uint32_t or_asynclistaddr;
 	uint32_t _reserved_0_;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t or_burstsize;
 	uint32_t or_txfilltuning;
 #define TXFIFO_THRESH_MASK		(0x3f << 16)
@@ -89,6 +90,7 @@ struct ehci_hcor {
 	uint32_t _reserved_1_[6];
 	uint32_t or_configflag;
 #define FLAG_CF		(1 << 0)	/* true:  we'll support "high speed" */
+#endif  /* #ifndef CONFIG_USB_EHCI_FARADAY */
 	uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
 #define PORTSC_PSPD(x)		(((x) >> 26) & 0x3)
 #define PORTSC_PSPD_FS			0x0
@@ -255,5 +257,8 @@ struct QH {
 /* Low level init functions */
 int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor);
 int ehci_hcd_stop(int index);
+#ifdef CONFIG_USB_EHCI_FARADAY
+int ehci_hcd_port_speed(struct ehci_hccr *hccr);
+#endif

 #endif /* USB_EHCI_H */
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..0249afd
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,71 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t msicr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[1];
+	uint32_t cxsr;	/* 0x11c: CX Status Register */
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t ioseasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t dma_data; /* 0x1d0: DMA CX Data Register */
+};
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..2d514b8
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,28 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Schedule Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v2 10/12] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (8 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 09/12] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 11:11       ` Wolfgang Denk
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
                       ` (2 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device as a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  922 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 931 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..d662387
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,922 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint32_t maxpacket:16;
+	uint32_t id:4;
+	uint32_t stopped:1;
+	uint32_t rsvd:11;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs      *iobase;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+#define USB_READ(r)			le32_to_cpu(readl(r))
+#define USB_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define USB_SETBITS(m, r)	setbits_le32(r, m)
+#define USB_CLRBITS(m, r)	clrbits_le32(r, m)
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType  = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes =    USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int
+fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id % 4) + 1);
+}
+
+static inline int
+ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) % 4);
+}
+
+static inline int
+ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs *regs = chip->iobase;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		USB_SETBITS(BIT_MASK(12), &regs->iep[ep - 1]);
+		mdelay(1);
+		USB_CLRBITS(BIT_MASK(12), &regs->iep[ep - 1]);
+		/* clear endpoint stall */
+		USB_CLRBITS(BIT_MASK(11), &regs->iep[ep - 1]);
+	} else {
+		/* reset endpoint */
+		USB_SETBITS(BIT_MASK(12), &regs->oep[ep - 1]);
+		mdelay(1);
+		USB_CLRBITS(BIT_MASK(12), &regs->oep[ep - 1]);
+		/* clear endpoint stall */
+		USB_CLRBITS(BIT_MASK(11), &regs->oep[ep - 1]);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs *regs = chip->iobase;
+	uint32_t i;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	USB_WRITE(BIT_MASK(5), &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	USB_WRITE(chip->addr, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	USB_WRITE(7, &regs->idle);
+
+	/* disable interrupts */
+	USB_WRITE(0x0f, &regs->imr);
+	USB_WRITE(0x07, &regs->gimr);
+	USB_WRITE(0x3f, &regs->gimr0);
+	USB_WRITE(0xf00ff, &regs->gimr1);
+	USB_WRITE(0x7ff, &regs->gimr2);
+
+	/* clear interrupts */
+	USB_WRITE(0x07, &regs->isr);
+	USB_WRITE(0x00, &regs->gisr);
+	USB_WRITE(0x00, &regs->gisr0);
+	USB_WRITE(0x00, &regs->gisr1);
+	USB_WRITE(0x00, &regs->gisr2);
+
+	/* chip reset */
+	USB_SETBITS(BIT_MASK(4), &regs->dev_ctrl);
+	while (USB_READ(&regs->dev_ctrl) & BIT_MASK(4))
+		;
+
+	/* CX FIFO reset */
+	USB_SETBITS(BIT_MASK(3), &regs->cxfifo);
+	while (USB_READ(&regs->cxfifo) & BIT_MASK(3))
+		;
+
+	/* create static ep-fifo map (EP1-FIFO0, EP2-FIFO1 ...)*/
+	USB_WRITE(0x33221100, &regs->epmap14);
+	USB_WRITE(0x00000000, &regs->epmap58);
+	USB_WRITE(0x04030201, &regs->fifomap);
+	USB_WRITE(0x00000000, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		USB_WRITE(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		USB_WRITE(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		USB_WRITE(BIT_MASK(12), &regs->fifocsr[i]);
+		while (USB_READ(&regs->fifocsr[i]) & BIT_MASK(12))
+			;
+	}
+
+	/* enable only device interrupt, interrupt=level,high active */
+	USB_WRITE(0x0e, &regs->imr);
+	USB_WRITE(0x07, &regs->isr);
+
+	/* disable EP0 IN/OUT interrupt */
+	USB_WRITE(0x06, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	USB_WRITE(0xf00ff, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	USB_WRITE(0x7e0, &regs->gimr2);
+	/* enable all group interrupt */
+	USB_WRITE(0x00, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	USB_WRITE(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	USB_SETBITS(BIT_MASK(2), &regs->dev_ctrl);
+
+	return 0;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->iobase;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	uint32_t fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		if (!(USB_READ(&regs->dma_ctrl) & 0x01)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+#ifndef CONFIG_SYS_DCACHE_OFF
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+	else
+		invalidate_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+#endif
+	USB_WRITE(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until fifo empty */
+			while (!(USB_READ(&regs->cxfifo) & 0x20))
+				;
+			USB_WRITE(BIT_MASK(4), &regs->dma_fifo);
+		} else {
+			/* Wait until fifo empty */
+			while (!(USB_READ(&regs->cxfifo) & (1 << (8 + fifo))))
+				;
+			USB_WRITE(1 << fifo, &regs->dma_fifo);
+		}
+		USB_WRITE((len << 8) | BIT_MASK(1), &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+		if (ep->id == 0) {
+			USB_WRITE(0x10, &regs->dma_fifo);
+			do {
+				blen = (USB_READ(&regs->cxfifo) >> 24) & 0x7f;
+			} while (blen < len);
+		} else {
+			USB_WRITE(1 << fifo, &regs->dma_fifo);
+			blen = USB_READ(&regs->fifocsr[fifo]) & 0x7ff;
+		}
+		len  = (len < blen) ? len : blen;
+		USB_WRITE(len << 8, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	USB_SETBITS(BIT_MASK(0), &regs->dma_ctrl);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		tmp = USB_READ(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & 0x80) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & 0x100) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & 0x07) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		USB_WRITE(BIT_MASK(4) | BIT_MASK(3), &regs->dma_ctrl);
+
+	USB_WRITE(0, &regs->gisr2);
+	USB_WRITE(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs *regs = chip->iobase;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (USB_READ(&regs->otgcsr) & BIT_MASK(21)) {
+			/* Mini-B */
+			if (USB_READ(&regs->dev_ctrl) & BIT_MASK(6)) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				USB_WRITE(0x044c, &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				USB_WRITE(0x2710, &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	USB_WRITE(0x10, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = USB_READ(&regs->dma_data);
+	tmp[1] = USB_READ(&regs->dma_data);
+	/* release data port */
+	USB_WRITE(0x00, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				USB_WRITE(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				USB_WRITE(chip->addr | BIT_MASK(7),
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue;
+			ret = CX_FINISH;
+			USB_WRITE(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				USB_SETBITS(BIT_MASK(11), &regs->iep[id - 1]);
+				USB_SETBITS(BIT_MASK(11), &regs->oep[id - 1]);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	}    /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		USB_SETBITS(BIT_MASK(0), &regs->cxfifo);
+		break;
+
+	case CX_STALL:
+		USB_SETBITS(BIT_MASK(2) | BIT_MASK(0), &regs->cxfifo);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs *regs = chip->iobase;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue))
+		USB_SETBITS(3 << (ep_to_fifo(chip, ep->id) * 2), &regs->gimr1);
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->iobase;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		USB_SETBITS(0x10 << (8 * id), &regs->fifomap);
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		USB_SETBITS(0x21 << (8 * id), &regs->fifocfg);
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		USB_SETBITS(0x22 << (8 * id), &regs->fifocfg);
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		USB_SETBITS(0x23 << (8 * id), &regs->fifocfg);
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->iobase;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	USB_CLRBITS(0x23 << (8 * id), &regs->fifocfg);
+	USB_CLRBITS(0x30 << (8 * id), &regs->fifomap);
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->iobase;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			USB_CLRBITS(3 << (ep_to_fifo(chip, ep->id) * 2),
+				&regs->gimr1);
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->iobase;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until fifo empty */
+			while ((USB_READ(&regs->cxfifo) & 0xf00) != 0xf00)
+				;
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				USB_SETBITS(BIT_MASK(11),
+					regs->iep[ep->id - 1]);
+			} else {
+				USB_SETBITS(BIT_MASK(11),
+					regs->oep[ep->id - 1]);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				USB_CLRBITS(BIT_MASK(11),
+					regs->iep[ep->id - 1]);
+			} else {
+				USB_CLRBITS(BIT_MASK(11),
+					regs->oep[ep->id - 1]);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs *regs = chip->iobase;
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			USB_SETBITS(BIT_MASK(5), &regs->dev_ctrl);
+			/* clear unplug bit (BIT0) */
+			USB_CLRBITS(BIT_MASK(0), &regs->phy_tmsr);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		USB_WRITE(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		USB_SETBITS(BIT_MASK(0), &regs->phy_tmsr);
+		/* disable the chip */
+		USB_CLRBITS(BIT_MASK(5), &regs->dev_ctrl);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->iobase;
+
+	return USB_READ(&regs->sof_fnr) & 0x7ff;
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.iobase = (void *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name    = "ep0",
+			.ops    = &fotg210_ep_ops,
+		},
+		.desc       = &ep0_desc,
+		.chip        = &controller,
+		.maxpacket    = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name    = "ep1",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name    = "ep2",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name    = "ep3",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name    = "ep4",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs *regs = chip->iobase;
+	uint32_t isr, gisr;
+
+	isr  = USB_READ(&regs->isr) & (~USB_READ(&regs->imr));
+	gisr = USB_READ(&regs->gisr) & (~USB_READ(&regs->gimr));
+	if (!(isr & BIT_MASK(0)) || !gisr)
+		return 0;
+
+	USB_WRITE(BIT_MASK(0), &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & BIT_MASK(0)) {
+		uint32_t st = USB_READ(&regs->gisr0);
+		USB_WRITE(0, &regs->gisr0);
+
+		if (st & BIT_MASK(4))
+			printf("fotg210: cmd error\n");
+
+		if (st & BIT_MASK(5))
+			printf("fotg210: cmd abort\n");
+
+		if (st & BIT_MASK(0))            /* setup */
+			fotg210_setup(chip);
+		else if (st & BIT_MASK(3))        /* command finish */
+			USB_SETBITS(BIT_MASK(0), &regs->cxfifo);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & BIT_MASK(1)) {
+		uint32_t id;
+		uint32_t st = USB_READ(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & (3 << (id * 2)))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & BIT_MASK(2)) {
+		uint32_t st = USB_READ(&regs->gisr2);
+		USB_WRITE(0, &regs->gisr2);
+
+		if (st & BIT_MASK(0))
+			printf("fotg210: reset by host\n");
+		else if (st & BIT_MASK(1))
+			printf("fotg210: suspend/removed\n");
+		else if (st & BIT_MASK(2))
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & BIT_MASK(3))
+			printf("fotg210: iso error\n");
+		if (st & BIT_MASK(4))
+			printf("fotg210: iso abort\n");
+		if (st & BIT_MASK(8))
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		dcache_enable();
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (9 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 10/12] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 11:13       ` Wolfgang Denk
  2013-04-18 19:09       ` Albert ARIBAUD
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 12/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-04-18 10:43     ` [U-Boot] [PATCH v2 00/12] " Wolfgang Denk
  12 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch would enable MMU for Faraday ARMv5TE cores.

Here is the abstract of this MMU design.

Assume SDRAM memory region starts at 0x10000000, and its size = 0x800000.

0x00000000 +-------------------+
           |                   |
           |     UN-CACHED     |
           |                   |
           |                   |
0x10000000 +-------------------+
           |  CACHED (SDRAM)   | <- It's where data/bss/stack lived.
           |                   |
           |                   |
0x10800000 +-------------------+
           |                   |
           |                   |
           |     UN-CACHED     |
           |                   |
           |                   |
0xFF800000 +-------------------+
           | UN-CACHED (SDRAM) | <- An un-cached shadow of the SDRAM.
           |                   |    dma_alloc_coherent() always returns
           |                   |    an address in this region.
0xFFFFFFFF +-------------------+

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
 arch/arm/include/asm/dma-mapping.h |   56 ++++++++++++++++++++++--
 arch/arm/include/asm/global_data.h |    4 ++
 arch/arm/include/asm/io.h          |   84 +++++++++++++++++++++++++++++++++++-
 arch/arm/lib/cache-cp15.c          |   42 ++++++++++++++++++
 common/cmd_boot.c                  |    4 ++
 5 files changed, 186 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..53c4edf 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -3,6 +3,9 @@
  * Stelian Pop <stelian@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
  *
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -24,22 +27,69 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <malloc.h>
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };

-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
+{
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	DECLARE_GLOBAL_DATA_PTR;
+#endif
+	void *va = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (va && handle)
+		*handle = virt_to_phys(va);
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		/* invalidate the buffer, convert to un-cached address */
+		if (va != NULL) {
+			invalidate_dcache_range((ulong)va, (ulong)va + len);
+			va = virt_to_uncached(va);
+		}
+	}
+#endif
+
+	return va;
+}
+
+static inline void dma_free_coherent(void *va)
 {
-	*handle = (unsigned long)malloc(len);
-	return (void *)*handle;
+	free(virt_to_cached(va));
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	DECLARE_GLOBAL_DATA_PTR;
+
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else
 	return (unsigned long)vaddr;
+#endif
 }

 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 37ac0da..bd18ff7 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -38,6 +38,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..17d8898 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/io.h
  *
  *  Copyright (C) 1996-2000 Russell King
+ *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -23,6 +24,8 @@
 #ifdef __KERNEL__

 #include <linux/types.h>
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
 #include <asm/byteorder.h>
 #include <asm/memory.h>
 #if 0	/* XXX###XXX */
@@ -57,9 +60,88 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)

 }

+#ifdef CONFIG_FARADAY
+
+# ifndef CONFIG_SYS_DCACHE_OFF
+
+static inline ulong uncached_base(volatile gd_t *gd)
+{
+	return (4096 - (gd->ram_size >> 20)) << 20;
+}
+# endif
+
+static inline void *virt_to_cached(void *va)
+{
+# ifndef CONFIG_SYS_DCACHE_OFF
+	DECLARE_GLOBAL_DATA_PTR;
+	ulong base = uncached_base(gd);
+
+	if (!gd->arch.cpu_mmu)
+		return va;
+
+	if ((ulong)va >= base &&
+		(ulong)va < (base + gd->ram_size))
+		va = (void *)((ulong)va - base + CONFIG_SYS_SDRAM_BASE);
+# endif	/* !CONFIG_SYS_DCACHE_OFF */
+
+	return va;
+}
+
+static inline void *virt_to_uncached(void *va)
+{
+# ifndef CONFIG_SYS_DCACHE_OFF
+	DECLARE_GLOBAL_DATA_PTR;
+	ulong base = uncached_base(gd);
+
+	if (!gd->arch.cpu_mmu)
+		return va;
+
+#  ifdef CONFIG_USE_IRQ
+	if ((ulong)va < SZ_1M)
+		return (void *)(base + (ulong)va);
+#  endif
+
+	if ((ulong)va >= CONFIG_SYS_SDRAM_BASE &&
+		(ulong)va < (CONFIG_SYS_SDRAM_BASE + gd->ram_size))
+		va = (void *)(base + ((ulong)va - CONFIG_SYS_SDRAM_BASE));
+# endif	/* !CONFIG_SYS_DCACHE_OFF */
+
+	return va;
+}
+
+#endif	/* CONFIG_FARADAY */
+
 static inline phys_addr_t virt_to_phys(void * vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+
+	DECLARE_GLOBAL_DATA_PTR;
+	bd_t *bd = gd->bd;
+	ulong base = uncached_base(gd);
+	ulong phys = (ulong)vaddr;
+
+	if (!gd->arch.cpu_mmu)
+		return (phys_addr_t)phys;
+
+	if (phys >= base) {
+		ulong bank;
+		ulong off = phys - base;
+		for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
+			if (bd->bi_dram[bank].size > off)
+				break;
+			off -= bd->bi_dram[bank].size;
+		}
+		phys = bd->bi_dram[bank].start + off;
+	}
+# ifdef CONFIG_USE_IRQ
+	else if (phys < SZ_1M && bd->bi_dram[0].start != 0)
+		phys = bd->bi_dram[0].start + phys;
+# endif
+
+	return (phys_addr_t)phys;
+#else
+	return (phys_addr_t)vaddr;
+#endif
 }

 /*
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 4abe1cf..eee8585 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -1,6 +1,8 @@
 /*
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -87,6 +89,10 @@ __weak void dram_bank_mmu_setup(int bank)
 {
 	bd_t *bd = gd->bd;
 	int	i;
+#ifdef CONFIG_FARADAY
+	ulong ubase, off;
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+#endif

 	debug("%s: bank: %d\n", __func__, bank);
 	for (i = bd->bi_dram[bank].start >> 20;
@@ -98,6 +104,32 @@ __weak void dram_bank_mmu_setup(int bank)
 		set_section_dcache(i, DCACHE_WRITEBACK);
 #endif
 	}
+#ifdef CONFIG_FARADAY
+# ifdef CONFIG_USE_IRQ
+	/* map the exception table to 0x00000000 if necessary */
+	if (bank == 0 && bd->bi_dram[bank].start != 0) {
+		u32 pa = bd->bi_dram[bank].start;
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
+#else
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
+#endif
+	}
+# endif
+	/* calculate address offset */
+	off  = 0;
+	for (i = 0; i < bank; ++i)
+		off += bd->bi_dram[bank].size;
+
+	/* create memory map */
+	ubase = (4096 - (gd->ram_size >> 20)) << 20;
+	for (i = 0; i < bd->bi_dram[bank].size >> 20; ++i) {
+		u32 pa = bd->bi_dram[bank].start + (i << 20);
+		/* create un-cached address map */
+		u32 va = ubase + off + (i << 20);
+		page_table[va >> 20] = pa | (3 << 10) | DCACHE_OFF;
+	}
+#endif
 }

 /* to activate the MMU we need to set up virtual memory: use 1M areas */
@@ -126,6 +158,10 @@ static inline void mmu_setup(void)

 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#ifdef CONFIG_FARADAY
+	reg |= CR_W;	/* enable write buffer */
+	reg |= CR_Z;	/* enable branch prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -140,9 +176,15 @@ static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;

+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
+
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | cache_bit);
diff --git a/common/cmd_boot.c b/common/cmd_boot.c
index d3836fd..b2477e8 100644
--- a/common/cmd_boot.c
+++ b/common/cmd_boot.c
@@ -50,6 +50,10 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])

 	printf ("## Starting application at 0x%08lX ...\n", addr);

+#if defined(__ARM__) && !defined(CONFIG_SYS_DCACHE_OFF)
+	cleanup_before_linux();
+#endif
+
 	/*
 	 * pass address parameter as argv[0] (aka command name),
 	 * and all remaining args
--
1.7.9.5

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

* [U-Boot] [PATCH v2 12/12] arm: add Faraday A36x SoC platform support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (10 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
@ 2013-04-18  9:25     ` Kuo-Jung Su
  2013-04-18 11:16       ` Wolfgang Denk
  2013-04-18 10:43     ` [U-Boot] [PATCH v2 00/12] " Wolfgang Denk
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-18  9:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday A36x EVB is a Faraday SoC platform evalution board used for
Faraday IP functional verification based on the well-known ARM AMBA 2.0
architecture.

Faraday A360 EVB:
   CPU: FA626TE
   NET: FTMAC110
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC010
   WDT: FTWDT010
   TMR: FTTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC020

Faraday A369 EVB:
   CPU: FA626TE(Master)/FA606TE(Slave)
   NET: FTGMAC100
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC011
   WDT: FTWDT010
   TMR: FTPWMTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC021

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
 arch/arm/cpu/faraday/Makefile             |   57 ++++
 arch/arm/cpu/faraday/a360/Makefile        |   49 +++
 arch/arm/cpu/faraday/a360/reset.c         |   26 ++
 arch/arm/cpu/faraday/a369/Makefile        |   50 +++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   75 +++++
 arch/arm/cpu/faraday/a369/reset.c         |   26 ++
 arch/arm/cpu/faraday/cmd_bootfa.c         |  132 ++++++++
 arch/arm/cpu/faraday/config.mk            |   33 ++
 arch/arm/cpu/faraday/cpu.c                |  238 +++++++++++++
 arch/arm/cpu/faraday/ftintc020.h          |   37 ++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  156 +++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.h        |   41 +++
 arch/arm/cpu/faraday/fttmr010.c           |  159 +++++++++
 arch/arm/cpu/faraday/fwimage.h            |   38 +++
 arch/arm/cpu/faraday/fwimage2.h           |   70 ++++
 arch/arm/cpu/faraday/interrupts.c         |  155 +++++++++
 arch/arm/cpu/faraday/start.S              |  523 +++++++++++++++++++++++++++++
 arch/arm/cpu/u-boot.lds                   |   11 +
 arch/arm/include/asm/arch-a360/hardware.h |   72 ++++
 arch/arm/include/asm/arch-a369/hardware.h |   98 ++++++
 arch/arm/include/asm/mach-types.h         |    1 +
 board/faraday/a360evb/Makefile            |   49 +++
 board/faraday/a360evb/board.c             |   67 ++++
 board/faraday/a360evb/clk.c               |   52 +++
 board/faraday/a360evb/config.mk           |   33 ++
 board/faraday/a360evb/lowlevel_init.S     |   33 ++
 board/faraday/a369evb/Makefile            |   49 +++
 board/faraday/a369evb/board.c             |  178 ++++++++++
 board/faraday/a369evb/clk.c               |   81 +++++
 board/faraday/a369evb/config.mk           |   33 ++
 board/faraday/a369evb/lowlevel_init.S     |  136 ++++++++
 boards.cfg                                |    3 +
 include/common.h                          |   13 +
 include/configs/a360.h                    |  185 ++++++++++
 include/configs/a369.h                    |   41 +++
 include/configs/a369_defaults.h           |  295 ++++++++++++++++
 include/configs/a369_fa606te.h            |   32 ++
 include/faraday/fttmr010.h                |   17 +
 38 files changed, 3344 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/reset.c
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/a369/reset.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftintc020.h
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.h
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_defaults.h
 create mode 100644 include/configs/a369_fa606te.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..fb712a1
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,57 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+src-y						:= interrupts.o
+src-$(CONFIG_FTPWMTMR010)	+= ftpwmtmr010.o
+src-$(CONFIG_FTTMR010)		+= fttmr010.o
+
+START	= start.o
+COBJS	= cpu.o cmd_bootfa.o $(src-y)
+
+ifdef	CONFIG_SPL_BUILD
+ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE
+START	:=
+endif
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..ccd55fa
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   := reset.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a360/reset.c b/arch/arm/cpu/faraday/a360/reset.c
new file mode 100644
index 0000000..ea2db58
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/reset.c
@@ -0,0 +1,26 @@
+/*
+ * arch/arm/cpu/faraday/a360/reset.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/ftwdt010_wdt.h>
+
+#define WDT_READ(r)		le32_to_cpu(readl(r))
+#define WDT_WRITE(v, r)	writel(cpu_to_le32(v), r)
+
+void reset_cpu(unsigned long ignored)
+{
+	struct ftwdt010_wdt *regs = (struct ftwdt010_wdt *)CONFIG_FTWDT010_BASE;
+
+	WDT_WRITE(0, &regs->wdcr);
+	WDT_WRITE(1000, &regs->wdload);
+	WDT_WRITE(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+	WDT_WRITE(FTWDT010_WDRESTART_MAGIC, &regs->wdrestart);
+}
diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..5c68d2d
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y                   := reset.o
+obj-$(CONFIG_CMD_FA606) += cmd_fa606.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/cmd_fa606.c b/arch/arm/cpu/faraday/a369/cmd_fa606.c
new file mode 100644
index 0000000..3aeca9e
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/cmd_fa606.c
@@ -0,0 +1,75 @@
+/*
+ * arch/arm/cpu/faraday/a369/cmd_fa606.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would start the A369 slave cpu - FA606TE, and also immediately
+ * halt the master cpu - FA626TE.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+#define SOC_READ(r)		le32_to_cpu(readl(r))
+#define SOC_WRITE(v, r)	writel(cpu_to_le32(v), r)
+
+static int do_fa606(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int addr = CONFIG_SYS_LOAD_ADDR;
+
+	if (argc >= 2)
+		addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("FA606 Image at 0x%08X\n", addr);
+	printf("FA626 is going to enter IDLE state, and never wake-up......\n");
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+	cleanup_before_linux();
+#endif
+
+	/* 1. FA606TE address offset = 0 */
+	printf("FA606 address shift disable.\n");
+	SOC_WRITE(0x00000000, CONFIG_AHBC2_BASE + 0x90);
+
+	/* 2. Generate a long-jump to 0x00000000 */
+	writel(le32_to_cpu(0xEA00000A), 0x00); /* b   0x30 */
+	writel(le32_to_cpu(addr),       0x20);
+	writel(le32_to_cpu(0xE3A00020), 0x30); /* mov r0, #32 ; 0x20 */
+	writel(le32_to_cpu(0xE590F000), 0x34); /* ldr pc, [r0] */
+
+	/* 3. Pinmux = ICE + LCD */
+	SOC_WRITE(0x00001078, CONFIG_SCU_BASE + 0x200);
+	SOC_WRITE(0x26877330, CONFIG_SCU_BASE + 0x228);
+	SOC_WRITE(0x000A0A0A, CONFIG_SCU_BASE + 0x22c);
+	SOC_WRITE(0x00003FFF, CONFIG_SCU_BASE + 0x230);
+	SOC_WRITE(0x00000065, CONFIG_SCU_BASE + 0x238);
+	SOC_WRITE(0x00000080, CONFIG_SCU_BASE + 0x23c);
+	udelay(5000);
+
+	/* 4. FA606 clock enable & reset */
+	SOC_WRITE(0x00000000, CONFIG_SCU_BASE + 0x028);
+	udelay(5000);
+	SOC_WRITE(0x00001878, CONFIG_SCU_BASE + 0x200);
+
+	/* 5. FA626 is going to enter IDLE state, and never wake-up */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15,0,r3,c7,c0,4\n"
+		:
+		:
+		: "r3"    /* clobber list */
+	);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	fa606, 2, 0, do_fa606,
+	"launch firmware with A369's built-in fa606te\n",
+	"fa606 [address] - mov pc of fa606te to the specified address.\n"
+);
diff --git a/arch/arm/cpu/faraday/a369/reset.c b/arch/arm/cpu/faraday/a369/reset.c
new file mode 100644
index 0000000..5bb37d5
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/reset.c
@@ -0,0 +1,26 @@
+/*
+ * arch/arm/cpu/faraday/a369/reset.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/ftwdt010_wdt.h>
+
+#define WDT_READ(r)		le32_to_cpu(readl(r))
+#define WDT_WRITE(v, r)	writel(cpu_to_le32(v), r)
+
+void reset_cpu(unsigned long ignored)
+{
+	struct ftwdt010_wdt *regs = (struct ftwdt010_wdt *)CONFIG_FTWDT010_BASE;
+
+	WDT_WRITE(0, &regs->wdcr);
+	WDT_WRITE(1000, &regs->wdload);
+	WDT_WRITE(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+	WDT_WRITE(FTWDT010_WDRESTART_MAGIC, &regs->wdrestart);
+}
diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..bcced38
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,132 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would try to boot faraday image from MMC/SD/USB/SPI/NAND/NOR
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *part = hdr->part;
+
+	for (i = 0; part[i].length > 0 && i < 10; ++i) {
+		if (strcmp(name, part[i].name) == 0) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				part[i].name, part[i].offset, part[i].length);
+			return part + i;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400",
+			CONFIG_SYS_FLASH_BASE,
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x",
+			CONFIG_SYS_FLASH_BASE + part->offset,
+			CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400",
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..ffb2e6c
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
+
+PLATFORM_CPPFLAGS += -march=armv5te
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..56c4d72
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,238 @@
+/*
+ * arch/arm/cpu/faraday/cpu.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/system.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+
+	disable_interrupts();
+
+	/* turn off D-cache */
+	dcache_disable();
+
+	/* flush I-cache */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15, 0, r3, c7, c5, 0\n" /* invalidate i-cache all */
+		:      /* output */
+		:      /* input */
+		: "r3" /* clobber list */
+	);
+
+	return 0;
+}
+
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#else
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c14,0\n" /* clean & invalidate d-cache all */
+		"mcr p15,0,r3,c7,c10,4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n" /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c10,4\n" /* drain write buffer */
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)   /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n" /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)  /* input */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c6,0\n" /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c5,0\n" /* invalidate i-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
+
+void enable_caches(void)
+{
+	icache_enable();
+
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		puts("MMU:   on\n");
+		dcache_enable();
+	} else
+#endif
+		puts("MMU:   off\n");
+}
+
+#ifdef CONFIG_ARCH_CPU_INIT
+
+int arch_cpu_init(void)
+{
+	unsigned int id, ctr;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		"mrc p15, 0, %1, c0, c0, 1\n"
+		: "=r"(id), "=r"(ctr) /* output */
+		: /* input */
+	);
+
+	gd->arch.cpu_id = id;
+
+	/* MMU/D-Cache */
+	switch (gd->arch.cpu_id >> 4) {
+	case 0x6604526:    /* FA526 */
+	case 0x6604626:    /* FA626 */
+	case 0x6605606:    /* FA606TE */
+		/* Disable MMU/D-Cache */
+		gd->arch.cpu_mmu = 0;
+		break;
+	default:
+		/* Enable MMU/D-Cache */
+		gd->arch.cpu_mmu = 1;
+		break;
+	}
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+	uint vid = gd->arch.cpu_id >> 24;
+	uint pid = (gd->arch.cpu_id & 0xfff0) >> 4;
+
+	/* build cpu_name */
+	switch (vid) {
+	case 0x66:	/* Faraday */
+		switch (gd->arch.cpu_id >> 16) {
+		case 0x6601:
+			sprintf(cpu_name, "FA%x", pid);
+			break;
+		default:
+			sprintf(cpu_name, "FA%xTE", pid);
+			break;
+		}
+		break;
+	case 0x41:	/* ARM */
+		if ((pid & 0xff0) == 0xc00)
+			sprintf(cpu_name, "Cortex-A%u", (pid & 0x00f));
+		else if (pid >= 0xa00)
+			sprintf(cpu_name, "ARM%x", 0x1000 + (pid - 0xa00));
+		else
+			sprintf(cpu_name, "ARM%x", pid);
+		break;
+	default:
+		sprintf(cpu_name, "Unknown");
+		break;
+	}
+
+	/* print cpu_info */
+	printf("CPU:   %s %u MHz\n",
+		cpu_name, (unsigned int)(clk_get_rate("CPU") / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("AHB") / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("APB") / 1000000));
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_DISPLAY_CPUINFO */
diff --git a/arch/arm/cpu/faraday/ftintc020.h b/arch/arm/cpu/faraday/ftintc020.h
new file mode 100644
index 0000000..e23d1e7
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftintc020.h
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTINTC020_H
+#define ARCH_ARM_CPU_FARADAY_FTINTC020_H
+
+struct ftintc020_pic_regs {
+	uint32_t src; /* source register */
+	uint32_t ena; /* enable register */
+	uint32_t scr; /* status clear register */
+	uint32_t tmr; /* trigger mode register */
+	uint32_t tlr; /* trigger level register */
+	uint32_t sr;  /* status register */
+	uint32_t rsvd[2];
+};
+
+struct ftintc020_regs {
+	/* IRQ/FIQ:  0 ~ 31 */
+	struct ftintc020_pic_regs irq32; /* 0x00 - 0x1C: IRQ 0 ~ 31 */
+	struct ftintc020_pic_regs fiq32; /* 0x20 - 0x3C: FIQ 0 ~ 31 */
+	uint32_t rsvd1[4];               /* 0x40 - 0x4C: Reserved */
+	uint32_t revision;               /* 0x50: Revision Register */
+	uint32_t feature;                /* 0x54: Feature Register */
+	uint32_t rsvd2[2];               /* 0x58 - 0x5C: Reserved */
+	/* IRQ/FIQ: 32 ~ 63 */
+	struct ftintc020_pic_regs irq64; /* 0x60 - 0x7C: IRQ 32 ~ 63 */
+	struct ftintc020_pic_regs fiq64; /* 0x80 - 0x9C: FIQ 32 ~ 63 */
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..39d5ba1
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,156 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include "ftpwmtmr010.h"
+
+#ifdef CONFIG_A369_FA606TE_PLATFORM
+#define TIMER_ID    4
+#else
+#define TIMER_ID    0
+#endif
+
+#define TMR_READ(r)		le32_to_cpu(readl(r))
+#define TMR_WRITE(v, r)	writel(cpu_to_le32(v), r)
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+static struct ftpwmtmr010_regs *regs = (void *)CONFIG_TIMER_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+
+	/* timer re-start */
+	TMR_WRITE(0, &regs->t[id].ctrl);
+	TMR_WRITE(BIT_MASK(id), &regs->isr);
+	TMR_WRITE(0, &regs->t[id].cmpb);
+	TMR_WRITE((sclk / 1000000) * usec, &regs->t[id].cntb);
+	TMR_WRITE(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(TMR_READ(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	TMR_WRITE(0, &regs->t[id].ctrl);
+	TMR_WRITE(BIT_MASK(id), &regs->isr);
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	int id = TIMER_ID;
+	++ticks;
+	TMR_WRITE(BIT_MASK(id), &regs->isr);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+
+	TMR_WRITE(0, &regs->t[id].ctrl);
+	TMR_WRITE(BIT_MASK(id), &regs->isr);
+
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	TMR_WRITE(0,
+		&regs->t[id].cmpb);
+	TMR_WRITE(sclk / CONFIG_SYS_HZ,
+		&regs->t[id].cntb);
+	TMR_WRITE(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+	irq_install_handler(CONFIG_TIMER_IRQ, (void *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+	enable_interrupts();
+#else
+	/* setup a 30 sec one-shot timer */
+	TMR_WRITE(0,
+		&regs->t[id].cmpb);
+	TMR_WRITE(30 * sclk,
+		&regs->t[id].cntb);
+	TMR_WRITE(CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+#endif    /* #ifdef CONFIG_USE_IRQ */
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = (30 * sclk - TMR_READ(&regs->t[TIMER_ID].cnto)) / s;
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+	sclk  = clk_get_rate("APB");
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (!TMR_READ(&regs->t[TIMER_ID].cnto)) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.h b/arch/arm/cpu/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..9455577
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..e8f1a2c
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,159 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+#define TMR_READ(r)			le32_to_cpu(readl(r))
+#define TMR_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define TMR_SETBITS(m, r)	setbits_le32(r, m)
+#define TMR_CLRBITS(m, r)	clrbits_le32(r, m)
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+static struct fttmr010 *regs = (void *)CONFIG_TIMER_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	/* Disable Timer2 */
+	TMR_CLRBITS(FTTMR010_TM2_CRMASK, &regs->cr);
+	/* Disable Timer2 interrupts */
+	TMR_WRITE(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	TMR_WRITE(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	TMR_WRITE((sclk / 1000000) * usec, &regs->timer2_counter);
+	TMR_WRITE(0, &regs->timer2_load);
+	TMR_WRITE(0, &regs->timer2_match1);
+	TMR_WRITE(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	TMR_SETBITS(FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE, &regs->cr);
+
+	/* Wait until timeout */
+	while (!(TMR_READ(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	++ticks;
+	TMR_WRITE(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	/* Disable Timer1 */
+	TMR_CLRBITS(FTTMR010_TM1_CRMASK, &regs->cr);
+	/* Disable Timer1 interrupts */
+	TMR_WRITE(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer1 interrupts */
+	TMR_WRITE(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt init */
+	irq_set_trigger(CONFIG_TIMER_IRQ, 1, 0);
+	irq_install_handler(CONFIG_TIMER_IRQ, (void *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+#endif
+
+	/* timer1 setup */
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	TMR_WRITE(sclk / CONFIG_SYS_HZ, &regs->timer1_counter);
+	TMR_WRITE(sclk / CONFIG_SYS_HZ, &regs->timer1_load);
+#else
+	/* setup a 30 sec one-shot timer */
+	TMR_WRITE(30 * sclk, &regs->timer1_counter);
+	TMR_WRITE(0, &regs->timer1_load);
+#endif
+	TMR_WRITE(0, &regs->timer1_match1);
+	TMR_WRITE(0, &regs->timer1_match2);
+
+	/* start timer1 with overflow interrupt enabled */
+	TMR_WRITE(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+	TMR_SETBITS(FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE,
+		&regs->cr);
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = ((30 * sclk) - TMR_READ(&regs->timer1_counter)) / s;
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+	sclk  = clk_get_rate("APB");
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (!TMR_READ(&regs->timer1_counter)) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..af4f2f9
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/cpu/faraday/fwimage.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t	count;
+	uint32_t	version; /* ycmo100525: for firmware image version */
+	uint32_t	addr[31];
+	uint32_t	data[31];
+};
+
+struct fwfile {
+	char		name[64];
+	uint32_t	size;
+	/* uint32_t	block[1]; */
+};
+
+struct fwimage {
+	/* 8 bytes */
+	uint32_t		magic;	/* Magic number */
+	uint32_t		length;	/* It shall not be greater than 2048 */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam	param;
+
+	struct fwfile	file[1];
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..27319a7
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/cpu/faraday/fwimage2.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+
+#include <image.h>
+#include "fwimage.h"
+
+/* 8 bytes struct for generic 32-bit memory write */
+struct fwmw32 {
+	uint32_t addr;
+	uint32_t data;
+};
+
+/* 72 bytes */
+struct fwpart {
+	/* offset: 0 ~ 63 */
+	char     name[32];
+
+	uint32_t offset;
+	uint32_t length;
+
+	uint32_t load;
+	uint32_t qcrc; /* Quick CRC32 against 256KB on both TOP & BOTTOM */
+
+	uint32_t flag;
+#define FWIMAGE2_FLAG_UIMAGE		0x00000001 /* Is a uImage ? */
+#define FWIMAGE2_FLAG_FILESYSTEM	0x00000010 /* Is a filesystem ? */
+
+	uint8_t  rsvd[12];
+
+	/* offset: 64 ~ 71 */
+	uint32_t magic1000; /* It's always 0x00001000 */
+	uint32_t magic0001; /* It's always 0x00000001 */
+};
+
+struct fwimage2 {
+	/*   4 bytes, magic */
+	uint32_t magic; /* Image Header Magic Number */
+#define FWIMAGE2_MAGIC			0x00484946 /* "FIH\0" */
+
+	/*   4 bytes, header length */
+	uint32_t hlen;      /* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwmw32 mw32[32];
+
+	/* 720 bytes, firmware partition table */
+	struct fwpart part[10];
+
+	/*   4 bytes */
+	uint32_t hcrc;  /* Image Header Checksum (CRC32) */
+
+	/*   4 bytes, revision */
+	uint32_t revision; /* Image Header Revision Code */
+#define FWIMAGE2_REVISION		0x00000201		/* v2.1 */
+
+	/*  32 bytes */
+	char     build[32]; /* Build Date (yyyy/mm/dd HH:MM:SS) */
+};	/* Total 1024 bytes */
+
+#endif
diff --git a/arch/arm/cpu/faraday/interrupts.c b/arch/arm/cpu/faraday/interrupts.c
new file mode 100644
index 0000000..162c454
--- /dev/null
+++ b/arch/arm/cpu/faraday/interrupts.c
@@ -0,0 +1,155 @@
+/*
+ * arch/arm/cpu/faraday/interrupts.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include "ftintc020.h"
+
+#ifdef CONFIG_USE_IRQ
+
+#define PIC_READ(r)			le32_to_cpu(readl(r))
+#define PIC_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define PIC_SETBITS(m, r)	setbits_le32(r, m)
+#define PIC_CLRBITS(m, r)	clrbits_le32(r, m)
+
+static struct ftintc020_regs *regs = (void *)CONFIG_PIC_BASE;
+
+struct _irq_handler {
+	void  *data;
+	void (*func)(void *data);
+};
+
+static struct _irq_handler IRQ_HANDLER[64];
+
+static inline void irq_acknowledge(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		PIC_WRITE(mask, &regs->irq32.scr);
+	else
+		PIC_WRITE(mask, &regs->irq64.scr);
+}
+
+void irq_enable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		PIC_SETBITS(mask, &regs->irq32.ena);
+	else
+		PIC_SETBITS(mask, &regs->irq64.ena);
+}
+
+void irq_disable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		PIC_CLRBITS(mask, &regs->irq32.ena);
+	else
+		PIC_CLRBITS(mask, &regs->irq64.ena);
+}
+
+void irq_set_trigger(int irq, int edge, int low)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (edge) {
+		if (irq < 32)
+			PIC_SETBITS(mask, &regs->irq32.tmr);
+		else
+			PIC_SETBITS(mask, &regs->irq64.tmr);
+	} else {
+		if (irq < 32)
+			PIC_CLRBITS(mask, &regs->irq32.tmr);
+		else
+			PIC_CLRBITS(mask, &regs->irq64.tmr);
+	}
+
+	if (low) {
+		if (irq < 32)
+			PIC_SETBITS(mask, &regs->irq32.tlr);
+		else
+			PIC_SETBITS(mask, &regs->irq64.tlr);
+	} else {
+		if (irq < 32)
+			PIC_CLRBITS(mask, &regs->irq32.tlr);
+		else
+			PIC_CLRBITS(mask, &regs->irq64.tlr);
+	}
+}
+
+void do_irq(struct pt_regs *pt_regs)
+{
+	int irq;
+	uint32_t stat;
+
+	irq  = 32;
+	stat = PIC_READ(&regs->irq64.sr);     /* IRQ 32 ~ 63 */
+	if (!stat) {
+		irq  = 0;
+		stat = PIC_READ(&regs->irq32.sr); /* IRQ  0 ~ 31 */
+	}
+	irq += ffs(stat) - 1;
+
+	if (irq < 0) {
+		printf("interrupts: no irq!?\n");
+	} else {
+		irq_acknowledge(irq);
+		IRQ_HANDLER[irq].func(IRQ_HANDLER[irq].data);
+	}
+}
+
+static void default_isr(void *data)
+{
+	printf("default_isr():  called for IRQ %d\n", (int)data);
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *hndl, void *data)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = hndl;
+		IRQ_HANDLER[irq].data = data;
+	}
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = default_isr;
+		IRQ_HANDLER[irq].data = (void *)irq;
+		irq_disable(irq);
+	}
+}
+
+int arch_interrupt_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(IRQ_HANDLER); ++i)
+		irq_free_handler(i);
+
+	/* hardware reset */
+	PIC_WRITE(0x00000000, &regs->irq32.ena);
+	PIC_WRITE(0xffffffff, &regs->irq32.scr);
+	PIC_WRITE(0x00000000, &regs->irq32.tmr);
+	PIC_WRITE(0x00000000, &regs->irq32.tlr);
+
+	PIC_WRITE(0x00000000, &regs->irq64.ena);
+	PIC_WRITE(0xffffffff, &regs->irq64.scr);
+	PIC_WRITE(0x00000000, &regs->irq64.tmr);
+	PIC_WRITE(0x00000000, &regs->irq64.tlr);
+
+	return 0;
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..2d5e1cd
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,523 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _image_copy_end_ofs
+_image_copy_end_ofs:
+	.word __image_copy_end - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * Relocate U-Boot to RAM
+	 * It's copied from the old u-boot release.
+	 */
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+	adr	r0, _start          /* r0 <- current position of code   */
+	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
+	teq     r0, r1          /* don't reloc during debug         */
+	bleq    rr_exit
+	ldr	r2, _end_ofs        /* r2 <- size of u-boot             */
+	add	r2, r0, r2          /* r2 <- source end address         */
+
+rr_loop:
+	ldmia r0!, {r3-r10}	/* copy from source address [r0]    */
+	stmia r1!, {r3-r10}	/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end addreee [r2]    */
+	blo	rr_loop
+
+	/* Adjust the pc to use the correct text address */
+	adr	r0, _start
+	ldr	r1, _TEXT_BASE
+	sub r2, pc, r0
+	add r2, r2, #4
+	add pc, r1, r2
+
+rr_exit:
+#endif  /* #if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD) */
+
+	bl	_main
+
+/*------------------------------------------------------------------------------*/
+
+/*
+ * void relocate_code(addr_moni)
+ *
+ * This function relocates the monitor code.
+ */
+	.globl	relocate_code
+relocate_code:
+	mov	r6, r0	/* save addr of destination */
+
+	adr	r0, _start
+	subs	r9, r6, r0		/* r9 <- relocation offset */
+	beq	relocate_done		/* skip relocation */
+	mov	r1, r6			/* r1 <- scratch for copy loop */
+	ldr	r3, _image_copy_end_ofs
+	add	r2, r0, r3		/* r2 <- source end address	    */
+
+copy_loop:
+	ldmia	r0!, {r10-r11}		/* copy from source address [r0]    */
+	stmia	r1!, {r10-r11}		/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end address [r2]    */
+	blo	copy_loop
+
+#ifndef CONFIG_SPL_BUILD
+	/*
+	 * fix .rel.dyn relocations
+	 */
+	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
+	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
+	add	r10, r10, r0		/* r10 <- sym table in FLASH */
+	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
+	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
+	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
+	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
+fixloop:
+	ldr	r0, [r2]   /* r0 <- location to fix up, IN FLASH! */
+	add	r0, r0, r9 /* r0 <- location to fix up in RAM */
+	ldr	r1, [r2, #4]
+	and	r7, r1, #0xff
+	cmp	r7, #23			/* relative fixup? */
+	beq	fixrel
+	cmp	r7, #2			/* absolute fixup? */
+	beq	fixabs
+	/* ignore unknown type of fixup */
+	b	fixnext
+fixabs:
+	/* absolute fix: set location to (offset) symbol value */
+	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
+	add	r1, r10, r1		/* r1 <- address of symbol in table */
+	ldr	r1, [r1, #4]		/* r1 <- symbol value */
+	add	r1, r1, r9		/* r1 <- relocated sym addr */
+	b	fixnext
+fixrel:
+	/* relative fix: increase location by offset */
+	ldr	r1, [r0]
+	add	r1, r1, r9
+fixnext:
+	str	r1, [r0]
+	add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */
+	cmp	r2, r3
+	blo	fixloop
+#endif
+
+relocate_done:
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ)
+	/* adjust exception table */
+	adr r0, _undefined_instruction
+	adr r2, _TEXT_BASE
+	ldr r1, [r2]
+adjustex:
+	ldr r3, [r0]
+	sub r3, r3, r1
+	add r3, r6, r3      /* r6 -> relocaddr */
+	str r3, [r0], #4
+	cmp r0, r2
+	blo adjustex
+
+	/* relocate exception table */
+	adr r0, _start
+	ldr	r1, =CONFIG_SYS_SDRAM_BASE
+	adr r2, _TEXT_BASE
+copyex:
+	ldr r3, [r0], #4 /* copy from source address [r0] */
+	str r3, [r1], #4 /* copy to   target address [r1] */
+	cmp	r0, r2       /* until source end addreee [r2] */
+	blo	copyex
+#endif	/* #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ) */
+	bx	lr
+
+#ifndef CONFIG_SPL_BUILD
+
+_rel_dyn_start_ofs:
+	.word __rel_dyn_start - _start
+_rel_dyn_end_ofs:
+	.word __rel_dyn_end - _start
+_dynsym_start_ofs:
+	.word __dynsym_start - _start
+
+#endif
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index d9bbee3..ac59fec 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -23,6 +23,8 @@
  * MA 02111-1307 USA
  */

+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -35,6 +37,15 @@ SECTIONS
 	{
 		__image_copy_start = .;
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}

diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..bd2921c
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,72 @@
+/*
+ * arch/arm/include/asm/arch-a360/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ASM_ARCH_HW_H
+#define ASM_ARCH_HW_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_NAND_FTNANDC020_BASE	0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+#define CONFIG_FTSSP010_GPIO_BASE	0x98700000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..872622c
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,98 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ASM_ARCH_HW_H
+#define ASM_ARCH_HW_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDR_BASE             0x93100000
+#define CONFIG_AHB_BASE             0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+#define CONFIG_FTSSP010_GPIO_BASE   0x92600000    /* GPIO 1 */
+
+/*
+ * NAND
+ */
+#define CONFIG_NAND_FTNANDC021_BASE 0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE1       0x90600000
+#define CONFIG_FTSDC010_BASE0       0x90500000
+#define CONFIG_FTSDC010_BASE        CONFIG_FTSDC010_BASE1
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+
+/*
+ * Ext. AHB
+ */
+#define CONFIG_EXTAHB_BASE          0xC0000000
+#define CONFIG_FTSPI020_BASE        CONFIG_EXTAHB_BASE
+
+#endif
diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
index 440b041..a103922 100644
--- a/arch/arm/include/asm/mach-types.h
+++ b/arch/arm/include/asm/mach-types.h
@@ -144,6 +144,7 @@ extern unsigned int __machine_arch_type;
 #define MACH_TYPE_AKITA                744
 #define MACH_TYPE_E330                 753
 #define MACH_TYPE_NOKIA770             755
+#define MACH_TYPE_FARADAY              758
 #define MACH_TYPE_CARMEVA              769
 #define MACH_TYPE_EDB9315A             772
 #define MACH_TYPE_STARGATE2            774
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..8d229fd
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,67 @@
+/*
+ * board/faraday/a360evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * pinmux
+ */
+static void pinmux_init(void)
+{
+	uint32_t tmp;
+
+	tmp = 0x00555500;
+	writel(cpu_to_le32(tmp), CONFIG_SCU_BASE + 0x24);
+	tmp = le32_to_cpu(readl(CONFIG_SCU_BASE + 0x18)) | 0x800002AA;
+	writel(cpu_to_le32(tmp), CONFIG_SCU_BASE + 0x18);
+	tmp = le32_to_cpu(readl(CONFIG_SCU_BASE + 0x1C)) | 0x82AAAAAA;
+	writel(cpu_to_le32(tmp), CONFIG_SCU_BASE + 0x1C);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	pinmux_init();
+
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	return ftmac110_initialize(bd);
+}
diff --git a/board/faraday/a360evb/clk.c b/board/faraday/a360evb/clk.c
new file mode 100644
index 0000000..a3db7a4
--- /dev/null
+++ b/board/faraday/a360evb/clk.c
@@ -0,0 +1,52 @@
+/*
+ * board/faraday/a360evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+static ulong clk_get_rate_ahb(void)
+{
+	uint32_t reg = le32_to_cpu(readl(CONFIG_PMU_BASE + 0x30));
+	return CONFIG_MAIN_CLK * ((reg >> 3) & 0x3f) / 8;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	uint32_t scu = le32_to_cpu(readl(CONFIG_SCU_BASE + 0x14));
+	uint32_t pmu = le32_to_cpu(readl(CONFIG_PMU_BASE + 0x0C));
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (scu & 0x200) ? 2 : 4;
+	return (pmu & 0x02) ? (clk * mul) : clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a360evb/config.mk b/board/faraday/a360evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a360evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..1ead608
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,33 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..b818071
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,178 @@
+/*
+ * board/faraday/a369evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <faraday/mmc.h>
+#include <faraday/nand.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define SOC_READ(r)			le32_to_cpu(readl(r))
+#define SOC_WRITE(v, r)		writel(cpu_to_le32(v), r)
+#define SOC_SETBITS(m, r)	setbits_le32(r, m)
+#define SOC_CLRBITS(m, r)	clrbits_le32(r, m)
+
+/*
+ * System Control Uint (pinmux)
+ */
+static void scu_init(void)
+{
+	/* If it's external CPU mode */
+	if (SOC_READ(CONFIG_SCU_BASE + 0x204) & BIT_MASK(2)) {
+		SOC_WRITE(0xc0008000, CONFIG_SCU_BASE + 0x028);
+		SOC_SETBITS(BIT_MASK(14), CONFIG_SCU_BASE + 0x200);
+	} else {
+#if CONFIG_SUPP_EXTAHB
+		/* Enable external AHB */
+		SOC_WRITE(0x40000000, CONFIG_SCU_BASE + 0x028);
+		SOC_WRITE(0x00001078, CONFIG_SCU_BASE + 0x200);
+		SOC_CLRBITS(0xf0, CONFIG_SCU_BASE + 0x228);
+		SOC_SETBITS(0x80, CONFIG_SCU_BASE + 0x228);
+#else
+		/* Enable SD1 */
+		SOC_WRITE(0x00000241, CONFIG_SCU_BASE + 0x238);
+#endif
+	}
+
+	/* Clock Setup: SD = 133MHz, SSP = APB (SPI mode) */
+	SOC_WRITE(0x000A0A0A, CONFIG_SCU_BASE + 0x22C);
+
+	/* Enable LCD for I2C/TVEncode work-around */
+	/* ... Clock div = (31+1) */
+	SOC_WRITE(0x1f00, CONFIG_FTLCDC200_BASE + 0x10c);
+	/* ... Enable LCD */
+	SOC_WRITE(0x0003, CONFIG_FTLCDC200_BASE + 0x000);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	/* 1. NOR Flash Setup */
+	/* Bank 0: base=0x00000000, size=64MB, 16bits */
+	SOC_WRITE(BIT_MASK(28) | (6 << 4) | 1, CONFIG_SMC_BASE + 0x00);
+	/* Bank 0: worst timing */
+	SOC_WRITE(0x0f1ff3ff, CONFIG_SMC_BASE + 0x04);
+
+	/* 2. Unused Area */
+	SOC_WRITE(0x00000000, CONFIG_SMC_BASE + 0x08);
+	SOC_WRITE(0x0f1ff3ff, CONFIG_SMC_BASE + 0x0C);
+	SOC_WRITE(0x00000000, CONFIG_SMC_BASE + 0x10);
+	SOC_WRITE(0x0f1ff3ff, CONFIG_SMC_BASE + 0x14);
+	SOC_WRITE(0x00000000, CONFIG_SMC_BASE + 0x18);
+	SOC_WRITE(0x0f1ff3ff, CONFIG_SMC_BASE + 0x1C);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	scu_init();
+	smc_init();
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC010_MCI)
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
+
+int board_nand_init(struct nand_chip *chip)
+{
+	int ret = 0;
+#ifdef CONFIG_NAND_FTNANDC021
+	uint32_t reg = SOC_READ(CONFIG_SCU_BASE + 0x204);
+
+	/* page shift */
+	switch ((reg & 0x180) >> 7) {
+	case 0:
+		chip->page_shift = 9;	/* 512 */
+		break;
+	case 1:
+		chip->page_shift = 11;	/* 2048 */
+		break;
+	case 2:
+	case 3:
+		chip->page_shift = 12;	/* 4096 */
+		break;
+	}
+
+	/* block shift */
+	switch ((reg & 0x600) >> 9) {
+	case 0: /* 16 pages */
+		chip->phys_erase_shift = chip->page_shift + 4;
+		break;
+	case 1: /* 32 pages */
+		chip->phys_erase_shift = chip->page_shift + 5;
+		break;
+	case 2: /* 64 pages */
+		chip->phys_erase_shift = chip->page_shift + 6;
+		break;
+	case 3: /* 128 pages */
+		chip->phys_erase_shift = chip->page_shift + 7;
+		break;
+	}
+
+	/* address cycle */
+	switch ((reg & 0x60) >> 5) {
+	case 0: /* NANDC_AP_3C: */
+		chip->priv = (void *)3;
+		break;
+	case 1: /* NANDC_AP_4C: */
+		chip->priv = (void *)4;
+		break;
+	case 2: /* NANDC_AP_5C: */
+	case 3:
+		chip->priv = (void *)5;
+		break;
+	}
+
+	ret = ftnandc021_probe(chip);
+#endif
+	return ret;
+}
diff --git a/board/faraday/a369evb/clk.c b/board/faraday/a369evb/clk.c
new file mode 100644
index 0000000..1fb73f7
--- /dev/null
+++ b/board/faraday/a369evb/clk.c
@@ -0,0 +1,81 @@
+/*
+ * board/faraday/a369evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+static ulong clk_get_rate_ahb(void)
+{
+	uint32_t reg = 0, mul = 4;
+	ulong ts;
+
+	/* Wait until PLL1 becomes stable or 5 ms timeout */
+	ts = get_timer(0);
+	do {
+		reg = le32_to_cpu(readl(CONFIG_SCU_BASE + 0x20));
+	} while (!(reg & BIT_MASK(1)) && (get_timer(ts) < 5));
+
+	mul = (reg >> 24) & 0x3f;
+
+	return (CONFIG_MAIN_CLK * mul) >> 3;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+#ifndef CONFIG_A369_FA606TE_PLATFORM
+	uint32_t reg;
+
+	/* If it's an internal CPU */
+	reg = le32_to_cpu(readl(CONFIG_SCU_BASE + 0x204));
+	if (!(reg & BIT_MASK(2))) {
+		reg = le32_to_cpu(readl(CONFIG_SCU_BASE + 0x08));
+		switch ((reg >> 3) & 3) {
+		case 0:
+			clk = clk << 0;
+			break;
+		case 1:
+			clk = clk << 1;
+			break;
+		default:
+			clk = clk << 2;
+			break;
+		}
+	}
+#endif
+
+	return clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a369evb/config.mk b/board/faraday/a369evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a369evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..a55fddb
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,136 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+	.macro	_v3_mw32
+
+	ldr r0, =0x1008
+	ldr r3, =0x1108
+_v3_mw32_loop:
+	cmp   r0, r3
+	movhs r1, #0
+	ldrlo r1, [r0, #0]
+	ldrlo r2, [r0, #4]
+	teq   r1, #0
+	strne r2, [r1, #0]
+	addne r0, #8
+	bne   _v3_mw32_loop
+
+	.endm	/* _v3_mw32 */
+
+	.macro	_sdram_enable
+
+	/* Clear SDRAM CKE, GPIO Hold, READ Hold */
+	ldr r0, =CONFIG_SCU_BASE
+	mov r1, #7
+	str r1, [r0, #0x14]
+
+	/* Wait until sdram ready */
+	ldr r0, =CONFIG_DDR_BASE
+_sdram_wait:
+	ldr r1, [r0, #0x04]
+	teq r1, #0x100
+	bne _sdram_wait
+
+	.endm	/* _sdram_enable */
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	/* Check image header */
+	ldr   r1, =0x1000
+	ldr   r0, [r1, #0]
+	ldr   r1, =0x00484946	/* "FIH\0" */
+	ldr   r2, =0x33333639	/* "3369" */
+	teq   r0, r1
+	teqne r0, r2
+	bne _exit
+	_v3_mw32
+	_sdram_enable
+
+#if 1
+	/* Create a shadow copy onto SDRAM (limited to 512K) */
+	mov	r0, #0               /* r0 <- start of source */
+	ldr	r1, =CONFIG_AHB_BASE
+	ldr r2, [r1,#0x18]
+	bic r1, r2, #0x000f0000  /* r1 <- SDRAM base */
+	mov	r2, #0x80000         /* r2 <- source end address (512KB) */
+
+_copy_loop:
+	ldmia	r0!, {r3-r10} /* copy from source address [r0] */
+	stmia	r1!, {r3-r10} /* copy to   target address [r1] */
+	cmp	r0, r2            /* until source end addreee [r2] */
+	ble	_copy_loop
+#else
+	/* Adjust lr(r14) to the remapped address */
+	ldr r0, =CONFIG_AHB_BASE
+	ldr r1, [r0,#0x18]    /* r1 = AHB slave 6 */
+	bic r1, r1, #0xff000000
+	bic r1, r1, #0x00f00000
+	lsr r1, r1, #16
+	add r1, r1, #20
+	mov r2, #1
+	lsl r2, r2, r1
+	add lr, lr, r2
+#endif
+
+	/* AHB remap */
+	mov r0, #0
+	ldr r1, =CONFIG_AHB_BASE
+	ldr r2, =CONFIG_DDR_BASE
+	/* magic (r5) = REG32(0x00) XOR 0xFFFFFFFF */
+	ldr r5, [r0, #0]
+	ldr r3, =0xffffffff
+	eor r5, r5, r3
+	/* r3 = REG32(CONFIG_IOBASE_DDR + 0x10) & 0x00FFFFFF */
+	ldr r3, [r2, #0x10]
+	bic r3, #0xff000000
+	/* r4 = 0x00100f01 */
+	ldr r4, =0x00100f01
+
+	/*
+	 * invalidate i-cache all to make sure the codes bellow
+	 * to be fetched into a single 32-bytes cache line
+	 */
+	mcr p15, 0, r0, c7, c5, 0
+
+	.align 5
+
+	str r3, [r2, #0x10] /* REG32(CONFIG_IOBASE_DDR + 0x10) &= 0x00FFFFFF */
+	str r4, [r1, #0x88] /* REG32(CONFIG_IOBASE_AHB + 0x88)  = 0x00100F01 */
+
+_remap_wait:
+	str r5, [r0, #0]
+	ldr r1, [r0, #0]
+	teq r1, r5
+	bne _remap_wait		/* while(magic != REG32(addr)) */
+
+_exit:
+	mov	pc, lr
diff --git a/boards.cfg b/boards.cfg
index f785da8..e2de722 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -73,6 +73,9 @@ mini2440                     arm         arm920t     mini2440            friendl
 VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
 smdk2410                     arm         arm920t     -                   samsung        s3c24x0
 omap1510inn                  arm         arm925t     -                   ti
+a360                         arm         faraday     a360evb             faraday        a360
+a369                         arm         faraday     a369evb             faraday        a369
+a369_fa606te                 arm         faraday     a369evb             faraday        a369
 integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap:CM926EJ_S
 integratorcp_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorcp:CM924EJ_S
 aspenite                     arm         arm926ejs   -                   Marvell        armada100
diff --git a/include/common.h b/include/common.h
index 0cfa6a8..fa134f3 100644
--- a/include/common.h
+++ b/include/common.h
@@ -112,6 +112,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_FARADAY
+#include <asm/arch/hardware.h>
+#endif

 #include <part.h>
 #include <flash.h>
@@ -257,6 +260,16 @@ typedef void (interrupt_handler_t)(void *);
 	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
 	(type *)( (char *)__mptr - offsetof(type,member) );})

+#ifdef CONFIG_FARADAY
+/* board/faraday/xxx/clk.c */
+extern ulong clk_get_rate(char *id);
+
+/* arch/arm/cpu/faraday/xxx/interrupt.c */
+extern void irq_set_trigger(int irq, int edge, int low);
+extern void irq_enable(int irq);
+extern void irq_disable(int irq);
+#endif
+
 /*
  * Function Prototypes
  */
diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..19a116e
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,185 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/*
+ * Hardware Resources (i.e. iobase, irq)
+ */
+#include <asm/arch/hardware.h>
+
+#define CONFIG_A360_PLATFORM        1
+#define CONFIG_SYS_NO_FLASH         1
+/* #define CONFIG_USE_IRQ           1 */
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+/* #define CONFIG_BOARD_EARLY_INIT_F   1 */
+#define CONFIG_BOARD_LATE_INIT      1
+
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_256M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_4M
+
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+/*
+ * CPU
+ */
+#define CONFIG_ARCH_CPU_INIT        1
+#define CONFIG_DISPLAY_CPUINFO      1
+#define CONFIG_FARADAY              1
+#define CONFIG_SYS_CACHELINE_SIZE   32
+
+/*
+ * Interrupt
+ */
+#if CONFIG_USE_IRQ
+#define CONFIG_FTINTC020            1
+#define CONFIG_PIC_BASE             CONFIG_FTINTC020_BASE
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010             1
+#define CONFIG_TIMER_BASE           CONFIG_FTTMR010_BASE
+#define CONFIG_TIMER_IRQ            CONFIG_FTTMR010_IRQ
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010             1
+
+/*
+ * Clock
+ */
+#define CONFIG_MAIN_CLK             40000000
+#define CONFIG_SYS_HZ               1000
+#define	CONFIG_SYS_MONITOR_LEN      SZ_256K
+
+/*
+ * U-Boot general commands
+ */
+#define CONFIG_CMD_AUTOSCRIPT       1 /* Autoscript Support */
+#define CONFIG_CMD_BDI              1 /* bdinfo */
+#define CONFIG_CMD_BOOTD            1 /* bootd */
+#define CONFIG_CMD_ECHO             1 /* echo arguments */
+#define CONFIG_CMD_ENV              1 /* saveenv */
+#define CONFIG_CMD_IMI              1 /* iminfo */
+#define CONFIG_CMD_MEMORY           1 /* md mm nm mw ... */
+#define CONFIG_CMD_NET              1 /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN              1 /* run command in env variable */
+#define CONFIG_CMD_CACHE            1 /* cache enable/disable command */
+#define CONFIG_CMD_ELF              1
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_CMDLINE_TAG          1 /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS    1
+#define CONFIG_INITRD_TAG           1
+
+/*
+ * Serial Info
+ */
+#define CONFIG_SYS_NS16550          1
+#define CONFIG_SYS_NS16550_SERIAL   1
+#define CONFIG_SYS_NS16550_CLK      18432000
+#define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+#define CONFIG_SYS_NS16550_MEM32    1
+#define CONFIG_SYS_NS16550_REG_SIZE -4
+#define CONFIG_CONS_INDEX           1
+#define CONFIG_BAUDRATE             38400
+#undef  CONFIG_HWFLOW
+#undef  CONFIG_MODEM_SUPPORT
+
+/*
+ * NIC driver
+ */
+#define CONFIG_FTMAC110        1
+#define CONFIG_ETHADDR         00:84:14:72:61:69 /* used by env_common.c */
+#define CONFIG_NETMASK         255.255.255.0
+#define CONFIG_IPADDR          10.0.0.123
+#define CONFIG_SERVERIP        10.0.0.128
+#define CONFIG_MII             1
+#define CONFIG_NET_MULTI       1
+#define CONFIG_NET_RETRY_COUNT 20
+#define CONFIG_DRIVER_ETHER    1
+#define CONFIG_CMD_MII         1
+#define CONFIG_CMD_PING        1
+
+/*
+ * Shell
+ */
+#define	CONFIG_SYS_HUSH_PARSER     1
+#define	CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+#define CONFIG_SYS_PROMPT          "=> "
+#define CONFIG_AUTO_COMPLETE       1
+#define CONFIG_CMDLINE_EDITING     1
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_NOWHERE      1
+#define CONFIG_ENV_OFFSET          0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND   0x07FE0000
+#define CONFIG_ENV_SIZE            0x00020000
+
+/*
+ * System
+ */
+#define CONFIG_SYS_LOAD_ADDR      0x01000000 /* default load address */
+#define CONFIG_SYS_BAUDRATE_TABLE { 115200, 57600, 38400, 19200, 9600 }
+#define CONFIG_SYS_CBSIZE         256 /* Console I/O Buffer Size */
+/* max number of command args */
+#define CONFIG_SYS_MAXARGS        32
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_LZMA               1
+#define CONFIG_TIMESTAMP          1
+#define CONFIG_SYS_LONGHELP       1
+#define CONFIG_VERSION_VARIABLE   1 /* include version env variable */
+
+/*
+ * FAT (USB & MMC)
+ */
+#define CONFIG_DOS_PARTITION      1
+#define CONFIG_CMD_FAT            1
+#define CONFIG_PARTITIONS         1
+
+/*
+ * USB
+ */
+#define CONFIG_USB_EHCI_FUSBH200           1
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+#define CONFIG_USB_EHCI                    1
+#define CONFIG_USB_EHCI_FARADAY            1
+#define CONFIG_EHCI_IS_TDI                 1
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+#define CONFIG_EHCI_DCACHE                 1
+#endif
+#define CONFIG_CMD_USB                     1
+#define CONFIG_USB_STORAGE                 1
+
+#endif
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..b884b9c
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,41 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_PLATFORM        1
+
+/* Support external AHB */
+/*
+#define CONFIG_SUPP_EXTAHB          1
+*/
+
+/* Support USB RNDIS Ethernet */
+/*
+#define CONFIG_SUPP_USB_RNDIS       1
+*/
+
+/* Disable NOR flash support */
+#define CONFIG_SYS_NO_FLASH         1
+
+/* Support interrupt */
+/*
+#define CONFIG_USE_IRQ              1
+*/
+
+/* Disable MMU/D-CACHE */
+/*
+#define CONFIG_SYS_DCACHE_OFF       1
+*/
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+#define CONFIG_SYS_ARM_CACHE_WRITETHROUGH 1
+#endif
+
+/* Transfer the control to the built-in slave cpu: FA606TE */
+#define CONFIG_CMD_FA606            1
+
+/* Hardware Resources (i.e. iobase, irq) */
+#include <asm/arch/hardware.h>
+
+#include "a369_defaults.h"
+
+#endif
diff --git a/include/configs/a369_defaults.h b/include/configs/a369_defaults.h
new file mode 100644
index 0000000..24219da
--- /dev/null
+++ b/include/configs/a369_defaults.h
@@ -0,0 +1,295 @@
+#ifndef __CONFIG_A369_DEFAULTS_H
+#define __CONFIG_A369_DEFAULTS_H
+
+/*
+ * Autoboot
+ */
+#define CONFIG_BOOTDELAY            3
+#define CONFIG_BOOTCOMMAND          "bootfa nand linux"
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+/* #define CONFIG_BOARD_EARLY_INIT_F   1 */
+#define CONFIG_BOARD_LATE_INIT      1
+
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_512M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_8M
+
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+/*
+ * CPU
+ */
+#define CONFIG_ARCH_CPU_INIT        1
+#define CONFIG_DISPLAY_CPUINFO      1
+#define CONFIG_FARADAY              1
+#define CONFIG_SYS_CACHELINE_SIZE	32
+
+/*
+ * Interrupt
+ */
+#if CONFIG_USE_IRQ
+# define CONFIG_FTINTC020           1
+# ifdef CONFIG_A369_PLATFORM
+#  define CONFIG_PIC_BASE           CONFIG_FTINTC020_BASE
+# else
+#  define CONFIG_PIC_BASE           CONFIG_FTINTC020_BASE1
+# endif
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010          1
+#define CONFIG_TIMER_BASE           CONFIG_FTPWMTMR010_BASE
+#define CONFIG_TIMER_IRQ            CONFIG_FTPWMTMR010_IRQ
+
+/*
+ * Clock
+ */
+#define CONFIG_MAIN_CLK             33000000
+#define CONFIG_SYS_HZ               1000
+#define CONFIG_SYS_MONITOR_LEN      SZ_256K
+
+/*
+ * U-Boot general commands
+ */
+#define CONFIG_CMD_AUTOSCRIPT       1 /* Autoscript Support */
+#define CONFIG_CMD_BDI              1 /* bdinfo */
+#define CONFIG_CMD_BOOTD            1 /* bootd */
+#define CONFIG_CMD_ECHO             1 /* echo arguments */
+#define CONFIG_CMD_ENV              1 /* saveenv */
+#define CONFIG_CMD_IMI              1 /* iminfo */
+#define CONFIG_CMD_MEMORY           1 /* md mm nm mw ... */
+#define CONFIG_CMD_NET              1 /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN              1 /* run command in env variable */
+#define CONFIG_CMD_CACHE            1 /* cache enable/disable command */
+#define CONFIG_CMD_ELF              1
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_CMDLINE_TAG          1 /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS    1
+#define CONFIG_INITRD_TAG           1
+
+/*
+ * Serial Info
+ */
+#define CONFIG_SYS_NS16550          1
+#define CONFIG_SYS_NS16550_SERIAL   1
+#define CONFIG_SYS_NS16550_CLK      18432000
+#define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+#define CONFIG_SYS_NS16550_MEM32    1
+#define CONFIG_SYS_NS16550_REG_SIZE -4
+#define CONFIG_CONS_INDEX           1
+#define CONFIG_BAUDRATE             38400
+#undef  CONFIG_HWFLOW
+#undef  CONFIG_MODEM_SUPPORT
+
+/*
+ * NIC driver
+ */
+#define CONFIG_FTGMAC100       1
+#define CONFIG_PHY_MAX_ADDR    32 /* used by Ratbert's ftgmac100 only */
+#define CONFIG_FTGMAC100_EGIGA 1  /* used by Ratbert's ftgmac100 only */
+#define CONFIG_ETHADDR         00:84:14:72:61:69 /* used by env_common.c */
+#define CONFIG_NETMASK         255.255.255.0
+#define CONFIG_IPADDR          10.0.0.123
+#define CONFIG_SERVERIP        10.0.0.128
+#define CONFIG_MII             1
+#define CONFIG_NET_MULTI       1
+#define CONFIG_NET_RETRY_COUNT 20
+#define CONFIG_DRIVER_ETHER    1
+#define CONFIG_CMD_MII         1
+#define CONFIG_CMD_PING        1
+
+/*
+ * I2C Controller
+ */
+#define CONFIG_FTI2C010             1
+#define CONFIG_HARD_I2C             1
+#define CONFIG_SYS_I2C_SPEED        5000
+#define CONFIG_SYS_I2C_SLAVE        0
+#define CONFIG_CMD_I2C              1
+#define CONFIG_I2C_CMD_TREE         1
+#define CONFIG_I2C_MULTI_BUS        1
+#define CONFIG_SYS_MAX_I2C_BUS      2
+
+/*
+ * EEPROM
+ */
+#define CONFIG_CMD_EEPROM                       1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS       3
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS   5
+#define CONFIG_SYS_I2C_MULTI_EEPROMS            1
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN          1
+#define CONFIG_ENV_EEPROM_IS_ON_I2C             1
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_SPI         1
+#define CONFIG_FTSSP010_GPIO_PIN    27
+#define CONFIG_SPI                  1
+#define CONFIG_HARD_SPI             1
+#define CONFIG_CMD_SPI              1
+#define CONFIG_ENV_SPI_BUS          0
+#define CONFIG_ENV_SPI_CS           0
+#define CONFIG_ENV_SPI_MAX_HZ       25000000
+#define CONFIG_DEFAULT_SPI_MODE     0
+
+/*
+ * SPI Flash
+ */
+#define CONFIG_FTSSP010_SPI         1
+/*
+#define CONFIG_FTSPI020             1
+*/
+#ifndef CONFIG_FTSPI020
+#define CONFIG_SPI_FLASH            1
+#define CONFIG_SPI_FLASH_MACRONIX   1
+#define CONFIG_SPI_FLASH_WINBOND    1
+#endif /* #ifndef CONFIG_FTSPI020 */
+#define CONFIG_CMD_SF               1
+#define CONFIG_SF_DEFAULT_MODE      SPI_MODE_0
+#define CONFIG_SF_DEFAULT_SPEED     25000000
+
+/*
+ * NOR Flash
+ */
+#ifndef CONFIG_SYS_NO_FLASH
+#define CONFIG_SYS_FLASH_CFI_WIDTH FLASH_CFI_16BIT
+#define CONFIG_SYS_FLASH_BASE      0x20000000
+#define PHYS_FLASH_SIZE            SZ_64M
+#define CONFIG_SYS_FLASH_CFI       1
+#define CONFIG_FLASH_CFI_DRIVER    1
+#define CONFIG_SYS_MAX_FLASH_BANKS 1
+#define CONFIG_SYS_MAX_FLASH_SECT  1024 /* max. sector number */
+#define CFG_FLASH_EMPTY_INFO       1 /* print 'E' for empty sector on flinfo */
+#define CONFIG_CMD_IMLS            1
+#define CONFIG_CMD_FLASH           1
+#endif    /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * NAND Flash
+ */
+#define CONFIG_NAND_FTNANDC021       1
+#define CONFIG_FTNANDC021_ACTIMING_1 0x02240264
+#define CONFIG_FTNANDC021_ACTIMING_2 0x42054209
+#define CONFIG_CMD_NAND              1
+#define CONFIG_SYS_MAX_NAND_DEVICE   1 /* Max number of NAND devices */
+#define CONFIG_SYS_NAND_BASE         CONFIG_NAND_FTNANDC021_BASE
+#define CONFIG_SYS_NAND_BASE_LIST    { CONFIG_NAND_FTNANDC021_BASE }
+#define CONFIG_MTD_NAND_VERIFY_WRITE 1
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER     1
+#define CONFIG_SYS_PROMPT_HUSH_PS2 "> "
+#define CONFIG_SYS_PROMPT          "=> "
+#define CONFIG_AUTO_COMPLETE       1
+#define CONFIG_CMDLINE_EDITING     1
+
+/*
+ * Environment
+ */
+#define CONFIG_CMD_SAVEENV       1
+#define CONFIG_ENV_IS_IN_NAND    1
+#define CONFIG_ENV_OFFSET        0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND 0x07FE0000
+#define CONFIG_ENV_SIZE          0x00020000
+
+/*
+ * System
+ */
+#define CONFIG_SYS_LOAD_ADDR      0x01000000  /* default load address */
+#define CONFIG_SYS_BAUDRATE_TABLE { 115200, 57600, 38400, 19200, 9600 }
+#define CONFIG_SYS_CBSIZE         256 /* Console I/O Buffer Size */
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS        32
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_LZMA               1
+#define CONFIG_TIMESTAMP          1
+#define CONFIG_SYS_LONGHELP       1
+#define CONFIG_VERSION_VARIABLE   1 /* include version env variable */
+
+/*
+ * FAT (USB & MMC)
+ */
+#define CONFIG_DOS_PARTITION 1
+#define CONFIG_CMD_FAT       1
+#define CONFIG_PARTITIONS    1
+
+/*
+ * MMC  (FTSDC010)
+ */
+#if 1
+#define CONFIG_FTSDC010_MCI    1
+#define CONFIG_FTSDC010_SDIO   1 /* The hardware core supports SDIO */
+#else
+#define CONFIG_FTSDC010        1
+#define CONFIG_FTSDC010_SDIO   1 /* The hardware core supports SDIO */
+#define CONFIG_FTSDC010_NUMBER 1
+#define CONFIG_SYS_CLK_FREQ    133000000 /* AHB clock */
+#endif
+#define CONFIG_MMC             1
+#define CONFIG_CMD_MMC         1
+#define CONFIG_GENERIC_MMC     1
+
+/*
+ * USB EHCI Host
+ */
+#define CONFIG_USB_EHCI_BASE               CONFIG_FUSBH200_BASE
+#if CONFIG_SUPP_USB_RNDIS
+#define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+#define CONFIG_USB_EHCI_BASE1              CONFIG_FOTG210_BASE
+#define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+#endif
+#define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+#define CONFIG_USB_EHCI                    1
+#define CONFIG_USB_EHCI_FARADAY            1
+#define CONFIG_EHCI_IS_TDI                 1
+#define CONFIG_CMD_USB                     1
+#define CONFIG_USB_STORAGE                 1
+
+/*
+ * USB Gadget
+ */
+#if CONFIG_SUPP_USB_RNDIS
+#define CONFIG_USB_GADGET           1
+#define CONFIG_USB_GADGET_FOTG210   1
+#define CONFIG_USB_GADGET_DUALSPEED 1
+#define CONFIG_USB_ETHER            1
+#define CONFIG_USB_ETH_RNDIS        1
+#define CONFIG_USBNET_DEV_ADDR      "00:41:71:00:00:55" /* U-Boot */
+#define CONFIG_USBNET_HOST_ADDR     "00:41:71:00:00:54" /* Host PC */
+#endif
+
+#endif
diff --git a/include/configs/a369_fa606te.h b/include/configs/a369_fa606te.h
new file mode 100644
index 0000000..8c90fd8
--- /dev/null
+++ b/include/configs/a369_fa606te.h
@@ -0,0 +1,32 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_FA606TE_PLATFORM 1
+
+/* Support external AHB */
+/*
+#define CONFIG_SUPP_EXTAHB           1
+*/
+
+/* Support USB RNDIS Ethernet */
+/*
+#define CONFIG_SUPP_USB_RNDIS        1
+*/
+
+/* Disable NOR flash support */
+#define CONFIG_SYS_NO_FLASH          1
+
+/* Support interrupt */
+/*
+#define CONFIG_USE_IRQ               1
+*/
+
+/* Disable CPU MMU support */
+#define CONFIG_SYS_DCACHE_OFF        1    /* Disable MMU/D-CACHE */
+
+/* Hardware Resources (i.e. iobase, irq) */
+#include <asm/arch/hardware.h>
+
+#include "a369_defaults.h"
+
+#endif
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 72abcb3..ef10f31 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -57,6 +57,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -70,4 +80,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support
  2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                       ` (11 preceding siblings ...)
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 12/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-04-18 10:43     ` Wolfgang Denk
  2013-04-22  1:27       ` Kuo-Jung Su
  12 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 10:43 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-1-git-send-email-dantesu@gmail.com> you wrote:
> 
> These patches introduce Faraday A36x SoC platform support.

Please run all your patches through checkpatch and clean up thew
reported warnings and errors before you resubmit.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"The algorithm to do that is extremely nasty. You might want  to  mug
someone with it."                   - M. Devine, Computer Science 340

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

* [U-Boot] [PATCH v2 03/12] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 03/12] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
@ 2013-04-18 10:52       ` Wolfgang Denk
  2013-04-22  2:56         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 10:52 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-4-git-send-email-dantesu@gmail.com> you wrote:
> 
> +/*******************************************************************/
> +/*               FTMAC110 DMA design issue                         */
> +/*                                             Dante Su 2010.02.03 */
> +/*                                                                 */
> +/* The DMA engine has a weird restriction that its Rx DMA engine   */
> +/* accepts only 16-bits aligned address, 32-bits aligned is not    */
> +/* acceptable. However this restriction does not apply to Tx DMA.  */
> +/* Conclusion:                                                     */
> +/* (1) Tx DMA Buffer Address:                                      */
> +/*     1 bytes aligned: Invalid                                    */
> +/*     2 bytes aligned: O.K                                        */
> +/*     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)       */
> +/* (2) Rx DMA Buffer Address:                                      */
> +/*     1 bytes aligned: Invalid                                    */
> +/*     2 bytes aligned: O.K                                        */
> +/*     4 bytes aligned: Invalid                                    */
> +/*******************************************************************/

Incorrect multi-line comment style. Please fix globally.

> +/* Register access macros */
> +#define MAC_READ(r)			le32_to_cpu(readl(r))
> +#define MAC_WRITE(v, r)		writel(cpu_to_le32(v), r)

Please drop these and use the real functions instead.

> +static char ftmac110_mac_addr[] = { 0x00, 0x41, 0x71, 0x00, 0x00, 0x52 };

NAK.  We do not allow static configuration of MAC addresses.

> +	ulong ts;
> +	uint32_t maccr;
> +	uint16_t pa, tmp;

Are you sure using  uint16_t  gives more efficient code than a plain
int?

> +	if (pa >= 32) {
> +		puts("ftmac110: phy device not found!\n");

make this a debug() ?

...
> +	MAC_WRITE(0x00001010, &regs->itc);
> +	MAC_WRITE(0x00000001, &regs->aptc);
> +	MAC_WRITE(0x00000390, &regs->dblac);
> +	MAC_WRITE(0x000003FF, &regs->isr);

What do these magic numbers mean?


> +struct ftmac110_rxd {
> +	/* RXDES0 */
> +#ifdef __ARMEB__
> +	uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
> +	uint32_t rsvd3:1;
> +	uint32_t frs:1;
> +	uint32_t lrs:1;
> +	uint32_t rsvd2:5;
> +	uint32_t error:5;
> +	uint32_t bcast:1;
> +	uint32_t mcast:1;
> +	uint32_t rsvd1:5;
> +	uint32_t len:11;
> +#else
> +	uint32_t len:11;
> +	uint32_t rsvd1:5;
> +	uint32_t mcast:1;
> +	uint32_t bcast:1;
> +	uint32_t error:5;
> +	uint32_t rsvd2:5;
> +	uint32_t lrs:1;
> +	uint32_t frs:1;
> +	uint32_t rsvd3:1;
> +	uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
> +#endif

NAK.  Please do NOT use bit fields.  They are non-portable and
dangerous.


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
A year spent in artificial intelligence is enough to make one believe
in God.

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

* [U-Boot] [PATCH v2 04/12] i2c: add Faraday FTI2C010 I2C controller support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 04/12] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
@ 2013-04-18 10:54       ` Wolfgang Denk
  2013-04-22  2:52         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 10:54 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-5-git-send-email-dantesu@gmail.com> you wrote:
...
> +#define I2C_READ(r)		le32_to_cpu(readl(r))
> +#define I2C_WRITE(v, r)	writel(cpu_to_le32(v), r)

Please drop these macros and use the real functions instead.


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Little known fact about Middle Earth:   The Hobbits had a very sophi-
sticated computer network!   It was a Tolkien Ring...

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
@ 2013-04-18 10:56       ` Wolfgang Denk
  2013-04-22  2:52         ` Kuo-Jung Su
  2013-08-08 13:38       ` Jagan Teki
  1 sibling, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 10:56 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-6-git-send-email-dantesu@gmail.com> you wrote:
...
> +/* Register access macros */
> +#define SPI_READ(r)			le32_to_cpu(readl(r))
> +#define SPI_WRITE(v, r)		writel(cpu_to_le32(v), r)
> +#define SPI_SETBITS(m, r)	setbits_le32(r, m)
> +#define SPI_CLRBITS(m, r)	clrbits_le32(r, m)

Ad before: drop these.

> +#ifdef CONFIG_FTSSP010_GPIO_BASE
> +#define SPI_GPIO_READ(p, r)	\
> +	le32_to_cpu(readl((p)->gpio.iobase + (r)))
> +#define SPI_GPIO_WRITE(p, v, r)	\
> +	writel(cpu_to_le32(v), (p)->gpio.iobase + (r))
> +#define SPI_GPIO_SETBITS(p, m, r)	\
> +	setbits_le32((p)->gpio.iobase + (r), m)
> +#define SPI_GPIO_CLRBITS(p, m, r)	\
> +	clrbits_le32((p)->gpio.iobase + (r), m)
> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */

We do not allos I/O accesses throug base addrss plus offset.
Please use proper C structs instead.


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Sorry, but my karma just ran over your dogma.

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

* [U-Boot] [PATCH v2 06/12] mmc: add an alternative driver to Faraday FTSDC010
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 06/12] mmc: add an alternative driver to Faraday FTSDC010 Kuo-Jung Su
@ 2013-04-18 10:57       ` Wolfgang Denk
  2013-04-22  2:51         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 10:57 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-7-git-send-email-dantesu@gmail.com> you wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTSDC010 is a MMC/SD host controller.
> Although there is already a driver in current u-boot release,
> which is modified from eSHDC and contributed by Andes Tech.
> Its performance is too terrible on Faraday A36x SoC platforms,
> so I turn to implement this new version of driver which is
> 10+ times faster than the old one.
> 
> If the hardware platform is avaiable, you may modify the
> 'include/configs/a369_defaults.h' for performance evaluation.

NAK.  Instead of adding another driver, please fix the problems of the
original one, or replace the old one with your new, better one.  We do
not want to have several drivers for the same piece of hardware.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"The greatest warriors are the ones who fight for peace."
- Holly Near

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
@ 2013-04-18 11:04       ` Wolfgang Denk
  2013-04-22  1:52         ` Kuo-Jung Su
  2013-04-18 19:44       ` Scott Wood
  1 sibling, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 11:04 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-8-git-send-email-dantesu@gmail.com> you wrote:
...
> +/* Register access macros */
> +#define NAND_READ(r)		le32_to_cpu(readl(r))
> +#define NAND_WRITE(v, r)	writel(cpu_to_le32(v), r)
> +#define NAND_SETBITS(m, r)	setbits_le32(r, m)
> +#define NAND_CLRBITS(m, r)	clrbits_le32(r, m)

As before: drop these.

> +	/* wait until chip ready */
> +	while (NAND_READ(&regs->srr) & SRR_CHIP_RESET)
> +		;

Please add a timeout (and fix similar locations in the rest of the
code if there are such).

> +	switch (priv->bksz / priv->pgsz) {
> +	case 16:
> +		bk = 0;
> +		break;
> +	case 32:
> +		bk = 1;
> +		break;
> +	case 64:
> +		bk = 2;
> +		break;
> +	case 128:
> +		bk = 3;
> +		break;
> +	}

	bk = ffs(priv->bksz / priv->pgsz) - 4;

?

> +	switch (priv->adrc) {
> +	case 3:
> +		ac = 0;
> +		break;
> +	case 4:
> +		ac = 1;
> +		break;
> +	case 5:
> +		ac = 2;
> +		break;
> +	}

	ac = priv->adrc - 3;

?


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"You're just jealous." "What, of an overgrown puppy  with  a  single-
figure IQ?"                      - Terry Pratchett, _Moving Pictures_

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

* [U-Boot] [PATCH v2 08/12] mtd: spi: add FTSPI020 SPI Flash controller support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 08/12] mtd: spi: add FTSPI020 SPI Flash " Kuo-Jung Su
@ 2013-04-18 11:08       ` Wolfgang Denk
  2013-04-22  1:51         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 11:08 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-9-git-send-email-dantesu@gmail.com> you wrote:
...
> +/* Register access macros */
> +#define SPI_READ(r)			le32_to_cpu(readl(r))
> +#define SPI_WRITE(v, r)		writel(cpu_to_le32(v), r)
> +#define SPI_SETBITS(m, r)	setbits_le32(r, m)
> +#define SPI_CLRBITS(m, r)	clrbits_le32(r, m)

see before...

> +	struct spi_flash_info *fl = (struct spi_flash_info *)flash;
> +	return fl->chip;

Please always insert a blank line between declarations and code.

> +static const struct spi_flash_param sf_list[] = {
> +
> +	/* Atmel -- some are (confusingly) marketed as "DataFlash" */
> +	{ "at25fs010",  0x1f6601, 0, 32 * 1024,   4 },
> +	{ "at25fs040",  0x1f6604, 0, 64 * 1024,   8 },
> +
> +	{ "at25df041a", 0x1f4401, 0, 64 * 1024,   8 },
> +	{ "at25df321a", 0x1f4701, 0, 64 * 1024,  64 },
> +	{ "at25df641",  0x1f4800, 0, 64 * 1024, 128 },
...

should we not rather move this into a separate, global header file?

> +	for (i = 0; i < ARRAY_SIZE(id32); ++i) {
> +		/* wait until rx ready */
> +		while (!(SPI_READ(&regs->sr) & SR_RFR))
> +			;

See previous note about timeouts.  Please fix globally.

> +	/* wait until command finish */
> +	while (!(SPI_READ(&regs->isr) & ISR_CMD))
> +		;

Ditto. etc. etc.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
"Ja, mach' nur einen Plan,    sei nur ein grosses Licht
und mach' dann noch 'nen zweiten Plan,    geh'n tun sie beide nicht."
                                     -- Bert Brecht, Dreigroschenoper

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

* [U-Boot] [PATCH v2 09/12] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 09/12] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-04-18 11:09       ` Wolfgang Denk
  2013-04-22  1:45         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 11:09 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-10-git-send-email-dantesu@gmail.com> you wrote:
...
> +#define HCD_READ(r)			le32_to_cpu(readl(r))
> +#define HCD_WRITE(v, r)		writel(cpu_to_le32(v), r)
> +#define HCD_SETBITS(m, r)	setbits_le32(r, m)
> +#define HCD_CLRBITS(m, r)	clrbits_le32(r, m)

As before...


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
I'm a programmer: I don't buy software, I write it.
                                                  -- Tom Christiansen

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

* [U-Boot] [PATCH v2 10/12] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 10/12] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
@ 2013-04-18 11:11       ` Wolfgang Denk
  2013-04-22  1:45         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 11:11 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-11-git-send-email-dantesu@gmail.com> you wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> The Faraday FOTG210 is an OTG chip which could operate
> as either an EHCI Host or a USB Device as a time.
...
> +	uint32_t maxpacket:16;
> +	uint32_t id:4;
> +	uint32_t stopped:1;
> +	uint32_t rsvd:11;

Please do NOT use bit fields.  Fix globally.

> +#define USB_READ(r)			le32_to_cpu(readl(r))
> +#define USB_WRITE(v, r)		writel(cpu_to_le32(v), r)
> +#define USB_SETBITS(m, r)	setbits_le32(r, m)
> +#define USB_CLRBITS(m, r)	clrbits_le32(r, m)

As before...


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
e-credibility: the non-guaranteeable likelihood that  the  electronic
data you're seeing is genuine rather than somebody's made-up crap.
- Karl Lehenbauer

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

* [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
@ 2013-04-18 11:13       ` Wolfgang Denk
  2013-04-22  1:23         ` Kuo-Jung Su
  2013-04-18 19:09       ` Albert ARIBAUD
  1 sibling, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 11:13 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-12-git-send-email-dantesu@gmail.com> you wrote:
...
> --- a/common/cmd_boot.c
> +++ b/common/cmd_boot.c
> @@ -50,6 +50,10 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> 
>  	printf ("## Starting application at 0x%08lX ...\n", addr);
> 
> +#if defined(__ARM__) && !defined(CONFIG_SYS_DCACHE_OFF)
> +	cleanup_before_linux();
> +#endif
> +
>  	/*
>  	 * pass address parameter as argv[0] (aka command name),
>  	 * and all remaining args

Thios affects global code. Please submit as separate patch.

And why exactly is this ARM specific?

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
My play was a complete success.  The audience was a failure.

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

* [U-Boot] [PATCH v2 12/12] arm: add Faraday A36x SoC platform support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 12/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-04-18 11:16       ` Wolfgang Denk
  2013-04-22  1:30         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2013-04-18 11:16 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1366277139-29728-13-git-send-email-dantesu@gmail.com> you wrote:
...
> +#define CONFIG_FTMAC110        1
> +#define CONFIG_ETHADDR         00:84:14:72:61:69 /* used by env_common.c */
> +#define CONFIG_NETMASK         255.255.255.0
> +#define CONFIG_IPADDR          10.0.0.123
> +#define CONFIG_SERVERIP        10.0.0.128

NAK.  We don't allow static global network configurations like that.


> +#define CONFIG_FTGMAC100       1
> +#define CONFIG_PHY_MAX_ADDR    32 /* used by Ratbert's ftgmac100 only */
> +#define CONFIG_FTGMAC100_EGIGA 1  /* used by Ratbert's ftgmac100 only */
> +#define CONFIG_ETHADDR         00:84:14:72:61:69 /* used by env_common.c */
> +#define CONFIG_NETMASK         255.255.255.0
> +#define CONFIG_IPADDR          10.0.0.123
> +#define CONFIG_SERVERIP        10.0.0.128

NAK again.

Hm... this looks like a LOT of repeated code.  Can you please factor
out the common parts into a separate file?


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
Vulcans worship peace above all.
	-- McCoy, "Return to Tomorrow", stardate 4768.3

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

* [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
  2013-04-18 11:13       ` Wolfgang Denk
@ 2013-04-18 19:09       ` Albert ARIBAUD
  2013-04-22  1:27         ` Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-04-18 19:09 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Thu, 18 Apr 2013 17:25:38 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch would enable MMU for Faraday ARMv5TE cores.
> 
> Here is the abstract of this MMU design.
> 
> Assume SDRAM memory region starts at 0x10000000, and its size = 0x800000.
> 
> 0x00000000 +-------------------+
>            |                   |
>            |     UN-CACHED     |
>            |                   |
>            |                   |
> 0x10000000 +-------------------+
>            |  CACHED (SDRAM)   | <- It's where data/bss/stack lived.
>            |                   |
>            |                   |
> 0x10800000 +-------------------+
>            |                   |
>            |                   |
>            |     UN-CACHED     |
>            |                   |
>            |                   |
> 0xFF800000 +-------------------+
>            | UN-CACHED (SDRAM) | <- An un-cached shadow of the SDRAM.
>            |                   |    dma_alloc_coherent() always returns
>            |                   |    an address in this region.
> 0xFFFFFFFF +-------------------+

The ASCII map is great for explaining, but I find it a bit big for a
commit message. Can you summarize it as lines like

0x00000000-0x0FFFFFFF  not cached
0x10000000-0x107FFFFF  cached (SDRAM)
...

?

> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> ---
>  arch/arm/include/asm/dma-mapping.h |   56 ++++++++++++++++++++++--
>  arch/arm/include/asm/global_data.h |    4 ++
>  arch/arm/include/asm/io.h          |   84 +++++++++++++++++++++++++++++++++++-
>  arch/arm/lib/cache-cp15.c          |   42 ++++++++++++++++++
>  common/cmd_boot.c                  |    4 ++
>  5 files changed, 186 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
> index 5bbb0a0..53c4edf 100644
> --- a/arch/arm/include/asm/dma-mapping.h
> +++ b/arch/arm/include/asm/dma-mapping.h
> @@ -3,6 +3,9 @@
>   * Stelian Pop <stelian@popies.net>
>   * Lead Tech Design <www.leadtechdesign.com>
>   *
> + * (C) Copyright 2010
> + * Dante Su <dantesu@faraday-tech.com>
> + *
>   * See file CREDITS for list of people who contributed to this
>   * project.
>   *
> @@ -24,22 +27,69 @@
>  #ifndef __ASM_ARM_DMA_MAPPING_H
>  #define __ASM_ARM_DMA_MAPPING_H
> 
> +#include <asm/u-boot.h>
> +#include <asm/global_data.h>
> +#include <asm/io.h>
> +#include <malloc.h>
> +
>  enum dma_data_direction {
>  	DMA_BIDIRECTIONAL	= 0,
>  	DMA_TO_DEVICE		= 1,
>  	DMA_FROM_DEVICE		= 2,
>  };
> 
> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
> +{
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +	DECLARE_GLOBAL_DATA_PTR;

I'd rather have the global data ptr be declared outside any function,
and only once.

> +#endif
> +	void *va = memalign(ARCH_DMA_MINALIGN, len);
> +
> +	if (va && handle)
> +		*handle = virt_to_phys(va);
> +
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +	if (gd->arch.cpu_mmu) {
> +		/* invalidate the buffer, convert to un-cached address */
> +		if (va != NULL) {
> +			invalidate_dcache_range((ulong)va, (ulong)va + len);
> +			va = virt_to_uncached(va);
> +		}
> +	}
> +#endif
> +
> +	return va;
> +}
> +
> +static inline void dma_free_coherent(void *va)
>  {
> -	*handle = (unsigned long)malloc(len);
> -	return (void *)*handle;
> +	free(virt_to_cached(va));
>  }

If I read this correctly, this code changes the semantics of
dma_alloc_coherent() for boards other than Faraday-based: before,
mempry was simply malloc()ed, now it would be memalign()ed then
virt_to_phys()ed. Why not simply keep the previous implementation under
a #else...#endif block?

>  static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
>  					   enum dma_data_direction dir)
>  {
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +	DECLARE_GLOBAL_DATA_PTR;
> +
> +	if (gd->arch.cpu_mmu) {
> +		switch (dir) {
> +		case DMA_BIDIRECTIONAL:
> +		case DMA_TO_DEVICE:
> +			flush_dcache_range((ulong)vaddr,
> +				(ulong)vaddr + len);
> +			break;
> +
> +		case DMA_FROM_DEVICE:
> +			invalidate_dcache_range((ulong)vaddr,
> +				(ulong)vaddr + len);
> +			break;
> +		}
> +	}
> +	return virt_to_phys((void *)vaddr);
> +#else
>  	return (unsigned long)vaddr;
> +#endif
>  }

Here we have such a #else/#endif, which makes sure non-Farady boards
are unaffected.

>  static inline void dma_unmap_single(volatile void *vaddr, size_t len,
> diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
> index 37ac0da..bd18ff7 100644
> --- a/arch/arm/include/asm/global_data.h
> +++ b/arch/arm/include/asm/global_data.h
> @@ -38,6 +38,10 @@ struct arch_global_data {
>  	unsigned long	pllb_rate_hz;
>  	unsigned long	at91_pllb_usb_init;
>  #endif
> +#ifdef CONFIG_FARADAY
> +	unsigned long   cpu_id;
> +	unsigned long   cpu_mmu;	/* has mmu */
> +#endif
>  	/* "static data" needed by most of timer.c on ARM platforms */
>  	unsigned long timer_rate_hz;
>  	unsigned long tbu;
> diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
> index 1fbc531..17d8898 100644
> --- a/arch/arm/include/asm/io.h
> +++ b/arch/arm/include/asm/io.h
> @@ -2,6 +2,7 @@
>   *  linux/include/asm-arm/io.h
>   *
>   *  Copyright (C) 1996-2000 Russell King
> + *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
>   *
>   * This program is free software; you can redistribute it and/or modify
>   * it under the terms of the GNU General Public License version 2 as
> @@ -23,6 +24,8 @@
>  #ifdef __KERNEL__
> 
>  #include <linux/types.h>
> +#include <asm/u-boot.h>
> +#include <asm/global_data.h>
>  #include <asm/byteorder.h>
>  #include <asm/memory.h>
>  #if 0	/* XXX###XXX */
> @@ -57,9 +60,88 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)
> 
>  }
> 
> +#ifdef CONFIG_FARADAY
> +
> +# ifndef CONFIG_SYS_DCACHE_OFF
> +
> +static inline ulong uncached_base(volatile gd_t *gd)
> +{
> +	return (4096 - (gd->ram_size >> 20)) << 20;

Symbolic constants or a comment would not hurt here.

> +}
> +# endif
> +
> +static inline void *virt_to_cached(void *va)
> +{
> +# ifndef CONFIG_SYS_DCACHE_OFF
> +	DECLARE_GLOBAL_DATA_PTR;
> +	ulong base = uncached_base(gd);
> +
> +	if (!gd->arch.cpu_mmu)
> +		return va;
> +
> +	if ((ulong)va >= base &&
> +		(ulong)va < (base + gd->ram_size))
> +		va = (void *)((ulong)va - base + CONFIG_SYS_SDRAM_BASE);
> +# endif	/* !CONFIG_SYS_DCACHE_OFF */
> +
> +	return va;
> +}
> +
> +static inline void *virt_to_uncached(void *va)
> +{
> +# ifndef CONFIG_SYS_DCACHE_OFF
> +	DECLARE_GLOBAL_DATA_PTR;
> +	ulong base = uncached_base(gd);
> +
> +	if (!gd->arch.cpu_mmu)
> +		return va;
> +
> +#  ifdef CONFIG_USE_IRQ
> +	if ((ulong)va < SZ_1M)
> +		return (void *)(base + (ulong)va);
> +#  endif
> +
> +	if ((ulong)va >= CONFIG_SYS_SDRAM_BASE &&
> +		(ulong)va < (CONFIG_SYS_SDRAM_BASE + gd->ram_size))
> +		va = (void *)(base + ((ulong)va - CONFIG_SYS_SDRAM_BASE));
> +# endif	/* !CONFIG_SYS_DCACHE_OFF */
> +
> +	return va;
> +}
> +
> +#endif	/* CONFIG_FARADAY */
> +
>  static inline phys_addr_t virt_to_phys(void * vaddr)
>  {
> -	return (phys_addr_t)(vaddr);
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +
> +	DECLARE_GLOBAL_DATA_PTR;
> +	bd_t *bd = gd->bd;
> +	ulong base = uncached_base(gd);
> +	ulong phys = (ulong)vaddr;
> +
> +	if (!gd->arch.cpu_mmu)
> +		return (phys_addr_t)phys;
> +
> +	if (phys >= base) {
> +		ulong bank;
> +		ulong off = phys - base;
> +		for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
> +			if (bd->bi_dram[bank].size > off)
> +				break;
> +			off -= bd->bi_dram[bank].size;
> +		}
> +		phys = bd->bi_dram[bank].start + off;
> +	}
> +# ifdef CONFIG_USE_IRQ
> +	else if (phys < SZ_1M && bd->bi_dram[0].start != 0)
> +		phys = bd->bi_dram[0].start + phys;
> +# endif
> +
> +	return (phys_addr_t)phys;
> +#else
> +	return (phys_addr_t)vaddr;
> +#endif
>  }
> 
>  /*
> diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
> index 4abe1cf..eee8585 100644
> --- a/arch/arm/lib/cache-cp15.c
> +++ b/arch/arm/lib/cache-cp15.c
> @@ -1,6 +1,8 @@
>  /*
>   * (C) Copyright 2002
>   * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
> + * (C) Copyright 2010
> + * Dante Su <dantesu@faraday-tech.com>
>   *
>   * See file CREDITS for list of people who contributed to this
>   * project.
> @@ -87,6 +89,10 @@ __weak void dram_bank_mmu_setup(int bank)
>  {
>  	bd_t *bd = gd->bd;
>  	int	i;
> +#ifdef CONFIG_FARADAY
> +	ulong ubase, off;
> +	u32 *page_table = (u32 *)gd->arch.tlb_addr;
> +#endif
> 
>  	debug("%s: bank: %d\n", __func__, bank);
>  	for (i = bd->bi_dram[bank].start >> 20;
> @@ -98,6 +104,32 @@ __weak void dram_bank_mmu_setup(int bank)
>  		set_section_dcache(i, DCACHE_WRITEBACK);
>  #endif
>  	}
> +#ifdef CONFIG_FARADAY
> +# ifdef CONFIG_USE_IRQ
> +	/* map the exception table to 0x00000000 if necessary */
> +	if (bank == 0 && bd->bi_dram[bank].start != 0) {
> +		u32 pa = bd->bi_dram[bank].start;
> +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
> +		page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
> +#else
> +		page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
> +#endif
> +	}
> +# endif
> +	/* calculate address offset */
> +	off  = 0;
> +	for (i = 0; i < bank; ++i)
> +		off += bd->bi_dram[bank].size;
> +
> +	/* create memory map */
> +	ubase = (4096 - (gd->ram_size >> 20)) << 20;
> +	for (i = 0; i < bd->bi_dram[bank].size >> 20; ++i) {
> +		u32 pa = bd->bi_dram[bank].start + (i << 20);
> +		/* create un-cached address map */
> +		u32 va = ubase + off + (i << 20);
> +		page_table[va >> 20] = pa | (3 << 10) | DCACHE_OFF;
> +	}
> +#endif
>  }
> 
>  /* to activate the MMU we need to set up virtual memory: use 1M areas */
> @@ -126,6 +158,10 @@ static inline void mmu_setup(void)
> 
>  	/* and enable the mmu */
>  	reg = get_cr();	/* get control reg. */
> +#ifdef CONFIG_FARADAY
> +	reg |= CR_W;	/* enable write buffer */
> +	reg |= CR_Z;	/* enable branch prediction */
> +#endif
>  	cp_delay();
>  	set_cr(reg | CR_M);
>  }
> @@ -140,9 +176,15 @@ static void cache_enable(uint32_t cache_bit)
>  {
>  	uint32_t reg;
> 
> +#ifdef CONFIG_FARADAY
> +	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
> +		return;
> +#endif
> +
>  	/* The data cache is not active unless the mmu is enabled too */
>  	if ((cache_bit == CR_C) && !mmu_enabled())
>  		mmu_setup();
> +
>  	reg = get_cr();	/* get control reg. */
>  	cp_delay();
>  	set_cr(reg | cache_bit);
> diff --git a/common/cmd_boot.c b/common/cmd_boot.c
> index d3836fd..b2477e8 100644
> --- a/common/cmd_boot.c
> +++ b/common/cmd_boot.c
> @@ -50,6 +50,10 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
> 
>  	printf ("## Starting application at 0x%08lX ...\n", addr);
> 
> +#if defined(__ARM__) && !defined(CONFIG_SYS_DCACHE_OFF)
> +	cleanup_before_linux();
> +#endif
> +
>  	/*
>  	 * pass address parameter as argv[0] (aka command name),
>  	 * and all remaining args
> --
> 1.7.9.5
> 


Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
  2013-04-18 11:04       ` Wolfgang Denk
@ 2013-04-18 19:44       ` Scott Wood
  2013-04-22  2:45         ` Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-04-18 19:44 UTC (permalink / raw)
  To: u-boot

On 04/18/2013 04:25:34 AM, Kuo-Jung Su wrote:
> diff --git a/drivers/mtd/nand/ftnandc021.c  
> b/drivers/mtd/nand/ftnandc021.c
> new file mode 100644
> index 0000000..58863dc
> --- /dev/null
> +++ b/drivers/mtd/nand/ftnandc021.c
> @@ -0,0 +1,544 @@
> +/*
> + * Faraday NAND Flash Controller
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later  
> version.
> + * See the file COPYING in the root directory of the source tree for  
> details.
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <asm/unaligned.h>
> +#include <nand.h>
> +#include <malloc.h>
> +
> +#include "ftnandc021.h"
> +
> +/* common bitmask of nand flash status register */
> +#define NAND_IOSTATUS_ERROR		BIT_MASK(0)
> +#define NAND_IOSTATUS_READY		BIT_MASK(6)
> +#define NAND_IOSTATUS_UNPROTCT	BIT_MASK(7)
> +
> +struct ftnandc021_chip {
> +	void    *iobase;

struct ftnandc021_regs __iomem *iobase;

> +	uint32_t cmd;
> +
> +	uint32_t pgidx;
> +
> +	uint32_t off;
> +	uint8_t  buf[256];
> +
> +	uint32_t adrc;	/* address cycle */
> +	uint32_t pgsz;	/* page size */
> +	uint32_t bksz;	/* block size */
> +};
> +
> +/* Register access macros */
> +#define NAND_READ(r)		le32_to_cpu(readl(r))
> +#define NAND_WRITE(v, r)	writel(cpu_to_le32(v), r)
> +#define NAND_SETBITS(m, r)	setbits_le32(r, m)
> +#define NAND_CLRBITS(m, r)	clrbits_le32(r, m)

Do we really need these wrappers?  At least use inline functions (with  
lowercase names) rather than ALLCAPS MACROS, but I don't see the point  
once you get rid of the byteswapping, which is broken.  readl() reads a  
little-endian register and returns a CPU-ordered value, and then you  
pass that CPU ordered value to a function that wants to take a little  
endian value and swap it again.  Likewise with writel, in reverse.

> +static struct nand_ecclayout ftnandc021_oob_2k = {
> +	.eccbytes = 24,
> +	.eccpos = {
> +		40, 41, 42, 43, 44, 45, 46, 47,
> +		48, 49, 50, 51, 52, 53, 54, 55,
> +		56, 57, 58, 59, 60, 61, 62, 63
> +	},
> +	.oobfree = {
> +		{
> +			.offset = 9,
> +			.length = 3
> +		}
> +	}
> +};

This layout doesn't seem to match what the code does.  The code says
there is no ECC, and only writes to specific fixed bytes of the OOB
(which doesn't match 3 bytes at offset 9).

> +static int
> +ftnandc021_reset(struct nand_chip *chip)

We don't generally do the "function name starts in column 0" thing in  
U-Boot.

> +{
> +	struct ftnandc021_chip *priv = chip->priv;
> +	struct ftnandc021_regs *regs = priv->iobase;

struct ftnandc021_regs __iomem *regs

Here and elsewhere, for "sparse" checking.

> +	uint32_t bk = 2;	/* 64 pages */
> +	uint32_t pg = 1;	/* 2k */
> +	uint32_t ac = 2;	/* 5 */

When do you actually use these default values, other than when one of  
the
switch statements fail to match -- which seems like it would be an error
condition; even if you don't explicitly check for the error it doesn't
seem good to paper over it by providing common values that might work.

> +#ifdef CONFIG_FTNANDC021_ACTIMING_1
> +	NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_1, &regs->atr[0]);
> +#endif
> +#ifdef CONFIG_FTNANDC021_ACTIMING_2
> +	NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_2, &regs->atr[1]);
> +#endif

Use CONFIG_SYS_ for things which describe hardware rather than user  
preference.  Document all CONFIG symbols (including CONFIG_SYS symbols)  
in the README.

> +	NAND_WRITE(0, &regs->ier);
> +	NAND_WRITE(0, &regs->pir);
> +	NAND_WRITE(0xff, &regs->bbiwr);
> +	NAND_WRITE(0xffffffff, &regs->lsnwr);
> +	NAND_WRITE(0xffffffff, &regs->crcwr);
> +
> +	if (chip->options & NAND_BUSWIDTH_16)
> +		NAND_WRITE(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT,  
> &regs->fcr);
> +	else
> +		NAND_WRITE(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
> +
> +	/* chip reset */
> +	NAND_WRITE(SRR_CHIP_RESET, &regs->srr);
> +
> +	/* wait until chip ready */
> +	while (NAND_READ(&regs->srr) & SRR_CHIP_RESET)
> +		;

Timeout?

> +	switch (priv->adrc) {
> +	case 3:
> +		ac = 0;
> +		break;
> +	case 4:
> +		ac = 1;
> +		break;
> +	case 5:
> +		ac = 2;
> +		break;
> +	}

ac = priv->adrc - 3;

> +static inline int
> +ftnandc021_ckst(struct ftnandc021_chip *priv)
> +{
> +	struct ftnandc021_regs *regs = priv->iobase;
> +	uint32_t st = NAND_READ(&regs->idr[1]);
> +
> +	if (st & NAND_IOSTATUS_ERROR)
> +		return -NAND_IOSTATUS_ERROR;
> +
> +	if (!(st & NAND_IOSTATUS_READY))
> +		return -NAND_IOSTATUS_READY;
> +
> +	if (!(st & NAND_IOSTATUS_UNPROTCT))
> +		return -NAND_IOSTATUS_UNPROTCT;
> +
> +	return 0;
> +}

Why the negation of NAND_IOSTATUS_*?  These aren't standard error
codes...  you don't even use the return value at all that I see, other
than checking zero or not-zero.

> +static uint8_t
> +ftnandc021_read_byte(struct mtd_info *mtd)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct ftnandc021_chip *priv = chip->priv;
> +	struct ftnandc021_regs *regs = priv->iobase;
> +	uint8_t ret = 0xff;
> +
> +	switch (priv->cmd) {
> +	case NAND_CMD_READID:
> +	case NAND_CMD_READOOB:
> +		ret = priv->buf[priv->off % 256];
> +		priv->off += 1;
> +		break;
> +	case NAND_CMD_STATUS:
> +		ret = (uint8_t)(NAND_READ(&regs->idr[1]) & 0xff);
> +		break;

Why "% 256" in one case but "& 0xff" in the other?

> +	default:
> +		debug("ftnandc021_read_byte: unknown cmd(0x%02X)\n",
> +			priv->cmd);

This is an error, not just debug info.  Use printf.

> +/**
> + * Read data from NAND controller into buffer
> + * @mtd: MTD device structure
> + * @buf: buffer to store date
> + * @len: number of bytes to read
> + */
> +static void
> +ftnandc021_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct ftnandc021_chip *priv = chip->priv;
> +	struct ftnandc021_regs *regs = priv->iobase;
> +	ulong off;
> +
> +	/* oob read */
> +	if (len <= mtd->oobsize) {
> +		ftnandc021_read_oob(mtd, buf, len);
> +		return;
> +	}

Are you sure that a length smaller than the oobsize always means that
it's an oob read?

> +	/* page read */
> +	for (off = 0; len > 0; len -= 4, off += 4) {
> +		while (!(NAND_READ(&regs->ior) & IOR_READY))
> +			;
> +		*(uint32_t *)(buf + off) = NAND_READ(&regs->dr);
> +	}

Why do you need to check IOR_READY here but not in read_byte?

> +static void
> +ftnandc021_cmdfunc(struct mtd_info *mtd, unsigned cmd, int column,  
> int pgidx)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct ftnandc021_chip *priv = chip->priv;
> +	struct ftnandc021_regs *regs = priv->iobase;
> +
> +	priv->cmd   = cmd;
> +	priv->pgidx = pgidx;
> +
> +	switch (cmd) {
> +	case NAND_CMD_READID:	/* 0x90 */
> +		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID)) {
> +			printf("ftnandc021: RDID failed.\n");
> +		} else {
> +			put_unaligned_le32(NAND_READ(&regs->idr[0]),
> +				priv->buf);
> +			put_unaligned_le32(NAND_READ(&regs->idr[1]),
> +				priv->buf + 4);
> +			priv->off = 0;
> +		}
> +		break;

Do error handling like this:

	if (ftnandc021_command(priv, FTNANDC021_CMD_RDID)) {
		printf(...);
		break;
	}

	put_unaligned...
	...

Why would it be unaligned?
Why _le32?
Can you not read a byte at a time here?

> +/**
> + * hardware specific access to control-lines
> + * @mtd: MTD device structure
> + * @cmd: command to device
> + * @ctrl:
> + * NAND_NCE: bit 0 -> don't care
> + * NAND_CLE: bit 1 -> Command Latch
> + * NAND_ALE: bit 2 -> Address Latch
> + *
> + * NOTE: boards may use different bits for these!!
> + */
> +static void
> +ftnandc021_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int  
> ctrl)
> +{
> +}

Just leave the function pointer NULL.

> +	chip->ecc.mode   = NAND_ECC_NONE;

Really, no ECC at all?  That is quite broken.  There is absolutely no  
way
to get access to the full OOB in order to do software ECC?

Or is it doing hardware ECC in a way that is transparent?  You should
still use NAND_ECC_HARD in that case.

> +	chip->ecc.layout = &ftnandc021_oob_2k;

What if it's not 2K NAND?

> diff --git a/include/faraday/nand.h b/include/faraday/nand.h
> new file mode 100644
> index 0000000..6d8efb2
> --- /dev/null
> +++ b/include/faraday/nand.h
> @@ -0,0 +1,16 @@
> +/*
> + * Faraday NAND Flash Controller
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later  
> version.
> + * See the file COPYING in the root directory of the source tree for  
> details.
> + */
> +
> +#ifndef _FARADAY_NAND_H
> +#define _FARADAY_NAND_H
> +
> +int ftnandc021_probe(struct nand_chip *chip);

New drivers should use CONFIG_SYS_NAND_SELF_INIT

-Scott

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

* [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores
  2013-04-18 11:13       ` Wolfgang Denk
@ 2013-04-22  1:23         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:23 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-12-git-send-email-dantesu@gmail.com> you wrote:
> ...
>> --- a/common/cmd_boot.c
>> +++ b/common/cmd_boot.c
>> @@ -50,6 +50,10 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>
>>       printf ("## Starting application at 0x%08lX ...\n", addr);
>>
>> +#if defined(__ARM__) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +     cleanup_before_linux();
>> +#endif
>> +
>>       /*
>>        * pass address parameter as argv[0] (aka command name),
>>        * and all remaining args
>
> Thios affects global code. Please submit as separate patch.

Got it, thanks

>
> And why exactly is this ARM specific?
>

Because it only has been tested on ARM platform only,
I'm not sure if the others arch. also has the function: cleanup_before_linux();

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> My play was a complete success.  The audience was a failure.



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores
  2013-04-18 19:09       ` Albert ARIBAUD
@ 2013-04-22  1:27         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:27 UTC (permalink / raw)
  To: u-boot

2013/4/19 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Thu, 18 Apr 2013 17:25:38 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch would enable MMU for Faraday ARMv5TE cores.
>>
>> Here is the abstract of this MMU design.
>>
>> Assume SDRAM memory region starts at 0x10000000, and its size = 0x800000.
>>
>> 0x00000000 +-------------------+
>>            |                   |
>>            |     UN-CACHED     |
>>            |                   |
>>            |                   |
>> 0x10000000 +-------------------+
>>            |  CACHED (SDRAM)   | <- It's where data/bss/stack lived.
>>            |                   |
>>            |                   |
>> 0x10800000 +-------------------+
>>            |                   |
>>            |                   |
>>            |     UN-CACHED     |
>>            |                   |
>>            |                   |
>> 0xFF800000 +-------------------+
>>            | UN-CACHED (SDRAM) | <- An un-cached shadow of the SDRAM.
>>            |                   |    dma_alloc_coherent() always returns
>>            |                   |    an address in this region.
>> 0xFFFFFFFF +-------------------+
>
> The ASCII map is great for explaining, but I find it a bit big for a
> commit message. Can you summarize it as lines like
>
> 0x00000000-0x0FFFFFFF  not cached
> 0x10000000-0x107FFFFF  cached (SDRAM)
> ...
>
> ?
>

Sure,
it would be updated in that way at next patch.

>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Albert Aribaud <albert.u.boot@aribaud.net>
>> ---
>>  arch/arm/include/asm/dma-mapping.h |   56 ++++++++++++++++++++++--
>>  arch/arm/include/asm/global_data.h |    4 ++
>>  arch/arm/include/asm/io.h          |   84 +++++++++++++++++++++++++++++++++++-
>>  arch/arm/lib/cache-cp15.c          |   42 ++++++++++++++++++
>>  common/cmd_boot.c                  |    4 ++
>>  5 files changed, 186 insertions(+), 4 deletions(-)
>>
>> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
>> index 5bbb0a0..53c4edf 100644
>> --- a/arch/arm/include/asm/dma-mapping.h
>> +++ b/arch/arm/include/asm/dma-mapping.h
>> @@ -3,6 +3,9 @@
>>   * Stelian Pop <stelian@popies.net>
>>   * Lead Tech Design <www.leadtechdesign.com>
>>   *
>> + * (C) Copyright 2010
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>>   * See file CREDITS for list of people who contributed to this
>>   * project.
>>   *
>> @@ -24,22 +27,69 @@
>>  #ifndef __ASM_ARM_DMA_MAPPING_H
>>  #define __ASM_ARM_DMA_MAPPING_H
>>
>> +#include <asm/u-boot.h>
>> +#include <asm/global_data.h>
>> +#include <asm/io.h>
>> +#include <malloc.h>
>> +
>>  enum dma_data_direction {
>>       DMA_BIDIRECTIONAL       = 0,
>>       DMA_TO_DEVICE           = 1,
>>       DMA_FROM_DEVICE         = 2,
>>  };
>>
>> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> +{
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +     DECLARE_GLOBAL_DATA_PTR;
>
> I'd rather have the global data ptr be declared outside any function,
> and only once.
>

Got it, thanks

>> +#endif
>> +     void *va = memalign(ARCH_DMA_MINALIGN, len);
>> +
>> +     if (va && handle)
>> +             *handle = virt_to_phys(va);
>> +
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +     if (gd->arch.cpu_mmu) {
>> +             /* invalidate the buffer, convert to un-cached address */
>> +             if (va != NULL) {
>> +                     invalidate_dcache_range((ulong)va, (ulong)va + len);
>> +                     va = virt_to_uncached(va);
>> +             }
>> +     }
>> +#endif
>> +
>> +     return va;
>> +}
>> +
>> +static inline void dma_free_coherent(void *va)
>>  {
>> -     *handle = (unsigned long)malloc(len);
>> -     return (void *)*handle;
>> +     free(virt_to_cached(va));
>>  }
>
> If I read this correctly, this code changes the semantics of
> dma_alloc_coherent() for boards other than Faraday-based: before,
> mempry was simply malloc()ed, now it would be memalign()ed then
> virt_to_phys()ed. Why not simply keep the previous implementation under
> a #else...#endif block?
>

Sorry, it's an accident, I'll have it fixed at next version.

>>  static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
>>                                          enum dma_data_direction dir)
>>  {
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +     DECLARE_GLOBAL_DATA_PTR;
>> +
>> +     if (gd->arch.cpu_mmu) {
>> +             switch (dir) {
>> +             case DMA_BIDIRECTIONAL:
>> +             case DMA_TO_DEVICE:
>> +                     flush_dcache_range((ulong)vaddr,
>> +                             (ulong)vaddr + len);
>> +                     break;
>> +
>> +             case DMA_FROM_DEVICE:
>> +                     invalidate_dcache_range((ulong)vaddr,
>> +                             (ulong)vaddr + len);
>> +                     break;
>> +             }
>> +     }
>> +     return virt_to_phys((void *)vaddr);
>> +#else
>>       return (unsigned long)vaddr;
>> +#endif
>>  }
>
> Here we have such a #else/#endif, which makes sure non-Farady boards
> are unaffected.
>
>>  static inline void dma_unmap_single(volatile void *vaddr, size_t len,
>> diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
>> index 37ac0da..bd18ff7 100644
>> --- a/arch/arm/include/asm/global_data.h
>> +++ b/arch/arm/include/asm/global_data.h
>> @@ -38,6 +38,10 @@ struct arch_global_data {
>>       unsigned long   pllb_rate_hz;
>>       unsigned long   at91_pllb_usb_init;
>>  #endif
>> +#ifdef CONFIG_FARADAY
>> +     unsigned long   cpu_id;
>> +     unsigned long   cpu_mmu;        /* has mmu */
>> +#endif
>>       /* "static data" needed by most of timer.c on ARM platforms */
>>       unsigned long timer_rate_hz;
>>       unsigned long tbu;
>> diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
>> index 1fbc531..17d8898 100644
>> --- a/arch/arm/include/asm/io.h
>> +++ b/arch/arm/include/asm/io.h
>> @@ -2,6 +2,7 @@
>>   *  linux/include/asm-arm/io.h
>>   *
>>   *  Copyright (C) 1996-2000 Russell King
>> + *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
>>   *
>>   * This program is free software; you can redistribute it and/or modify
>>   * it under the terms of the GNU General Public License version 2 as
>> @@ -23,6 +24,8 @@
>>  #ifdef __KERNEL__
>>
>>  #include <linux/types.h>
>> +#include <asm/u-boot.h>
>> +#include <asm/global_data.h>
>>  #include <asm/byteorder.h>
>>  #include <asm/memory.h>
>>  #if 0        /* XXX###XXX */
>> @@ -57,9 +60,88 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)
>>
>>  }
>>
>> +#ifdef CONFIG_FARADAY
>> +
>> +# ifndef CONFIG_SYS_DCACHE_OFF
>> +
>> +static inline ulong uncached_base(volatile gd_t *gd)
>> +{
>> +     return (4096 - (gd->ram_size >> 20)) << 20;
>
> Symbolic constants or a comment would not hurt here.
>

Got it, thanks

>> +}
>> +# endif
>> +
>> +static inline void *virt_to_cached(void *va)
>> +{
>> +# ifndef CONFIG_SYS_DCACHE_OFF
>> +     DECLARE_GLOBAL_DATA_PTR;
>> +     ulong base = uncached_base(gd);
>> +
>> +     if (!gd->arch.cpu_mmu)
>> +             return va;
>> +
>> +     if ((ulong)va >= base &&
>> +             (ulong)va < (base + gd->ram_size))
>> +             va = (void *)((ulong)va - base + CONFIG_SYS_SDRAM_BASE);
>> +# endif      /* !CONFIG_SYS_DCACHE_OFF */
>> +
>> +     return va;
>> +}
>> +
>> +static inline void *virt_to_uncached(void *va)
>> +{
>> +# ifndef CONFIG_SYS_DCACHE_OFF
>> +     DECLARE_GLOBAL_DATA_PTR;
>> +     ulong base = uncached_base(gd);
>> +
>> +     if (!gd->arch.cpu_mmu)
>> +             return va;
>> +
>> +#  ifdef CONFIG_USE_IRQ
>> +     if ((ulong)va < SZ_1M)
>> +             return (void *)(base + (ulong)va);
>> +#  endif
>> +
>> +     if ((ulong)va >= CONFIG_SYS_SDRAM_BASE &&
>> +             (ulong)va < (CONFIG_SYS_SDRAM_BASE + gd->ram_size))
>> +             va = (void *)(base + ((ulong)va - CONFIG_SYS_SDRAM_BASE));
>> +# endif      /* !CONFIG_SYS_DCACHE_OFF */
>> +
>> +     return va;
>> +}
>> +
>> +#endif       /* CONFIG_FARADAY */
>> +
>>  static inline phys_addr_t virt_to_phys(void * vaddr)
>>  {
>> -     return (phys_addr_t)(vaddr);
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +
>> +     DECLARE_GLOBAL_DATA_PTR;
>> +     bd_t *bd = gd->bd;
>> +     ulong base = uncached_base(gd);
>> +     ulong phys = (ulong)vaddr;
>> +
>> +     if (!gd->arch.cpu_mmu)
>> +             return (phys_addr_t)phys;
>> +
>> +     if (phys >= base) {
>> +             ulong bank;
>> +             ulong off = phys - base;
>> +             for (bank = 0; bank < CONFIG_NR_DRAM_BANKS; ++bank) {
>> +                     if (bd->bi_dram[bank].size > off)
>> +                             break;
>> +                     off -= bd->bi_dram[bank].size;
>> +             }
>> +             phys = bd->bi_dram[bank].start + off;
>> +     }
>> +# ifdef CONFIG_USE_IRQ
>> +     else if (phys < SZ_1M && bd->bi_dram[0].start != 0)
>> +             phys = bd->bi_dram[0].start + phys;
>> +# endif
>> +
>> +     return (phys_addr_t)phys;
>> +#else
>> +     return (phys_addr_t)vaddr;
>> +#endif
>>  }
>>
>>  /*
>> diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
>> index 4abe1cf..eee8585 100644
>> --- a/arch/arm/lib/cache-cp15.c
>> +++ b/arch/arm/lib/cache-cp15.c
>> @@ -1,6 +1,8 @@
>>  /*
>>   * (C) Copyright 2002
>>   * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
>> + * (C) Copyright 2010
>> + * Dante Su <dantesu@faraday-tech.com>
>>   *
>>   * See file CREDITS for list of people who contributed to this
>>   * project.
>> @@ -87,6 +89,10 @@ __weak void dram_bank_mmu_setup(int bank)
>>  {
>>       bd_t *bd = gd->bd;
>>       int     i;
>> +#ifdef CONFIG_FARADAY
>> +     ulong ubase, off;
>> +     u32 *page_table = (u32 *)gd->arch.tlb_addr;
>> +#endif
>>
>>       debug("%s: bank: %d\n", __func__, bank);
>>       for (i = bd->bi_dram[bank].start >> 20;
>> @@ -98,6 +104,32 @@ __weak void dram_bank_mmu_setup(int bank)
>>               set_section_dcache(i, DCACHE_WRITEBACK);
>>  #endif
>>       }
>> +#ifdef CONFIG_FARADAY
>> +# ifdef CONFIG_USE_IRQ
>> +     /* map the exception table to 0x00000000 if necessary */
>> +     if (bank == 0 && bd->bi_dram[bank].start != 0) {
>> +             u32 pa = bd->bi_dram[bank].start;
>> +#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
>> +             page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
>> +#else
>> +             page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
>> +#endif
>> +     }
>> +# endif
>> +     /* calculate address offset */
>> +     off  = 0;
>> +     for (i = 0; i < bank; ++i)
>> +             off += bd->bi_dram[bank].size;
>> +
>> +     /* create memory map */
>> +     ubase = (4096 - (gd->ram_size >> 20)) << 20;
>> +     for (i = 0; i < bd->bi_dram[bank].size >> 20; ++i) {
>> +             u32 pa = bd->bi_dram[bank].start + (i << 20);
>> +             /* create un-cached address map */
>> +             u32 va = ubase + off + (i << 20);
>> +             page_table[va >> 20] = pa | (3 << 10) | DCACHE_OFF;
>> +     }
>> +#endif
>>  }
>>
>>  /* to activate the MMU we need to set up virtual memory: use 1M areas */
>> @@ -126,6 +158,10 @@ static inline void mmu_setup(void)
>>
>>       /* and enable the mmu */
>>       reg = get_cr(); /* get control reg. */
>> +#ifdef CONFIG_FARADAY
>> +     reg |= CR_W;    /* enable write buffer */
>> +     reg |= CR_Z;    /* enable branch prediction */
>> +#endif
>>       cp_delay();
>>       set_cr(reg | CR_M);
>>  }
>> @@ -140,9 +176,15 @@ static void cache_enable(uint32_t cache_bit)
>>  {
>>       uint32_t reg;
>>
>> +#ifdef CONFIG_FARADAY
>> +     if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
>> +             return;
>> +#endif
>> +
>>       /* The data cache is not active unless the mmu is enabled too */
>>       if ((cache_bit == CR_C) && !mmu_enabled())
>>               mmu_setup();
>> +
>>       reg = get_cr(); /* get control reg. */
>>       cp_delay();
>>       set_cr(reg | cache_bit);
>> diff --git a/common/cmd_boot.c b/common/cmd_boot.c
>> index d3836fd..b2477e8 100644
>> --- a/common/cmd_boot.c
>> +++ b/common/cmd_boot.c
>> @@ -50,6 +50,10 @@ static int do_go(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>>
>>       printf ("## Starting application at 0x%08lX ...\n", addr);
>>
>> +#if defined(__ARM__) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +     cleanup_before_linux();
>> +#endif
>> +
>>       /*
>>        * pass address parameter as argv[0] (aka command name),
>>        * and all remaining args
>> --
>> 1.7.9.5
>>
>
>
> Amicalement,
> --
> Albert.



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support
  2013-04-18 10:43     ` [U-Boot] [PATCH v2 00/12] " Wolfgang Denk
@ 2013-04-22  1:27       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:27 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-1-git-send-email-dantesu@gmail.com> you wrote:
>>
>> These patches introduce Faraday A36x SoC platform support.
>
> Please run all your patches through checkpatch and clean up thew
> reported warnings and errors before you resubmit.
>

Got it, thanks

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> "The algorithm to do that is extremely nasty. You might want  to  mug
> someone with it."                   - M. Devine, Computer Science 340



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 12/12] arm: add Faraday A36x SoC platform support
  2013-04-18 11:16       ` Wolfgang Denk
@ 2013-04-22  1:30         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:30 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-13-git-send-email-dantesu@gmail.com> you wrote:
> ...
>> +#define CONFIG_FTMAC110        1
>> +#define CONFIG_ETHADDR         00:84:14:72:61:69 /* used by env_common.c */
>> +#define CONFIG_NETMASK         255.255.255.0
>> +#define CONFIG_IPADDR          10.0.0.123
>> +#define CONFIG_SERVERIP        10.0.0.128
>
> NAK.  We don't allow static global network configurations like that.
>
>

Got it, thanks

>> +#define CONFIG_FTGMAC100       1
>> +#define CONFIG_PHY_MAX_ADDR    32 /* used by Ratbert's ftgmac100 only */
>> +#define CONFIG_FTGMAC100_EGIGA 1  /* used by Ratbert's ftgmac100 only */
>> +#define CONFIG_ETHADDR         00:84:14:72:61:69 /* used by env_common.c */
>> +#define CONFIG_NETMASK         255.255.255.0
>> +#define CONFIG_IPADDR          10.0.0.123
>> +#define CONFIG_SERVERIP        10.0.0.128
>
> NAK again.
>
> Hm... this looks like a LOT of repeated code.  Can you please factor
> out the common parts into a separate file?
>
>

Sure, I'll define a common file for these stuff at next patch.

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> Vulcans worship peace above all.
>         -- McCoy, "Return to Tomorrow", stardate 4768.3



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 10/12] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-04-18 11:11       ` Wolfgang Denk
@ 2013-04-22  1:45         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:45 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-11-git-send-email-dantesu@gmail.com> you wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> The Faraday FOTG210 is an OTG chip which could operate
>> as either an EHCI Host or a USB Device as a time.
> ...
>> +     uint32_t maxpacket:16;
>> +     uint32_t id:4;
>> +     uint32_t stopped:1;
>> +     uint32_t rsvd:11;
>
> Please do NOT use bit fields.  Fix globally.
>

Got it, thanks

>> +#define USB_READ(r)                  le32_to_cpu(readl(r))
>> +#define USB_WRITE(v, r)              writel(cpu_to_le32(v), r)
>> +#define USB_SETBITS(m, r)    setbits_le32(r, m)
>> +#define USB_CLRBITS(m, r)    clrbits_le32(r, m)
>
> As before...
>
>

Got it, thanks

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> e-credibility: the non-guaranteeable likelihood that  the  electronic
> data you're seeing is genuine rather than somebody's made-up crap.
> - Karl Lehenbauer



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 09/12] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-18 11:09       ` Wolfgang Denk
@ 2013-04-22  1:45         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:45 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-10-git-send-email-dantesu@gmail.com> you wrote:
> ...
>> +#define HCD_READ(r)                  le32_to_cpu(readl(r))
>> +#define HCD_WRITE(v, r)              writel(cpu_to_le32(v), r)
>> +#define HCD_SETBITS(m, r)    setbits_le32(r, m)
>> +#define HCD_CLRBITS(m, r)    clrbits_le32(r, m)
>
> As before...
>

Got it, thanks

>
> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> I'm a programmer: I don't buy software, I write it.
>                                                   -- Tom Christiansen



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 08/12] mtd: spi: add FTSPI020 SPI Flash controller support
  2013-04-18 11:08       ` Wolfgang Denk
@ 2013-04-22  1:51         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:51 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-9-git-send-email-dantesu@gmail.com> you wrote:
> ...
>> +/* Register access macros */
>> +#define SPI_READ(r)                  le32_to_cpu(readl(r))
>> +#define SPI_WRITE(v, r)              writel(cpu_to_le32(v), r)
>> +#define SPI_SETBITS(m, r)    setbits_le32(r, m)
>> +#define SPI_CLRBITS(m, r)    clrbits_le32(r, m)
>
> see before...
>

Got it, thanks

>> +     struct spi_flash_info *fl = (struct spi_flash_info *)flash;
>> +     return fl->chip;
>
> Please always insert a blank line between declarations and code.
>

Got it, thanks

>> +static const struct spi_flash_param sf_list[] = {
>> +
>> +     /* Atmel -- some are (confusingly) marketed as "DataFlash" */
>> +     { "at25fs010",  0x1f6601, 0, 32 * 1024,   4 },
>> +     { "at25fs040",  0x1f6604, 0, 64 * 1024,   8 },
>> +
>> +     { "at25df041a", 0x1f4401, 0, 64 * 1024,   8 },
>> +     { "at25df321a", 0x1f4701, 0, 64 * 1024,  64 },
>> +     { "at25df641",  0x1f4800, 0, 64 * 1024, 128 },
> ...
>
> should we not rather move this into a separate, global header file?
>

Sure, I'll make it a separate file or a global header file if possible.

>> +     for (i = 0; i < ARRAY_SIZE(id32); ++i) {
>> +             /* wait until rx ready */
>> +             while (!(SPI_READ(&regs->sr) & SR_RFR))
>> +                     ;
>
> See previous note about timeouts.  Please fix globally.
>
>> +     /* wait until command finish */
>> +     while (!(SPI_READ(&regs->isr) & ISR_CMD))
>> +             ;
>
> Ditto. etc. etc.
>

Got it, thanks

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> "Ja, mach' nur einen Plan,    sei nur ein grosses Licht
> und mach' dann noch 'nen zweiten Plan,    geh'n tun sie beide nicht."
>                                      -- Bert Brecht, Dreigroschenoper



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-18 11:04       ` Wolfgang Denk
@ 2013-04-22  1:52         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  1:52 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-8-git-send-email-dantesu@gmail.com> you wrote:
> ...
>> +/* Register access macros */
>> +#define NAND_READ(r)         le32_to_cpu(readl(r))
>> +#define NAND_WRITE(v, r)     writel(cpu_to_le32(v), r)
>> +#define NAND_SETBITS(m, r)   setbits_le32(r, m)
>> +#define NAND_CLRBITS(m, r)   clrbits_le32(r, m)
>
> As before: drop these.
>

Got it, thanks

>> +     /* wait until chip ready */
>> +     while (NAND_READ(&regs->srr) & SRR_CHIP_RESET)
>> +             ;
>
> Please add a timeout (and fix similar locations in the rest of the
> code if there are such).
>

Got it, thanks

>> +     switch (priv->bksz / priv->pgsz) {
>> +     case 16:
>> +             bk = 0;
>> +             break;
>> +     case 32:
>> +             bk = 1;
>> +             break;
>> +     case 64:
>> +             bk = 2;
>> +             break;
>> +     case 128:
>> +             bk = 3;
>> +             break;
>> +     }
>
>         bk = ffs(priv->bksz / priv->pgsz) - 4;
>
> ?
>

Got it, thanks

>> +     switch (priv->adrc) {
>> +     case 3:
>> +             ac = 0;
>> +             break;
>> +     case 4:
>> +             ac = 1;
>> +             break;
>> +     case 5:
>> +             ac = 2;
>> +             break;
>> +     }
>
>         ac = priv->adrc - 3;
>
> ?
>
>

Got it, thanks

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> "You're just jealous." "What, of an overgrown puppy  with  a  single-
> figure IQ?"                      - Terry Pratchett, _Moving Pictures_



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-18 19:44       ` Scott Wood
@ 2013-04-22  2:45         ` Kuo-Jung Su
  2013-04-22 23:11           ` Scott Wood
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  2:45 UTC (permalink / raw)
  To: u-boot

2013/4/19 Scott Wood <scottwood@freescale.com>:
> On 04/18/2013 04:25:34 AM, Kuo-Jung Su wrote:
>>
>> diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
>> new file mode 100644
>> index 0000000..58863dc
>> --- /dev/null
>> +++ b/drivers/mtd/nand/ftnandc021.c
>> @@ -0,0 +1,544 @@
>> +/*
>> + * Faraday NAND Flash Controller
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for
>> details.
>> + */
>> +
>> +#include <common.h>
>> +#include <asm/io.h>
>> +#include <asm/unaligned.h>
>> +#include <nand.h>
>> +#include <malloc.h>
>> +
>> +#include "ftnandc021.h"
>> +
>> +/* common bitmask of nand flash status register */
>> +#define NAND_IOSTATUS_ERROR            BIT_MASK(0)
>> +#define NAND_IOSTATUS_READY            BIT_MASK(6)
>> +#define NAND_IOSTATUS_UNPROTCT BIT_MASK(7)
>> +
>> +struct ftnandc021_chip {
>> +       void    *iobase;
>
>
> struct ftnandc021_regs __iomem *iobase;
>
>

Got it, thanks.

>> +       uint32_t cmd;
>> +
>> +       uint32_t pgidx;
>> +
>> +       uint32_t off;
>> +       uint8_t  buf[256];
>> +
>> +       uint32_t adrc;  /* address cycle */
>> +       uint32_t pgsz;  /* page size */
>> +       uint32_t bksz;  /* block size */
>> +};
>> +
>> +/* Register access macros */
>> +#define NAND_READ(r)           le32_to_cpu(readl(r))
>> +#define NAND_WRITE(v, r)       writel(cpu_to_le32(v), r)
>> +#define NAND_SETBITS(m, r)     setbits_le32(r, m)
>> +#define NAND_CLRBITS(m, r)     clrbits_le32(r, m)
>
>
> Do we really need these wrappers?  At least use inline functions (with
> lowercase names) rather than ALLCAPS MACROS, but I don't see the point once
> you get rid of the byteswapping, which is broken.  readl() reads a
> little-endian register and returns a CPU-ordered value, and then you pass
> that CPU ordered value to a function that wants to take a little endian
> value and swap it again.  Likewise with writel, in reverse.
>
>

No, we don't need these wrappers, they're here only because my
miss-understanding
about readl()/writel(), I don't know they've already done these for me.
I'll drop these wrappers at next patch.

>> +static struct nand_ecclayout ftnandc021_oob_2k = {
>> +       .eccbytes = 24,
>> +       .eccpos = {
>> +               40, 41, 42, 43, 44, 45, 46, 47,
>> +               48, 49, 50, 51, 52, 53, 54, 55,
>> +               56, 57, 58, 59, 60, 61, 62, 63
>> +       },
>> +       .oobfree = {
>> +               {
>> +                       .offset = 9,
>> +                       .length = 3
>> +               }
>> +       }
>> +};
>
>
> This layout doesn't seem to match what the code does.  The code says
> there is no ECC, and only writes to specific fixed bytes of the OOB
> (which doesn't match 3 bytes at offset 9).
>
>

Sorry, it's my bad, I forget to clean it up.
In my private base, it's possible to turn-on ECC support to FTNADC021
with the following issues:

1. When ECC is enabled, FTNANDC021 would always do ECC on every data block,
   including the blank block(all 0xff).
   What I mean is 'With ECC enabled, we'll have ECC errors on non-ecc
proected data blocks or even the blank block'.

2. FTNANDC021 would stop upon ECC errors, a chip reset is required to
make it work again.

3. There are only 4 bytes data + 1 byte Bad Block Info available to software,
   and because of the ECC issues above.
   I'll have to use 1 byte of data to tag if this block is 'not blank',
   to make it possible to cancel the operation on these blocks
   to prevent the chip to be stopped. (It means that I don't have to reset chip)
   And thus if the ECC is enabled, there are only 3 data bytes
available to software,
   which makes it not possible to support BBT. (BBT requres 4 data bytes in OOB)

So in this patch, I'll prefer ECC disabled.
BTW, because of the issues above, this chip has been faced out many years ago.
It would only be available to A369 or QEMU, and never in mass production.
And thus I think it's ok to have ECC disabled in this patch.

>> +static int
>> +ftnandc021_reset(struct nand_chip *chip)
>
>
> We don't generally do the "function name starts in column 0" thing in
> U-Boot.
>
>
>> +{
>> +       struct ftnandc021_chip *priv = chip->priv;
>> +       struct ftnandc021_regs *regs = priv->iobase;
>
>
> struct ftnandc021_regs __iomem *regs
>
> Here and elsewhere, for "sparse" checking.
>
>

Got it, thanks

>> +       uint32_t bk = 2;        /* 64 pages */
>> +       uint32_t pg = 1;        /* 2k */
>> +       uint32_t ac = 2;        /* 5 */
>
>
> When do you actually use these default values, other than when one of the
> switch statements fail to match -- which seems like it would be an error
> condition; even if you don't explicitly check for the error it doesn't
> seem good to paper over it by providing common values that might work.
>
>

Got it, thanks.
I'll make it a fatal error when we got troubles to parse system straps.

>> +#ifdef CONFIG_FTNANDC021_ACTIMING_1
>> +       NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_1, &regs->atr[0]);
>> +#endif
>> +#ifdef CONFIG_FTNANDC021_ACTIMING_2
>> +       NAND_WRITE(CONFIG_FTNANDC021_ACTIMING_2, &regs->atr[1]);
>> +#endif
>
>
> Use CONFIG_SYS_ for things which describe hardware rather than user
> preference.  Document all CONFIG symbols (including CONFIG_SYS symbols) in
> the README.
>
>

Got it, thanks

>> +       NAND_WRITE(0, &regs->ier);
>> +       NAND_WRITE(0, &regs->pir);
>> +       NAND_WRITE(0xff, &regs->bbiwr);
>> +       NAND_WRITE(0xffffffff, &regs->lsnwr);
>> +       NAND_WRITE(0xffffffff, &regs->crcwr);
>> +
>> +       if (chip->options & NAND_BUSWIDTH_16)
>> +               NAND_WRITE(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT,
>> &regs->fcr);
>> +       else
>> +               NAND_WRITE(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
>> +
>> +       /* chip reset */
>> +       NAND_WRITE(SRR_CHIP_RESET, &regs->srr);
>> +
>> +       /* wait until chip ready */
>> +       while (NAND_READ(&regs->srr) & SRR_CHIP_RESET)
>> +               ;
>
>
> Timeout?
>
>

Got it, thanks.
I'll add a timeout for it.

>> +       switch (priv->adrc) {
>> +       case 3:
>> +               ac = 0;
>> +               break;
>> +       case 4:
>> +               ac = 1;
>> +               break;
>> +       case 5:
>> +               ac = 2;
>> +               break;
>> +       }
>
>
> ac = priv->adrc - 3;
>

Got it, thanks

>> +static inline int
>> +ftnandc021_ckst(struct ftnandc021_chip *priv)
>> +{
>> +       struct ftnandc021_regs *regs = priv->iobase;
>> +       uint32_t st = NAND_READ(&regs->idr[1]);
>> +
>> +       if (st & NAND_IOSTATUS_ERROR)
>> +               return -NAND_IOSTATUS_ERROR;
>> +
>> +       if (!(st & NAND_IOSTATUS_READY))
>> +               return -NAND_IOSTATUS_READY;
>> +
>> +       if (!(st & NAND_IOSTATUS_UNPROTCT))
>> +               return -NAND_IOSTATUS_UNPROTCT;
>> +
>> +       return 0;
>> +}
>
>
> Why the negation of NAND_IOSTATUS_*?  These aren't standard error
> codes...  you don't even use the return value at all that I see, other
> than checking zero or not-zero.
>
>

It's for my personal debugging purpose, and it would be removed at next patch.

>> +static uint8_t
>> +ftnandc021_read_byte(struct mtd_info *mtd)
>> +{
>> +       struct nand_chip *chip = mtd->priv;
>> +       struct ftnandc021_chip *priv = chip->priv;
>> +       struct ftnandc021_regs *regs = priv->iobase;
>> +       uint8_t ret = 0xff;
>> +
>> +       switch (priv->cmd) {
>> +       case NAND_CMD_READID:
>> +       case NAND_CMD_READOOB:
>> +               ret = priv->buf[priv->off % 256];
>> +               priv->off += 1;
>> +               break;
>> +       case NAND_CMD_STATUS:
>> +               ret = (uint8_t)(NAND_READ(&regs->idr[1]) & 0xff);
>> +               break;
>
>
> Why "% 256" in one case but "& 0xff" in the other?
>
>

Sorry, I don't know, too. :P
It would be fixed latter.

>> +       default:
>> +               debug("ftnandc021_read_byte: unknown cmd(0x%02X)\n",
>> +                       priv->cmd);
>
>
> This is an error, not just debug info.  Use printf.
>
>

Got it, thanks

>> +/**
>> + * Read data from NAND controller into buffer
>> + * @mtd: MTD device structure
>> + * @buf: buffer to store date
>> + * @len: number of bytes to read
>> + */
>> +static void
>> +ftnandc021_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
>> +{
>> +       struct nand_chip *chip = mtd->priv;
>> +       struct ftnandc021_chip *priv = chip->priv;
>> +       struct ftnandc021_regs *regs = priv->iobase;
>> +       ulong off;
>> +
>> +       /* oob read */
>> +       if (len <= mtd->oobsize) {
>> +               ftnandc021_read_oob(mtd, buf, len);
>> +               return;
>> +       }
>
>
> Are you sure that a length smaller than the oobsize always means that
> it's an oob read?
>
>

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

* [U-Boot] [PATCH v2 06/12] mmc: add an alternative driver to Faraday FTSDC010
  2013-04-18 10:57       ` Wolfgang Denk
@ 2013-04-22  2:51         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  2:51 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-7-git-send-email-dantesu@gmail.com> you wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday FTSDC010 is a MMC/SD host controller.
>> Although there is already a driver in current u-boot release,
>> which is modified from eSHDC and contributed by Andes Tech.
>> Its performance is too terrible on Faraday A36x SoC platforms,
>> so I turn to implement this new version of driver which is
>> 10+ times faster than the old one.
>>
>> If the hardware platform is avaiable, you may modify the
>> 'include/configs/a369_defaults.h' for performance evaluation.
>
> NAK.  Instead of adding another driver, please fix the problems of the
> original one, or replace the old one with your new, better one.  We do
> not want to have several drivers for the same piece of hardware.
>

Got it, thanks.
I plan to replace it with my own new one at next patch.
And I'll make a CC to Andes to see if they has any issue.

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> "The greatest warriors are the ones who fight for peace."
> - Holly Near



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-04-18 10:56       ` Wolfgang Denk
@ 2013-04-22  2:52         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  2:52 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-6-git-send-email-dantesu@gmail.com> you wrote:
> ...
>> +/* Register access macros */
>> +#define SPI_READ(r)                  le32_to_cpu(readl(r))
>> +#define SPI_WRITE(v, r)              writel(cpu_to_le32(v), r)
>> +#define SPI_SETBITS(m, r)    setbits_le32(r, m)
>> +#define SPI_CLRBITS(m, r)    clrbits_le32(r, m)
>
> Ad before: drop these.
>

Got it, thanks

>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>> +#define SPI_GPIO_READ(p, r)  \
>> +     le32_to_cpu(readl((p)->gpio.iobase + (r)))
>> +#define SPI_GPIO_WRITE(p, v, r)      \
>> +     writel(cpu_to_le32(v), (p)->gpio.iobase + (r))
>> +#define SPI_GPIO_SETBITS(p, m, r)    \
>> +     setbits_le32((p)->gpio.iobase + (r), m)
>> +#define SPI_GPIO_CLRBITS(p, m, r)    \
>> +     clrbits_le32((p)->gpio.iobase + (r), m)
>> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */
>
> We do not allos I/O accesses throug base addrss plus offset.
> Please use proper C structs instead.
>
>

Got it, thanks

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> Sorry, but my karma just ran over your dogma.



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 04/12] i2c: add Faraday FTI2C010 I2C controller support
  2013-04-18 10:54       ` Wolfgang Denk
@ 2013-04-22  2:52         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  2:52 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-5-git-send-email-dantesu@gmail.com> you wrote:
> ...
>> +#define I2C_READ(r)          le32_to_cpu(readl(r))
>> +#define I2C_WRITE(v, r)      writel(cpu_to_le32(v), r)
>
> Please drop these macros and use the real functions instead.
>
>

Got it, thanks

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> Little known fact about Middle Earth:   The Hobbits had a very sophi-
> sticated computer network!   It was a Tolkien Ring...



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 03/12] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-04-18 10:52       ` Wolfgang Denk
@ 2013-04-22  2:56         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-22  2:56 UTC (permalink / raw)
  To: u-boot

2013/4/18 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1366277139-29728-4-git-send-email-dantesu@gmail.com> you wrote:
>>
>> +/*******************************************************************/
>> +/*               FTMAC110 DMA design issue                         */
>> +/*                                             Dante Su 2010.02.03 */
>> +/*                                                                 */
>> +/* The DMA engine has a weird restriction that its Rx DMA engine   */
>> +/* accepts only 16-bits aligned address, 32-bits aligned is not    */
>> +/* acceptable. However this restriction does not apply to Tx DMA.  */
>> +/* Conclusion:                                                     */
>> +/* (1) Tx DMA Buffer Address:                                      */
>> +/*     1 bytes aligned: Invalid                                    */
>> +/*     2 bytes aligned: O.K                                        */
>> +/*     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)       */
>> +/* (2) Rx DMA Buffer Address:                                      */
>> +/*     1 bytes aligned: Invalid                                    */
>> +/*     2 bytes aligned: O.K                                        */
>> +/*     4 bytes aligned: Invalid                                    */
>> +/*******************************************************************/
>
> Incorrect multi-line comment style. Please fix globally.
>

Got it, thanks

>> +/* Register access macros */
>> +#define MAC_READ(r)                  le32_to_cpu(readl(r))
>> +#define MAC_WRITE(v, r)              writel(cpu_to_le32(v), r)
>
> Please drop these and use the real functions instead.
>

Got it, thanks.

>> +static char ftmac110_mac_addr[] = { 0x00, 0x41, 0x71, 0x00, 0x00, 0x52 };
>
> NAK.  We do not allow static configuration of MAC addresses.
>

Got it, thanks.

>> +     ulong ts;
>> +     uint32_t maccr;
>> +     uint16_t pa, tmp;
>
> Are you sure using  uint16_t  gives more efficient code than a plain
> int?
>

No, it won't.
It' would be fixed latter.

>> +     if (pa >= 32) {
>> +             puts("ftmac110: phy device not found!\n");
>
> make this a debug() ?
>
> ...

Got it, thanks

>> +     MAC_WRITE(0x00001010, &regs->itc);
>> +     MAC_WRITE(0x00000001, &regs->aptc);
>> +     MAC_WRITE(0x00000390, &regs->dblac);
>> +     MAC_WRITE(0x000003FF, &regs->isr);
>
> What do these magic numbers mean?
>
>

Got it, thanks.
I'll add comments to these timing control registers

>> +struct ftmac110_rxd {
>> +     /* RXDES0 */
>> +#ifdef __ARMEB__
>> +     uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
>> +     uint32_t rsvd3:1;
>> +     uint32_t frs:1;
>> +     uint32_t lrs:1;
>> +     uint32_t rsvd2:5;
>> +     uint32_t error:5;
>> +     uint32_t bcast:1;
>> +     uint32_t mcast:1;
>> +     uint32_t rsvd1:5;
>> +     uint32_t len:11;
>> +#else
>> +     uint32_t len:11;
>> +     uint32_t rsvd1:5;
>> +     uint32_t mcast:1;
>> +     uint32_t bcast:1;
>> +     uint32_t error:5;
>> +     uint32_t rsvd2:5;
>> +     uint32_t lrs:1;
>> +     uint32_t frs:1;
>> +     uint32_t rsvd3:1;
>> +     uint32_t owner:1; /* BIT: 31 - 1:Hardware, 0: Software */
>> +#endif
>
> NAK.  Please do NOT use bit fields.  They are non-portable and
> dangerous.
>
>

Got it, thanks

> Best regards,
>
> Wolfgang Denk
>
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
> A year spent in artificial intelligence is enough to make one believe
> in God.



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-22  2:45         ` Kuo-Jung Su
@ 2013-04-22 23:11           ` Scott Wood
  2013-04-23  1:19             ` Kuo-Jung Su
  2013-04-23  1:22             ` Kuo-Jung Su
  0 siblings, 2 replies; 311+ messages in thread
From: Scott Wood @ 2013-04-22 23:11 UTC (permalink / raw)
  To: u-boot

On 04/21/2013 09:45:00 PM, Kuo-Jung Su wrote:
> Sorry, it's my bad, I forget to clean it up.
> In my private base, it's possible to turn-on ECC support to FTNADC021
> with the following issues:
> 
> 1. When ECC is enabled, FTNANDC021 would always do ECC on every data  
> block,
>    including the blank block(all 0xff).
>    What I mean is 'With ECC enabled, we'll have ECC errors on non-ecc
> proected data blocks or even the blank block'.

fsl_ifc_nand is similar -- when we see an uncorrectable error, we check  
whether the page is blank.

> 2. FTNANDC021 would stop upon ECC errors, a chip reset is required to
> make it work again.

This sounds bad, though.  I assume that this is more than just  
resetting the NAND controller -- that you're resetting the entire  
system on a chip or similar?

> 3. There are only 4 bytes data + 1 byte Bad Block Info available to  
> software,
>    and because of the ECC issues above.
>    I'll have to use 1 byte of data to tag if this block is 'not  
> blank',
>    to make it possible to cancel the operation on these blocks
>    to prevent the chip to be stopped. (It means that I don't have to  
> reset chip)
>    And thus if the ECC is enabled, there are only 3 data bytes
> available to software,
>    which makes it not possible to support BBT. (BBT requres 4 data  
> bytes in OOB)

You could define a custom BBT descriptor that uses fewer bytes.

> So in this patch, I'll prefer ECC disabled.
> BTW, because of the issues above, this chip has been faced out many  
> years ago.
> It would only be available to A369 or QEMU, and never in mass  
> production.
> And thus I think it's ok to have ECC disabled in this patch.

Why do we need support in U-Boot, then?  Couldn't you just have QEMU  
model saner hardware?  What is A369?

> >> +       /* page read */
> >> +       for (off = 0; len > 0; len -= 4, off += 4) {
> >> +               while (!(NAND_READ(&regs->ior) & IOR_READY))
> >> +                       ;
> >> +               *(uint32_t *)(buf + off) = NAND_READ(&regs->dr);
> >> +       }
> >
> >
> > Why do you need to check IOR_READY here but not in read_byte?
> >
> >
> 
> Because there is no any hardware access in 'read_byte'.
> The FTNANDC021 simplily does not support byte access by default.
> (I mean it's possible to update hardware RTL code,
> but it's not the case to A369)
> So I add some tricks to READ_ID, READ_OOB and READ_STATUS.
> The actual hardware access is performed at ftnandc021_cmdfunc(),
> The ftnandc021_read_byte() simpily access the cached data buffer.

OK, so you're assuming that the OOB will never be larger than the  
256-byte software buffer?

-Scott

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-22 23:11           ` Scott Wood
@ 2013-04-23  1:19             ` Kuo-Jung Su
  2013-04-23 22:57               ` Scott Wood
  2013-04-23  1:22             ` Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-23  1:19 UTC (permalink / raw)
  To: u-boot

2013/4/23 Scott Wood <scottwood@freescale.com>:
> On 04/21/2013 09:45:00 PM, Kuo-Jung Su wrote:
>>
>> Sorry, it's my bad, I forget to clean it up.
>> In my private base, it's possible to turn-on ECC support to FTNADC021
>> with the following issues:
>>
>> 1. When ECC is enabled, FTNANDC021 would always do ECC on every data
>> block,
>>    including the blank block(all 0xff).
>>    What I mean is 'With ECC enabled, we'll have ECC errors on non-ecc
>> proected data blocks or even the blank block'.
>
>
> fsl_ifc_nand is similar -- when we see an uncorrectable error, we check
> whether the page is blank.
>
>

Good, I'm not alone....

>> 2. FTNANDC021 would stop upon ECC errors, a chip reset is required to
>> make it work again.
>
>
> This sounds bad, though.  I assume that this is more than just resetting the
> NAND controller -- that you're resetting the entire system on a chip or
> similar?
>
>

No, just reset the NAND controller. Since it's simply a peripheral device
attached to the bus, and supports only PIO mode.

>> 3. There are only 4 bytes data + 1 byte Bad Block Info available to
>> software,
>>    and because of the ECC issues above.
>>    I'll have to use 1 byte of data to tag if this block is 'not blank',
>>    to make it possible to cancel the operation on these blocks
>>    to prevent the chip to be stopped. (It means that I don't have to reset
>> chip)
>>    And thus if the ECC is enabled, there are only 3 data bytes
>> available to software,
>>    which makes it not possible to support BBT. (BBT requres 4 data bytes
>> in OOB)
>
>
> You could define a custom BBT descriptor that uses fewer bytes.
>
>

As far as I know, it's O.K to Linux, but requires some source file updated
to u-boot in old release. (i.e. u-boot-2009.01, which was the original
target release to FTNANDC021)
I'll check if it's now O.K to do that in u-boot. (I means no source
code needs to be modified, except FTNANDC021.[ch])

>> So in this patch, I'll prefer ECC disabled.
>> BTW, because of the issues above, this chip has been faced out many years
>> ago.
>> It would only be available to A369 or QEMU, and never in mass production.
>> And thus I think it's ok to have ECC disabled in this patch.
>
>
> Why do we need support in U-Boot, then?  Couldn't you just have QEMU model
> saner hardware?  What is A369?
>
>

A369 is a short for 'Faraday A369 SoC Evaluation Platform' with IC
design companies as
its target customers, which means A369 should never be the ASIC used
in mass production.
And the FTNANDC021 is actually designed for SSD applications, the
general software (e.g. linux)
is never put into consideration during IP/CHIP design process.

It's an an accident that the FTNANDC021 get integrated into the A369.
Although the NAND controller of A369 is considered a bad chip, the
NAND flash is still a primary storage
to A369. So it still needs to be integrated to U-Boot to make
everything work correctly.

The QEMU model for A369 is out several month ago, its primary target
is to provide ROM code development
environment for myself.
However 80% of the peripheral chips have been modeled at the end. (The
20% is MPEG4/H.264 and SATA)

It's now known to work properly with U-boot, eCos, Linux and even Android Linux.
So I integrate the QEMU model into my open-source Faraday SDK, and thus
the QEMU modeled A369 would be the primary target platform from now on.

That's why I think the ECC function is optional to FTNANDC021, and the
reason why I want it to be integrated to U-Boot.

BTW, I'm still struggling for QEMU contribution. So all the stuff are
still available at my own github account only.
And of course, they're not the up-to-date source tree, because the
github is actually my secondary storage.

P.S: My github account is 'dantesu1218', there you could find the
stuff described above.
If you really want to have a try on it, I'll suggest starting from
'falinux', it's a copy-cat of uClinuc & buildroot.
Which means user only needs to run 'make menuconfig', falinux would
gather all the stuff for him.

>> >> +       /* page read */
>> >> +       for (off = 0; len > 0; len -= 4, off += 4) {
>> >> +               while (!(NAND_READ(&regs->ior) & IOR_READY))
>> >> +                       ;
>> >> +               *(uint32_t *)(buf + off) = NAND_READ(&regs->dr);
>> >> +       }
>> >
>> >
>> > Why do you need to check IOR_READY here but not in read_byte?
>> >
>> >
>>
>> Because there is no any hardware access in 'read_byte'.
>> The FTNANDC021 simplily does not support byte access by default.
>> (I mean it's possible to update hardware RTL code,
>> but it's not the case to A369)
>> So I add some tricks to READ_ID, READ_OOB and READ_STATUS.
>> The actual hardware access is performed at ftnandc021_cmdfunc(),
>> The ftnandc021_read_byte() simpily access the cached data buffer.
>
>
> OK, so you're assuming that the OOB will never be larger than the 256-byte
> software buffer?
>
> -Scott



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-22 23:11           ` Scott Wood
  2013-04-23  1:19             ` Kuo-Jung Su
@ 2013-04-23  1:22             ` Kuo-Jung Su
  1 sibling, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-23  1:22 UTC (permalink / raw)
  To: u-boot

2013/4/23 Scott Wood <scottwood@freescale.com>:
> On 04/21/2013 09:45:00 PM, Kuo-Jung Su wrote:
>>
>> Sorry, it's my bad, I forget to clean it up.
>> In my private base, it's possible to turn-on ECC support to FTNADC021
>> with the following issues:
>>
>> 1. When ECC is enabled, FTNANDC021 would always do ECC on every data
>> block,
>>    including the blank block(all 0xff).
>>    What I mean is 'With ECC enabled, we'll have ECC errors on non-ecc
>> proected data blocks or even the blank block'.
>
>
> fsl_ifc_nand is similar -- when we see an uncorrectable error, we check
> whether the page is blank.
>
>
>> 2. FTNANDC021 would stop upon ECC errors, a chip reset is required to
>> make it work again.
>
>
> This sounds bad, though.  I assume that this is more than just resetting the
> NAND controller -- that you're resetting the entire system on a chip or
> similar?
>
>
>> 3. There are only 4 bytes data + 1 byte Bad Block Info available to
>> software,
>>    and because of the ECC issues above.
>>    I'll have to use 1 byte of data to tag if this block is 'not blank',
>>    to make it possible to cancel the operation on these blocks
>>    to prevent the chip to be stopped. (It means that I don't have to reset
>> chip)
>>    And thus if the ECC is enabled, there are only 3 data bytes
>> available to software,
>>    which makes it not possible to support BBT. (BBT requres 4 data bytes
>> in OOB)
>
>
> You could define a custom BBT descriptor that uses fewer bytes.
>
>
>> So in this patch, I'll prefer ECC disabled.
>> BTW, because of the issues above, this chip has been faced out many years
>> ago.
>> It would only be available to A369 or QEMU, and never in mass production.
>> And thus I think it's ok to have ECC disabled in this patch.
>
>
> Why do we need support in U-Boot, then?  Couldn't you just have QEMU model
> saner hardware?  What is A369?
>
>
>> >> +       /* page read */
>> >> +       for (off = 0; len > 0; len -= 4, off += 4) {
>> >> +               while (!(NAND_READ(&regs->ior) & IOR_READY))
>> >> +                       ;
>> >> +               *(uint32_t *)(buf + off) = NAND_READ(&regs->dr);
>> >> +       }
>> >
>> >
>> > Why do you need to check IOR_READY here but not in read_byte?
>> >
>> >
>>
>> Because there is no any hardware access in 'read_byte'.
>> The FTNANDC021 simplily does not support byte access by default.
>> (I mean it's possible to update hardware RTL code,
>> but it's not the case to A369)
>> So I add some tricks to READ_ID, READ_OOB and READ_STATUS.
>> The actual hardware access is performed at ftnandc021_cmdfunc(),
>> The ftnandc021_read_byte() simpily access the cached data buffer.
>
>
> OK, so you're assuming that the OOB will never be larger than the 256-byte
> software buffer?
>

No, that's my bad.
I don't really understand NAND flash protocol 4 years ago, I'm now
re-writing the read/write stuff
with correct column address handling.

> -Scott



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-23  1:19             ` Kuo-Jung Su
@ 2013-04-23 22:57               ` Scott Wood
  2013-04-24  1:03                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-04-23 22:57 UTC (permalink / raw)
  To: u-boot

On 04/22/2013 08:19:18 PM, Kuo-Jung Su wrote:
> 2013/4/23 Scott Wood <scottwood@freescale.com>:
> > On 04/21/2013 09:45:00 PM, Kuo-Jung Su wrote:
> >> 2. FTNANDC021 would stop upon ECC errors, a chip reset is required  
> to
> >> make it work again.
> >
> >
> > This sounds bad, though.  I assume that this is more than just  
> resetting the
> > NAND controller -- that you're resetting the entire system on a  
> chip or
> > similar?
> >
> >
> 
> No, just reset the NAND controller. Since it's simply a peripheral  
> device
> attached to the bus, and supports only PIO mode.

OK, so what's the downside to resetting the chip on an ECC error?   
Performance when reading a bunch of blank pages?

> > You could define a custom BBT descriptor that uses fewer bytes.
> >
> >
> 
> As far as I know, it's O.K to Linux, but requires some source file  
> updated
> to u-boot in old release. (i.e. u-boot-2009.01, which was the original
> target release to FTNANDC021)
> I'll check if it's now O.K to do that in u-boot. (I means no source
> code needs to be modified, except FTNANDC021.[ch])

The NAND code has been updated since then (currently corresponds to  
Linux 3.0), though I'm not sure what the problem would have been even  
back then.

> A369 is a short for 'Faraday A369 SoC Evaluation Platform' with IC
> design companies as
> its target customers, which means A369 should never be the ASIC used
> in mass production.
> And the FTNANDC021 is actually designed for SSD applications, the
> general software (e.g. linux)
> is never put into consideration during IP/CHIP design process.
> 
> It's an an accident that the FTNANDC021 get integrated into the A369.
> Although the NAND controller of A369 is considered a bad chip, the
> NAND flash is still a primary storage
> to A369. So it still needs to be integrated to U-Boot to make
> everything work correctly.
> 
> The QEMU model for A369 is out several month ago, its primary target
> is to provide ROM code development
> environment for myself.
> However 80% of the peripheral chips have been modeled at the end. (The
> 20% is MPEG4/H.264 and SATA)
> 
> It's now known to work properly with U-boot, eCos, Linux and even  
> Android Linux.
> So I integrate the QEMU model into my open-source Faraday SDK, and  
> thus
> the QEMU modeled A369 would be the primary target platform from now  
> on.
> 
> That's why I think the ECC function is optional to FTNANDC021, and the
> reason why I want it to be integrated to U-Boot.

It could still be a problem during evaluation, though I guess you don't  
support MLC NAND chips which would need it the most.  I won't block it,  
but at least make sure it prints a prominent warning message.

-Scott

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

* [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-23 22:57               ` Scott Wood
@ 2013-04-24  1:03                 ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-24  1:03 UTC (permalink / raw)
  To: u-boot

2013/4/24 Scott Wood <scottwood@freescale.com>:
> On 04/22/2013 08:19:18 PM, Kuo-Jung Su wrote:
>>
>> 2013/4/23 Scott Wood <scottwood@freescale.com>:
>> > On 04/21/2013 09:45:00 PM, Kuo-Jung Su wrote:
>> >> 2. FTNANDC021 would stop upon ECC errors, a chip reset is required to
>> >> make it work again.
>> >
>> >
>> > This sounds bad, though.  I assume that this is more than just resetting
>> > the
>> > NAND controller -- that you're resetting the entire system on a chip or
>> > similar?
>> >
>> >
>>
>> No, just reset the NAND controller. Since it's simply a peripheral device
>> attached to the bus, and supports only PIO mode.
>
>
> OK, so what's the downside to resetting the chip on an ECC error?
> Performance when reading a bunch of blank pages?
>
>

1. I'm lazy and coward.
2. It do impact the performance very much, because the ECC error is currently
   detected by a ~200ms NAND flash command timeout.

Now I plan to enable ECC in the next patch, and I'll check
if it's possible to detect ECC error more directly and cancel command wait.

P.S:
Both the RTL and datasheet of FTNANDC021 are buggy,
and the IP designer has quit from Faraday years.
I have to do it by trial and error.... so I'll always say 'I'll try....'

>> > You could define a custom BBT descriptor that uses fewer bytes.
>> >
>> >
>>
>> As far as I know, it's O.K to Linux, but requires some source file updated
>> to u-boot in old release. (i.e. u-boot-2009.01, which was the original
>> target release to FTNANDC021)
>> I'll check if it's now O.K to do that in u-boot. (I means no source
>> code needs to be modified, except FTNANDC021.[ch])
>
>
> The NAND code has been updated since then (currently corresponds to Linux
> 3.0), though I'm not sure what the problem would have been even back then.
>
>

That sounds good!
But I've found that BBT support has been dropped from default settings of Linux
by myself years ago, I simply forget it.
It means that I don't even need to create a customized BBT header.

P.S:
The BBT was turned on to accelerate bad block scan in old days.
Because the former driver written by one of my colleague, always read
a full page rather than oob only. It takes +5 min to scan bad blocks
from 256MB flash.
However the driver has been re-written with reading oob only at
several years ago,
it now takes < 1 sec to scan bad blocks from 512MB flash, so I drop
the BBT support by then.

>> A369 is a short for 'Faraday A369 SoC Evaluation Platform' with IC
>> design companies as
>> its target customers, which means A369 should never be the ASIC used
>> in mass production.
>> And the FTNANDC021 is actually designed for SSD applications, the
>> general software (e.g. linux)
>> is never put into consideration during IP/CHIP design process.
>>
>> It's an an accident that the FTNANDC021 get integrated into the A369.
>> Although the NAND controller of A369 is considered a bad chip, the
>> NAND flash is still a primary storage
>> to A369. So it still needs to be integrated to U-Boot to make
>> everything work correctly.
>>
>> The QEMU model for A369 is out several month ago, its primary target
>> is to provide ROM code development
>> environment for myself.
>> However 80% of the peripheral chips have been modeled at the end. (The
>> 20% is MPEG4/H.264 and SATA)
>>
>> It's now known to work properly with U-boot, eCos, Linux and even Android
>> Linux.
>> So I integrate the QEMU model into my open-source Faraday SDK, and thus
>> the QEMU modeled A369 would be the primary target platform from now on.
>>
>> That's why I think the ECC function is optional to FTNANDC021, and the
>> reason why I want it to be integrated to U-Boot.
>
>
> It could still be a problem during evaluation, though I guess you don't
> support MLC NAND chips which would need it the most.  I won't block it, but
> at least make sure it prints a prominent warning message.
>

Don't worry about that, I've made my mind to enable ECC at next patch.
Sorry for the mess that I've done.

> -Scott


--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 01/12] mtd: spi: winbond: add W25PXX support Kuo-Jung Su
@ 2013-04-26  8:02       ` Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 01/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
                           ` (11 more replies)
  0 siblings, 12 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

To: u-boot at lists.denx.de
CC: Albert Aribaud <albert.u.boot@aribaud.net>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

    http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

    https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU:

1. Download the QEMU source tree

    $ git clone -b qemu-1.3.0 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

    $ ./configure --target-list=arm-softmmu
    $ make
    $ make install

3. Launch u-boot with QEMU:

    $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-devel/u-boot

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (11):
  arm: add MMU/D-Cache support for Faraday cores
  net: ftgmac100: add MMU/D-cache support
  net: add Faraday FTMAC110 10/100Mbps ethernet support
  i2c: add Faraday FTI2C010 I2C controller support
  spi: add Faraday FTSPI010 SPI controller support
  mmc: update the Faraday FTSDC010 driver to fix performance issue
  mtd: nand: add Faraday FTNANDC021 NAND controller support
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support
  video: add Faraday FTLCDC200 LCD controller support
  arm: add Faraday A36x SoC platform support

 README                                    |    7 +
 arch/arm/cpu/faraday/Makefile             |   57 ++
 arch/arm/cpu/faraday/a360/Makefile        |   49 ++
 arch/arm/cpu/faraday/a369/Makefile        |   50 ++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   72 +++
 arch/arm/cpu/faraday/cmd_bootfa.c         |  132 ++++
 arch/arm/cpu/faraday/config.mk            |   33 +
 arch/arm/cpu/faraday/cpu.c                |  238 +++++++
 arch/arm/cpu/faraday/ftintc020.h          |   37 ++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  156 +++++
 arch/arm/cpu/faraday/ftpwmtmr010.h        |   41 ++
 arch/arm/cpu/faraday/fttmr010.c           |  156 +++++
 arch/arm/cpu/faraday/fwimage.h            |   38 ++
 arch/arm/cpu/faraday/fwimage2.h           |   70 +++
 arch/arm/cpu/faraday/interrupts.c         |  151 +++++
 arch/arm/cpu/faraday/reset.c              |   38 ++
 arch/arm/cpu/faraday/start.S              |  523 ++++++++++++++++
 arch/arm/cpu/u-boot.lds                   |   11 +
 arch/arm/include/asm/arch-a360/hardware.h |   73 +++
 arch/arm/include/asm/arch-a360/pmu.h      |   39 ++
 arch/arm/include/asm/arch-a360/scu.h      |   27 +
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++
 arch/arm/include/asm/arch-a369/scu.h      |   48 ++
 arch/arm/include/asm/dma-mapping.h        |   60 +-
 arch/arm/include/asm/global_data.h        |    4 +
 arch/arm/include/asm/io.h                 |  154 ++++-
 arch/arm/include/asm/mach-types.h         |    1 +
 arch/arm/include/asm/system.h             |    7 +-
 arch/arm/lib/cache-cp15.c                 |   30 +
 board/faraday/a360evb/Makefile            |   49 ++
 board/faraday/a360evb/board.c             |   65 ++
 board/faraday/a360evb/clk.c               |   57 ++
 board/faraday/a360evb/config.mk           |   33 +
 board/faraday/a360evb/lowlevel_init.S     |   33 +
 board/faraday/a369evb/Makefile            |   49 ++
 board/faraday/a369evb/board.c             |  188 ++++++
 board/faraday/a369evb/clk.c               |   72 +++
 board/faraday/a369evb/config.mk           |   33 +
 board/faraday/a369evb/lowlevel_init.S     |  136 ++++
 boards.cfg                                |    3 +
 common/usb_hub.c                          |    5 +
 drivers/i2c/Makefile                      |    1 +
 drivers/i2c/fti2c010.c                    |  360 +++++++++++
 drivers/i2c/fti2c010.h                    |   71 +++
 drivers/mmc/Makefile                      |    2 +-
 drivers/mmc/ftsdc010_esdhc.c              |  687 ---------------------
 drivers/mmc/ftsdc010_mci.c                |  375 ++++++++++++
 drivers/mtd/cfi_flash.c                   |    2 +-
 drivers/mtd/nand/Makefile                 |    1 +
 drivers/mtd/nand/ftnandc021.c             |  724 ++++++++++++++++++++++
 drivers/mtd/nand/ftnandc021.h             |  137 +++++
 drivers/net/Makefile                      |    1 +
 drivers/net/ftgmac100.c                   |   70 ++-
 drivers/net/ftmac110.c                    |  471 ++++++++++++++
 drivers/net/ftmac110.h                    |  126 ++++
 drivers/spi/Makefile                      |    1 +
 drivers/spi/ftssp010_spi.c                |  385 ++++++++++++
 drivers/spi/ftssp010_spi.h                |   86 +++
 drivers/usb/gadget/Makefile               |    1 +
 drivers/usb/gadget/fotg210.c              |  953 +++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h         |    8 +
 drivers/usb/host/Makefile                 |    1 +
 drivers/usb/host/ehci-faraday.c           |  122 ++++
 drivers/usb/host/ehci-hcd.c               |   11 +
 drivers/usb/host/ehci.h                   |    5 +
 drivers/video/Makefile                    |    1 +
 drivers/video/ftlcdc200.c                 |  144 +++++
 drivers/video/ftlcdc200_panel.c           |  210 +++++++
 include/common.h                          |   13 +
 include/configs/a360.h                    |   63 ++
 include/configs/a369-common.h             |   74 +++
 include/configs/a369.h                    |   33 +
 include/configs/a369_fa606te.h            |   26 +
 include/configs/a36x-common.h             |  303 +++++++++
 include/faraday/ftgpio010.h               |   25 +
 include/faraday/ftlcdc200.h               |  179 ++++++
 include/faraday/ftsdc010.h                |   16 +-
 include/faraday/fttmr010.h                |   17 +
 include/faraday/mmc.h                     |   16 +
 include/faraday/nand.h                    |   34 +
 include/lcd.h                             |   33 +
 include/netdev.h                          |    1 +
 include/usb/fotg210.h                     |   71 +++
 include/usb/fusbh200.h                    |   28 +
 84 files changed, 8275 insertions(+), 726 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftintc020.h
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.h
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 arch/arm/cpu/faraday/reset.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h
 delete mode 100644 drivers/mmc/ftsdc010_esdhc.c
 create mode 100644 drivers/mmc/ftsdc010_mci.c
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/mtd/nand/ftnandc021.h
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h
 create mode 100644 drivers/spi/ftssp010_spi.c
 create mode 100644 drivers/spi/ftssp010_spi.h
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/a36x-common.h
 create mode 100644 include/faraday/ftgpio010.h
 create mode 100644 include/faraday/ftlcdc200.h
 create mode 100644 include/faraday/mmc.h
 create mode 100644 include/faraday/nand.h
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v3 01/11] arm: add MMU/D-Cache support for Faraday cores
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 02/11] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
                           ` (10 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch updates the map_physmem()/unmap_physmem(), and use
them to implement dma_alloc_coherent(), dma_free_coherent().

It uses 1MB section for each mapping, and thus waste lots of
address space, however this should still be good enough for
tiny systems (i.e. u-boot).

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
 arch/arm/include/asm/dma-mapping.h |   60 +++++++++++++-
 arch/arm/include/asm/global_data.h |    4 +
 arch/arm/include/asm/io.h          |  154 ++++++++++++++++++++++++++++++++++--
 arch/arm/include/asm/system.h      |    7 +-
 arch/arm/lib/cache-cp15.c          |   30 +++++++
 drivers/mtd/cfi_flash.c            |    2 +-
 6 files changed, 243 insertions(+), 14 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..9b56d79 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -3,6 +3,9 @@
  * Stelian Pop <stelian@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
  *
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -24,22 +27,75 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H
 
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };
 
-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	*handle = (unsigned long)malloc(len);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (va && gd->arch.cpu_mmu) {
+		invalidate_dcache_range((ulong)va, (ulong)va + len);
+		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
+		if (!map)
+			free(va);
+		va = map;
+	}
+
+	if (handle)
+		*handle = virt_to_phys(va);
+
+	return va;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+}
+
+static inline void dma_free_coherent(void *vaddr, ulong len)
+{
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	unmap_physmem(vaddr, len);
+	vaddr = (void *)virt_to_phys(vaddr);
+#endif
+	free(vaddr);
 }
 
 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (unsigned long)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }
 
 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 37ac0da..bd18ff7 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -38,6 +38,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..739febd 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/io.h
  *
  *  Copyright (C) 1996-2000 Russell King
+ *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -28,9 +29,30 @@
 #if 0	/* XXX###XXX */
 #include <asm/arch/hardware.h>
 #endif	/* XXX###XXX */
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/system.h>
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#ifndef CONFIG_MMAP_START
+#define CONFIG_MMAP_START   0xd0000000
+#endif
+
+#ifndef CONFIG_MMAP_END
+#define CONFIG_MMAP_END     0xfff00000
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* arch/$(ARCH)/lib/cache.c */
+void flush_dcache_all(void);
+void flush_dcache_range(ulong start, ulong stop);
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 
 static inline void sync(void)
 {
+	flush_dcache_all();
 }
 
 /*
@@ -39,27 +61,143 @@ static inline void sync(void)
  * properties specified by "flags".
  */
 #define MAP_NOCACHE	(0)
-#define MAP_WRCOMBINE	(0)
-#define MAP_WRBACK	(0)
-#define MAP_WRTHROUGH	(0)
+#define MAP_WRCOMBINE	(1)
+#define MAP_WRBACK	(2)
+#define MAP_WRTHROUGH	(3)
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+static inline void map_flush(ulong start, ulong end)
+{
+	flush_dcache_range(start, end);
+
+	/* invalidate D-TLB */
+	start &= 0xfff00000;
+	end = (end + 0x000fffff) & 0xfff00000;
+	__asm__ __volatile__ (
+		"mov r3, %0\n"
+		"1:\n"
+		"mcr p15, 0, r3, c8, c6, 1\n"
+		"add r3, r3, #4096\n"
+		"cmp r3, %1\n"
+		"blo 1b\n"
+		: /* output */
+		: "r"(start), "r"(end) /* input */
+		: "r3" /* clobber list */
+	);
+}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 
 static inline void *
-map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+map_physmem(phys_addr_t paddr, ulong len, ulong flags)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 vaddr, nattr, oattr, addr, size, end;
+
+	/* 1. check if we have to create a mapping for it */
+	vaddr = paddr;
+	addr  = page_table[vaddr >> 20] & 0xfff00000;
+	oattr = page_table[vaddr >> 20] & 0x1f;
+	switch (flags) {
+	case MAP_WRCOMBINE:
+		nattr = DCACHE_WRITECOMBINE;
+		break;
+	case MAP_WRTHROUGH:
+		nattr = DCACHE_WRITETHROUGH;
+		break;
+	case MAP_WRBACK:
+		nattr = DCACHE_WRITEBACK;
+		break;
+	default:
+		nattr = DCACHE_OFF;
+		break;
+	}
+	if ((nattr == oattr) && (vaddr == addr))
+		return (void *)paddr;
+
+	/* 2. find a contiguous region for it */
+	end = (paddr + len + 0x000fffff) & 0xfff00000;
+	len = end - (paddr & 0xfff00000);
+	size = 0;
+	addr = CONFIG_MMAP_START;
+	vaddr = addr;
+	while (addr < CONFIG_MMAP_END) {
+		/* if va == pa, then it's free to use */
+		if (addr == (page_table[addr >> 20] & 0xfff00000)) {
+			size += SZ_1M;
+		} else {
+			size = 0;
+			vaddr = addr + SZ_1M;
+		}
+		if (size >= len)
+			break;
+		addr += SZ_1M;
+	}
+	if (size < len)
+		return NULL;
+
+	/* 3. create the map */
+	map_flush(vaddr, vaddr + size);
+	addr = vaddr;
+	vaddr += paddr & 0x000fffff;
+	paddr &= 0xfff00000;
+	while (size) {
+		page_table[addr >> 20] = paddr | (3 << 10) | nattr;
+		size -= SZ_1M;
+		addr += SZ_1M;
+		paddr += SZ_1M;
+	}
+	return (void *)vaddr;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (void *)paddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }
 
 /*
  * Take down a mapping set up by map_physmem().
  */
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
+static inline void unmap_physmem(void *vaddr, ulong len)
 {
-
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 addr, end;
+
+	/* 1. skip on NULL pointer */
+	if (!vaddr)
+		return;
+
+	/* 2. check if it's the right address map */
+	addr = (u32)vaddr;
+	if ((page_table[addr >> 20] & 0xfff00000) == addr)
+		return;
+
+	/* 3. reset the map */
+	end = (addr + len + 0x000fffff) & 0xfff00000;
+	addr &= 0xfff00000;
+	map_flush(addr, end);
+	while (addr < end) {
+		page_table[addr >> 20] = addr | (3 << 10) | DCACHE_OFF;
+		addr += SZ_1M;
+	}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }
 
-static inline phys_addr_t virt_to_phys(void * vaddr)
+static inline phys_addr_t virt_to_phys(void *vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	phys_addr_t phys = (phys_addr_t)vaddr;
+
+	if (!gd->arch.cpu_mmu || !vaddr)
+		return phys;
+
+	phys = page_table[(u32)vaddr >> 20] & 0xfff00000;
+	phys += (u32)vaddr & 0x000fffff;
+
+	return phys;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	return (phys_addr_t)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }
 
 /*
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 760345f..050b707 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -97,9 +97,10 @@ static inline void set_dacr(unsigned int val)
 
 /* options available for data cache on each page */
 enum dcache_option {
-	DCACHE_OFF = 0x12,
-	DCACHE_WRITETHROUGH = 0x1a,
-	DCACHE_WRITEBACK = 0x1e,
+	DCACHE_OFF = 0x12,          /* non-cached + non-buffered */
+	DCACHE_WRITECOMBINE = 0x16, /* non-cached + buffered */
+	DCACHE_WRITETHROUGH = 0x1a, /* cached + non-buffered */
+	DCACHE_WRITEBACK = 0x1e,    /* cached + buffered */
 };
 
 /* Size of an MMU section */
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 4abe1cf..ea29e83 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -1,6 +1,8 @@
 /*
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -98,6 +100,24 @@ __weak void dram_bank_mmu_setup(int bank)
 		set_section_dcache(i, DCACHE_WRITEBACK);
 #endif
 	}
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+
+# ifdef CONFIG_USE_IRQ
+	/* make sure the exception table is at 0x00000000 */
+	if (!bank && bd->bi_dram[bank].start) {
+		u32 pa = bd->bi_dram[bank].start;
+		u32 *page_table = (u32 *)gd->arch.tlb_addr;
+
+#  ifdef CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
+#  else
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
+#  endif
+	}
+# endif /* # ifdef CONFIG_USE_IRQ */
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }
 
 /* to activate the MMU we need to set up virtual memory: use 1M areas */
@@ -126,6 +146,10 @@ static inline void mmu_setup(void)
 
 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#ifdef CONFIG_FARADAY
+	reg |= CR_W;	/* enable write buffer */
+	reg |= CR_Z;	/* enable branch prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -140,9 +164,15 @@ static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;
 
+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
+
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | cache_bit);
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 22d8440..49bdcff 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1818,7 +1818,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)
 					break;
 				else
 					unmap_physmem((void *)info->start[0],
-						      MAP_NOCACHE);
+						      info->portwidth);
 			}
 		}
 
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 02/11] net: ftgmac100: add MMU/D-cache support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 01/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] net: update FTGMAC100 for " Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
                           ` (9 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Joe Hershberger <joe.hershberger@gmail.com>
---
 drivers/net/ftgmac100.c |   70 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 69ba57d..2dbb328 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -27,11 +27,13 @@
 #include <malloc.h>
 #include <net.h>
 #include <asm/io.h>
+#include <asm/dma-mapping.h>
 #include <linux/mii.h>
 
 #include "ftgmac100.h"
 
 #define ETH_ZLEN	60
+#define CFG_XBUF_SIZE	1536
 
 /* RBSR - hw default init value is also 0x640 */
 #define RBSR_DEFAULT_VALUE	0x640
@@ -40,8 +42,10 @@
 #define PKTBUFSTX	4	/* must be power of 2 */
 
 struct ftgmac100_data {
-	struct ftgmac100_txdes txdes[PKTBUFSTX];
-	struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+	ulong txdes_dma;
+	struct ftgmac100_txdes *txdes;
+	ulong rxdes_dma;
+	struct ftgmac100_rxdes *rxdes;
 	int tx_index;
 	int rx_index;
 	int phy_addr;
@@ -375,13 +379,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 {
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
-	struct ftgmac100_txdes *txdes = priv->txdes;
-	struct ftgmac100_rxdes *rxdes = priv->rxdes;
+	struct ftgmac100_txdes *txdes;
+	struct ftgmac100_rxdes *rxdes;
 	unsigned int maccr;
+	void *buf;
 	int i;
 
 	debug("%s()\n", __func__);
 
+	if (!priv->txdes) {
+		txdes = dma_alloc_coherent(
+			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+		if (!txdes)
+			panic("ftgmac100: out of memory\n");
+		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+		priv->txdes = txdes;
+	}
+	txdes = priv->txdes;
+
+	if (!priv->rxdes) {
+		rxdes = dma_alloc_coherent(
+			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+		if (!rxdes)
+			panic("ftgmac100: out of memory\n");
+		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+		priv->rxdes = rxdes;
+	}
+	rxdes = priv->rxdes;
+
 	/* set the ethernet address */
 	ftgmac100_set_mac_from_env(dev);
 
@@ -397,21 +422,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 
 	for (i = 0; i < PKTBUFSTX; i++) {
 		/* TXBUF_BADR */
-		txdes[i].txdes3 = 0;
+		if (!txdes[i].txdes2) {
+			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+			if (!buf)
+				panic("ftgmac100: out of memory\n");
+			txdes[i].txdes3 = virt_to_phys(buf);
+			txdes[i].txdes2 = (uint)buf;
+		}
 		txdes[i].txdes1 = 0;
 	}
 
 	for (i = 0; i < PKTBUFSRX; i++) {
 		/* RXBUF_BADR */
-		rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i];
+		if (!rxdes[i].rxdes2) {
+			buf = NetRxPackets[i];
+			rxdes[i].rxdes3 = virt_to_phys(buf);
+			rxdes[i].rxdes2 = (uint)buf;
+		}
 		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
 	}
 
 	/* transmit ring */
-	writel((unsigned int)txdes, &ftgmac100->txr_badr);
+	writel(priv->txdes_dma, &ftgmac100->txr_badr);
 
 	/* receive ring */
-	writel((unsigned int)rxdes, &ftgmac100->rxr_badr);
+	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);
 
 	/* poll receive descriptor automatically */
 	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -466,8 +501,11 @@ static int ftgmac100_recv(struct eth_device *dev)
 	debug("%s(): RX buffer %d, %x received\n",
 	       __func__, priv->rx_index, rxlen);
 
+	/* invalidate d-cache */
+	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
 	/* pass the packet up to the protocol layers. */
-	NetReceive((void *)curr_des->rxdes3, rxlen);
+	NetReceive((void *)curr_des->rxdes2, rxlen);
 
 	/* release buffer to DMA */
 	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
@@ -485,7 +523,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
 	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
-	int start;
 
 	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
 		debug("%s(): no TX descriptor available\n", __func__);
@@ -496,8 +533,8 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 
 	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;
 
-	/* initiate a transmit sequence */
-	curr_des->txdes3 = (unsigned int)packet;	/* TXBUF_BADR */
+	memcpy((void *)curr_des->txdes2, (void *)packet, length);
+	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);
 
 	/* only one descriptor on TXBUF */
 	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
@@ -509,15 +546,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	/* start transmit */
 	writel(1, &ftgmac100->txpd);
 
-	/* wait for transfer to succeed */
-	start = get_timer(0);
-	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
-		if (get_timer(0) >= 5) {
-			debug("%s(): timed out\n", __func__);
-			return -1;
-		}
-	}
-
 	debug("%s(): packet sent\n", __func__);
 
 	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 01/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 02/11] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-05-02 16:03           ` Tom Rini
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 04/11] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
                           ` (8 subsequent siblings)
  11 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTMAC110 10/100Mbps supports half-word data transfer for Linux.
However it has a weird DMA alignment issue:

(1) Tx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: O.K

(2) Rx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: Invalid!!!

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Joe Hershberger <joe.hershberger@gmail.com>
---
 drivers/net/Makefile   |    1 +
 drivers/net/ftmac110.c |  471 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ftmac110.h |  126 +++++++++++++
 include/netdev.h       |    1 +
 4 files changed, 599 insertions(+)
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 786a656..0e23817 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
 COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
+COBJS-$(CONFIG_FTMAC110) += ftmac110.o
 COBJS-$(CONFIG_FTMAC100) += ftmac100.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
new file mode 100644
index 0000000..04f886f
--- /dev/null
+++ b/drivers/net/ftmac110.c
@@ -0,0 +1,471 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#define CFG_RXDES_NUM   8
+#define CFG_TXDES_NUM   2
+#define CFG_XBUF_SIZE   1536
+
+/*
+ * FTMAC110 DMA design issue
+ *
+ * Its DMA engine has a weird restriction that its Rx DMA engine
+ * accepts only 16-bits aligned address, 32-bits aligned is not
+ * acceptable. However this restriction does not apply to Tx DMA.
+ *
+ * Conclusion:
+ * (1) Tx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
+ * (2) Rx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: Invalid
+ */
+
+struct ftmac110_chip {
+	void __iomem *regs;
+	uint32_t imr;
+	uint32_t maccr;
+	uint32_t lnkup;
+	uint32_t phy_addr;
+
+	struct ftmac110_rxd *rxd;
+	ulong                rxd_dma;
+	uint32_t             rxd_idx;
+
+	struct ftmac110_txd *txd;
+	ulong                txd_dma;
+	uint32_t             txd_idx;
+};
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint16_t ret = 0xffff;
+
+	tmp = PHYCR_READ
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT)
+		| 0x30000000;
+
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		tmp = readl(&regs->phycr);
+		if (tmp & PHYCR_READ)
+			continue;
+		break;
+	}
+
+	if (tmp & PHYCR_READ)
+		debug("ftmac110: mdio read timeout\n");
+	else
+		ret = (uint16_t)(tmp & 0xffff);
+
+	return ret;
+}
+
+static void mdio_write(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+
+	tmp = PHYCR_WRITE
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT)
+		| 0x30000000;
+
+	writel(phydata, &regs->phydr);
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		if (readl(&regs->phycr) & PHYCR_WRITE)
+			continue;
+		break;
+	}
+
+	if (readl(&regs->phycr) & PHYCR_WRITE)
+		debug("ftmac110: mdio write timeout\n");
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+	ulong ts;
+	uint32_t maccr;
+	uint16_t pa, tmp;
+	struct ftmac110_chip *chip = dev->priv;
+
+	maccr = MACCR_100M | MACCR_FD;
+
+	/* 0. find the phy device  */
+	for (pa = 0; pa < 32; ++pa) {
+		tmp = mdio_read(dev, pa, MII_PHYSID1);
+		if (tmp == 0xFFFF || tmp == 0x0000)
+			continue;
+		break;
+	}
+	if (pa >= 32) {
+		puts("ftmac110: phy device not found!\n");
+		return maccr;
+	} else {
+		chip->phy_addr = pa;
+	}
+
+	/* 1. check link status */
+	chip->lnkup = 0;
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		if (mdio_read(dev, chip->phy_addr, MII_BMSR)
+			& BMSR_LSTATUS) {
+			chip->lnkup = 1;
+			break;
+		}
+	}
+	if (!chip->lnkup) {
+		puts("ftmac110: link down\n");
+		goto exit;
+	}
+
+	/* 2. check A/N status */
+	for (ts = get_timer(0); get_timer(ts) < 1000; ) {
+		if (mdio_read(dev, chip->phy_addr, MII_BMSR)
+			& BMSR_ANEGCOMPLETE)
+			break;
+	}
+	if (get_timer(ts) >= 1000) {
+		puts("ftmac110: A/N failed\n");
+		goto exit;
+	}
+
+	/* 3. build MACCR with the PHY status */
+	tmp  = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
+	tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
+
+	/* 3-1. 10/100Mbps Detection */
+	if (tmp & LPA_100FULL)        /* 100Mbps full-duplex */
+		maccr = MACCR_100M | MACCR_FD;
+	else if (tmp & LPA_100HALF)   /* 100Mbps half-duplex */
+		maccr = MACCR_100M;
+	else if (tmp & LPA_10FULL)    /* 10Mbps full-duplex */
+		maccr = MACCR_FD;
+	else if (tmp & LPA_10HALF)    /* 10Mbps half-duplex */
+		maccr = 0;
+	else
+		maccr = MACCR_100M | MACCR_FD;
+
+	printf("ftmac110: %d Mbps, %s\n",
+		   (maccr & MACCR_100M) ? 100 : 10,
+		   (maccr & MACCR_FD) ? "Full" : "half");
+
+exit:
+	return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+	uint8_t *a;
+	uint32_t i, maccr;
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+
+	/* 1. MAC reset */
+	writel(MACCR_RESET, &regs->maccr);
+	for (i = get_timer(0); get_timer(i) < 1000; ) {
+		if (readl(&regs->maccr) & MACCR_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->maccr) & MACCR_RESET) {
+		printf("ftmac110: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* 1-1. Init tx ring */
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		/* owned by SW */
+		chip->txd[i].ctrl = 0;
+	}
+	chip->txd_idx = 0;
+
+	/* 1-2. Init rx ring */
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		/* owned by HW */
+		chip->rxd[i].ctrl = cpu_to_le32(FTMAC110_RXCTRL_OWNER);
+	}
+	chip->rxd_idx = 0;
+
+	/* 2. PHY status query */
+	maccr = ftmac110_phyqry(dev);
+
+	/* 3. Fix up the MACCR value */
+	chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+		| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+	chip->imr = 0;
+
+	/* 4. MAC address setup */
+	a = dev->enetaddr;
+	writel(a[1] | (a[0] << 8), &regs->mac[0]);
+	writel(a[5] | (a[4] << 8) | (a[3] << 16)
+		| (a[2] << 24), &regs->mac[1]);
+
+	/* 5. MAC registers setup */
+	writel(chip->rxd_dma, &regs->rxbar);
+	writel(chip->txd_dma, &regs->txbar);
+	/* interrupt at every packet transmit/receive */
+	writel(0x00001010, &regs->itc);
+	/* tx/rx poll interval=5.12us; rx_poll_cnt=1 */
+	writel(0x00000001, &regs->aptc);
+	/* rx fifo: high=1536, low=512 */
+	writel(0x00000390, &regs->dblac);
+	/* clear all interrupt status */
+	writel(0x000003FF, &regs->isr);
+	writel(chip->imr, &regs->imr);
+	writel(chip->maccr, &regs->maccr);
+
+	return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+	debug("ftmac110: probe\n");
+
+	if (ftmac110_reset(dev))
+		return -1;
+
+	return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+
+	writel(0, &regs->imr);
+	writel(0, &regs->maccr);
+
+	debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *packet, int length)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	struct ftmac110_txd *des;
+
+	if (!chip->lnkup)
+		return 0;
+
+	if (length <= 0 || length > CFG_XBUF_SIZE) {
+		printf("ftmac110: bad tx packet length(%d)\n", length);
+		return 0;
+	}
+
+	if (length < 60)
+		length = 60;
+
+	des = &chip->txd[chip->txd_idx];
+	if (le32_to_cpu(des->ctrl) & FTMAC110_TXCTRL_OWNER) {
+		/* kick-off Tx DMA */
+		writel(0xffffffff, &regs->txpd);
+		printf("ftmac110: out of txd\n");
+		return 0;
+	}
+
+	memcpy(des->vbuf, (void *)packet, length);
+	dma_map_single(des->vbuf, length, DMA_TO_DEVICE);
+
+	/* update length, fts and lts */
+	des->conf &= cpu_to_le32(0xe0000000);
+	des->conf |= cpu_to_le32(length
+		| FTMAC110_TXCONF_FTS | FTMAC110_TXCONF_LTS);
+
+	/* set owner bit and clear others */
+	des->ctrl = cpu_to_le32(FTMAC110_TXCTRL_OWNER);
+
+	/* kick-off Tx DMA */
+	writel(0xffffffff, &regs->txpd);
+
+	chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
+
+	return length;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_rxd *des;
+	uint32_t ctrl, len, rlen = 0;
+	uint8_t *buf;
+
+	if (!chip->lnkup)
+		return 0;
+
+	do {
+		des = &chip->rxd[chip->rxd_idx];
+		ctrl = le32_to_cpu(des->ctrl);
+		if (ctrl & FTMAC110_RXCTRL_OWNER)
+			break;
+
+		len = ctrl & FTMAC110_RXCTRL_LEN_MASK;
+		buf = des->vbuf;
+
+		if (ctrl & FTMAC110_RXCTRL_ERRMASK) {
+			printf("ftmac110: rx error\n");
+		} else {
+			dma_map_single(buf, len, DMA_FROM_DEVICE);
+			NetReceive(buf, len);
+			rlen += len;
+		}
+
+		/* owned by hardware */
+		des->ctrl = cpu_to_le32(FTMAC110_RXCTRL_OWNER);
+
+		chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
+	} while (0);
+
+	return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		*value = mdio_read(dev, addr, reg);
+	}
+
+	return ret;
+}
+
+static int ftmac110_mdio_write(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		mdio_write(dev, addr, reg, value);
+	}
+
+	return ret;
+}
+
+#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+	int i, card_nr = 0;
+	struct eth_device *dev;
+	struct ftmac110_chip *chip;
+
+	dev = malloc(sizeof(*dev) + sizeof(*chip));
+	if (dev == NULL) {
+		panic("ftmac110: out of memory 1\n");
+		return -1;
+	}
+	chip = (struct ftmac110_chip *)(dev + 1);
+	memset(dev, 0, sizeof(*dev) + sizeof(*chip));
+
+	sprintf(dev->name, "FTMAC110#%d", card_nr);
+
+	dev->iobase = CONFIG_FTMAC110_BASE;
+	chip->regs = (void __iomem *)dev->iobase;
+	dev->priv = chip;
+	dev->init = ftmac110_probe;
+	dev->halt = ftmac110_halt;
+	dev->send = ftmac110_send;
+	dev->recv = ftmac110_recv;
+
+	if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
+		eth_random_enetaddr(dev->enetaddr);
+
+	/* allocate tx descriptors (it must be 16 bytes aligned) */
+	chip->txd = dma_alloc_coherent(
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
+	if (!chip->txd)
+		panic("ftmac110: out of memory 3\n");
+	memset(chip->txd, 0,
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+		if (!va)
+			panic("ftmac110: out of memory 4\n");
+		chip->txd[i].vbuf  = va;
+		chip->txd[i].buf = cpu_to_le32(virt_to_phys(va));
+		chip->txd[i].conf = 0;
+		chip->txd[i].ctrl = 0; /* owned by SW */
+	}
+	chip->txd[i - 1].conf |= cpu_to_le32(FTMAC110_TXCONF_END);
+	chip->txd_idx = 0;
+
+	/* allocate rx descriptors (it must be 16 bytes aligned) */
+	chip->rxd = dma_alloc_coherent(
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
+	if (!chip->rxd)
+		panic("ftmac110: out of memory 4\n");
+	memset((void *)chip->rxd, 0,
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+		if (!va)
+			panic("ftmac110: out of memory 5\n");
+		/* it needs to be exactly 2 bytes aligned */
+		va = ((uint8_t *)va + 2);
+		chip->rxd[i].vbuf = va;
+		chip->rxd[i].buf = cpu_to_le32(virt_to_phys(va));
+		chip->rxd[i].conf = cpu_to_le32(CFG_XBUF_SIZE);
+		chip->rxd[i].ctrl = cpu_to_le32(FTMAC110_RXCTRL_OWNER);
+	}
+	chip->rxd[i - 1].conf |= cpu_to_le32(FTMAC110_RXCONF_END);
+	chip->rxd_idx = 0;
+
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+	card_nr++;
+
+	return card_nr;
+}
diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h
new file mode 100644
index 0000000..3db3468
--- /dev/null
+++ b/drivers/net/ftmac110.h
@@ -0,0 +1,126 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTMAC110_H
+#define _FTMAC110_H
+
+struct ftmac110_regs {
+	uint32_t isr;    /* 0x00: Interrups Status Register */
+	uint32_t imr;    /* 0x04: Interrupt Mask Register */
+	uint32_t mac[2]; /* 0x08: MAC Address */
+	uint32_t mht[2]; /* 0x10: Multicast Hash Table 0 Register */
+	uint32_t txpd;   /* 0x18: Transmit Poll Demand Register */
+	uint32_t rxpd;   /* 0x1c: Receive Poll Demand register */
+	uint32_t txbar;  /* 0x20: Tx Ring Base Address Register */
+	uint32_t rxbar;  /* 0x24: Rx Ring Base Address Register */
+	uint32_t itc;    /* 0x28: Interrupt Timer Control Register */
+	uint32_t aptc;   /* 0x2C: Automatic Polling Timer Control Register */
+	uint32_t dblac;  /* 0x30: DMA Burst Length&Arbitration Control */
+	uint32_t revr;   /* 0x34: Revision Register */
+	uint32_t fear;   /* 0x38: Feature Register */
+	uint32_t rsvd[19];
+	uint32_t maccr;  /* 0x88: MAC Control Register */
+	uint32_t macsr;  /* 0x8C: MAC Status Register */
+	uint32_t phycr;  /* 0x90: PHY Control Register */
+	uint32_t phydr;  /* 0x94: PHY Data Register */
+	uint32_t fcr;    /* 0x98: Flow Control Register */
+	uint32_t bpr;    /* 0x9C: Back Pressure Register */
+};
+
+/* Interrupt status/mask register(ISR/IMR) bits */
+#define ISR_PHYSTCHG     (1 << 9) /* phy status change */
+#define ISR_AHBERR       (1 << 8) /* bus error */
+#define ISR_RXLOST       (1 << 7) /* rx lost due to fifo overflow */
+#define ISR_RXFIFO       (1 << 6) /* rx to fifo */
+#define ISR_TXLOST       (1 << 5) /* tx lost due to collision */
+#define ISR_TXOK         (1 << 4) /* tx to ethernet */
+#define ISR_NOTXBUF      (1 << 3) /* out of tx buffer */
+#define ISR_TXFIFO       (1 << 2) /* packets transmitted to fifo */
+#define ISR_NORXBUF      (1 << 1) /* out of rx buffer */
+#define ISR_RXOK         (1 << 0) /* packets received to buffer (ram) */
+
+/* MACC control bits */
+#define MACCR_100M       (1 << 18) /* 100Mbps mode */
+#define MACCR_RXBCST     (1 << 17) /* receive all broadcast packet */
+#define MACCR_RXMCST     (1 << 16) /* receive all multicast packet */
+#define MACCR_FD         (1 << 15) /* full duplex */
+#define MACCR_CRCAPD     (1 << 14) /* append crc to transmit packet */
+#define MACCR_RXALL      (1 << 12) /* ignore dst address */
+#define MACCR_RXFTL      (1 << 11) /* rx packet even it's > 1518 byte */
+#define MACCR_RXRUNT     (1 << 10) /* rx packet even it's < 64 byte */
+#define MACCR_RXMCSTHT   (1 << 9)  /* rx multicast per hash table */
+#define MACCR_RXEN       (1 << 8)  /* rx enable */
+#define MACCR_RXINHDTX   (1 << 6)  /* rx in half duplex tx */
+#define MACCR_TXEN       (1 << 5)  /* tx enable */
+#define MACCR_CRCDIS     (1 << 4)  /* rx packet even it's crc error */
+#define MACCR_LOOPBACK   (1 << 3)  /* Internal loop-back */
+#define MACCR_RESET      (1 << 2)  /* reset */
+#define MACCR_RXDMAEN    (1 << 1)  /* enable rx dma */
+#define MACCR_TXDMAEN    (1 << 0)  /* enable tx dma */
+
+/* MDIO PHY bits */
+#define PHYCR_READ       (1 << 26)
+#define PHYCR_WRITE      (1 << 27)
+#define PHYCR_REG_SHIFT  21
+#define PHYCR_ADDR_SHIFT 16
+
+/*
+ * descriptor structure
+ */
+struct ftmac110_rxd {
+	/* Hardware control fields */
+	uint32_t ctrl;
+	uint32_t conf;
+	uint32_t buf;
+
+	/* Software control field */
+	void *vbuf;
+};
+
+#define FTMAC110_RXCTRL_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_RXCTRL_FRS         BIT_MASK(29) /* 1st pkt desc */
+#define FTMAC110_RXCTRL_LRS         BIT_MASK(28) /* last pkt desc */
+#define FTMAC110_RXCTRL_ODDNB       BIT_MASK(22) /* odd nibble */
+#define FTMAC110_RXCTRL_RUNT        BIT_MASK(21) /* runt pkt */
+#define FTMAC110_RXCTRL_FTL         BIT_MASK(20) /* frame too long */
+#define FTMAC110_RXCTRL_CRC         BIT_MASK(19) /* pkt crc error */
+#define FTMAC110_RXCTRL_ERR         BIT_MASK(18) /* bus error */
+#define FTMAC110_RXCTRL_ERRMASK     (0x1f << 18) /* all errors */
+#define FTMAC110_RXCTRL_BCST        BIT_MASK(17) /* Bcst pkt */
+#define FTMAC110_RXCTRL_MCST        BIT_MASK(16) /* Mcst pkt */
+#define FTMAC110_RXCTRL_LEN_MASK    0x7ff
+#define FTMAC110_RXCTRL_LEN_SHIFT   0
+
+#define FTMAC110_RXCONF_END         BIT_MASK(31)
+#define FTMAC110_RXCONF_BUFSZ_MASK  0x7ff
+#define FTMAC110_RXCONF_BUFSZ_SHIFT 0
+
+struct ftmac110_txd {
+	/* Hardware control fields */
+	uint32_t ctrl;
+	uint32_t conf;
+	uint32_t buf;
+
+	/* Software control field */
+	void *vbuf;
+};
+
+#define FTMAC110_TXCTRL_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_TXCTRL_COL         0x00000003   /* collision */
+
+#define FTMAC110_TXCONF_END         BIT_MASK(31) /* end of ring */
+#define FTMAC110_TXCONF_TXIC        BIT_MASK(30) /* tx done interrupt */
+#define FTMAC110_TXCONF_TX2FIC      BIT_MASK(29) /* tx fifo interrupt */
+#define FTMAC110_TXCONF_FTS         BIT_MASK(28) /* 1st pkt desc */
+#define FTMAC110_TXCONF_LTS         BIT_MASK(27) /* last pkt desc */
+#define FTMAC110_TXCONF_BUFSZ_MASK  0x7ff
+#define FTMAC110_TXCONF_BUFSZ_SHIFT 0
+
+#endif  /* FTMAC110_H */
diff --git a/include/netdev.h b/include/netdev.h
index fd3e243..48c2fe5 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -67,6 +67,7 @@ int fecmxc_initialize(bd_t *bis);
 int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
 int ftgmac100_initialize(bd_t *bits);
 int ftmac100_initialize(bd_t *bits);
+int ftmac110_initialize(bd_t *bits);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 04/11] i2c: add Faraday FTI2C010 I2C controller support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (2 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-04-29  3:34           ` Heiko Schocher
  2013-05-07  6:32           ` [U-Boot] [PATCH v4 03/16] " Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 05/11] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
                           ` (7 subsequent siblings)
  11 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTI2C010 is a multi-function I2C controller
which supports both master and slave mode.
This patch simplily implements the master mode only.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Heiko Schocher <hs@denx.de>
---
 drivers/i2c/Makefile   |    1 +
 drivers/i2c/fti2c010.c |  360 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/fti2c010.h |   71 ++++++++++
 3 files changed, 432 insertions(+)
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 5dbdbe3..ed2b8c0 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
 COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
 COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
 COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
+COBJS-$(CONFIG_FTI2C010) += fti2c010.o
 COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
 COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
 COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
new file mode 100644
index 0000000..52a46bf
--- /dev/null
+++ b/drivers/i2c/fti2c010.c
@@ -0,0 +1,360 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+
+#include "fti2c010.h"
+
+#define I2C_RD        1
+#define I2C_WR        0
+
+struct fti2c010_chip {
+	void __iomem *regs;
+	uint32_t bus;
+	uint32_t speed;
+};
+
+#if defined(CONFIG_HARD_I2C)
+
+static struct fti2c010_chip chip_list[] = {
+#ifdef CONFIG_I2C_MULTI_BUS
+# ifdef CONFIG_FTI2C010_BASE
+	{
+		.bus   = 0,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE1
+	{
+		.bus   = 1,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE1,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE2
+	{
+		.bus   = 2,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE2,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE3
+	{
+		.bus   = 3,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE3,
+	},
+# endif
+#else    /* #ifdef CONFIG_I2C_MULTI_BUS */
+	{
+		.bus   = 0,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE,
+	},
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+};
+
+static struct fti2c010_chip *priv = chip_list;
+
+static int fti2c010_wait(uint32_t mask)
+{
+	int ret = -1;
+	uint32_t stat, t;
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	for (t = get_timer(0); get_timer(t) < 100; ) {
+		stat = readl(&regs->sr);
+		if ((stat & mask) == mask) {
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * u-boot I2C API
+ */
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+	if (speed || priv->speed == 0)
+		i2c_set_bus_speed(speed);
+}
+
+/*
+ * Probe the given I2C chip address.  Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uchar chip)
+{
+	int rc;
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	/* 1. Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_WR, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* 2. Select device register */
+	writel(0, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_WR, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		writel(paddr[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Get register data
+	 */
+
+	/* B.1 Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_RD, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* B.2 Get register data */
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		uint32_t stat = SR_DR;
+		if (pos == len - 1) {
+			ctrl |= CR_NAK | CR_STOP;
+			stat |= SR_ACK;
+		}
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(stat);
+		if (rc)
+			break;
+		buf[pos] = (uchar)(readl(&regs->dr) & 0xFF);
+	}
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_WR, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		writel(paddr[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Set register data
+	 */
+
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		if (pos == len - 1)
+			ctrl |= CR_STOP;
+		writel(buf[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
+ * Functions for setting the current I2C bus and its speed
+ */
+#ifdef CONFIG_I2C_MULTI_BUS
+
+/*
+ * i2c_set_bus_num:
+ *
+ *  Change the active I2C bus.  Subsequent read/write calls will
+ *  go to this one.
+ *
+ *    bus - bus index, zero based
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_num(unsigned int bus)
+{
+	if (bus >= sizeof(chip_list) / sizeof(chip_list[0]))
+		return -1;
+	priv = chip_list + bus;
+	i2c_init(5000, 0);
+	return 0;
+}
+
+/*
+ * i2c_get_bus_num:
+ *
+ *  Returns index of currently active I2C bus.  Zero-based.
+ */
+
+unsigned int i2c_get_bus_num(void)
+{
+	return priv->bus;
+}
+
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+
+/*
+ * i2c_set_bus_speed:
+ *
+ *  Change the speed of the active I2C bus
+ *
+ *    speed - bus speed in Hz
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_speed(unsigned int speed)
+{
+	struct fti2c010_regs __iomem *regs = priv->regs;
+#ifdef CONFIG_FTI2C010_SCLK
+	ulong apb = CONFIG_FTI2C010_SCLK;
+#else
+	ulong apb = clk_get_rate("I2C");
+#endif
+	ulong div = 0x640;
+	ulong gsr = 0;
+	ulong tsr = 0x20;
+	ulong ts;
+
+	writel(BIT_MASK(0), &regs->cr);
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		if (!(readl(&regs->cr) & BIT_MASK(0)))
+			break;
+	}
+
+	/* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
+	priv->speed = apb / (2 * (div + 2) + gsr);
+
+	if (speed > 0) {
+		for (div = 0; div < 0x1000000; ++div) {
+			priv->speed = apb / (2 * (div + 2) + gsr);
+			if (priv->speed < speed)
+				break;
+		}
+	}
+
+	writel((gsr << 10) | tsr, &regs->tgsr);
+	writel(div, &regs->cdr);
+
+	return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ *  Returns speed of currently active I2C bus in Hz
+ */
+
+unsigned int i2c_get_bus_speed(void)
+{
+	return priv->speed;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/fti2c010.h b/drivers/i2c/fti2c010.h
new file mode 100644
index 0000000..214f55a
--- /dev/null
+++ b/drivers/i2c/fti2c010.h
@@ -0,0 +1,71 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTI2C010_H
+#define _FTI2C010_H
+
+/*
+ * FTI2C010 registers
+ */
+struct fti2c010_regs {
+	uint32_t cr;  /* 0x00: control register */
+	uint32_t sr;  /* 0x04: status register */
+	uint32_t cdr; /* 0x08: clock division register */
+	uint32_t dr;  /* 0x0c: data register */
+	uint32_t sar; /* 0x10: slave address register */
+	uint32_t tgsr;/* 0x14: time & glitch suppression register */
+	uint32_t bmr; /* 0x18: bus monitor register */
+	uint32_t rsvd[5];
+	uint32_t revr;/* 0x30: revision register */
+};
+
+/*
+ * REG_CTRL
+ */
+#define CR_ALIEN      0x2000  /* Arbitration lose */
+#define CR_SAMIEN     0x1000  /* slave address match */
+#define CR_STOPIEN    0x800   /* stop condition */
+#define CR_BERRIEN    0x400   /* non ACK response */
+#define CR_DRIEN      0x200   /* data receive */
+#define CR_DTIEN      0x100   /* data transmit */
+#define CR_TBEN       0x80    /* transfer byte enable */
+#define CR_NAK        0x40    /* NACK */
+#define CR_STOP       0x20    /* stop */
+#define CR_START      0x10    /* start */
+#define CR_GCEN       0x8     /* general call */
+#define CR_SCLEN      0x4     /* enable clock */
+#define CR_I2CEN      0x2     /* enable I2C */
+#define CR_I2CRST     0x1     /* reset I2C */
+#define CR_ENABLE	\
+	(CR_ALIEN | CR_SAMIEN | CR_STOPIEN | CR_BERRIEN \
+	| CR_DRIEN | CR_DTIEN | CR_SCLEN | CR_I2CEN)
+
+/*
+ * REG_STAT
+ */
+#define SR_CLRAL      0x400
+#define SR_CLRGC      0x200
+#define SR_CLRSAM     0x100
+#define SR_CLRSTOP    0x80
+#define SR_CLRBERR    0x40
+#define SR_DR         0x20     /* DR received one new data byte */
+#define SR_DT         0x10     /* DR trandmitted one new data byte */
+#define SR_BB         0x8
+#define SR_BUSY       0x4
+#define SR_ACK        0x2
+#define SR_RW         0x1
+
+/*
+ * REG_BMR
+ */
+#define BMR_SCL         0x2
+#define BMR_SDA         0x1
+
+#endif /* EOF */
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 05/11] spi: add Faraday FTSPI010 SPI controller support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (3 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 04/11] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-05-07  6:34           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue Kuo-Jung Su
                           ` (6 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FTSSP010 is a multi-function controller
which supports I2S/SPI/SSP/AC97/SPDIF.
This patch simpily implements the SPI mode only.
BTW the DMA and CS/Clock control logic has been
altered since revision 1.19.0. So this patch
would 1st detects the revision id of the underlying
chip, and then switch to the corresponding control
routines.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
---
 drivers/spi/Makefile        |    1 +
 drivers/spi/ftssp010_spi.c  |  385 +++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/ftssp010_spi.h  |   86 ++++++++++
 include/faraday/ftgpio010.h |   25 +++
 4 files changed, 497 insertions(+)
 create mode 100644 drivers/spi/ftssp010_spi.c
 create mode 100644 drivers/spi/ftssp010_spi.h
 create mode 100644 include/faraday/ftgpio010.h

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d08609e..947d60e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
 COBJS-$(CONFIG_CF_SPI) += cf_spi.o
 COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
 COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
+COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
 COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
 COBJS-$(CONFIG_ICH_SPI) +=  ich.o
 COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
new file mode 100644
index 0000000..bc873c9
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.c
@@ -0,0 +1,385 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <malloc.h>
+
+#include <faraday/ftgpio010.h>
+#include "ftssp010_spi.h"
+
+struct ftssp010_chip {
+	void __iomem *regs;
+	uint32_t fifo;
+	uint32_t rev;
+	uint32_t div;
+	uint32_t mode;
+
+	struct {
+		void __iomem *regs;
+		uint32_t      pin;
+	} gpio;
+};
+
+static struct ftssp010_chip chip_list[] = {
+#ifdef CONFIG_FTSSP010_BASE
+	{
+		.regs = (void __iomem *)CONFIG_FTSSP010_BASE,
+# ifdef CONFIG_FTSSP010_GPIO_BASE
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE,
+			CONFIG_FTSSP010_GPIO_PIN
+		},
+# endif
+	},
+#endif /* #ifdef CONFIG_FTSSP010_BASE */
+#ifdef CONFIG_FTSSP010_BASE1
+	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE1, },
+# ifdef CONFIG_FTSSP010_GPIO_BASE1
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE1,
+			CONFIG_FTSSP010_GPIO_PIN1
+		},
+# endif
+#endif
+#ifdef CONFIG_FTSSP010_BASE2
+	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE2, },
+# ifdef CONFIG_FTSSP010_GPIO_BASE2
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE2,
+			CONFIG_FTSSP010_GPIO_PIN2
+		},
+# endif
+#endif
+#ifdef CONFIG_FTSSP010_BASE3
+	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE3, },
+# ifdef CONFIG_FTSSP010_GPIO_BASE3
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE3,
+			CONFIG_FTSSP010_GPIO_PIN3
+		},
+# endif
+#endif
+};
+
+static inline int ftssp010_wait_tx(struct ftssp010_chip *chip)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		if (!(readl(&regs->sr) & SR_TFNF))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftssp010: tx timeout\n");
+
+	return ret;
+}
+
+static inline int ftssp010_wait_rx(struct ftssp010_chip *chip)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		if (!SR_RFVE(readl(&regs->sr)))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftssp010: rx timeout\n");
+
+	return ret;
+}
+
+static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t xmsk = 0;
+
+		if (tx_buf) {
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_tx(chip);
+				writel(*txb++, &regs->dr);
+			}
+			xmsk |= CR2_TXEN | CR2_TXDOE;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+		}
+		if (rx_buf) {
+			xmsk |= CR2_RXEN;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_rx(chip);
+				*rxb++ = (uint8_t)readl(&regs->dr);
+			}
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t tmp;
+
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_tx(chip);
+			writel(txb ? (*txb++) : 0, &regs->dr);
+		}
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_rx(chip);
+			tmp = readl(&regs->dr);
+			if (rxb)
+				*rxb++ = (uint8_t)tmp;
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------
+ * Determine if a SPI chipselect is valid.
+ * This function is provided by the board if the low-level SPI driver
+ * needs it to determine if a given chipselect is actually valid.
+ *
+ * Returns: 1 if bus:cs identifies a valid chip on this board, 0
+ * otherwise.
+ */
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	int ret = 0;
+	struct ftssp010_chip *chip;
+	struct ftssp010_regs __iomem *regs;
+	uint32_t txfifo, rxfifo;
+
+	if (bus >= ARRAY_SIZE(chip_list))
+		return ret;
+
+	chip = chip_list + bus;
+	regs = chip->regs;
+	chip->rev = readl(&regs->revr);
+	txfifo = FEAR_TXFIFO(readl(&regs->fear));
+	rxfifo = FEAR_RXFIFO(readl(&regs->fear));
+	chip->fifo = min(txfifo, rxfifo);
+
+	debug("ftssp010: rev=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
+
+	if (chip->rev >= 0x00011900) {
+		if (cs < 4)
+			ret = 1;
+	} else if (!cs) {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		struct ftgpio010_regs *gpio = chip->gpio.regs;
+		uint32_t mask = BIT_MASK(chip->gpio.pin);
+
+		/* setup gpio pin as an output pin */
+		setbits_le32(&gpio->dir, mask);
+		ret = 1;
+#endif
+	}
+
+	return ret;
+}
+
+/*-----------------------------------------------------------------------
+ * Activate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should activate the chip select
+ * to the device identified by "slave".
+ */
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+
+	/* cs pull low */
+	if (chip->rev >= 0x00011900) {
+		writel((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
+			| CR2_RXFCLR, &regs->cr[2]);
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		struct ftgpio010_regs *gpio = chip->gpio.regs;
+		uint32_t mask = BIT_MASK(chip->gpio.pin);
+
+		setbits_le32(&gpio->clr, mask);
+#endif
+	}
+	udelay_masked(1);
+}
+
+/*-----------------------------------------------------------------------
+ * Deactivate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should deactivate the chip
+ * select to the device identified by "slave".
+ */
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	ulong ts;
+
+	/* wait until device idle */
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		if (readl(&regs->sr) & SR_BUSY)
+			continue;
+		break;
+	}
+	if (readl(&regs->sr) & SR_BUSY)
+		printf("ftspi010: busy timeout at cs deactivate\n");
+
+	/* cs pull high */
+	if (chip->rev >= 0x00011900) {
+		writel((slave->cs << 10) | CR2_FS, &regs->cr[2]);
+	} else {
+#ifdef CONFIG_FTSSP010_GPIO_BASE
+		struct ftgpio010_regs *gpio = chip->gpio.regs;
+		uint32_t mask = BIT_MASK(chip->gpio.pin);
+
+		setbits_le32(&gpio->set, mask);
+#endif
+	}
+	udelay_masked(1);
+}
+
+void spi_init(void)
+{
+}
+
+struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
+{
+	uint32_t clk, div;
+	struct spi_slave *ss;
+	struct ftssp010_chip *chip;
+
+	if (!spi_cs_is_valid(bus, cs))
+		return NULL;
+
+	if (mode != SPI_MODE_0) {
+		printf("ftssp010: MODE%d is not supported\n", mode);
+		return NULL;
+	}
+
+	ss = malloc(sizeof(struct spi_slave));
+	if (!ss)
+		return NULL;
+
+	ss->bus = bus;
+	ss->cs  = cs;
+
+#ifdef CONFIG_FTSSP010_SCLK
+	clk = CONFIG_FTSSP010_SCLK;
+#else
+	clk = clk_get_rate("SSP");
+#endif
+	if (max_hz > 0) {
+		for (div = 0; div < 0xFFFF; ++div) {
+			if ((clk / (2 * (div + 1))) <= max_hz)
+				break;
+		}
+	} else {
+		div = 7;
+	}
+
+	chip = chip_list + bus;
+	chip->div  = div;
+	chip->mode = mode;
+
+	debug("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
+
+	return ss;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+
+	writel(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
+
+	if (chip->rev >= 0x00011900) {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
+			&regs->cr[0]);
+		writel(CR2_TXFCLR | CR2_RXFCLR,
+			&regs->cr[2]);
+	} else {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
+			&regs->cr[0]);
+		writel(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
+			&regs->cr[2]);
+	}
+
+	spi_cs_deactivate(slave);
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+
+	writel(0, &regs->cr[2]);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+			 const void *dout, void *din, unsigned long flags)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	uint32_t len = bitlen >> 3;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(slave);
+
+	if (chip->rev >= 0x00011900)
+		ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags);
+	else
+		ftssp010_spi_work_transfer(chip, dout, din, len, flags);
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(slave);
+
+	return 0;
+}
diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
new file mode 100644
index 0000000..5ad7c47
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.h
@@ -0,0 +1,86 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTSSP010_H
+#define _FTSSP010_H
+
+/* FTSSP010 HW Registers */
+struct ftssp010_regs {
+	uint32_t cr[3];/* control register */
+	uint32_t sr;   /* status register */
+	uint32_t icr;  /* interrupt control register */
+	uint32_t isr;  /* interrupt status register */
+	uint32_t dr;   /* data register */
+	uint32_t rsvd[17];
+	uint32_t revr; /* revision register */
+	uint32_t fear; /* feature register */
+};
+
+/* Control register 0  */
+#define CR0_FFMT_MASK       (7 << 12)
+#define CR0_FFMT_SSP        (0 << 12)
+#define CR0_FFMT_SPI        (1 << 12)
+#define CR0_FFMT_MICROWIRE  (2 << 12)
+#define CR0_FFMT_I2S        (3 << 12)
+#define CR0_FFMT_AC97       (4 << 12)
+#define CR0_FLASH           (1 << 11)
+#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
+#define CR0_LBM             (1 << 7)  /* Loopback mode */
+#define CR0_LSB             (1 << 6)  /* LSB first */
+#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
+#define CR0_FSJUSTIFY       (1 << 4)
+#define CR0_OPM_SLAVE       (0 << 2)
+#define CR0_OPM_MASTER      (3 << 2)
+#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
+#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
+#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
+#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
+#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
+#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
+
+/* Control Register 1 */
+
+#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
+#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
+#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
+
+/* Control Register 2 */
+#define CR2_FSOS(x)         (((x) & 0x03) << 10)	/* FS/CS Select */
+#define CR2_FS              (1 << 9)	/* FS/CS Signal Level */
+#define CR2_TXEN            (1 << 8)	/* Tx Enable */
+#define CR2_RXEN            (1 << 7)	/* Rx Enable */
+#define CR2_SSPRST          (1 << 6)	/* SSP reset */
+#define CR2_TXFCLR          (1 << 3)	/* TX FIFO Clear */
+#define CR2_RXFCLR          (1 << 2)	/* RX FIFO Clear */
+#define CR2_TXDOE           (1 << 1)	/* TX Data Output Enable */
+#define CR2_SSPEN           (1 << 0)	/* SSP Enable */
+
+/*
+ * Status Register
+ */
+#define SR_RFF       (1 << 0) /* receive FIFO full */
+#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
+#define SR_BUSY      (1 << 2) /* bus is busy */
+#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid entries */
+#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */
+
+/*
+ * Feature Register
+ */
+#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
+#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
+#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
+#define FEAR_AC97        (1 << 24)
+#define FEAR_I2S         (1 << 25)
+#define FEAR_SPI_MWR     (1 << 26)
+#define FEAR_SSP         (1 << 27)
+#define FEAR_SPDIF       (1 << 28)
+
+#endif
diff --git a/include/faraday/ftgpio010.h b/include/faraday/ftgpio010.h
new file mode 100644
index 0000000..2dc45f2
--- /dev/null
+++ b/include/faraday/ftgpio010.h
@@ -0,0 +1,25 @@
+/*
+ * Faraday GPIO Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTGPIO010_H
+#define __FTGPIO010_H
+
+struct ftgpio010_regs {
+	uint32_t out;     /* 0x00: Data Output */
+	uint32_t in;      /* 0x04: Data Input */
+	uint32_t dir;     /* 0x08: Pin Direction */
+	uint32_t bypass;  /* 0x0c: Bypass */
+	uint32_t set;     /* 0x10: Data Set */
+	uint32_t clr;     /* 0x14: Data Clear */
+	uint32_t pull_up; /* 0x18: Pull-Up Enabled */
+	uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */
+};
+
+#endif /* __FTGPIO010_H */
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (4 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 05/11] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-05-03 22:35           ` Andy Fleming
  2013-05-07  6:32           ` [U-Boot] [PATCH v4] mmc: update Faraday FTSDC010 for rw performance Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
                           ` (5 subsequent siblings)
  11 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTSDC010 is a MMC/SD host controller.
Although there is already a driver in current u-boot release,
which is modified from eSHDC and contributed by Andes Tech.

Its performance is too terrible on Faraday A36x SoC platforms,
so I turn to implement this new version of driver which is
10+ times faster than the old one.

It's carefully designed to be compatible to Andes chips,
so it should be safe to replace it.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Andy Fleming <afleming@gmail.com>
---
 drivers/mmc/Makefile         |    2 +-
 drivers/mmc/ftsdc010_esdhc.c |  687 ------------------------------------------
 drivers/mmc/ftsdc010_mci.c   |  375 +++++++++++++++++++++++
 include/faraday/ftsdc010.h   |   16 +-
 include/faraday/mmc.h        |   16 +
 5 files changed, 405 insertions(+), 691 deletions(-)
 delete mode 100644 drivers/mmc/ftsdc010_esdhc.c
 create mode 100644 drivers/mmc/ftsdc010_mci.c
 create mode 100644 include/faraday/mmc.h

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 1d6faa2..2f07168 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -32,7 +32,7 @@ endif
 COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
 COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
-COBJS-$(CONFIG_FTSDC010) += ftsdc010_esdhc.o
+COBJS-$(CONFIG_FTSDC010) += ftsdc010_mci.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
 COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c
deleted file mode 100644
index 42f0e0c..0000000
--- a/drivers/mmc/ftsdc010_esdhc.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * Copyright (C) 2011 Andes Technology Corporation
- * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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
- */
-
-#include <config.h>
-#include <common.h>
-#include <mmc.h>
-
-#include <asm/io.h>
-#include <faraday/ftsdc010.h>
-
-/*
- * supported mmc hosts
- * setting the number CONFIG_FTSDC010_NUMBER in your configuration file.
- */
-static struct mmc ftsdc010_dev[CONFIG_FTSDC010_NUMBER];
-static struct mmc_host ftsdc010_host[CONFIG_FTSDC010_NUMBER];
-
-static struct ftsdc010_mmc *ftsdc010_get_base_mmc(int dev_index)
-{
-	return (struct ftsdc010_mmc *)CONFIG_FTSDC010_BASE + dev_index;
-}
-
-#ifdef DEBUG
-static void ftsdc010_dump_reg(struct mmc_host *host)
-{
-	debug("cmd: %08x\n",		readl(&host->reg->cmd));
-	debug("argu: %08x\n",		readl(&host->reg->argu));
-	debug("rsp0: %08x\n",		readl(&host->reg->rsp0));
-	debug("rsp1: %08x\n",		readl(&host->reg->rsp1));
-	debug("rsp2: %08x\n",		readl(&host->reg->rsp2));
-	debug("rsp3: %08x\n",		readl(&host->reg->rsp3));
-	debug("rsp_cmd: %08x\n",	readl(&host->reg->rsp_cmd));
-	debug("dcr: %08x\n",		readl(&host->reg->dcr));
-	debug("dtr: %08x\n",		readl(&host->reg->dtr));
-	debug("dlr: %08x\n",		readl(&host->reg->dlr));
-	debug("status: %08x\n",		readl(&host->reg->status));
-	debug("clr: %08x\n",		readl(&host->reg->clr));
-	debug("int_mask: %08x\n",	readl(&host->reg->int_mask));
-	debug("pcr: %08x\n",		readl(&host->reg->pcr));
-	debug("ccr: %08x\n",		readl(&host->reg->ccr));
-	debug("bwr: %08x\n",		readl(&host->reg->bwr));
-	debug("dwr: %08x\n",		readl(&host->reg->dwr));
-	debug("feature: %08x\n",	readl(&host->reg->feature));
-	debug("rev: %08x\n",		readl(&host->reg->rev));
-}
-#endif
-
-static unsigned int enable_imask(struct ftsdc010_mmc *reg, unsigned int imask)
-{
-	unsigned int newmask;
-
-	newmask = readl(&reg->int_mask);
-	newmask |= imask;
-
-	writel(newmask, &reg->int_mask);
-
-	return newmask;
-}
-
-static void ftsdc010_pio_read(struct mmc_host *host, char *buf, unsigned int size)
-{
-	unsigned int fifo;
-	unsigned int fifo_words;
-	unsigned int *ptr;
-	unsigned int status;
-	unsigned int retry = 0;
-
-	/* get_data_buffer */
-	ptr = (unsigned int *)buf;
-
-	while (size) {
-		status = readl(&host->reg->status);
-		debug("%s: size: %08x\n", __func__, size);
-
-		if (status & FTSDC010_STATUS_FIFO_ORUN) {
-
-			debug("%s: FIFO OVERRUN: sta: %08x\n",
-					__func__, status);
-
-			fifo = host->fifo_len > size ?
-				size : host->fifo_len;
-
-			size -= fifo;
-
-			fifo_words = fifo >> 2;
-
-			while (fifo_words--)
-				*ptr++ = readl(&host->reg->dwr);
-
-			/*
-			 * for adding some delays for SD card to put
-			 * data into FIFO again
-			 */
-			udelay(4*FTSDC010_DELAY_UNIT);
-
-#ifdef CONFIG_FTSDC010_SDIO
-			/* sdio allow non-power-of-2 blksz */
-			if (fifo & 3) {
-				unsigned int n = fifo & 3;
-				unsigned int data = readl(&host->reg->dwr);
-
-				unsigned char *p = (unsigned char *)ptr;
-
-				while (n--) {
-					*p++ = data;
-					data >>= 8;
-				}
-			}
-#endif
-		} else {
-			udelay(1);
-			if (++retry >= FTSDC010_PIO_RETRY) {
-				debug("%s: PIO_RETRY timeout\n", __func__);
-				return;
-			}
-		}
-	}
-}
-
-static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
-			unsigned int size)
-{
-	unsigned int fifo;
-	unsigned int *ptr;
-	unsigned int status;
-	unsigned int retry = 0;
-
-	/* get data buffer */
-	ptr = (unsigned int *)buf;
-
-	while (size) {
-		status = readl(&host->reg->status);
-
-		if (status & FTSDC010_STATUS_FIFO_URUN) {
-			fifo = host->fifo_len > size ?
-				size : host->fifo_len;
-
-			size -= fifo;
-
-			fifo = (fifo + 3) >> 2;
-
-			while (fifo--) {
-				writel(*ptr, &host->reg->dwr);
-				ptr++;
-			}
-		} else {
-			udelay(1);
-			if (++retry >= FTSDC010_PIO_RETRY) {
-				debug("%s: PIO_RETRY timeout\n", __func__);
-				return;
-			}
-		}
-	}
-}
-
-static int ftsdc010_check_rsp(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int sta, clear;
-
-	sta = readl(&host->reg->status);
-	debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
-	/* check RSP TIMEOUT or FAIL */
-	if (sta & FTSDC010_STATUS_RSP_TIMEOUT) {
-		/* RSP TIMEOUT */
-		debug("%s: RSP timeout: sta: %08x\n", __func__, sta);
-
-		clear |= FTSDC010_CLR_RSP_TIMEOUT;
-		writel(clear, &host->reg->clr);
-
-		return TIMEOUT;
-	} else if (sta & FTSDC010_STATUS_RSP_CRC_FAIL) {
-		/* clear response fail bit */
-		debug("%s: RSP CRC FAIL: sta: %08x\n", __func__, sta);
-
-		clear |= FTSDC010_CLR_RSP_CRC_FAIL;
-		writel(clear, &host->reg->clr);
-
-		return COMM_ERR;
-	} else if (sta & FTSDC010_STATUS_RSP_CRC_OK) {
-
-		/* clear response CRC OK bit */
-		clear |= FTSDC010_CLR_RSP_CRC_OK;
-	}
-
-	writel(clear, &host->reg->clr);
-	return 0;
-}
-
-static int ftsdc010_check_data(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int sta, clear;
-
-	sta = readl(&host->reg->status);
-	debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
-	/* check DATA TIMEOUT or FAIL */
-	if (data) {
-
-		/* Transfer Complete */
-		if (sta & FTSDC010_STATUS_DATA_END)
-			clear |= FTSDC010_STATUS_DATA_END;
-
-		/* Data CRC_OK */
-		if (sta & FTSDC010_STATUS_DATA_CRC_OK)
-			clear |= FTSDC010_STATUS_DATA_CRC_OK;
-
-		/* DATA TIMEOUT or DATA CRC FAIL */
-		if (sta & FTSDC010_STATUS_DATA_TIMEOUT) {
-			/* DATA TIMEOUT */
-			debug("%s: DATA TIMEOUT: sta: %08x\n", __func__, sta);
-
-			clear |= FTSDC010_STATUS_DATA_TIMEOUT;
-			writel(clear, &host->reg->clr);
-
-			return TIMEOUT;
-		} else if (sta & FTSDC010_STATUS_DATA_CRC_FAIL) {
-			/* DATA CRC FAIL */
-			debug("%s: DATA CRC FAIL: sta: %08x\n", __func__, sta);
-
-			clear |= FTSDC010_STATUS_DATA_CRC_FAIL;
-			writel(clear, &host->reg->clr);
-
-			return COMM_ERR;
-		}
-		writel(clear, &host->reg->clr);
-	}
-	return 0;
-}
-
-static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-
-#ifdef CONFIG_FTSDC010_SDIO
-	unsigned int scon;
-#endif
-	unsigned int ccon;
-	unsigned int mask, tmpmask;
-	unsigned int ret;
-	unsigned int sta, i;
-
-	ret = 0;
-
-	if (data)
-		mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
-	else if (cmd->resp_type & MMC_RSP_PRESENT)
-		mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
-	else
-		mask = FTSDC010_INT_MASK_CMD_SEND;
-
-	/* write argu reg */
-	debug("%s: argu: %08x\n", __func__, host->reg->argu);
-	writel(cmd->cmdarg, &host->reg->argu);
-
-	/* setup commnad */
-	ccon = FTSDC010_CMD_IDX(cmd->cmdidx);
-
-	/* setup command flags */
-	ccon |= FTSDC010_CMD_CMD_EN;
-
-	/*
-	 * This hardware didn't support specific commands for mapping
-	 * MMC_RSP_BUSY and MMC_RSP_OPCODE. Hence we don't deal with it.
-	 */
-	if (cmd->resp_type & MMC_RSP_PRESENT) {
-		ccon |= FTSDC010_CMD_NEED_RSP;
-		mask |= FTSDC010_INT_MASK_RSP_CRC_OK |
-			FTSDC010_INT_MASK_RSP_CRC_FAIL;
-	}
-
-	if (cmd->resp_type & MMC_RSP_136)
-		ccon |= FTSDC010_CMD_LONG_RSP;
-
-	/* In Linux driver, MMC_CMD_APP_CMD is checked in last_opcode */
-	if (host->last_opcode == MMC_CMD_APP_CMD)
-		ccon |= FTSDC010_CMD_APP_CMD;
-
-#ifdef CONFIG_FTSDC010_SDIO
-	scon = readl(&host->reg->sdio_ctrl1);
-	if (host->card_type == MMC_TYPE_SDIO)
-		scon |= FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
-	else
-		scon &= ~FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
-	writel(scon, &host->reg->sdio_ctrl1);
-#endif
-
-	/* record last opcode for specifing the command type to hardware */
-	host->last_opcode = cmd->cmdidx;
-
-	/* write int_mask reg */
-	tmpmask = readl(&host->reg->int_mask);
-	tmpmask |= mask;
-	writel(tmpmask, &host->reg->int_mask);
-
-	/* write cmd reg */
-	debug("%s: ccon: %08x\n", __func__, ccon);
-	writel(ccon, &host->reg->cmd);
-
-	/* check CMD_SEND */
-	for (i = 0; i < FTSDC010_CMD_RETRY; i++) {
-		/*
-		 * If we read status register too fast
-		 * will lead hardware error and the RSP_TIMEOUT
-		 * flag will be raised incorrectly.
-		 */
-		udelay(16*FTSDC010_DELAY_UNIT);
-		sta = readl(&host->reg->status);
-
-		/* Command Complete */
-		/*
-		 * Note:
-		 *	Do not clear FTSDC010_CLR_CMD_SEND flag.
-		 *	(by writing FTSDC010_CLR_CMD_SEND bit to clear register)
-		 *	It will make the driver becomes very slow.
-		 *	If the operation hasn't been finished, hardware will
-		 *	clear this bit automatically.
-		 *	In origin, the driver will clear this flag if there is
-		 *	no data need to be read.
-		 */
-		if (sta & FTSDC010_STATUS_CMD_SEND)
-			break;
-	}
-
-	if (i > FTSDC010_CMD_RETRY) {
-		printf("%s: send command timeout\n", __func__);
-		return TIMEOUT;
-	}
-
-	/* check rsp status */
-	ret = ftsdc010_check_rsp(mmc, cmd, data);
-	if (ret)
-		return ret;
-
-	/* read response if we have RSP_OK */
-	if (ccon & FTSDC010_CMD_LONG_RSP) {
-		cmd->response[0] = readl(&host->reg->rsp3);
-		cmd->response[1] = readl(&host->reg->rsp2);
-		cmd->response[2] = readl(&host->reg->rsp1);
-		cmd->response[3] = readl(&host->reg->rsp0);
-	} else {
-		cmd->response[0] = readl(&host->reg->rsp0);
-	}
-
-	/* read/write data */
-	if (data && (data->flags & MMC_DATA_READ)) {
-		ftsdc010_pio_read(host, data->dest,
-				data->blocksize * data->blocks);
-	} else if (data && (data->flags & MMC_DATA_WRITE)) {
-		ftsdc010_pio_write(host, data->src,
-				data->blocksize * data->blocks);
-	}
-
-	/* check data status */
-	if (data) {
-		ret = ftsdc010_check_data(mmc, cmd, data);
-		if (ret)
-			return ret;
-	}
-
-	udelay(FTSDC010_DELAY_UNIT);
-	return ret;
-}
-
-static unsigned int cal_blksz(unsigned int blksz)
-{
-	unsigned int blksztwo = 0;
-
-	while (blksz >>= 1)
-		blksztwo++;
-
-	return blksztwo;
-}
-
-static int ftsdc010_setup_data(struct mmc *mmc, struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int dcon, newmask;
-
-	/* configure data transfer paramter */
-	if (!data)
-		return 0;
-
-	if (((data->blocksize - 1) & data->blocksize) != 0) {
-		printf("%s: can't do non-power-of 2 sized block transfers"
-			" (blksz %d)\n", __func__, data->blocksize);
-		return -1;
-	}
-
-	/*
-	 * We cannot deal with unaligned blocks with more than
-	 * one block being transfered.
-	 */
-	if ((data->blocksize <= 2) && (data->blocks > 1)) {
-			printf("%s: can't do non-word sized block transfers"
-				" (blksz %d)\n", __func__, data->blocksize);
-			return -1;
-	}
-
-	/* data length */
-	dcon = data->blocksize * data->blocks;
-	writel(dcon, &host->reg->dlr);
-
-	/* write data control */
-	dcon = cal_blksz(data->blocksize);
-
-	/* add to IMASK register */
-	newmask = (FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT);
-
-	/*
-	 * enable UNDERRUN will trigger interrupt immediatedly
-	 * So setup it when rsp is received successfully
-	 */
-	if (data->flags & MMC_DATA_WRITE) {
-		dcon |= FTSDC010_DCR_DATA_WRITE;
-	} else {
-		dcon &= ~FTSDC010_DCR_DATA_WRITE;
-		newmask |= FTSDC010_STATUS_FIFO_ORUN;
-	}
-	enable_imask(host->reg, newmask);
-
-#ifdef CONFIG_FTSDC010_SDIO
-	/* always reset fifo since last transfer may fail */
-	dcon |= FTSDC010_DCR_FIFO_RST;
-
-	if (data->blocks > 1)
-		dcon |= FTSDC010_SDIO_CTRL1_SDIO_BLK_MODE;
-#endif
-
-	/* enable data transfer which will be pended until cmd is send */
-	dcon |= FTSDC010_DCR_DATA_EN;
-	writel(dcon, &host->reg->dcr);
-
-	return 0;
-}
-
-static int ftsdc010_send_request(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	int ret;
-
-	if (data) {
-		ret = ftsdc010_setup_data(mmc, data);
-
-		if (ret) {
-			printf("%s: setup data error\n", __func__);
-			return -1;
-		}
-
-		if ((data->flags & MMC_DATA_BOTH_DIR) == MMC_DATA_BOTH_DIR) {
-			printf("%s: data is both direction\n", __func__);
-			return -1;
-		}
-	}
-
-	/* Send command */
-	ret = ftsdc010_send_cmd(mmc, cmd, data);
-	return ret;
-}
-
-static int ftsdc010_card_detect(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int sta;
-
-	sta = readl(&host->reg->status);
-	debug("%s: card status: %08x\n", __func__, sta);
-
-	return (sta & FTSDC010_STATUS_CARD_DETECT) ? 0 : 1;
-}
-
-static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	int ret;
-
-	if (ftsdc010_card_detect(mmc) == 0) {
-		printf("%s: no medium present\n", __func__);
-		return -1;
-	} else {
-		ret = ftsdc010_send_request(mmc, cmd, data);
-		return ret;
-	}
-}
-
-static void ftsdc010_set_clk(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned char clk_div;
-	unsigned int real_rate;
-	unsigned int clock;
-
-	debug("%s: mmc_set_clock: %x\n", __func__, mmc->clock);
-	clock = readl(&host->reg->ccr);
-
-	if (mmc->clock == 0) {
-		real_rate = 0;
-		clock |= FTSDC010_CCR_CLK_DIS;
-	} else {
-		debug("%s, mmc->clock: %08x, origin clock: %08x\n",
-			 __func__, mmc->clock, clock);
-
-		for (clk_div = 0; clk_div <= 127; clk_div++) {
-			real_rate = (CONFIG_SYS_CLK_FREQ / 2) /
-					(2 * (clk_div + 1));
-
-			if (real_rate <= mmc->clock)
-				break;
-		}
-
-		debug("%s: computed real_rate: %x, clk_div: %x\n",
-			 __func__, real_rate, clk_div);
-
-		if (clk_div > 127)
-			debug("%s: no match clock rate, %x\n",
-				__func__, mmc->clock);
-
-		clock = (clock & ~FTSDC010_CCR_CLK_DIV(0x7f)) |
-				FTSDC010_CCR_CLK_DIV(clk_div);
-
-		clock &= ~FTSDC010_CCR_CLK_DIS;
-	}
-
-	debug("%s, set clock: %08x\n", __func__, clock);
-	writel(clock, &host->reg->ccr);
-}
-
-static void ftsdc010_set_ios(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int power;
-	unsigned long val;
-	unsigned int bus_width;
-
-	debug("%s: bus_width: %x, clock: %d\n",
-		__func__, mmc->bus_width, mmc->clock);
-
-	/* set pcr: power on */
-	power = readl(&host->reg->pcr);
-	power |= FTSDC010_PCR_POWER_ON;
-	writel(power, &host->reg->pcr);
-
-	if (mmc->clock)
-		ftsdc010_set_clk(mmc);
-
-	/* set bwr: bus width reg */
-	bus_width = readl(&host->reg->bwr);
-	bus_width &= ~(FTSDC010_BWR_WIDE_8_BUS | FTSDC010_BWR_WIDE_4_BUS |
-			FTSDC010_BWR_SINGLE_BUS);
-
-	if (mmc->bus_width == 8)
-		bus_width |= FTSDC010_BWR_WIDE_8_BUS;
-	else if (mmc->bus_width == 4)
-		bus_width |= FTSDC010_BWR_WIDE_4_BUS;
-	else
-		bus_width |= FTSDC010_BWR_SINGLE_BUS;
-
-	writel(bus_width, &host->reg->bwr);
-
-	/* set fifo depth */
-	val = readl(&host->reg->feature);
-	host->fifo_len = FTSDC010_FEATURE_FIFO_DEPTH(val) * 4; /* 4 bytes */
-
-	/* set data timeout register */
-	val = -1;
-	writel(val, &host->reg->dtr);
-}
-
-static void ftsdc010_reset(struct mmc_host *host)
-{
-	unsigned int timeout;
-	unsigned int sta;
-
-	/* Do SDC_RST: Software reset for all register */
-	writel(FTSDC010_CMD_SDC_RST, &host->reg->cmd);
-
-	host->clock = 0;
-
-	/* this hardware has no reset finish flag to read */
-	/* wait 100ms maximum */
-	timeout = 100;
-
-	/* hw clears the bit when it's done */
-	while (readl(&host->reg->dtr) != 0) {
-		if (timeout == 0) {
-			printf("%s: reset timeout error\n", __func__);
-			return;
-		}
-		timeout--;
-		udelay(10*FTSDC010_DELAY_UNIT);
-	}
-
-	sta = readl(&host->reg->status);
-	if (sta & FTSDC010_STATUS_CARD_CHANGE)
-		writel(FTSDC010_CLR_CARD_CHANGE, &host->reg->clr);
-}
-
-static int ftsdc010_core_init(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int mask;
-	unsigned int major, minor, revision;
-
-	/* get hardware version */
-	host->version = readl(&host->reg->rev);
-
-	major = FTSDC010_REV_MAJOR(host->version);
-	minor = FTSDC010_REV_MINOR(host->version);
-	revision = FTSDC010_REV_REVISION(host->version);
-
-	printf("ftsdc010 hardware ver: %d_%d_r%d\n", major, minor, revision);
-
-	/* Interrupt MASK register init - mask all */
-	writel(0x0, &host->reg->int_mask);
-
-	mask = FTSDC010_INT_MASK_CMD_SEND |
-		FTSDC010_INT_MASK_DATA_END |
-		FTSDC010_INT_MASK_CARD_CHANGE;
-#ifdef CONFIG_FTSDC010_SDIO
-	mask |= FTSDC010_INT_MASK_CP_READY |
-		FTSDC010_INT_MASK_CP_BUF_READY |
-		FTSDC010_INT_MASK_PLAIN_TEXT_READY |
-		FTSDC010_INT_MASK_SDIO_IRPT;
-#endif
-
-	writel(mask, &host->reg->int_mask);
-
-	return 0;
-}
-
-int ftsdc010_mmc_init(int dev_index)
-{
-	struct mmc *mmc;
-	struct mmc_host *host;
-
-	mmc = &ftsdc010_dev[dev_index];
-
-	sprintf(mmc->name, "FTSDC010 SD/MMC");
-	mmc->priv = &ftsdc010_host[dev_index];
-	mmc->send_cmd = ftsdc010_request;
-	mmc->set_ios = ftsdc010_set_ios;
-	mmc->init = ftsdc010_core_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
-
-	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
-
-	mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
-
-	mmc->f_min = CONFIG_SYS_CLK_FREQ / 2 / (2*128);
-	mmc->f_max = CONFIG_SYS_CLK_FREQ / 2 / 2;
-
-	ftsdc010_host[dev_index].clock = 0;
-	ftsdc010_host[dev_index].reg = ftsdc010_get_base_mmc(dev_index);
-	mmc_register(mmc);
-
-	/* reset mmc */
-	host = (struct mmc_host *)mmc->priv;
-	ftsdc010_reset(host);
-
-	return 0;
-}
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
new file mode 100644
index 0000000..380f9e6
--- /dev/null
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -0,0 +1,375 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <faraday/ftsdc010.h>
+
+struct ftsdc010_chip {
+	void __iomem *regs;
+	uint32_t wprot;   /* write protected (locked) */
+	uint32_t rate;    /* actual SD clock in Hz */
+	uint32_t sclk;    /* FTSDC010 source clock in Hz */
+	uint32_t fifo;    /* fifo depth in bytes */
+	uint32_t acmd;
+};
+
+static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	int ret = TIMEOUT;
+	uint32_t ts, st;
+	uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
+	uint32_t arg   = mmc_cmd->cmdarg;
+	uint32_t flags = mmc_cmd->resp_type;
+
+	cmd |= FTSDC010_CMD_CMD_EN;
+
+	if (chip->acmd) {
+		cmd |= FTSDC010_CMD_APP_CMD;
+		chip->acmd = 0;
+	}
+
+	if (flags & MMC_RSP_PRESENT)
+		cmd |= FTSDC010_CMD_NEED_RSP;
+
+	if (flags & MMC_RSP_136)
+		cmd |= FTSDC010_CMD_LONG_RSP;
+
+	writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
+		&regs->clr);
+	writel(arg, &regs->argu);
+	writel(cmd, &regs->cmd);
+
+	if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
+		for (ts = get_timer(0); get_timer(ts) < 100; ) {
+			if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
+				writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
+				ret = 0;
+				break;
+			}
+		}
+	} else {
+		st = 0;
+		for (ts = get_timer(0); get_timer(ts) < 100; ) {
+			st = readl(&regs->status);
+			writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
+			if (st & FTSDC010_STATUS_RSP_MASK)
+				break;
+		}
+		if (st & FTSDC010_STATUS_RSP_CRC_OK) {
+			if (flags & MMC_RSP_136) {
+				mmc_cmd->response[0] = readl(&regs->rsp3);
+				mmc_cmd->response[1] = readl(&regs->rsp2);
+				mmc_cmd->response[2] = readl(&regs->rsp1);
+				mmc_cmd->response[3] = readl(&regs->rsp0);
+			} else {
+				mmc_cmd->response[0] = readl(&regs->rsp0);
+			}
+			ret = 0;
+		} else {
+			debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
+				mmc_cmd->cmdidx, st);
+		}
+	}
+
+	if (ret) {
+		debug("ftsdc010: cmd timeout (op code=%d)\n",
+			mmc_cmd->cmdidx);
+	} else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
+		chip->acmd = 1;
+	}
+
+	return ret;
+}
+
+static void ftsdc010_clkset(struct ftsdc010_chip *chip, uint32_t rate)
+{
+	uint32_t div;
+	uint32_t clk = chip->sclk;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+	for (div = 0; div < 0x7f; ++div) {
+		if (rate >= clk / (2 * (div + 1)))
+			break;
+	}
+	writel(FTSDC010_CCR_CLK_SD | FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
+
+	chip->rate = clk / (2 * (div + 1));
+}
+
+static inline int ftsdc010_is_ro(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	const uint8_t *csd = (const uint8_t *)mmc->csd;
+
+	if (chip->wprot || (csd[1] & 0x30))
+		return 1;
+
+	return 0;
+}
+
+static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
+{
+	int ret = TIMEOUT;
+	uint32_t st, ts;
+
+	for (ts = get_timer(0); get_timer(ts) < 500; ) {
+		st = readl(&regs->status);
+		if (!(st & mask))
+			continue;
+		writel(st & mask, &regs->clr);
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		debug("ftsdc010: wait st(0x%x) timeout\n", mask);
+
+	return ret;
+}
+
+/*
+ * u-boot mmc api
+ */
+
+static int ftsdc010_request(
+	struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	int ret = UNUSABLE_ERR;
+	uint32_t len = 0;
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+	if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
+		printf("ftsdc010: the card is write protected!\n");
+		return ret;
+	}
+
+	if (data) {
+		uint32_t dcr;
+
+		len = data->blocksize * data->blocks;
+
+		/* 1. data disable + fifo reset */
+		writel(FTSDC010_DCR_FIFO_RST, &regs->dcr);
+
+		/* 2. clear status register */
+		writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
+			| FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
+
+		/* 3. data timeout (1 sec) */
+		writel(chip->rate, &regs->dtr);
+
+		/* 4. data length (bytes) */
+		writel(len, &regs->dlr);
+
+		/* 5. data enable */
+		dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
+		if (data->flags & MMC_DATA_WRITE)
+			dcr |= FTSDC010_DCR_DATA_WRITE;
+		writel(dcr, &regs->dcr);
+	}
+
+	ret = ftsdc010_send_cmd(mmc, cmd);
+	if (ret) {
+		printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
+		return ret;
+	}
+
+	if (!data)
+		return ret;
+
+	if (data->flags & MMC_DATA_WRITE) {
+		const uint8_t *buf = (const uint8_t *)data->src;
+
+		while (len > 0) {
+			int wlen;
+
+			/* wait for tx ready */
+			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
+			if (ret)
+				break;
+
+			/* write bytes to ftsdc010 */
+			for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
+				writel(*(uint32_t *)buf, &regs->dwr);
+				buf  += 4;
+				wlen += 4;
+			}
+
+			len -= wlen;
+		}
+
+	} else {
+		uint8_t *buf = (uint8_t *)data->dest;
+
+		while (len > 0) {
+			int rlen;
+
+			/* wait for rx ready */
+			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
+			if (ret)
+				break;
+
+			/* fetch bytes from ftsdc010 */
+			for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
+				*(uint32_t *)buf = readl(&regs->dwr);
+				buf  += 4;
+				rlen += 4;
+			}
+
+			len -= rlen;
+		}
+
+	}
+
+	if (!ret) {
+		ret = ftsdc010_wait(regs,
+			FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
+	}
+
+	return ret;
+}
+
+static void ftsdc010_set_ios(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+	ftsdc010_clkset(chip, mmc->clock);
+
+	if (mmc->clock > 25000000)
+		setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+	else
+		clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+
+	clrbits_le32(&regs->bwr, 0x07);
+	switch (mmc->bus_width) {
+	case 4:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_WIDE_4_BUS);
+		break;
+	case 8:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_WIDE_8_BUS);
+		break;
+	default:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_SINGLE_BUS);
+		break;
+	}
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	uint32_t ts;
+
+	if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
+		return NO_CARD_ERR;
+
+	if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
+		printf("ftsdc010: write protected\n");
+		chip->wprot = 1;
+	}
+
+	chip->fifo = (readl(&regs->feature) & 0xff) << 2;
+
+	/* 1. chip reset */
+	writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
+	for (ts = get_timer(0); get_timer(ts) < 500; ) {
+		if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
+			continue;
+		break;
+	}
+	if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
+		printf("ftsdc010: reset failed\n");
+		return UNUSABLE_ERR;
+	}
+
+	/* 2. enter low speed mode (400k card detection) */
+	ftsdc010_clkset(chip, 400000);
+
+	/* 3. interrupt disabled */
+	writel(0, &regs->int_mask);
+
+	return 0;
+}
+
+int ftsdc010_mmc_init(int devid)
+{
+	struct mmc *mmc;
+	struct ftsdc010_chip *chip;
+	struct ftsdc010_mmc __iomem *regs;
+#ifdef CONFIG_FTSDC010_BASE_LIST
+	uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
+
+	if (devid < 0 || devid >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[devid];
+#else
+	regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
+#endif
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		return -ENOMEM;
+	memset(mmc, 0, sizeof(struct mmc));
+
+	chip = malloc(sizeof(struct ftsdc010_chip));
+	if (!chip) {
+		free(mmc);
+		return -ENOMEM;
+	}
+	memset(chip, 0, sizeof(struct ftsdc010_chip));
+
+	chip->regs = regs;
+	mmc->priv  = chip;
+
+	sprintf(mmc->name, "ftsdc010");
+	mmc->send_cmd = ftsdc010_request;
+	mmc->set_ios  = ftsdc010_set_ios;
+	mmc->init     = ftsdc010_init;
+
+	switch ((readl(&regs->bwr) >> 3) & 3) {
+	case 1:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz
+			| MMC_MODE_4BIT;
+		break;
+	case 2:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz
+			| MMC_MODE_4BIT | MMC_MODE_8BIT;
+		break;
+	default:
+		mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+		break;
+	}
+
+#ifdef CONFIG_SYS_CLK_FREQ
+	chip->sclk = CONFIG_SYS_CLK_FREQ;
+#else
+	chip->sclk = clk_get_rate("SDC");
+#endif
+
+	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->f_max     = chip->sclk / 2;
+	mmc->f_min     = chip->sclk / 0x100;
+	mmc->block_dev.part_type = PART_TYPE_DOS;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/include/faraday/ftsdc010.h b/include/faraday/ftsdc010.h
index c34dde7..d8c289c 100644
--- a/include/faraday/ftsdc010.h
+++ b/include/faraday/ftsdc010.h
@@ -23,6 +23,9 @@
 #define __FTSDC010_H
 
 #ifndef __ASSEMBLY__
+
+#include "mmc.h"
+
 /* sd controller register */
 struct ftsdc010_mmc {
 	unsigned int	cmd;		/* 0x00 - command reg		*/
@@ -67,9 +70,6 @@ struct mmc_host {
 	unsigned int card_type;		/* Card type */
 };
 
-/* functions */
-int ftsdc010_mmc_init(int dev_index);
-
 #endif	/* __ASSEMBLY__ */
 
 /* global defines */
@@ -143,6 +143,15 @@ int ftsdc010_mmc_init(int dev_index);
 #define FTSDC010_STATUS_SDIO_IRPT		(1 << 16) /* SDIO card intr */
 #define FTSDC010_STATUS_DATA0_STATUS		(1 << 17)
 #endif /* CONFIG_FTSDC010_SDIO */
+#define FTSDC010_STATUS_RSP_ERROR	\
+	(FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_RSP_TIMEOUT)
+#define FTSDC010_STATUS_RSP_MASK	\
+	(FTSDC010_STATUS_RSP_ERROR | FTSDC010_STATUS_RSP_CRC_OK)
+#define FTSDC010_STATUS_DATA_ERROR	\
+	(FTSDC010_STATUS_DATA_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT)
+#define FTSDC010_STATUS_DATA_MASK	\
+	(FTSDC010_STATUS_DATA_ERROR | FTSDC010_STATUS_DATA_CRC_OK \
+	| FTSDC010_STATUS_DATA_END)
 
 /* 0x2c - clear register */
 #define FTSDC010_CLR_RSP_CRC_FAIL		(1 << 0)
@@ -192,6 +201,7 @@ int ftsdc010_mmc_init(int dev_index);
 #define FTSDC010_CCR_CLK_DIV(x)			(((x) & 0x7f) << 0)
 #define FTSDC010_CCR_CLK_SD			(1 << 7) /* 0: MMC, 1: SD */
 #define FTSDC010_CCR_CLK_DIS			(1 << 8)
+#define FTSDC010_CCR_CLK_HISPD			(1 << 9) /* high speed */
 
 /* card type */
 #define FTSDC010_CARD_TYPE_SD			FTSDC010_CLOCK_REG_CARD_TYPE
diff --git a/include/faraday/mmc.h b/include/faraday/mmc.h
new file mode 100644
index 0000000..7c7bfaf
--- /dev/null
+++ b/include/faraday/mmc.h
@@ -0,0 +1,16 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FARADAY_MMC_H
+#define __FARADAY_MMC_H
+
+int ftsdc010_mmc_init(int dev_index);
+
+#endif /* _FARADAY_MMC_H */
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (5 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-04-26 23:41           ` Scott Wood
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
                           ` (4 subsequent siblings)
  11 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is a integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Scott Wood <scottwood@freescale.com>
---
 README                        |    7 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  724 +++++++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/ftnandc021.h |  137 ++++++++
 include/faraday/nand.h        |   34 ++
 5 files changed, 903 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/mtd/nand/ftnandc021.h
 create mode 100644 include/faraday/nand.h

diff --git a/README b/README
index 862bb3e..adc198f 100644
--- a/README
+++ b/README
@@ -3872,6 +3872,13 @@ Low Level (hardware related) configuration options:
 		- drivers/mtd/nand/ndfc.c
 		- drivers/mtd/nand/mxc_nand.c
 
+- CONFIG_SYS_NAND_TIMING
+		Defined to tell the NAND controller that the NAND chip is using
+		a customized timing parameters.
+		Not all NAND drivers use this symbol.
+		Example of drivers that use it:
+		- drivers/mtd/nand/ftnandc021.c
+
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
 		a default value will be used.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 35769c5..f6f89f0 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -63,6 +63,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..39c181f
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,724 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <nand.h>
+#include <malloc.h>
+#include <faraday/nand.h>
+
+#include "ftnandc021.h"
+
+#define CFG_HWECC	/* Enable hardware ECC */
+
+struct ftnandc021_chip {
+	void __iomem *regs;
+	int col;    /* current column address */
+	int row;    /* current row address/page index */
+	int cmd;    /* current NAND command code */
+	int cmd_hc; /* current FTNANDC021 command code */
+
+	struct {
+		int idx;
+		int len;
+		u8  dat[NAND_MAX_OOBSIZE];
+	} buf;
+};
+
+static struct nand_ecclayout ftnandc021_ecclayout[] = {
+	{ /* page size = 512 (oob size = 16) */
+		.eccbytes = 6,
+		.eccpos = { 0, 1, 2, 3, 6, 7 },
+		.oobfree = {
+#ifdef CFG_HWECC
+			{ 9, 3 },
+#else
+			{ 8, 4 },
+#endif
+		}
+	},
+	{ /* page size = 2048 (oob size = 64) */
+		.eccbytes = 24,
+		.eccpos = {
+			40, 41, 42, 43, 44, 45, 46, 47,
+			48, 49, 50, 51, 52, 53, 54, 55,
+			56, 57, 58, 59, 60, 61, 62, 63
+		},
+		.oobfree = {
+#ifdef CFG_HWECC
+			{ 9, 3 },
+#else
+			{ 8, 4 },
+#endif
+		},
+	},
+	{ /* page size = 4096 (oob size = 128) */
+		.eccbytes = 48,
+		.eccpos = {
+			80, 81, 82, 83, 84, 85, 86, 87,
+			88, 89, 90, 91, 92, 93, 94, 95,
+			96, 97, 98, 99, 100, 101, 102, 103,
+			104, 105, 106, 107, 108, 109, 110, 111,
+			112, 113, 114, 115, 116, 117, 118, 119,
+			120, 121, 122, 123, 124, 125, 126, 127
+		},
+		.oobfree = {
+#ifdef CFG_HWECC
+			{ 9, 7 },
+#else
+			{ 8, 8 },
+#endif
+		},
+	},
+};
+
+static inline int ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t st = readl(&regs->idr[1]);
+
+	if (st & NAND_STATUS_FAIL)
+		return -EIO;
+
+	if (!(st & NAND_STATUS_READY))
+		return -EBUSY;
+
+	if (!(st & NAND_STATUS_WP))
+		return -EIO;
+
+	return 0;
+}
+
+static inline int ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	char rc = 'c';
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < 200; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			rc = 'e';
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	switch (rc) {
+	case 'e':
+		printf("ftnandc021: ecc timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	case 'c':
+		printf("ftnandc021: cmd timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	default:
+		break;
+	}
+
+	return rc ? -ETIMEDOUT : 0;
+}
+
+#ifdef CFG_HWECC
+
+static int ftnandc021_reset(struct nand_chip *chip);
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd);
+static void ftnandc021_write_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len);
+
+static void ftnandc021_ecc_hwctl(struct mtd_info *mtd, int mode)
+{
+	/* nothing needs to be done */
+}
+
+static int ftnandc021_ecc_calculate(struct mtd_info *mtd, const uint8_t *dat,
+	uint8_t *ecc_code)
+{
+	return 0;
+}
+
+static int ftnandc021_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
+	uint8_t *read_ecc, uint8_t *calc_ecc)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t st = readl(&regs->ecc_sr);
+	int ret = 0;
+
+	if (st & ECC_SR_CERR) {
+		printf("ftnandc021: ecc corection error\n");
+		ret = -EIO;
+	} else if (st & ECC_SR_ERR) {
+		printf("ftnandc021: ecc error\n");
+		ret = -EIO;
+	}
+
+	return ret;
+}
+
+static int ftnandc021_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	printf("ftnandc021: read_page_raw is not supported\n");
+	return -EIO;
+}
+
+static void ftnandc021_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	printf("ftnandc021: write_page_raw is not supported\n");
+}
+
+#endif /* #ifdef CFG_HWECC */
+
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = 0;
+
+	priv->cmd_hc = cmd;
+
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : (We have queued data at the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+	case FTNANDC021_CMD_WRPG:
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+static int ftnandc021_reset(struct nand_chip *chip)
+{
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t ts, bk, pg, ac, mask;
+#ifdef CONFIG_SYS_NAND_TIMING
+	uint32_t timing[] = CONFIG_SYS_NAND_TIMING;
+
+	writel(timing[0], &regs->atr[0]);
+	writel(timing[1], &regs->atr[1]);
+#endif
+
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	mask = SRR_CHIP_RESET;
+#ifdef CFG_HWECC
+	mask |= SRR_ECC_EN;
+#endif
+	writel(mask, &regs->srr);
+	for (ts = get_timer(0); get_timer(ts) < 500; ) {
+		if (readl(&regs->srr) & SRR_CHIP_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->srr) & SRR_CHIP_RESET) {
+		printf("ftnandc021: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* sanity check on page size */
+	if (info->pgsz != 512 && info->pgsz != 2048 && info->pgsz != 4096) {
+		printf("ftnandc021: invalid page size=%d\n", info->pgsz);
+		return -EINVAL;
+	}
+
+	bk = ffs(info->bksz / info->pgsz) - 5;
+	pg = (info->pgsz < 2048) ? 0 : (ffs(info->pgsz) - 11);
+	ac = info->alen - 3;
+
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* IO mode = PIO */
+	writel(0, &regs->bcr);
+
+	/* ECC mode */
+	chip->ecc.layout         = ftnandc021_ecclayout + pg;
+#ifdef CFG_HWECC
+	chip->ecc.bytes          = chip->ecc.layout->eccbytes;
+	chip->ecc.size           = info->pgsz;
+	chip->ecc.steps          = 1;
+	chip->ecc.hwctl          = ftnandc021_ecc_hwctl;
+	chip->ecc.calculate      = ftnandc021_ecc_calculate;
+	chip->ecc.correct        = ftnandc021_ecc_correct;
+	chip->ecc.read_page_raw  = ftnandc021_read_page_raw;
+	chip->ecc.write_page_raw = ftnandc021_write_page_raw;
+	chip->ecc.mode           = NAND_ECC_HW;
+#else
+	chip->ecc.mode           = NAND_ECC_NONE;
+#endif
+
+	/* reset the attached flash */
+	if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+		return -ENXIO;
+
+	return 0;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv))
+		ret = 0;
+	else if (!(readl(&regs->sr) & SR_READY))
+		ret = 0;
+
+	return ret;
+}
+
+static int ftnandc021_pio_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = -ETIMEDOUT;
+	uint32_t ts;
+
+	for (ts = get_timer(0); get_timer(ts) < 200; ) {
+		if (!(readl(&regs->ior) & IOR_READY))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftnandc021: pio timeout\n");
+
+	return ret;
+}
+
+static void ftnandc021_read_oob(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t tmp;
+
+	memset(buf, 0xff, len);
+
+	/* bad block */
+	buf[chip->badblockpos] = readl(&regs->bbird) & 0xff;
+
+	/* data */
+	tmp = readl(&regs->crcrd);
+	buf[8] = (tmp >> 0) & 0xff;
+	buf[9] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >=  4096) {
+		buf[12] = (tmp >> 16) & 0xff;
+		buf[13] = (tmp >> 24) & 0xff;
+	}
+
+	tmp = readl(&regs->lsnrd);
+	buf[10] = (tmp >> 0) & 0xff;
+	buf[11] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[14] = (tmp >> 16) & 0xff;
+		buf[15] = (tmp >> 24) & 0xff;
+	}
+}
+
+static void ftnandc021_write_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t tmp;
+
+	/* bad block */
+	tmp = buf[chip->badblockpos];
+	writel(tmp, &regs->bbiwr);
+
+	/* data */
+#ifdef CFG_HWECC
+	/* mark it as 'not blank' */
+	tmp = 'W';
+#else
+	tmp = buf[8];
+#endif
+	tmp |= buf[9] << 8;
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	writel(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	writel(tmp, &regs->lsnwr);
+}
+
+static uint8_t ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd_hc) {
+	case FTNANDC021_CMD_RDID:
+	case FTNANDC021_CMD_RDOOB:
+		if (priv->buf.idx >= priv->buf.len)
+			break;
+		ret = priv->buf.dat[priv->buf.idx];
+		priv->buf.idx += 1;
+		break;
+	case FTNANDC021_CMD_RDST:
+		ret = (uint8_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: unknown cmd=0x%x in read_byte\n",
+			priv->cmd_hc);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t ret = 0xffff;
+	uint8_t *buf = (uint8_t *)&ret;
+
+	/* LSB format */
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return ret;
+}
+
+static int ftnandc021_copy_oob(struct mtd_info *mtd, int off,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	int pos;
+
+	pos = min(off, mtd->oobsize);
+	len = min(mtd->oobsize - pos, len);
+	memcpy(buf, priv->buf.dat + pos, len);
+
+	return len;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void ftnandc021_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int off;
+
+	if (priv->col >= mtd->writesize) {
+		len = ftnandc021_copy_oob(mtd,
+			priv->col - mtd->writesize, buf, len);
+		priv->col += len;
+		if (priv->cmd == NAND_CMD_READOOB)
+			priv->buf.idx += len;
+		return;
+	}
+
+	if (priv->cmd == NAND_CMD_READOOB)
+		BUG();	/* should never happen */
+
+#ifdef CFG_HWECC
+	/* skip if it's a blank page */
+	if (priv->buf.dat[8] != 'W') {
+		memset(buf, 0xff, len);
+		return;
+	}
+#endif
+
+	off = 0;
+	while (off < len && priv->col < mtd->writesize) {
+		ftnandc021_pio_wait(priv);
+		*(uint32_t *)(buf + off) = readl(&regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	if (!ftnandc021_wait(priv)
+		&& off < len && priv->col >= mtd->writesize) {
+		len = ftnandc021_copy_oob(mtd,
+			priv->col - mtd->writesize, buf + off, len - off);
+		off += len;
+		priv->col += len;
+	}
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void ftnandc021_write_buf(
+	struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int off;
+
+	/*
+	 * FTNANDC021 HW design issues:
+	 *
+	 * 1. OOB data must be set before issuing write command,
+	 *    so it's too late to do it right here
+	 * 2. Only after command issued, the data register
+	 *    could accept data.
+	 */
+	if (priv->col >= mtd->writesize)
+		return;
+
+	for (off = 0; off < len && priv->col < mtd->writesize; ) {
+		ftnandc021_pio_wait(priv);
+		writel(*(uint32_t *)(buf + off), &regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int ftnandc021_verify_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	int ret = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021: out of memory\n");
+		return -ENOMEM;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			ret = -EINVAL;
+	}
+
+	free(tmp);
+	return ret;
+}
+
+static void ftnandc021_cmdfunc(struct mtd_info *mtd,
+	unsigned cmd, int col, int row)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct faraday_nand_chip *info = chip->priv;
+	struct ftnandc021_chip *priv = info->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+
+	priv->cmd = cmd;
+	priv->col = col;
+	priv->row = row;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID)) {
+			printf("ftnandc021: RDID failed.\n");
+			break;
+		}
+		priv->buf.idx = 0;
+		priv->buf.len = 8;
+		put_unaligned_le32(readl(&regs->idr[0]),
+			priv->buf.dat);
+		put_unaligned_le32(readl(&regs->idr[1]),
+			priv->buf.dat + 4);
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		writel(row, &regs->pir);
+		writel(1, &regs->pcr);
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+			break;
+		}
+		if (mtd->oobsize > NAND_MAX_OOBSIZE)
+			BUG(); /* should never happen */
+		ftnandc021_read_oob(mtd, priv->buf.dat, mtd->oobsize);
+		priv->buf.idx = 0;
+		priv->buf.len = mtd->oobsize;
+		priv->col = mtd->writesize;
+		break;
+
+	case NAND_CMD_READ0:	/* 0x00 */
+		writel(row, &regs->pir);
+		writel(1, &regs->pcr);
+#ifdef CFG_HWECC
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+			break;
+		}
+		ftnandc021_read_oob(mtd, priv->buf.dat, mtd->oobsize);
+		/* cancel if it's a blank page */
+		if (priv->buf.dat[8] != 'W') {
+			debug("ftnandc021: skip page %d\n", row);
+			break;
+		}
+#endif
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG))
+			printf("ftnandc021: RDPG failed.\n");
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		writel(row, &regs->pir);
+		writel(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK))
+			printf("ftnandc021: ERBLK failed\n");
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDST))
+			printf("ftnandc021: RDST failed\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		writel(row, &regs->pir);
+		writel(1, &regs->pcr);
+		/* OOB data must be set before issuing command */
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->oobsize);
+		if (priv->col >= mtd->writesize) {
+			if (ftnandc021_command(priv, FTNANDC021_CMD_WROOB))
+				printf("ftnandc021: WROOB failed\n");
+		} else {
+			if (ftnandc021_command(priv, FTNANDC021_CMD_WRPG))
+				printf("ftnandc021: WRPG failed\n");
+		}
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		/* nothing needs to be done */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+			printf("ftnandc021: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021: unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void ftnandc021_hwcontrol(struct mtd_info *mtd,
+	int cmd, unsigned int ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int ftnandc021_init(struct nand_chip *chip)
+{
+	struct faraday_nand_chip *info;
+	struct ftnandc021_chip *priv;
+
+	info = chip->priv;
+	if (!info)
+		return -EINVAL;
+
+	priv = calloc(1, sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -ENOMEM;
+	info->priv = priv;
+	priv->regs = info->regs;
+
+	debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n",
+		   info->pgsz >> 10, info->bksz >> 10, info->alen);
+
+	/* hardware reset */
+	if (ftnandc021_reset(chip))
+		return -EINVAL;
+
+	/* hwcontrol always must be implemented */
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	return 0;
+}
diff --git a/drivers/mtd/nand/ftnandc021.h b/drivers/mtd/nand/ftnandc021.h
new file mode 100644
index 0000000..eb75d73
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.h
@@ -0,0 +1,137 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTNANDC021_H
+#define _FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+ /* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4];/* ECC Parity Register */
+	uint32_t ecc_sr; /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+ /* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsn;	 /* LSN Initialize */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+ /* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+ /* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* bit mask */
+#define ECC_SR_CERR      BIT_MASK(3)  /* correction error */
+#define ECC_SR_ERR       BIT_MASK(2)  /* ecc error */
+#define ECC_SR_DEC       BIT_MASK(1)  /* ecc decode finished */
+#define ECC_SR_ENC       BIT_MASK(0)  /* ecc encode finished */
+
+#define SR_BLANK         BIT_MASK(7)  /* blanking check failed */
+#define SR_ECC           BIT_MASK(6)  /* ecc timeout */
+#define SR_STS           BIT_MASK(4)  /* status error */
+#define SR_CRC           BIT_MASK(3)  /* crc error */
+#define SR_CMD           BIT_MASK(2)  /* command finished */
+#define SR_READY         BIT_MASK(1)  /* chip ready/busy */
+#define SR_ENA           BIT_MASK(0)  /* chip enabled */
+
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        BIT_MASK(7)  /* command start */
+
+#define FCR_SWCRC        BIT_MASK(8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       BIT_MASK(7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        BIT_MASK(4)  /* 16 bit data bus */
+#define FCR_WPROT        BIT_MASK(3)  /* write protected */
+#define FCR_NOSC         BIT_MASK(2)  /* bypass status check error */
+#define FCR_MICRON       BIT_MASK(1)  /* Micron 2-plane command */
+#define FCR_NOBC         BIT_MASK(0)  /* skip blanking check error */
+
+#define IER_ENA          BIT_MASK(7)  /* interrupt enabled */
+#define IER_ECC          BIT_MASK(3)  /* ecc error timeout */
+#define IER_STS          BIT_MASK(2)  /* status error */
+#define IER_CRC          BIT_MASK(1)  /* crc error */
+#define IER_CMD          BIT_MASK(0)  /* command finished */
+
+#define IOR_READY        BIT_MASK(0)  /* PIO ready */
+
+#define SRR_ECC_EN       BIT_MASK(8)  /* ECC enabled */
+#define SRR_NANDC_RESET  BIT_MASK(2)  /* NANDC reset */
+#define SRR_BMC_RESET    BIT_MASK(1)  /* BMC reset */
+#define SRR_ECC_RESET    BIT_MASK(0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* FTNANDC021 integrated command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02   /* reset flash */
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+#endif
diff --git a/include/faraday/nand.h b/include/faraday/nand.h
new file mode 100644
index 0000000..144ec13
--- /dev/null
+++ b/include/faraday/nand.h
@@ -0,0 +1,34 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FARADAY_NAND_H
+#define __FARADAY_NAND_H
+
+#include <nand.h>
+
+/**
+ * struct faraday_nand_chip - chip level device structure
+ * @regs: base address of hardware registers
+ * @priv: hardware controller specific settings
+ * @alen: address length/cycle
+ * @pgsz: page size (byte)
+ * @bksz: block size (byte)
+ */
+struct faraday_nand_chip {
+	void __iomem *regs;
+	void *priv;
+	uint32_t alen;
+	uint32_t pgsz;
+	uint32_t bksz;
+};
+
+int ftnandc021_init(struct nand_chip *chip);
+
+#endif /* _FARADAY_NAND_H */
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (6 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-04-26 12:19           ` Marek Vasut
  2013-05-07  6:26           ` [U-Boot] [PATCH v4 0/2] usb: ehci: add Faraday USB EHCI&Gadget support Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 09/11] " Kuo-Jung Su
                           ` (3 subsequent siblings)
  11 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch add supports to both Faraday FUSBH200 and FOTG210,
these controllers slightly differ from standard EHCI specification.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
 common/usb_hub.c                |    5 ++
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  122 +++++++++++++++++++++++++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |   11 ++++
 drivers/usb/host/ehci.h         |    5 ++
 include/usb/fotg210.h           |   71 +++++++++++++++++++++++
 include/usb/fusbh200.h          |   28 +++++++++
 7 files changed, 243 insertions(+)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index b5eeb62..26d66b8 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -375,6 +375,11 @@ static int usb_hub_configure(struct usb_device *dev)
 		return -1;
 	}
 
+#ifdef CONFIG_USB_EHCI_FARADAY
+	/* Faraday USB 2.0 EHCI chips need a long long delay here */
+	mdelay(250);
+#endif
+
 	if (usb_get_hub_status(dev, buffer) < 0) {
 		USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
 				dev->status);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..adf57d1
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,122 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
+{
+	union ehci_faraday_regs __iomem *regs = (void *)hccr;
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs __iomem *regs;
+#ifdef CONFIG_USB_EHCI_BASE_LIST
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+#else
+	uint32_t base_list[] = { CONFIG_USB_EHCI_BASE };
+#endif
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_hci_fotg2xx(hccr)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, BIT_MASK(5));
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, BIT_MASK(4));
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, BIT_MASK(5));
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, BIT_MASK(4));
+		mdelay(1);
+		/* Disable OTG & device interrupts, interrupt=level-high */
+		writel(0x0b, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(0x07, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BIT_MASK(3));
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BIT_MASK(4));
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+int ehci_hcd_port_speed(struct ehci_hccr *hccr)
+{
+	int ret = 0;
+	int speed;
+	union ehci_faraday_regs __iomem *regs = (void *)hccr;
+
+	if (ehci_hci_fotg2xx(hccr))
+		speed = (readl(&regs->otg.otgcsr) >> 22) & 0x03;
+	else
+		speed = (readl(&regs->usb.bmcsr) >>  9) & 0x03;
+
+	switch (speed) {
+	case 0:    /* full speed */
+		break;
+
+	case 1:    /* low  speed */
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+
+	case 2:    /* high speed */
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..450d217 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -149,8 +149,10 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t tmp;
 	uint32_t *reg_ptr;
+#endif
 	int ret = 0;
 
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,6 +165,7 @@ static int ehci_reset(int index)
 		goto out;
 	}
 
+#ifndef CONFIG_USB_EHCI_FARADAY
 	if (ehci_is_TDI()) {
 		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
 		tmp = ehci_readl(reg_ptr);
@@ -172,6 +175,7 @@ static int ehci_reset(int index)
 #endif
 		ehci_writel(reg_ptr, tmp);
 	}
+#endif	/* !CONFIG_USB_EHCI_FARADAY */
 
 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -711,6 +715,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
 
 		if (ehci_is_TDI()) {
+#ifdef CONFIG_USB_EHCI_FARADAY
+			tmpbuf[1] |= ehci_hcd_port_speed(ctrl->hccr) >> 8;
+#else
 			switch (PORTSC_PSPD(reg)) {
 			case PORTSC_PSPD_FS:
 				break;
@@ -722,6 +729,7 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 				break;
 			}
+#endif
 		} else {
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
 		}
@@ -950,10 +958,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);
 
+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index d090f0a..9309ede 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -82,6 +82,7 @@ struct ehci_hcor {
 	uint32_t or_periodiclistbase;
 	uint32_t or_asynclistaddr;
 	uint32_t _reserved_0_;
+#ifndef CONFIG_USB_EHCI_FARADAY
 	uint32_t or_burstsize;
 	uint32_t or_txfilltuning;
 #define TXFIFO_THRESH_MASK		(0x3f << 16)
@@ -89,6 +90,7 @@ struct ehci_hcor {
 	uint32_t _reserved_1_[6];
 	uint32_t or_configflag;
 #define FLAG_CF		(1 << 0)	/* true:  we'll support "high speed" */
+#endif  /* #ifndef CONFIG_USB_EHCI_FARADAY */
 	uint32_t or_portsc[CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS];
 #define PORTSC_PSPD(x)		(((x) >> 26) & 0x3)
 #define PORTSC_PSPD_FS			0x0
@@ -255,5 +257,8 @@ struct QH {
 /* Low level init functions */
 int ehci_hcd_init(int index, struct ehci_hccr **hccr, struct ehci_hcor **hcor);
 int ehci_hcd_stop(int index);
+#ifdef CONFIG_USB_EHCI_FARADAY
+int ehci_hcd_port_speed(struct ehci_hccr *hccr);
+#endif
 
 #endif /* USB_EHCI_H */
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..0249afd
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,71 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t msicr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[1];
+	uint32_t cxsr;	/* 0x11c: CX Status Register */
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t ioseasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t dma_data; /* 0x1d0: DMA CX Data Register */
+};
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..2d514b8
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,28 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Schedule Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+#endif
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 09/11] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (7 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-04-26 12:21           ` Marek Vasut
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 10/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
                           ` (2 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device as a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  953 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 962 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..e79b6af
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,953 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs __iomem *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType  = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes =    USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id % 4) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) % 4);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs __iomem *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], BIT_MASK(12));
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], BIT_MASK(12));
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], BIT_MASK(11));
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], BIT_MASK(12));
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], BIT_MASK(12));
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], BIT_MASK(11));
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+	uint32_t i, ts;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(BIT_MASK(5), &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(chip->addr, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable interrupts */
+	writel(0x0f, &regs->imr);
+	writel(0x07, &regs->gimr);
+	writel(0x3f, &regs->gimr0);
+	writel(0xf00ff, &regs->gimr1);
+	writel(0x7ff, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(0x07, &regs->isr);
+	writel(0x00, &regs->gisr);
+	writel(0x00, &regs->gisr0);
+	writel(0x00, &regs->gisr1);
+	writel(0x00, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, BIT_MASK(4));
+	for (ts = get_timer(0); get_timer(ts) < 200; ) {
+		if (readl(&regs->dev_ctrl) & BIT_MASK(4))
+			continue;
+		break;
+	}
+	if (readl(&regs->dev_ctrl) & BIT_MASK(4)) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, BIT_MASK(3));
+	for (ts = get_timer(0); get_timer(ts) < 200; ) {
+		if (readl(&regs->cxfifo) & BIT_MASK(3))
+			continue;
+		break;
+	}
+	if (readl(&regs->cxfifo) & BIT_MASK(3)) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(0x33221100, &regs->epmap14);
+	writel(0x00000000, &regs->epmap58);
+	writel(0x04030201, &regs->fifomap);
+	writel(0x00000000, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(BIT_MASK(12), &regs->fifocsr[i]);
+		for (ts = get_timer(0); get_timer(ts) < 200; ) {
+			if (readl(&regs->fifocsr[i]) & BIT_MASK(12))
+				continue;
+			break;
+		}
+		if (readl(&regs->fifocsr[i]) & BIT_MASK(12)) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(0x0e, &regs->imr);
+	writel(0x07, &regs->isr);
+
+	/* disable EP0 IN/OUT interrupt */
+	writel(0x06, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(0xf00ff, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(0x7e0, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0x00, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, BIT_MASK(2));
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < 200; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	uint32_t fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		if (!(readl(&regs->dma_ctrl) & 0x01)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+#ifndef CONFIG_SYS_DCACHE_OFF
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+	else
+		invalidate_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+#endif
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until fifo empty */
+			fotg210_cxwait(chip, 0x20);
+			writel(BIT_MASK(4), &regs->dma_fifo);
+		} else {
+			/* Wait until fifo empty */
+			fotg210_cxwait(chip, 1 << (8 + fifo));
+			writel(1 << fifo, &regs->dma_fifo);
+		}
+		writel((len << 8) | BIT_MASK(1), &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+		if (ep->id == 0) {
+			writel(0x10, &regs->dma_fifo);
+			do {
+				blen = (readl(&regs->cxfifo) >> 24) & 0x7f;
+			} while (blen < len);
+		} else {
+			writel(1 << fifo, &regs->dma_fifo);
+			blen = readl(&regs->fifocsr[fifo]) & 0x7ff;
+		}
+		len  = (len < blen) ? len : blen;
+		writel(len << 8, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, BIT_MASK(0));
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < 100; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & 0x80) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & 0x100) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & 0x07) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(BIT_MASK(4) | BIT_MASK(3), &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs __iomem *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & BIT_MASK(21)) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & BIT_MASK(6)) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				writel(0x044c, &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				writel(0x2710, &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(0x10, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->dma_data);
+	tmp[1] = readl(&regs->dma_data);
+	/* release data port */
+	writel(0x00, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(chip->addr | BIT_MASK(7),
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], BIT_MASK(11));
+				setbits_le32(&regs->oep[id - 1], BIT_MASK(11));
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, BIT_MASK(0));
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, BIT_MASK(2) | BIT_MASK(0));
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue))
+		setbits_le32(&regs->gimr1, 3 << (ep_to_fifo(chip, ep->id) * 2));
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, 0x10 << (8 * id));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg, 0x21 << (8 * id));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg, 0x22 << (8 * id));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg, 0x23 << (8 * id));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, 0x23 << (8 * id));
+	clrbits_le32(&regs->fifomap, 0x30 << (8 * id));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				3 << (ep_to_fifo(chip, ep->id) * 2));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					BIT_MASK(11));
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					BIT_MASK(11));
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					BIT_MASK(11));
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					BIT_MASK(11));
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, BIT_MASK(5));
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, BIT_MASK(0));
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, BIT_MASK(0));
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, BIT_MASK(5));
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs __iomem *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return readl(&regs->sof_fnr) & 0x7ff;
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name    = "ep0",
+			.ops    = &fotg210_ep_ops,
+		},
+		.desc       = &ep0_desc,
+		.chip        = &controller,
+		.maxpacket    = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name    = "ep1",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name    = "ep2",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name    = "ep3",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name    = "ep4",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	uint32_t isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & BIT_MASK(0)) || !gisr)
+		return 0;
+
+	writel(BIT_MASK(0), &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & BIT_MASK(0)) {
+		uint32_t st = readl(&regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & BIT_MASK(4))
+			printf("fotg210: cmd error\n");
+
+		if (st & BIT_MASK(5))
+			printf("fotg210: cmd abort\n");
+
+		if (st & BIT_MASK(0))            /* setup */
+			fotg210_setup(chip);
+		else if (st & BIT_MASK(3))        /* command finish */
+			setbits_le32(&regs->cxfifo, BIT_MASK(0));
+	}
+
+	/* FIFO interrupts */
+	if (gisr & BIT_MASK(1)) {
+		uint32_t id;
+		uint32_t st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & (3 << (id * 2)))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & BIT_MASK(2)) {
+		uint32_t st = readl(&regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & BIT_MASK(0))
+			printf("fotg210: reset by host\n");
+		else if (st & BIT_MASK(1))
+			printf("fotg210: suspend/removed\n");
+		else if (st & BIT_MASK(2))
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & BIT_MASK(3))
+			printf("fotg210: iso error\n");
+		if (st & BIT_MASK(4))
+			printf("fotg210: iso abort\n");
+		if (st & BIT_MASK(8))
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		dcache_enable();
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif
 
+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 10/11] video: add Faraday FTLCDC200 LCD controller support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (8 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 09/11] " Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-05-06 20:18           ` Anatolij Gustschin
  2013-05-07  6:34           ` [U-Boot] [PATCH v2] " Kuo-Jung Su
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 11/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-05-02 22:27         ` [U-Boot] [PATCH v3 00/11] " Tom Rini
  11 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTLCDC200 Color LCD controller performs translation of
pixel-coded data into the required formats and timings to
drive a variety of single/dual mono and color LCDs.

Depending on the LCD type and mode, the unpacked data can represent:
   1. an actual true display gray or color value
   2. an address to a 256 x 16 bit wide palette RAM gray or color value.

The FTLCDC200 generates 4 individual interrupts for:
   1. DMA FIFO underflow
   2. base address update
   3. vertical status
   4. bus error.

There is also a single combined interrupt that is raised when any of
the individual interrupts become active.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Anatolij Gustschin <agust@denx.de>
---
 drivers/video/Makefile          |    1 +
 drivers/video/ftlcdc200.c       |  144 +++++++++++++++++++++++++++
 drivers/video/ftlcdc200_panel.c |  210 +++++++++++++++++++++++++++++++++++++++
 include/faraday/ftlcdc200.h     |  179 +++++++++++++++++++++++++++++++++
 include/lcd.h                   |   33 ++++++
 5 files changed, 567 insertions(+)
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/faraday/ftlcdc200.h

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 53952ab..ec8df26 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
 				exynos_mipi_dsi_lowlevel.o
 COBJS-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o
 COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
+COBJS-$(CONFIG_FTLCDC200) += ftlcdc200.o ftlcdc200_panel.o
 COBJS-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o
 COBJS-$(CONFIG_PXA_LCD) += pxa_lcd.o
 COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o
diff --git a/drivers/video/ftlcdc200.c b/drivers/video/ftlcdc200.c
new file mode 100644
index 0000000..a9c1198
--- /dev/null
+++ b/drivers/video/ftlcdc200.c
@@ -0,0 +1,144 @@
+/*
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Kuo-Jung Su <dantesu@gmail.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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+static struct ftlcdc200_regs __iomem *regs
+	= (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+static void ftlcdc2xx_fixup(struct vidinfo *panel)
+{
+	u_long ht, vt;
+	u_long div, clk;
+	long fps = 60;
+	long upper = 32767;
+	long lower = -32767;
+
+	if (panel->vl_fps)
+		return;
+
+	/* If it's serial mode */
+	if (panel->vl_serial & SPPR_SERIAL)
+		clk = clk_get_rate("AHB") / 3;
+	else
+		clk = clk_get_rate("AHB");
+
+	/* Derive clock divisor */
+	ht = panel->vl_col + panel->vl_hbp + panel->vl_hfp + panel->vl_hsw;
+	vt = panel->vl_row + panel->vl_vbp + panel->vl_vfp + panel->vl_vsw;
+	for (div = 1; div <= 0x7f; ++div) {
+		long tmp = (clk / div / ht / vt);
+		if (fps > tmp) {
+			lower = tmp;
+			break;
+		}
+		upper = tmp;
+	}
+	if ((upper - fps) > (fps - lower))
+		div += 1;
+	div = (div > 1) ? (div - 1) : div;
+
+	/* Update hardware register cache */
+	panel->vl_polarity = (panel->vl_polarity & (~0x7f00))
+		| ((div - 1) << 8);
+
+	/* Derive real frame rate */
+	panel->vl_fps = (u_long)(clk / div / ht / vt);
+
+	debug("ftlcdc200: %s\n", panel->vl_name);
+	debug("ftlcdc200: fps=%u (%u < FPS < %u)\n",
+		   (unsigned int)panel->vl_fps,
+		   (unsigned int)lower,
+		   (unsigned int)upper);
+	debug("ftlcdc200: div=%u (ahb=%u MHz)\n",
+		   (unsigned int)div,
+		   (unsigned int)clk_get_rate("AHB") / 1000000);
+}
+
+/* setcolreg used in 8bpp/16bpp */
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+/* initcolregs used in monochrome */
+void lcd_initcolregs(void)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+	uint32_t i, v;
+
+	/*
+	 * initialize the contrast lookup table and the Red, Green, Blue
+	 * gamma lookup table, fill the straight line x-y=0 to the contrast
+	 * and gamma lookup table
+	 */
+	for (i = 0; i < 64; i++) {
+		v = 0x03020100 + 0x04040404 * i;
+		writel(v, &regs->gamma_r[i]);
+		writel(v, &regs->gamma_g[i]);
+		writel(v, &regs->gamma_b[i]);
+	}
+
+	writel(virt_to_phys(lcdbase), &regs->fb0);
+
+	debug("ftlcdc200: fb_base=0x%08X at 0x%08X\n",
+		(uint32_t)lcdbase, readl(&regs->fb0));
+}
+
+void lcd_enable(void)
+{
+	struct vidinfo *panel = &panel_info;
+
+	/* 1. derive the clock parameters at runtime */
+	ftlcdc2xx_fixup(panel);
+	/* 2. disable lcd */
+	writel(0, &regs->fer);
+	/* 3. setup panel parameters */
+	writel(panel->vl_pixel, &regs->ppr);
+	writel(HTCR_PL(panel->vl_col) | HTCR_HSYNC(panel->vl_hsw)
+		| HTCR_HBP(panel->vl_hbp) | HTCR_HFP(panel->vl_hfp),
+		&regs->htcr);
+	writel(VTCR0_LF(panel->vl_row) | VTCR0_VSYNC(panel->vl_vsw)
+		| VTCR0_VFP(panel->vl_vfp), &regs->vtcr[0]);
+	writel(VTCR1_VBP(panel->vl_vbp), &regs->vtcr[1]);
+	writel(panel->vl_polarity, &regs->pcr);
+	writel(panel->vl_serial, &regs->sppr);
+	writel(panel->vl_ccir656, &regs->ccir);
+	/* 4. default 4 cycles delay for all framebuffer */
+	writel(0x04040404, &regs->fifo);
+	/* 5. disable & clean interrupts */
+	writel(0x00, &regs->ier);
+	writel(0x0f, &regs->iscr);
+	/* 6. enable lcd */
+	writel(panel->vl_enable, &regs->fer);
+}
+
+ulong calc_fbsize(void)
+{
+	return ((panel_info.vl_col * panel_info.vl_row *
+			 NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
+}
diff --git a/drivers/video/ftlcdc200_panel.c b/drivers/video/ftlcdc200_panel.c
new file mode 100644
index 0000000..ca1a091
--- /dev/null
+++ b/drivers/video/ftlcdc200_panel.c
@@ -0,0 +1,210 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+struct vidinfo panel_info = {
+#if defined(CONFIG_FTLCDC200_320X240P_SHARP)
+	.vl_name  = "SHARP-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x10,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x10,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0f,
+	.vl_vbp   = 0x07,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBLP,
+	.vl_polarity = POL_DIV(23) | POL_IHS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240P_AUO)
+	.vl_name  = "AUO-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PWROFF,
+	.vl_polarity = POL_DIV(21) | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240S_AUO)
+	.vl_name  = "AUO-320x240s",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(1),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_640X480P_PV)
+	.vl_name  = "PV-640x480p",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x63,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2D,
+	.vl_vsw   = 0x44,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(6) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480S_TPO)
+	.vl_name  = "TPO-800x480s",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x01,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(1) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(0),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_TPO)
+	.vl_name  = "TPO-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x04,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0xD4,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x0A,
+	.vl_vbp   = 0x22,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_CPT)
+	/* Chunghwa Picture Tubes - CLAA048LA0BCT */
+	.vl_name  = "CPT-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x32,
+	.vl_hbp   = 0x31,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0E,
+	.vl_vbp   = 0x05,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X600_VGA)
+	.vl_name  = "D-SUB: VGA-800x600",
+	.vl_col   = 800,
+	.vl_row   = 600,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(3) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_1024X768_VGA)
+	.vl_name  = "D-SUB: VGA-1024x768",
+	.vl_col   = 1024,
+	.vl_row   = 768,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(2) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_720X480_NTSC)
+	.vl_name  = "A/V: NTSC-720x480",
+	.vl_col   = 720,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x06,
+	.vl_hfp   = 0x7D,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x0F,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1A,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 3,
+#elif defined(CONFIG_FTLCDC200_640X480_NTSC)
+	.vl_name  = "A/V: NTSC-640x480",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x02,
+	.vl_hfp   = 0xD1,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x10,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x19,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 1,
+#else
+#error "Please specific target LCD panel."
+#endif
+};
diff --git a/include/faraday/ftlcdc200.h b/include/faraday/ftlcdc200.h
new file mode 100644
index 0000000..9d7cc33
--- /dev/null
+++ b/include/faraday/ftlcdc200.h
@@ -0,0 +1,179 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTLCDC200_H
+#define __FTLCDC200_H
+
+/* FTLCDC200 Registers */
+struct ftlcdc200_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t fer;  /* 0x000: Function Enable Register */
+	uint32_t ppr;  /* 0x004: Panel Pixel Register */
+	uint32_t ier;  /* 0x008: Interrupt Enable Register */
+	uint32_t iscr; /* 0x00C: Interrupt Status Clear Register */
+	uint32_t isr;  /* 0x010: Interrupt Status Register */
+	uint32_t rsvd0[1];
+	uint32_t fb0;  /* 0x018: Framebuffer Base Register 0 */
+	uint32_t rsvd1[2];
+	uint32_t fb1;  /* 0x024: Framebuffer Base Register 1 */
+	uint32_t rsvd2[2];
+	uint32_t fb2;  /* 0x030: Framebuffer Base Register 2 */
+	uint32_t rsvd3[2];
+	uint32_t fb3;  /* 0x03C: Framebuffer Base Register 3 */
+	uint32_t rsvd4[2];
+	uint32_t patg; /* 0x048: Pattern Generator */
+	uint32_t fifo; /* 0x04C: FIFO Threshold */
+	uint32_t gpio; /* 0x050: GPIO */
+	uint32_t rsvd5[43];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t htcr;    /* Horizontal Timing Control Register */
+	uint32_t vtcr[2]; /* Vertical Timing Control Register */
+	uint32_t pcr;     /* Polarity Control Register */
+	uint32_t rsvd6[60];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t sppr;    /* Serial Panel Pixel Register */
+	uint32_t ccir;    /* CCIR565 Register */
+	uint32_t rsvd7[62];
+
+	/* 0x300 ~ 0x3ff */
+	uint32_t pipr;    /* Picture-In-Picture Register */
+	uint32_t pip1pos; /* Sub-picture 1 position */
+	uint32_t pip1dim; /* Sub-picture 1 dimension */
+	uint32_t pip2pos; /* Sub-picture 2 position */
+	uint32_t pip2dim; /* Sub-picture 2 dimension */
+	uint32_t rsvd8[59];
+
+	/* 0x400 ~ 0x5ff */
+	uint32_t cmnt[4]; /* Color Management */
+	uint32_t rsvd9[124];
+
+	/* 0x600 ~ 0x6ff */
+	uint32_t gamma_r[64]; /* RED - Gamma Correct */
+
+	/* 0x700 ~ 0x7ff */
+	uint32_t gamma_g[64]; /* GREEN - Gamma Correct */
+
+	/* 0x800 ~ 0x8ff */
+	uint32_t gamma_b[64]; /* BLUE - Gamma Correct */
+
+	/* 0x900 ~ 0x9ff */
+	uint32_t rsvd10[64];
+
+	/* 0xa00 ~ 0xbff */
+	uint32_t palette[128];  /* Palette Write Port */
+
+	/* 0xc00 ~ 0xcff */
+	uint32_t cstn_cr;       /* CSTN Control Register */
+	uint32_t cstn_pr;       /* CSTN Parameter Register */
+	uint32_t rsvd11[62];
+
+	/* 0xd00 ~ 0xdff */
+	uint32_t cstn_bmap[16]; /* CSTN bitmap write port */
+	uint32_t rsvd12[48];
+};
+
+/* LCD Function Enable Register */
+#define FER_EN          (1 << 0)    /* chip enabled */
+#define FER_ON          (1 << 1)    /* screen on */
+#define FER_YUV420      (3 << 2)
+#define FER_YUV422      (2 << 2)
+#define FER_YUV         (1 << 3)    /* 1:YUV, 0:RGB */
+
+/* LCD Panel Pixel Register */
+#define PPR_BPP_1       (0 << 0)
+#define PPR_BPP_2       (1 << 0)
+#define PPR_BPP_4       (2 << 0)
+#define PPR_BPP_8       (3 << 0)
+#define PPR_BPP_16      (4 << 0)
+#define PPR_BPP_24      (5 << 0)
+#define PPR_BPP_MASK    (7 << 0)
+#define PPR_PWROFF      (1 << 3)
+#define PPR_BGR         (1 << 4)
+#define PPR_ENDIAN_LBLP (0 << 5)
+#define PPR_ENDIAN_BBBP (1 << 5)
+#define PPR_ENDIAN_LBBP (2 << 5)
+#define PPR_ENDIAN_MASK (3 << 5)
+#define PPR_RGB1        (PPR_BPP_1)
+#define PPR_RGB2        (PPR_BPP_2)
+#define PPR_RGB4        (PPR_BPP_4)
+#define PPR_RGB8        (PPR_BPP_8)
+#define PPR_RGB12       (PPR_BPP_16 | (2 << 7))
+#define PPR_RGB16_555   (PPR_BPP_16 | (1 << 7))
+#define PPR_RGB16_565   (PPR_BPP_16 | (0 << 7))
+#define PPR_RGB24       (PPR_BPP_24)
+#define PPR_RGB32       (PPR_BPP_24)
+#define PPR_RGB_MASK    (PPR_BPP_MASK | (3 << 7))
+#define PPR_VCOMP_VSYNC (0 << 9)
+#define PPR_VCOMP_VBP   (1 << 9)
+#define PPR_VCOMP_VAIMG (2 << 9)
+#define PPR_VCOMP_VFP   (3 << 9)
+#define PPR_VCOMP_MASK  (3 << 9)
+#define	PPR_PANEL_6BIT  (0 << 11)
+#define	PPR_PANEL_8BIT  (1 << 11)
+#define	PPR_DITHER565   (0 << 12)
+#define	PPR_DITHER555   (1 << 12)
+#define	PPR_DITHER444   (2 << 12)
+#define	PPR_HCLK_RESET  (1 << 14)
+#define	PPR_LCCLK_RESET (1 << 15)
+
+/* LCD Interrupt Enable Register */
+#define IER_FIFOUR      (1 << 0)
+#define IER_NEXTFB      (1 << 1)
+#define IER_VCOMP       (1 << 2)
+#define IER_BUSERR      (1 << 3)
+
+/* LCD Interrupt Status Register */
+#define ISR_FIFOUR      (1 << 0)
+#define ISR_NEXTFB      (1 << 1)
+#define ISR_VCOMP       (1 << 2)
+#define ISR_BUSERR      (1 << 3)
+
+/* LCD Horizontal Timing Control Register */
+#define HTCR_HBP(x)     ((((x) - 1) & 0xff) << 24)
+#define HTCR_HFP(x)     ((((x) - 1) & 0xff) << 16)
+#define HTCR_HSYNC(x)   ((((x) - 1) & 0xff) << 8)
+#define HTCR_PL(x)      (((x >> 4) - 1) & 0xff)
+
+/* LCD Vertical Timing Control Register 0 */
+#define VTCR0_VFP(x)    (((x) & 0xff) << 24)
+#define VTCR0_VSYNC(x)  ((((x) - 1) & 0x3f) << 16)
+#define VTCR0_LF(x)     (((x) - 1) & 0xfff)
+
+/* LCD Vertical Timing Control Register 1 */
+#define VTCR1_VBP(x)    ((x) & 0xff)
+
+/* LCD Polarity Control Register */
+#define POL_IVS         (1 << 0)
+#define POL_IHS         (1 << 1)
+#define POL_ICK         (1 << 2)
+#define POL_IDE         (1 << 3)
+#define POL_IPWR        (1 << 4)
+#define POL_DIV(x)      ((((x) - 1) & 0x7f) << 8)
+
+/* LCD Serial Panel Pixel Register */
+#define SPPR_SERIAL     (1 << 0)
+#define SPPR_DELTA      (1 << 1)
+#define SPPR_CS(x)      ((x) << 2)
+#define SPPR_CS_RGB     (0 << 2)
+#define SPPR_CS_BRG     (1 << 2)
+#define SPPR_CS_GBR     (2 << 2)
+#define SPPR_LSR        (1 << 4)
+#define SPPR_AUO052     (1 << 5)
+
+/* LCD CCIR656 Register */
+#define CCIR_PAL        (0 << 0)
+#define CCIR_NTSC       (1 << 0)
+#define CCIR_P640       (0 << 1)
+#define CCIR_P720       (1 << 1)
+#define CCIR_PHASE(x)   ((x) << 2)
+
+#endif /* __FTLCDC200_H */
diff --git a/include/lcd.h b/include/lcd.h
index c6e7fc5..1d9e584 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -253,6 +253,39 @@ typedef struct vidinfo {
 
 void init_panel_info(vidinfo_t *vid);
 
+#elif defined(CONFIG_FTLCDC200)
+
+typedef struct vidinfo {
+	ushort	vl_col;		/* Number of columns (i.e. 800) */
+	ushort	vl_row;		/* Number of rows (i.e. 600) */
+
+	u_char	vl_bpix;	/* Bits per pixel, 0 = 1, 1 = 2 ... 4 = 16 */
+
+	/* Timing Parameters */
+	u_char	vl_fps;		/* Frame per second */
+
+	u_char	vl_hsw;
+	u_char	vl_hbp;
+	u_char	vl_hfp;
+
+	u_char	vl_vsw;
+	u_char	vl_vbp;
+	u_char	vl_vfp;
+
+	/* Pre-defined FTLCDC200 register values */
+	u_long	vl_enable;	/* LCDEnable */
+	u_long	vl_pixel;	/* PanelPixel */
+	u_long	vl_polarity;/* Polarity */
+	u_long	vl_serial;	/* SerialPanelPixel */
+	u_long	vl_ccir656;	/* CCIR656 */
+
+	/* Panel name */
+	char	*vl_name;
+
+	ushort	*cmap;		/* Pointer to the colormap */
+	void	*priv;		/* Pointer to driver-specific data */
+} vidinfo_t;
+
 #else
 
 typedef struct vidinfo {
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 11/11] arm: add Faraday A36x SoC platform support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (9 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 10/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
@ 2013-04-26  8:02         ` Kuo-Jung Su
  2013-05-02 22:27         ` [U-Boot] [PATCH v3 00/11] " Tom Rini
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-26  8:02 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday A36x EVB is a Faraday SoC platform evalution board used for
Faraday IP functional verification based on the well-known ARM AMBA 2.0
architecture.

Faraday A360 EVB:
   CPU: FA626TE
   NET: FTMAC110
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC010
   WDT: FTWDT010
   TMR: FTTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC020

Faraday A369 EVB:
   CPU: FA626TE(Master)/FA606TE(Slave)
   NET: FTGMAC100
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC011
   WDT: FTWDT010
   TMR: FTPWMTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC021

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
 arch/arm/cpu/faraday/Makefile             |   57 ++++
 arch/arm/cpu/faraday/a360/Makefile        |   49 +++
 arch/arm/cpu/faraday/a369/Makefile        |   50 +++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   72 ++++
 arch/arm/cpu/faraday/cmd_bootfa.c         |  132 ++++++++
 arch/arm/cpu/faraday/config.mk            |   33 ++
 arch/arm/cpu/faraday/cpu.c                |  238 +++++++++++++
 arch/arm/cpu/faraday/ftintc020.h          |   37 ++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  156 +++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.h        |   41 +++
 arch/arm/cpu/faraday/fttmr010.c           |  156 +++++++++
 arch/arm/cpu/faraday/fwimage.h            |   38 +++
 arch/arm/cpu/faraday/fwimage2.h           |   70 ++++
 arch/arm/cpu/faraday/interrupts.c         |  151 +++++++++
 arch/arm/cpu/faraday/reset.c              |   38 +++
 arch/arm/cpu/faraday/start.S              |  523 +++++++++++++++++++++++++++++
 arch/arm/cpu/u-boot.lds                   |   11 +
 arch/arm/include/asm/arch-a360/hardware.h |   73 ++++
 arch/arm/include/asm/arch-a360/pmu.h      |   39 +++
 arch/arm/include/asm/arch-a360/scu.h      |   27 ++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++
 arch/arm/include/asm/arch-a369/scu.h      |   48 +++
 arch/arm/include/asm/mach-types.h         |    1 +
 board/faraday/a360evb/Makefile            |   49 +++
 board/faraday/a360evb/board.c             |   65 ++++
 board/faraday/a360evb/clk.c               |   57 ++++
 board/faraday/a360evb/config.mk           |   33 ++
 board/faraday/a360evb/lowlevel_init.S     |   33 ++
 board/faraday/a369evb/Makefile            |   49 +++
 board/faraday/a369evb/board.c             |  188 +++++++++++
 board/faraday/a369evb/clk.c               |   72 ++++
 board/faraday/a369evb/config.mk           |   33 ++
 board/faraday/a369evb/lowlevel_init.S     |  136 ++++++++
 boards.cfg                                |    3 +
 include/common.h                          |   13 +
 include/configs/a360.h                    |   63 ++++
 include/configs/a369-common.h             |   74 ++++
 include/configs/a369.h                    |   33 ++
 include/configs/a369_fa606te.h            |   26 ++
 include/configs/a36x-common.h             |  303 +++++++++++++++++
 include/faraday/fttmr010.h                |   17 +
 41 files changed, 3375 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftintc020.h
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.h
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 arch/arm/cpu/faraday/reset.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/a36x-common.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..b6d55b8
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,57 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+src-y						:= interrupts.o reset.o
+src-$(CONFIG_FTPWMTMR010)	+= ftpwmtmr010.o
+src-$(CONFIG_FTTMR010)		+= fttmr010.o
+
+START	= start.o
+COBJS	= cpu.o cmd_bootfa.o $(src-y)
+
+ifdef	CONFIG_SPL_BUILD
+ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE
+START	:=
+endif
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..7113f66
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..4dddd36
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+obj-$(CONFIG_CMD_FA606) += cmd_fa606.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/cmd_fa606.c b/arch/arm/cpu/faraday/a369/cmd_fa606.c
new file mode 100644
index 0000000..8c0d2a5
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/cmd_fa606.c
@@ -0,0 +1,72 @@
+/*
+ * arch/arm/cpu/faraday/a369/cmd_fa606.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would start the A369 slave cpu - FA606TE, and also immediately
+ * halt the master cpu - FA626TE.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+
+static int do_fa606(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int addr = CONFIG_SYS_LOAD_ADDR;
+
+	if (argc >= 2)
+		addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("FA606TE Image at 0x%08X\n", addr);
+	printf("FA626TE is going to halt...\n");
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+	cleanup_before_linux();
+#endif
+
+	/* 1. FA606TE address offset = 0 */
+	printf("FA606 address shift disable.\n");
+	writel(0x00000000, CONFIG_AHBC2_BASE + 0x90);
+
+	/* 2. Generate a long-jump to 0x00000000 */
+	writel(0xEA00000A, 0x00); /* b   0x30 */
+	writel(addr,       0x20);
+	writel(0xE3A00020, 0x30); /* mov r0, #32 ; 0x20 */
+	writel(0xE590F000, 0x34); /* ldr pc, [r0] */
+
+	/* 3. Pinmux = ICE + LCD */
+	writel(0x00001078, CONFIG_SCU_BASE + 0x200);
+	writel(0x26877330, CONFIG_SCU_BASE + 0x228);
+	writel(0x000A0A0A, CONFIG_SCU_BASE + 0x22c);
+	writel(0x00003FFF, CONFIG_SCU_BASE + 0x230);
+	writel(0x00000065, CONFIG_SCU_BASE + 0x238);
+	writel(0x00000080, CONFIG_SCU_BASE + 0x23c);
+	udelay(5000);
+
+	/* 4. FA606TE clock enable & reset */
+	writel(0x00000000, CONFIG_SCU_BASE + 0x028);
+	udelay(5000);
+	writel(0x00001878, CONFIG_SCU_BASE + 0x200);
+
+	/* 5. FA626TE is going to halt... */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15,0,r3,c7,c0,4\n"
+		:
+		:
+		: "r3" /* clobber list */
+	);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	fa606, 2, 0, do_fa606,
+	"launch firmware with A369's built-in fa606te\n",
+	"fa606 [address] - mov pc of fa606te to the specified address.\n"
+);
diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..bcced38
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,132 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would try to boot faraday image from MMC/SD/USB/SPI/NAND/NOR
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *part = hdr->part;
+
+	for (i = 0; part[i].length > 0 && i < 10; ++i) {
+		if (strcmp(name, part[i].name) == 0) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				part[i].name, part[i].offset, part[i].length);
+			return part + i;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400",
+			CONFIG_SYS_FLASH_BASE,
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x",
+			CONFIG_SYS_FLASH_BASE + part->offset,
+			CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400",
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f03030a
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
+
+PLATFORM_CPPFLAGS += -march=armv4
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..56c4d72
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,238 @@
+/*
+ * arch/arm/cpu/faraday/cpu.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/system.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+
+	disable_interrupts();
+
+	/* turn off D-cache */
+	dcache_disable();
+
+	/* flush I-cache */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15, 0, r3, c7, c5, 0\n" /* invalidate i-cache all */
+		:      /* output */
+		:      /* input */
+		: "r3" /* clobber list */
+	);
+
+	return 0;
+}
+
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#else
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c14,0\n" /* clean & invalidate d-cache all */
+		"mcr p15,0,r3,c7,c10,4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n" /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c10,4\n" /* drain write buffer */
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)   /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n" /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)  /* input */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c6,0\n" /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c5,0\n" /* invalidate i-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
+
+void enable_caches(void)
+{
+	icache_enable();
+
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		puts("MMU:   on\n");
+		dcache_enable();
+	} else
+#endif
+		puts("MMU:   off\n");
+}
+
+#ifdef CONFIG_ARCH_CPU_INIT
+
+int arch_cpu_init(void)
+{
+	unsigned int id, ctr;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		"mrc p15, 0, %1, c0, c0, 1\n"
+		: "=r"(id), "=r"(ctr) /* output */
+		: /* input */
+	);
+
+	gd->arch.cpu_id = id;
+
+	/* MMU/D-Cache */
+	switch (gd->arch.cpu_id >> 4) {
+	case 0x6604526:    /* FA526 */
+	case 0x6604626:    /* FA626 */
+	case 0x6605606:    /* FA606TE */
+		/* Disable MMU/D-Cache */
+		gd->arch.cpu_mmu = 0;
+		break;
+	default:
+		/* Enable MMU/D-Cache */
+		gd->arch.cpu_mmu = 1;
+		break;
+	}
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+	uint vid = gd->arch.cpu_id >> 24;
+	uint pid = (gd->arch.cpu_id & 0xfff0) >> 4;
+
+	/* build cpu_name */
+	switch (vid) {
+	case 0x66:	/* Faraday */
+		switch (gd->arch.cpu_id >> 16) {
+		case 0x6601:
+			sprintf(cpu_name, "FA%x", pid);
+			break;
+		default:
+			sprintf(cpu_name, "FA%xTE", pid);
+			break;
+		}
+		break;
+	case 0x41:	/* ARM */
+		if ((pid & 0xff0) == 0xc00)
+			sprintf(cpu_name, "Cortex-A%u", (pid & 0x00f));
+		else if (pid >= 0xa00)
+			sprintf(cpu_name, "ARM%x", 0x1000 + (pid - 0xa00));
+		else
+			sprintf(cpu_name, "ARM%x", pid);
+		break;
+	default:
+		sprintf(cpu_name, "Unknown");
+		break;
+	}
+
+	/* print cpu_info */
+	printf("CPU:   %s %u MHz\n",
+		cpu_name, (unsigned int)(clk_get_rate("CPU") / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("AHB") / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("APB") / 1000000));
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_DISPLAY_CPUINFO */
diff --git a/arch/arm/cpu/faraday/ftintc020.h b/arch/arm/cpu/faraday/ftintc020.h
new file mode 100644
index 0000000..e23d1e7
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftintc020.h
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTINTC020_H
+#define ARCH_ARM_CPU_FARADAY_FTINTC020_H
+
+struct ftintc020_pic_regs {
+	uint32_t src; /* source register */
+	uint32_t ena; /* enable register */
+	uint32_t scr; /* status clear register */
+	uint32_t tmr; /* trigger mode register */
+	uint32_t tlr; /* trigger level register */
+	uint32_t sr;  /* status register */
+	uint32_t rsvd[2];
+};
+
+struct ftintc020_regs {
+	/* IRQ/FIQ:  0 ~ 31 */
+	struct ftintc020_pic_regs irq32; /* 0x00 - 0x1C: IRQ 0 ~ 31 */
+	struct ftintc020_pic_regs fiq32; /* 0x20 - 0x3C: FIQ 0 ~ 31 */
+	uint32_t rsvd1[4];               /* 0x40 - 0x4C: Reserved */
+	uint32_t revision;               /* 0x50: Revision Register */
+	uint32_t feature;                /* 0x54: Feature Register */
+	uint32_t rsvd2[2];               /* 0x58 - 0x5C: Reserved */
+	/* IRQ/FIQ: 32 ~ 63 */
+	struct ftintc020_pic_regs irq64; /* 0x60 - 0x7C: IRQ 32 ~ 63 */
+	struct ftintc020_pic_regs fiq64; /* 0x80 - 0x9C: FIQ 32 ~ 63 */
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..d9cc142
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,156 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include "ftpwmtmr010.h"
+
+#ifdef CONFIG_A369_FA606TE_PLATFORM
+#define TIMER_ID    4
+#else
+#define TIMER_ID    0
+#endif
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+static struct ftpwmtmr010_regs __iomem *regs =
+	(void __iomem *)CONFIG_TIMER_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((sclk / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	int id = TIMER_ID;
+
+	++ticks;
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	writel(0,
+		&regs->t[id].cmpb);
+	writel(sclk / CONFIG_SYS_HZ,
+		&regs->t[id].cntb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+	irq_install_handler(CONFIG_TIMER_IRQ, (void *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+	enable_interrupts();
+#else
+	/* setup a 30 sec one-shot timer */
+	writel(0,
+		&regs->t[id].cmpb);
+	writel(30 * sclk,
+		&regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+#endif    /* #ifdef CONFIG_USE_IRQ */
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = (30 * sclk - readl(&regs->t[TIMER_ID].cnto)) / s;
+
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+	sclk  = clk_get_rate("APB");
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (!readl(&regs->t[TIMER_ID].cnto)) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.h b/arch/arm/cpu/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..9455577
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..39fb59f
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,156 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+static struct fttmr010 __iomem *regs = (void __iomem *)CONFIG_TIMER_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((sclk / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	++ticks;
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+	/* Disable Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt init */
+	irq_set_trigger(CONFIG_TIMER_IRQ, 1, 0);
+	irq_install_handler(CONFIG_TIMER_IRQ, (void *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+#endif
+
+	/* timer1 setup */
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	writel(sclk / CONFIG_SYS_HZ, &regs->timer1_counter);
+	writel(sclk / CONFIG_SYS_HZ, &regs->timer1_load);
+#else
+	/* setup a 30 sec one-shot timer */
+	writel(30 * sclk, &regs->timer1_counter);
+	writel(0, &regs->timer1_load);
+#endif
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* start timer1 with overflow interrupt enabled */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = ((30 * sclk) - readl(&regs->timer1_counter)) / s;
+
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+	sclk  = clk_get_rate("APB");
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (!readl(&regs->timer1_counter)) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..af4f2f9
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/cpu/faraday/fwimage.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t	count;
+	uint32_t	version; /* ycmo100525: for firmware image version */
+	uint32_t	addr[31];
+	uint32_t	data[31];
+};
+
+struct fwfile {
+	char		name[64];
+	uint32_t	size;
+	/* uint32_t	block[1]; */
+};
+
+struct fwimage {
+	/* 8 bytes */
+	uint32_t		magic;	/* Magic number */
+	uint32_t		length;	/* It shall not be greater than 2048 */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam	param;
+
+	struct fwfile	file[1];
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..27319a7
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/cpu/faraday/fwimage2.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+
+#include <image.h>
+#include "fwimage.h"
+
+/* 8 bytes struct for generic 32-bit memory write */
+struct fwmw32 {
+	uint32_t addr;
+	uint32_t data;
+};
+
+/* 72 bytes */
+struct fwpart {
+	/* offset: 0 ~ 63 */
+	char     name[32];
+
+	uint32_t offset;
+	uint32_t length;
+
+	uint32_t load;
+	uint32_t qcrc; /* Quick CRC32 against 256KB on both TOP & BOTTOM */
+
+	uint32_t flag;
+#define FWIMAGE2_FLAG_UIMAGE		0x00000001 /* Is a uImage ? */
+#define FWIMAGE2_FLAG_FILESYSTEM	0x00000010 /* Is a filesystem ? */
+
+	uint8_t  rsvd[12];
+
+	/* offset: 64 ~ 71 */
+	uint32_t magic1000; /* It's always 0x00001000 */
+	uint32_t magic0001; /* It's always 0x00000001 */
+};
+
+struct fwimage2 {
+	/*   4 bytes, magic */
+	uint32_t magic; /* Image Header Magic Number */
+#define FWIMAGE2_MAGIC			0x00484946 /* "FIH\0" */
+
+	/*   4 bytes, header length */
+	uint32_t hlen;      /* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwmw32 mw32[32];
+
+	/* 720 bytes, firmware partition table */
+	struct fwpart part[10];
+
+	/*   4 bytes */
+	uint32_t hcrc;  /* Image Header Checksum (CRC32) */
+
+	/*   4 bytes, revision */
+	uint32_t revision; /* Image Header Revision Code */
+#define FWIMAGE2_REVISION		0x00000201		/* v2.1 */
+
+	/*  32 bytes */
+	char     build[32]; /* Build Date (yyyy/mm/dd HH:MM:SS) */
+};	/* Total 1024 bytes */
+
+#endif
diff --git a/arch/arm/cpu/faraday/interrupts.c b/arch/arm/cpu/faraday/interrupts.c
new file mode 100644
index 0000000..aa21dce
--- /dev/null
+++ b/arch/arm/cpu/faraday/interrupts.c
@@ -0,0 +1,151 @@
+/*
+ * arch/arm/cpu/faraday/interrupts.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include "ftintc020.h"
+
+#ifdef CONFIG_USE_IRQ
+
+static struct ftintc020_regs __iomem *regs
+	= (void __iomem *)CONFIG_PIC_BASE;
+
+struct _irq_handler {
+	void  *data;
+	void (*func)(void *data);
+};
+
+static struct _irq_handler IRQ_HANDLER[64];
+
+static inline void irq_acknowledge(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		writel(mask, &regs->irq32.scr);
+	else
+		writel(mask, &regs->irq64.scr);
+}
+
+void irq_enable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		setbits_le32(&regs->irq32.ena, mask);
+	else
+		setbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_disable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		clrbits_le32(&regs->irq32.ena, mask);
+	else
+		clrbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_set_trigger(int irq, int edge, int low)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (edge) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tmr, mask);
+		else
+			setbits_le32(&regs->irq64.tmr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tmr, mask);
+		else
+			clrbits_le32(&regs->irq64.tmr, mask);
+	}
+
+	if (low) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tlr, mask);
+		else
+			setbits_le32(&regs->irq64.tlr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tlr, mask);
+		else
+			clrbits_le32(&regs->irq64.tlr, mask);
+	}
+}
+
+void do_irq(struct pt_regs *pt_regs)
+{
+	int irq;
+	uint32_t stat;
+
+	irq  = 32;
+	stat = readl(&regs->irq64.sr);     /* IRQ 32 ~ 63 */
+	if (!stat) {
+		irq  = 0;
+		stat = readl(&regs->irq32.sr); /* IRQ  0 ~ 31 */
+	}
+	irq += ffs(stat) - 1;
+
+	if (irq < 0) {
+		printf("interrupts: no irq!?\n");
+	} else {
+		irq_acknowledge(irq);
+		IRQ_HANDLER[irq].func(IRQ_HANDLER[irq].data);
+	}
+}
+
+static void default_isr(void *data)
+{
+	printf("default_isr():  called for IRQ %d\n", (int)data);
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *hndl, void *data)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = hndl;
+		IRQ_HANDLER[irq].data = data;
+	}
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = default_isr;
+		IRQ_HANDLER[irq].data = (void *)irq;
+		irq_disable(irq);
+	}
+}
+
+int arch_interrupt_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(IRQ_HANDLER); ++i)
+		irq_free_handler(i);
+
+	/* hardware reset */
+	writel(0x00000000, &regs->irq32.ena);
+	writel(0xffffffff, &regs->irq32.scr);
+	writel(0x00000000, &regs->irq32.tmr);
+	writel(0x00000000, &regs->irq32.tlr);
+
+	writel(0x00000000, &regs->irq64.ena);
+	writel(0xffffffff, &regs->irq64.scr);
+	writel(0x00000000, &regs->irq64.tmr);
+	writel(0x00000000, &regs->irq64.tlr);
+
+	return 0;
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
diff --git a/arch/arm/cpu/faraday/reset.c b/arch/arm/cpu/faraday/reset.c
new file mode 100644
index 0000000..80afabb
--- /dev/null
+++ b/arch/arm/cpu/faraday/reset.c
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/cpu/faraday/reset.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/ftwdt010_wdt.h>
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt __iomem *regs =
+		(struct ftwdt010_wdt __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with System Reset Function */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+	/* Kick it to make sure it's in running state */
+	writel(FTWDT010_WDRESTART_MAGIC, &regs->wdrestart);
+#else
+	uint32_t start = CONFIG_SYS_TEXT_BASE;
+
+	__asm__ __volatile__ (
+		"mov pc, %0\n"
+		: /* output */
+		: "r"(start) /* input */
+	);
+#endif
+}
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..577d900
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,523 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _image_copy_end_ofs
+_image_copy_end_ofs:
+	.word __image_copy_end - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * Relocate U-Boot to RAM
+	 * It's copied from the old u-boot release.
+	 */
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+	adr	r0, _start          /* r0 <- current position of code   */
+	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
+	teq     r0, r1          /* don't reloc during debug         */
+	bleq    rr_exit
+	ldr	r2, _end_ofs        /* r2 <- size of u-boot             */
+	add	r2, r0, r2          /* r2 <- source end address         */
+
+rr_loop:
+	ldmia r0!, {r3-r10}	/* copy from source address [r0]    */
+	stmia r1!, {r3-r10}	/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end addreee [r2]    */
+	blo	rr_loop
+
+	/* Adjust the pc to use the correct text address */
+	adr	r0, _start
+	ldr	r1, _TEXT_BASE
+	sub r2, pc, r0
+	add r2, r2, #4
+	add pc, r1, r2
+
+rr_exit:
+#endif  /* #if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD) */
+
+	bl	_main
+
+/*---------------------------------------------------------------------*/
+
+/*
+ * void relocate_code(addr_moni)
+ *
+ * This function relocates the monitor code.
+ */
+	.globl	relocate_code
+relocate_code:
+	mov	r6, r0	/* save addr of destination */
+
+	adr	r0, _start
+	subs	r9, r6, r0		/* r9 <- relocation offset */
+	beq	relocate_done		/* skip relocation */
+	mov	r1, r6			/* r1 <- scratch for copy loop */
+	ldr	r3, _image_copy_end_ofs
+	add	r2, r0, r3		/* r2 <- source end address	    */
+
+copy_loop:
+	ldmia	r0!, {r10-r11}		/* copy from source address [r0]    */
+	stmia	r1!, {r10-r11}		/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end address [r2]    */
+	blo	copy_loop
+
+#ifndef CONFIG_SPL_BUILD
+	/*
+	 * fix .rel.dyn relocations
+	 */
+	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
+	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
+	add	r10, r10, r0		/* r10 <- sym table in FLASH */
+	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
+	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
+	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
+	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
+fixloop:
+	ldr	r0, [r2]   /* r0 <- location to fix up, IN FLASH! */
+	add	r0, r0, r9 /* r0 <- location to fix up in RAM */
+	ldr	r1, [r2, #4]
+	and	r7, r1, #0xff
+	cmp	r7, #23			/* relative fixup? */
+	beq	fixrel
+	cmp	r7, #2			/* absolute fixup? */
+	beq	fixabs
+	/* ignore unknown type of fixup */
+	b	fixnext
+fixabs:
+	/* absolute fix: set location to (offset) symbol value */
+	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
+	add	r1, r10, r1		/* r1 <- address of symbol in table */
+	ldr	r1, [r1, #4]		/* r1 <- symbol value */
+	add	r1, r1, r9		/* r1 <- relocated sym addr */
+	b	fixnext
+fixrel:
+	/* relative fix: increase location by offset */
+	ldr	r1, [r0]
+	add	r1, r1, r9
+fixnext:
+	str	r1, [r0]
+	add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */
+	cmp	r2, r3
+	blo	fixloop
+#endif
+
+relocate_done:
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ)
+	/* adjust exception table */
+	adr r0, _undefined_instruction
+	adr r2, _TEXT_BASE
+	ldr r1, [r2]
+adjustex:
+	ldr r3, [r0]
+	sub r3, r3, r1
+	add r3, r6, r3      /* r6 -> relocaddr */
+	str r3, [r0], #4
+	cmp r0, r2
+	blo adjustex
+
+	/* relocate exception table */
+	adr r0, _start
+	ldr	r1, =CONFIG_SYS_SDRAM_BASE
+	adr r2, _TEXT_BASE
+copyex:
+	ldr r3, [r0], #4 /* copy from source address [r0] */
+	str r3, [r1], #4 /* copy to   target address [r1] */
+	cmp	r0, r2       /* until source end addreee [r2] */
+	blo	copyex
+#endif	/* #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ) */
+	bx	lr
+
+#ifndef CONFIG_SPL_BUILD
+
+_rel_dyn_start_ofs:
+	.word __rel_dyn_start - _start
+_rel_dyn_end_ofs:
+	.word __rel_dyn_end - _start
+_dynsym_start_ofs:
+	.word __dynsym_start - _start
+
+#endif
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index d9bbee3..ac59fec 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -23,6 +23,8 @@
  * MA 02111-1307 USA
  */
 
+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -35,6 +37,15 @@ SECTIONS
 	{
 		__image_copy_start = .;
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}
 
diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..9ddefed
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,73 @@
+/*
+ * arch/arm/include/asm/arch-a360/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC020_BASE		0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+#define CONFIG_FTSSP010_GPIO_BASE	0x98700000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+#define CONFIG_FOTG210_BASE         0x90B00000
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/pmu.h b/arch/arm/include/asm/arch-a360/pmu.h
new file mode 100644
index 0000000..51b9391
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/pmu.h
@@ -0,0 +1,39 @@
+/*
+ * asm/arch-a360/pmu.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_PMU_H
+#define __ASM_ARCH_PMU_H
+
+struct a360pmu_regs {
+	uint32_t idr;      /* ID register */
+	uint32_t rsvd0;
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pmr;      /* Power mode register */
+
+	uint32_t pmcr;     /* Power manager control register */
+	uint32_t peer;     /* Power manager edge detect enable register */
+	uint32_t pesr;     /* Power manager edge detect status register */
+	uint32_t rsvd1;
+
+	uint32_t pmsr;     /* Power manager status register */
+	uint32_t pgsr;     /* Power manager GPIO sleep state register */
+	uint32_t rsvd2;
+	uint32_t mcr;      /* Misc. control register */
+
+	uint32_t pdcr;     /* PLL/DLL control register */
+	uint32_t rsvd3[7];
+
+	uint32_t pspr[16]; /* Power manager scratch pad register */
+
+	uint32_t rsvd4[3];
+	uint32_t jssr;     /* Jumper setting status register */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/scu.h b/arch/arm/include/asm/arch-a360/scu.h
new file mode 100644
index 0000000..6fbd1b8
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/scu.h
@@ -0,0 +1,27 @@
+/*
+ * asm/arch-a360/scu.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a360scu_regs {
+	uint32_t idr;      /* 0x00: ID Register */
+	uint32_t gcr;      /* 0x04: General Control Register */
+	uint32_t ccr;      /* 0x08: Clock Configuration Register */
+	uint32_t hcer;     /* 0x0C: AHB Clock Enable Register */
+	uint32_t pcer;     /* 0x10: APB Clock Enable Register */
+	uint32_t csr;      /* 0x14: Configuration Strap Register */
+	uint32_t iomcr[4]; /* IO Mux Control Register */
+	uint32_t iopcr[2]; /* IO Parameter Control Register */
+	uint32_t cescr;    /* CPU Edge Sync Control Register */
+	uint32_t expcr[3]; /* PCI-Express Control Register */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..4c9f105
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDR_BASE             0x93100000
+#define CONFIG_AHB_BASE             0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/scu.h b/arch/arm/include/asm/arch-a369/scu.h
new file mode 100644
index 0000000..46304a9
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/scu.h
@@ -0,0 +1,48 @@
+/*
+ * arch/arm/include/asm/arch-a369/scu.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a369scu_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* HCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+#endif
diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
index 440b041..a103922 100644
--- a/arch/arm/include/asm/mach-types.h
+++ b/arch/arm/include/asm/mach-types.h
@@ -144,6 +144,7 @@ extern unsigned int __machine_arch_type;
 #define MACH_TYPE_AKITA                744
 #define MACH_TYPE_E330                 753
 #define MACH_TYPE_NOKIA770             755
+#define MACH_TYPE_FARADAY              758
 #define MACH_TYPE_CARMEVA              769
 #define MACH_TYPE_EDB9315A             772
 #define MACH_TYPE_STARGATE2            774
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..40b1d89
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,65 @@
+/*
+ * board/faraday/a360evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <asm/arch/scu.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a360scu_regs __iomem *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+/*
+ * pinmux
+ */
+static void pinmux_init(void)
+{
+	writel(0x00555500, &scu->iomcr[3]);
+	setbits_le32(&scu->iomcr[0], 0x800002AA);
+	setbits_le32(&scu->iomcr[1], 0x82AAAAAA);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	pinmux_init();
+
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	return ftmac110_initialize(bd);
+}
diff --git a/board/faraday/a360evb/clk.c b/board/faraday/a360evb/clk.c
new file mode 100644
index 0000000..1a8a224
--- /dev/null
+++ b/board/faraday/a360evb/clk.c
@@ -0,0 +1,57 @@
+/*
+ * board/faraday/a360evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/pmu.h>
+
+static struct a360scu_regs __iomem *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a360pmu_regs __iomem *pmu = (void __iomem *)CONFIG_PMU_BASE;
+
+static ulong clk_get_rate_ahb(void)
+{
+	return CONFIG_MAIN_CLK * ((readl(&pmu->pdcr) >> 3) & 0x3f) / 8;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	uint32_t s = readl(&scu->csr);
+	uint32_t p = readl(&pmu->pmr);
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (s & 0x200) ? 2 : 4;
+
+	return (p & 0x02) ? (clk * mul) : clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a360evb/config.mk b/board/faraday/a360evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a360evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..1ead608
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,33 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..d05b33e
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,188 @@
+/*
+ * board/faraday/a369evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+#include <asm/arch/scu.h>
+#include <faraday/mmc.h>
+#include <faraday/nand.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftlcdc200.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a369scu_regs __iomem *scu
+	= (void __iomem *)CONFIG_SCU_BASE;
+
+static struct ftlcdc200_regs __iomem *lcd
+	= (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+static struct ftsmc020 __iomem *smc
+	= (void __iomem *)CONFIG_SMC_BASE;
+
+/*
+ * System Control Uint (pinmux)
+ */
+static void scu_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&scu->ehwcfg) & BIT_MASK(2)) {
+		writel(0xc0008000, &scu->hclkgr);
+		setbits_le32(&scu->gpmux, BIT_MASK(14));
+	} else {
+#ifdef CONFIG_SUPP_EXTAHB
+		/* Enable external AHB */
+		writel(0x40000000, &scu->hclkgr);
+		writel(0x00001078, &scu->gpmux);
+		clrbits_le32(&scu->sccfg[0], 0xf0);
+		setbits_le32(&scu->sccfg[0], 0x80);
+#else
+		/* Enable SD1 */
+		writel(0x00000241, &scu->mfpmux[0]);
+#endif
+	}
+
+	/* Clock Setup: SD = 133MHz, SSP = APB (SPI mode) */
+	writel(0x000A0A0A, &scu->sccfg[1]);
+
+	/* Enable LCD for I2C/TVEncode work-around */
+	/* ... Clock div = (31+1) */
+	writel(0x1f00, &lcd->pcr);
+	/* ... Enable LCD */
+	writel(0x0003, &lcd->fer);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	/* 1. NOR flash */
+	/* Bank 0: base=0x00000000, size=64MB, 16bits */
+	writel(BIT_MASK(28) | (6 << 4) | 1, &smc->bank[0].cr);
+	/* Bank 0: worst timing */
+	writel(0x0f1ff3ff, &smc->bank[0].tpr);
+
+	/* 2. Unused Area */
+	writel(0x00000000, &smc->bank[1].cr);
+	writel(0x0f1ff3ff, &smc->bank[1].tpr);
+	writel(0x00000000, &smc->bank[2].cr);
+	writel(0x0f1ff3ff, &smc->bank[2].tpr);
+	writel(0x00000000, &smc->bank[3].cr);
+	writel(0x0f1ff3ff, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	scu_init();
+	smc_init();
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC010_MCI)
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_SYS_NAND_SELF_INIT
+void board_nand_init(void)
+{
+	int devnum = 0;
+	struct mtd_info *mtd = &nand_info[devnum];
+	struct nand_chip *chip;
+	struct faraday_nand_chip *info;
+	uint32_t reg = readl(&scu->ehwcfg);
+
+	chip = calloc(1, sizeof(*chip) + sizeof(*info));
+	if (!chip)
+		return;
+	info = (void *)(chip + 1);
+	info->regs = (void __iomem *)CONFIG_SYS_NAND_BASE;
+	chip->priv = info;
+	chip->IO_ADDR_R = NULL;
+	chip->IO_ADDR_W = NULL;
+	mtd->priv = chip;
+
+	/* page size */
+	switch ((reg & 0x180) >> 7) {
+	case 0:
+		chip->page_shift = 9;	/* 512 */
+		break;
+	case 1:
+		chip->page_shift = 11;	/* 2048 */
+		break;
+	case 2:
+	case 3:
+		chip->page_shift = 12;	/* 4096 */
+		break;
+	}
+	info->pgsz = 1 << chip->page_shift;
+
+	/* block size */
+	chip->phys_erase_shift = chip->page_shift + 4 + ((reg & 0x600) >> 9);
+	info->bksz = 1 << chip->phys_erase_shift;
+
+	/* address length/cycle */
+	info->alen = 3 + ((reg & 0x60) >> 5);
+
+	if (ftnandc021_init(chip))
+		goto bni_err;
+
+	if (nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS))
+		goto bni_err;
+
+	nand_register(devnum);
+
+	return;
+
+bni_err:
+	free(chip);
+}
+#endif /* #ifdef CONFIG_SYS_NAND_SELF_INIT */
diff --git a/board/faraday/a369evb/clk.c b/board/faraday/a369evb/clk.c
new file mode 100644
index 0000000..de33215
--- /dev/null
+++ b/board/faraday/a369evb/clk.c
@@ -0,0 +1,72 @@
+/*
+ * board/faraday/a369evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+
+static struct a369scu_regs __iomem *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+static ulong clk_get_rate_ahb(void)
+{
+	uint32_t tmp = 0, mul = 4;
+	ulong ts;
+
+	/* Wait until PLL1 becomes stable or 5 ms timeout */
+	ts = get_timer(0);
+	do {
+		tmp = readl(&scu->pllcr);
+	} while (!(tmp & BIT_MASK(1)) && (get_timer(ts) < 5));
+
+	mul = (tmp >> 24) & 0x3f;
+	return (CONFIG_MAIN_CLK * mul) >> 3;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+#ifndef CONFIG_A369_FA606TE_PLATFORM
+	uint32_t tmp;
+
+	/* If it's an internal CPU */
+	tmp = readl(&scu->ehwcfg);
+	if (!(tmp & BIT_MASK(2))) {
+		tmp = readl(&scu->hwcfg);
+		tmp = min(2, (tmp >> 3) & 3);
+		clk = clk << tmp;
+	}
+#endif
+	return clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a369evb/config.mk b/board/faraday/a369evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a369evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..a55fddb
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,136 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+	.macro	_v3_mw32
+
+	ldr r0, =0x1008
+	ldr r3, =0x1108
+_v3_mw32_loop:
+	cmp   r0, r3
+	movhs r1, #0
+	ldrlo r1, [r0, #0]
+	ldrlo r2, [r0, #4]
+	teq   r1, #0
+	strne r2, [r1, #0]
+	addne r0, #8
+	bne   _v3_mw32_loop
+
+	.endm	/* _v3_mw32 */
+
+	.macro	_sdram_enable
+
+	/* Clear SDRAM CKE, GPIO Hold, READ Hold */
+	ldr r0, =CONFIG_SCU_BASE
+	mov r1, #7
+	str r1, [r0, #0x14]
+
+	/* Wait until sdram ready */
+	ldr r0, =CONFIG_DDR_BASE
+_sdram_wait:
+	ldr r1, [r0, #0x04]
+	teq r1, #0x100
+	bne _sdram_wait
+
+	.endm	/* _sdram_enable */
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	/* Check image header */
+	ldr   r1, =0x1000
+	ldr   r0, [r1, #0]
+	ldr   r1, =0x00484946	/* "FIH\0" */
+	ldr   r2, =0x33333639	/* "3369" */
+	teq   r0, r1
+	teqne r0, r2
+	bne _exit
+	_v3_mw32
+	_sdram_enable
+
+#if 1
+	/* Create a shadow copy onto SDRAM (limited to 512K) */
+	mov	r0, #0               /* r0 <- start of source */
+	ldr	r1, =CONFIG_AHB_BASE
+	ldr r2, [r1,#0x18]
+	bic r1, r2, #0x000f0000  /* r1 <- SDRAM base */
+	mov	r2, #0x80000         /* r2 <- source end address (512KB) */
+
+_copy_loop:
+	ldmia	r0!, {r3-r10} /* copy from source address [r0] */
+	stmia	r1!, {r3-r10} /* copy to   target address [r1] */
+	cmp	r0, r2            /* until source end addreee [r2] */
+	ble	_copy_loop
+#else
+	/* Adjust lr(r14) to the remapped address */
+	ldr r0, =CONFIG_AHB_BASE
+	ldr r1, [r0,#0x18]    /* r1 = AHB slave 6 */
+	bic r1, r1, #0xff000000
+	bic r1, r1, #0x00f00000
+	lsr r1, r1, #16
+	add r1, r1, #20
+	mov r2, #1
+	lsl r2, r2, r1
+	add lr, lr, r2
+#endif
+
+	/* AHB remap */
+	mov r0, #0
+	ldr r1, =CONFIG_AHB_BASE
+	ldr r2, =CONFIG_DDR_BASE
+	/* magic (r5) = REG32(0x00) XOR 0xFFFFFFFF */
+	ldr r5, [r0, #0]
+	ldr r3, =0xffffffff
+	eor r5, r5, r3
+	/* r3 = REG32(CONFIG_IOBASE_DDR + 0x10) & 0x00FFFFFF */
+	ldr r3, [r2, #0x10]
+	bic r3, #0xff000000
+	/* r4 = 0x00100f01 */
+	ldr r4, =0x00100f01
+
+	/*
+	 * invalidate i-cache all to make sure the codes bellow
+	 * to be fetched into a single 32-bytes cache line
+	 */
+	mcr p15, 0, r0, c7, c5, 0
+
+	.align 5
+
+	str r3, [r2, #0x10] /* REG32(CONFIG_IOBASE_DDR + 0x10) &= 0x00FFFFFF */
+	str r4, [r1, #0x88] /* REG32(CONFIG_IOBASE_AHB + 0x88)  = 0x00100F01 */
+
+_remap_wait:
+	str r5, [r0, #0]
+	ldr r1, [r0, #0]
+	teq r1, r5
+	bne _remap_wait		/* while(magic != REG32(addr)) */
+
+_exit:
+	mov	pc, lr
diff --git a/boards.cfg b/boards.cfg
index 8b7933f..941f158 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -73,6 +73,9 @@ mini2440                     arm         arm920t     mini2440            friendl
 VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
 smdk2410                     arm         arm920t     -                   samsung        s3c24x0
 omap1510inn                  arm         arm925t     -                   ti
+a360                         arm         faraday     a360evb             faraday        a360
+a369                         arm         faraday     a369evb             faraday        a369
+a369_fa606te                 arm         faraday     a369evb             faraday        a369
 integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap:CM926EJ_S
 integratorcp_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorcp:CM924EJ_S
 aspenite                     arm         arm926ejs   -                   Marvell        armada100
diff --git a/include/common.h b/include/common.h
index 0cfa6a8..fa134f3 100644
--- a/include/common.h
+++ b/include/common.h
@@ -112,6 +112,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_FARADAY
+#include <asm/arch/hardware.h>
+#endif
 
 #include <part.h>
 #include <flash.h>
@@ -257,6 +260,16 @@ typedef void (interrupt_handler_t)(void *);
 	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
 	(type *)( (char *)__mptr - offsetof(type,member) );})
 
+#ifdef CONFIG_FARADAY
+/* board/faraday/xxx/clk.c */
+extern ulong clk_get_rate(char *id);
+
+/* arch/arm/cpu/faraday/xxx/interrupt.c */
+extern void irq_set_trigger(int irq, int edge, int low);
+extern void irq_enable(int irq);
+extern void irq_disable(int irq);
+#endif
+
 /*
  * Function Prototypes
  */
diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..5b9da4d
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,63 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Main oscillator (HZ) */
+#define CONFIG_MAIN_CLK             40000000
+
+/*
+ * Memory Configuration
+ */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_256M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_PIN    26
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * A36x Common Configuration
+ */
+#include "a36x-common.h"
+
+#endif
diff --git a/include/configs/a369-common.h b/include/configs/a369-common.h
new file mode 100644
index 0000000..bdfb273
--- /dev/null
+++ b/include/configs/a369-common.h
@@ -0,0 +1,74 @@
+#ifndef __CONFIG_A369_COMMON_H
+#define __CONFIG_A369_COMMON_H
+
+#include <asm/hardware.h>
+
+/*
+ * A369 Platform Common Configuration
+ */
+
+/* Main oscillator (HZ) */
+#define CONFIG_MAIN_CLK             33000000
+
+/*
+ * Memory Configuration
+ */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_512M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* NAND Flash */
+#define CONFIG_SYS_MAX_NAND_DEVICE  1 /* Max. num. of devices */
+#define CONFIG_SYS_NAND_TIMING      { 0x02240264, 0x42054209 }
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_BASE   0x92600000 /* GPIO 1 */
+#define CONFIG_FTSSP010_GPIO_PIN    27
+
+/* NOR Flash */
+/*
+#define PHYS_FLASH_SIZE             SZ_64M
+#define CONFIG_SYS_FLASH_BASE       0x20000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH  FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS  1
+#define CONFIG_SYS_MAX_FLASH_SECT   1024
+*/
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_IN_NAND
+#define CONFIG_ENV_OFFSET           0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND    0x07FE0000
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * A36x Common Configuration
+ */
+#include "a36x-common.h"
+
+#endif
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..40e6b60
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,33 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_PLATFORM
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+#define CONFIG_USE_IRQ
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Support runtime switching to built-in slave core: FA606TE */
+#define CONFIG_CMD_FA606
+
+/* Autoboot */
+#define CONFIG_BOOTDELAY            3
+#define CONFIG_BOOTCOMMAND          "bootfa nand linux"
+
+/*
+ * A369 Common Configuration
+ */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/a369_fa606te.h b/include/configs/a369_fa606te.h
new file mode 100644
index 0000000..9fb1b0a
--- /dev/null
+++ b/include/configs/a369_fa606te.h
@@ -0,0 +1,26 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_FA606TE_PLATFORM
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/*
+ * A369 Common Configuration
+ */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/a36x-common.h b/include/configs/a36x-common.h
new file mode 100644
index 0000000..8ae6730
--- /dev/null
+++ b/include/configs/a36x-common.h
@@ -0,0 +1,303 @@
+#ifndef __CONFIG_A36X_COMMON_H
+#define __CONFIG_A36X_COMMON_H
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+#define CONFIG_BOARD_LATE_INIT      1
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_8M
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+/*
+ * CPU
+ */
+#define CONFIG_FARADAY
+#define CONFIG_ARCH_CPU_INIT
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_SYS_CACHELINE_SIZE	32
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+/*
+ * Interrupt
+ */
+#ifdef CONFIG_USE_IRQ
+# define CONFIG_FTINTC020
+# ifdef CONFIG_A369_PLATFORM
+#  define CONFIG_PIC_BASE           CONFIG_FTINTC020_BASE
+# else
+#  define CONFIG_PIC_BASE           CONFIG_FTINTC020_BASE1
+# endif
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_SYS_HZ               1000
+
+#ifdef CONFIG_FTTMR010_BASE
+# define CONFIG_FTTMR010
+# define CONFIG_TIMER_BASE           CONFIG_FTTMR010_BASE
+# define CONFIG_TIMER_IRQ            CONFIG_FTTMR010_IRQ
+#endif /* CONFIG_FTTMR010_BASE */
+
+#ifdef CONFIG_FTPWMTMR010_BASE
+# define CONFIG_FTPWMTMR010
+# define CONFIG_TIMER_BASE           CONFIG_FTPWMTMR010_BASE
+# define CONFIG_TIMER_IRQ            CONFIG_FTPWMTMR010_IRQ
+#endif /* CONFIG_FTPWMTMR010_BASE */
+
+/*
+ * Serial Info
+ */
+#ifdef CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# ifndef CONFIG_SYS_NS16550_CLK
+#  define CONFIG_SYS_NS16550_CLK     18432000
+# endif
+# define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE -4
+# define CONFIG_CONS_INDEX           1
+# define CONFIG_BAUDRATE             38400
+# undef  CONFIG_HWFLOW
+# undef  CONFIG_MODEM_SUPPORT
+#endif /* #ifdef CONFIG_FTUART010_BASE */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTMAC110_BASE
+# define CONFIG_FTMAC110
+#endif
+#ifdef CONFIG_FTGMAC100_BASE
+# define CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA    /* Used by Ratbert's ftgmac100 only */
+#endif
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR    32 /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT 20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif
+
+/*
+ * I2C Controller
+ */
+#ifdef CONFIG_FTI2C010_BASE3
+# define CONFIG_SYS_MAX_I2C_BUS      4
+#elif defined(CONFIG_FTI2C010_BASE2)
+# define CONFIG_SYS_MAX_I2C_BUS      3
+#elif defined(CONFIG_FTI2C010_BASE1)
+# define CONFIG_SYS_MAX_I2C_BUS      2
+#elif defined(CONFIG_FTI2C010_BASE)
+# define CONFIG_SYS_MAX_I2C_BUS      1
+#else
+# define CONFIG_SYS_MAX_I2C_BUS      0
+#endif
+#if CONFIG_SYS_MAX_I2C_BUS > 0
+# define CONFIG_FTI2C010
+# define CONFIG_HARD_I2C
+# define CONFIG_SYS_I2C_SPEED        5000
+# define CONFIG_SYS_I2C_SLAVE        0
+# define CONFIG_CMD_I2C
+# define CONFIG_I2C_CMD_TREE
+#endif
+#if CONFIG_SYS_MAX_I2C_BUS > 1
+# define CONFIG_I2C_MULTI_BUS
+#endif
+
+/*
+ * I2C-EEPROM
+ */
+#ifdef CONFIG_ENV_EEPROM_IS_ON_I2C
+# define CONFIG_CMD_EEPROM
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      3
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  5
+# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN         1
+# define CONFIG_SYS_I2C_MULTI_EEPROMS
+#endif
+
+/*
+ * SPI Bus
+ */
+#ifdef CONFIG_FTSSP010_BASE
+# define CONFIG_FTSSP010_SPI
+# define CONFIG_SPI
+# define CONFIG_HARD_SPI
+# define CONFIG_CMD_SPI
+# define CONFIG_ENV_SPI_BUS         0
+# define CONFIG_ENV_SPI_CS          0
+# define CONFIG_ENV_SPI_MAX_HZ      25000000
+# define CONFIG_DEFAULT_SPI_MODE    SPI_MODE_0
+#endif
+
+/*
+ * SPI Flash
+ */
+#ifdef CONFIG_FTSPI020_BASE
+# define CONFIG_FTSPI020
+#elif defined(CONFIG_SPI)
+# define CONFIG_SPI_FLASH
+# define CONFIG_SPI_FLASH_MACRONIX
+# define CONFIG_SPI_FLASH_WINBOND
+#endif
+
+#if defined(CONFIG_FTSPI020) || defined(CONFIG_SPI_FLASH)
+# define CONFIG_CMD_SF
+# define CONFIG_SF_DEFAULT_MODE     SPI_MODE_0
+# define CONFIG_SF_DEFAULT_SPEED    25000000
+#endif
+
+/*
+ * NOR Flash
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* print 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * NAND Flash
+ */
+#ifdef CONFIG_FTNANDC021_BASE
+# define CONFIG_SYS_NAND_SELF_INIT
+# define CONFIG_NAND_FTNANDC021
+# define CONFIG_SYS_NAND_BASE           CONFIG_FTNANDC021_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+#endif
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010_BASE
+# define CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* The hardware core supports SDIO */
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 0
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#if defined(CONFIG_SUPP_USB_RNDIS) && defined(CONFIG_FOTG210_BASE)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+#endif
+
+/*
+ * LCD
+ */
+#if defined(CONFIG_SUPP_VGA_CONSOLE) && defined(CONFIG_FTLCDC200_BASE)
+# define CONFIG_FTLCDC200
+# define CONFIG_FTLCDC200_800X480S_TPO
+# define LCD_BPP                    4 /* 16-bit per pixel */
+# define CONFIG_LCD
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+#ifndef CONFIG_SYS_LOAD_ADDR        /* Default load address */
+# define CONFIG_SYS_LOAD_ADDR       (CONFIG_SYS_SDRAM_BASE + SZ_1M)
+#endif
+/* Console Baud-Rate Table */
+#define CONFIG_SYS_BAUDRATE_TABLE   { 115200, 57600, 38400, 19200, 9600 }
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 72abcb3..ef10f31 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -57,6 +57,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)
 
+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -70,4 +80,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)
 
+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
-- 
1.7.9.5

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

* [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-04-26 12:19           ` Marek Vasut
  2013-04-29  3:10             ` Kuo-Jung Su
  2013-05-07  6:26           ` [U-Boot] [PATCH v4 0/2] usb: ehci: add Faraday USB EHCI&Gadget support Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-04-26 12:19 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch add supports to both Faraday FUSBH200 and FOTG210,
> these controllers slightly differ from standard EHCI specification.

How do they differ?

> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
>  common/usb_hub.c                |    5 ++
>  drivers/usb/host/Makefile       |    1 +
>  drivers/usb/host/ehci-faraday.c |  122
> +++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-hcd.c     | 
>  11 ++++
>  drivers/usb/host/ehci.h         |    5 ++
>  include/usb/fotg210.h           |   71 +++++++++++++++++++++++
>  include/usb/fusbh200.h          |   28 +++++++++
>  7 files changed, 243 insertions(+)
>  create mode 100644 drivers/usb/host/ehci-faraday.c
>  create mode 100644 include/usb/fotg210.h
>  create mode 100644 include/usb/fusbh200.h
> 
> diff --git a/common/usb_hub.c b/common/usb_hub.c
> index b5eeb62..26d66b8 100644
> --- a/common/usb_hub.c
> +++ b/common/usb_hub.c
> @@ -375,6 +375,11 @@ static int usb_hub_configure(struct usb_device *dev)
>  		return -1;
>  	}
> 
> +#ifdef CONFIG_USB_EHCI_FARADAY
> +	/* Faraday USB 2.0 EHCI chips need a long long delay here */

Why? Do they need it only for root hub or for all the hub down the road as well?

> +	mdelay(250);
> +#endif
> +
>  	if (usb_get_hub_status(dev, buffer) < 0) {
>  		USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
>  				dev->status);
> diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
> index 87a5970..98f2a10 100644
> --- a/drivers/usb/host/Makefile
> +++ b/drivers/usb/host/Makefile
> @@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
>  else
>  COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
>  endif
> +COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
>  COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
>  COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
>  COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
> diff --git a/drivers/usb/host/ehci-faraday.c
> b/drivers/usb/host/ehci-faraday.c new file mode 100644
> index 0000000..adf57d1
> --- /dev/null
> +++ b/drivers/usb/host/ehci-faraday.c
> @@ -0,0 +1,122 @@
> +/*
> + * Faraday USB 2.0 EHCI Controller
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later version.
> + * See the file COPYING in the root directory of the source tree for
> details. + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <usb.h>
> +#include <usb/fusbh200.h>
> +#include <usb/fotg210.h>
> +
> +#include "ehci.h"
> +
> +union ehci_faraday_regs {
> +	struct fusbh200_regs usb;
> +	struct fotg210_regs  otg;
> +};
> +
> +static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
> +{
> +	union ehci_faraday_regs __iomem *regs = (void *)hccr;
> +	return !readl(&regs->usb.easstr);
> +}
> +
> +/*
> + * Create the appropriate control structures to manage
> + * a new EHCI host controller.
> + */
> +int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
> +		struct ehci_hcor **ret_hcor)
> +{
> +	struct ehci_hccr *hccr;
> +	struct ehci_hcor *hcor;
> +	union ehci_faraday_regs __iomem *regs;
> +#ifdef CONFIG_USB_EHCI_BASE_LIST
> +	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
> +#else
> +	uint32_t base_list[] = { CONFIG_USB_EHCI_BASE };
> +#endif
> +
> +	if (index < 0 || index >= ARRAY_SIZE(base_list))
> +		return -1;
> +	regs = (void __iomem *)base_list[index];
> +	hccr = (struct ehci_hccr *)&regs->usb.hccr;
> +	hcor = (struct ehci_hcor *)&regs->usb.hcor;
> +
> +	if (ehci_hci_fotg2xx(hccr)) {
> +		/* A-device bus reset */
> +		/* ... Power off A-device */
> +		setbits_le32(&regs->otg.otgcsr, BIT_MASK(5));

Do these bits not have names?

[...]

> +int ehci_hcd_port_speed(struct ehci_hccr *hccr)
> +{
> +	int ret = 0;
> +	int speed;
> +	union ehci_faraday_regs __iomem *regs = (void *)hccr;
> +
> +	if (ehci_hci_fotg2xx(hccr))
> +		speed = (readl(&regs->otg.otgcsr) >> 22) & 0x03;
> +	else
> +		speed = (readl(&regs->usb.bmcsr) >>  9) & 0x03;

Same here, what're these magic numbers?

> +	switch (speed) {
> +	case 0:    /* full speed */
> +		break;
> +
> +	case 1:    /* low  speed */
> +		ret = USB_PORT_STAT_LOW_SPEED;
> +		break;
> +
> +	case 2:    /* high speed */
> +		ret = USB_PORT_STAT_HIGH_SPEED;
> +		break;
> +
> +	default:
> +		printf("ehci-faraday: invalid device speed\n");
> +		break;
> +	}
> +
> +	return ret;
> +}
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index c816878..450d217 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -149,8 +149,10 @@ static int handshake(uint32_t *ptr, uint32_t mask,
> uint32_t done, int usec) static int ehci_reset(int index)
>  {
>  	uint32_t cmd;
> +#ifndef CONFIG_USB_EHCI_FARADAY
>  	uint32_t tmp;
>  	uint32_t *reg_ptr;
> +#endif
>  	int ret = 0;
> 
>  	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
> @@ -163,6 +165,7 @@ static int ehci_reset(int index)
>  		goto out;
>  	}
> 
> +#ifndef CONFIG_USB_EHCI_FARADAY

Wouldn't it suffice to set your EHCI is not TDI ?

>  	if (ehci_is_TDI()) {
>  		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
>  		tmp = ehci_readl(reg_ptr);
> @@ -172,6 +175,7 @@ static int ehci_reset(int index)
>  #endif
>  		ehci_writel(reg_ptr, tmp);
>  	}
> +#endif	/* !CONFIG_USB_EHCI_FARADAY */

[...]

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

* [U-Boot] [PATCH v3 09/11] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 09/11] " Kuo-Jung Su
@ 2013-04-26 12:21           ` Marek Vasut
  2013-04-29  3:11             ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-04-26 12:21 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> The Faraday FOTG210 is an OTG chip which could operate
> as either an EHCI Host or a USB Device as a time.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>

Same rambling as for the other patch, bits should have proper names defined in 
the fotg_....h header file. You should avoid calling 
dcache_enable()/dcache_disable() throughout the driver, why do you need to do 
that? Rather implement proper cacheline flushing/invalidation.

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
@ 2013-04-26 23:41           ` Scott Wood
  2013-04-29  3:28             ` Kuo-Jung Su
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-04-26 23:41 UTC (permalink / raw)
  To: u-boot

On 04/26/2013 03:02:36 AM, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTNANDC021 is a integrated NAND flash controller.
> It use a build-in command table to abstract the underlying
> NAND flash control logic.
> 
> For example:
> 
> Issuing a command 0x10 to FTNANDC021 would result in
> a page write + a read status operation.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Scott Wood <scottwood@freescale.com>
> ---
>  README                        |    7 +
>  drivers/mtd/nand/Makefile     |    1 +
>  drivers/mtd/nand/ftnandc021.c |  724  
> +++++++++++++++++++++++++++++++++++++++++
>  drivers/mtd/nand/ftnandc021.h |  137 ++++++++
>  include/faraday/nand.h        |   34 ++
>  5 files changed, 903 insertions(+)
>  create mode 100644 drivers/mtd/nand/ftnandc021.c
>  create mode 100644 drivers/mtd/nand/ftnandc021.h
>  create mode 100644 include/faraday/nand.h
> 
> diff --git a/README b/README
> index 862bb3e..adc198f 100644
> --- a/README
> +++ b/README
> @@ -3872,6 +3872,13 @@ Low Level (hardware related) configuration  
> options:
>  		- drivers/mtd/nand/ndfc.c
>  		- drivers/mtd/nand/mxc_nand.c
> 
> +- CONFIG_SYS_NAND_TIMING
> +		Defined to tell the NAND controller that the NAND chip  
> is using
> +		a customized timing parameters.
> +		Not all NAND drivers use this symbol.
> +		Example of drivers that use it:
> +		- drivers/mtd/nand/ftnandc021.c

This doesn't seem to have any standardized meaning (even if that meaning
is applicable to only a subset of controllers), so please call it
CONFIG_SYS_FTNANDC021_TIMING and document the ftnandc021-specific
semantics.

> diff --git a/drivers/mtd/nand/ftnandc021.c  
> b/drivers/mtd/nand/ftnandc021.c
> new file mode 100644
> index 0000000..39c181f
> --- /dev/null
> +++ b/drivers/mtd/nand/ftnandc021.c
> @@ -0,0 +1,724 @@
> +/*
> + * Faraday NAND Flash Controller
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later  
> version.
> + * See the file COPYING in the root directory of the source tree for  
> details.
> + */
> +
> +#include <common.h>
> +#include <asm/errno.h>
> +#include <asm/io.h>
> +#include <asm/unaligned.h>
> +#include <nand.h>
> +#include <malloc.h>
> +#include <faraday/nand.h>
> +
> +#include "ftnandc021.h"
> +
> +#define CFG_HWECC	/* Enable hardware ECC */

If this is really to be optional, call it CONFIG_FTNANDC021_ECC (HWECC
suggests the alternative is SW ECC, not no ECC) and define it in the
board config file (or better, invert it to CONFIG_FTNANDC021_NO_ECC so
ECC is the default).

If it's not meant to be optional, just remove the non-ECC code.

If the ECC doesn't cause major problems in a reasonable use case, I'd
rather see the non-ECC code just removed.

> +static struct nand_ecclayout ftnandc021_ecclayout[] = {
> +	{ /* page size = 512 (oob size = 16) */
> +		.eccbytes = 6,
> +		.eccpos = { 0, 1, 2, 3, 6, 7 },
> +		.oobfree = {
> +#ifdef CFG_HWECC
> +			{ 9, 3 },
> +#else
> +			{ 8, 4 },
> +#endif
> +		}
> +	},
> +	{ /* page size = 2048 (oob size = 64) */
> +		.eccbytes = 24,
> +		.eccpos = {
> +			40, 41, 42, 43, 44, 45, 46, 47,
> +			48, 49, 50, 51, 52, 53, 54, 55,
> +			56, 57, 58, 59, 60, 61, 62, 63
> +		},
> +		.oobfree = {
> +#ifdef CFG_HWECC
> +			{ 9, 3 },
> +#else
> +			{ 8, 4 },
> +#endif
> +		},
> +	},
> +	{ /* page size = 4096 (oob size = 128) */
> +		.eccbytes = 48,
> +		.eccpos = {
> +			80, 81, 82, 83, 84, 85, 86, 87,
> +			88, 89, 90, 91, 92, 93, 94, 95,
> +			96, 97, 98, 99, 100, 101, 102, 103,
> +			104, 105, 106, 107, 108, 109, 110, 111,
> +			112, 113, 114, 115, 116, 117, 118, 119,
> +			120, 121, 122, 123, 124, 125, 126, 127
> +		},
> +		.oobfree = {
> +#ifdef CFG_HWECC
> +			{ 9, 7 },
> +#else
> +			{ 8, 8 },
> +#endif
> +		},
> +	},
> +};

Shouldn't .eccpos depend on HWECC?

> +static int ftnandc021_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
> +	uint8_t *read_ecc, uint8_t *calc_ecc)
> +{
> +	struct nand_chip *chip = mtd->priv;
> +	struct faraday_nand_chip *info = chip->priv;
> +	struct ftnandc021_chip *priv = info->priv;
> +	struct ftnandc021_regs __iomem *regs = priv->regs;
> +	uint32_t st = readl(&regs->ecc_sr);
> +	int ret = 0;
> +
> +	if (st & ECC_SR_CERR) {
> +		printf("ftnandc021: ecc corection error\n");
> +		ret = -EIO;
> +	} else if (st & ECC_SR_ERR) {
> +		printf("ftnandc021: ecc error\n");
> +		ret = -EIO;
> +	}
> +
> +	return ret;

Can you detect correctable errors?

> +#ifdef CFG_HWECC
> +	chip->ecc.bytes          = chip->ecc.layout->eccbytes;
> +	chip->ecc.size           = info->pgsz;
> +	chip->ecc.steps          = 1;

Is it really all in one step, regardless of page size?

-Scott

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

* [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-26 12:19           ` Marek Vasut
@ 2013-04-29  3:10             ` Kuo-Jung Su
  2013-04-29 22:50               ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-29  3:10 UTC (permalink / raw)
  To: u-boot

2013/4/26 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch add supports to both Faraday FUSBH200 and FOTG210,
>> these controllers slightly differ from standard EHCI specification.
>
> How do they differ?
>

1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
    are not only un-implemented, but also removed from its register address
    space, which means we have to update the 'struct ehci_hcor' of ehci.h

2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC implementations.
    (It should be a hardware bug, but no one wants to fix it.)

I'll add these description to commit log at next patch.

>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>>  common/usb_hub.c                |    5 ++
>>  drivers/usb/host/Makefile       |    1 +
>>  drivers/usb/host/ehci-faraday.c |  122
>> +++++++++++++++++++++++++++++++++++++++ drivers/usb/host/ehci-hcd.c     |
>>  11 ++++
>>  drivers/usb/host/ehci.h         |    5 ++
>>  include/usb/fotg210.h           |   71 +++++++++++++++++++++++
>>  include/usb/fusbh200.h          |   28 +++++++++
>>  7 files changed, 243 insertions(+)
>>  create mode 100644 drivers/usb/host/ehci-faraday.c
>>  create mode 100644 include/usb/fotg210.h
>>  create mode 100644 include/usb/fusbh200.h
>>
>> diff --git a/common/usb_hub.c b/common/usb_hub.c
>> index b5eeb62..26d66b8 100644
>> --- a/common/usb_hub.c
>> +++ b/common/usb_hub.c
>> @@ -375,6 +375,11 @@ static int usb_hub_configure(struct usb_device *dev)
>>               return -1;
>>       }
>>
>> +#ifdef CONFIG_USB_EHCI_FARADAY
>> +     /* Faraday USB 2.0 EHCI chips need a long long delay here */
>
> Why? Do they need it only for root hub or for all the hub down the road as well?
>

root hub only.

>> +     mdelay(250);
>> +#endif
>> +
>>       if (usb_get_hub_status(dev, buffer) < 0) {
>>               USB_HUB_PRINTF("usb_hub_configure: failed to get Status %lX\n",
>>                               dev->status);
>> diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
>> index 87a5970..98f2a10 100644
>> --- a/drivers/usb/host/Makefile
>> +++ b/drivers/usb/host/Makefile
>> @@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
>>  else
>>  COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
>>  endif
>> +COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
>>  COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
>>  COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
>>  COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
>> diff --git a/drivers/usb/host/ehci-faraday.c
>> b/drivers/usb/host/ehci-faraday.c new file mode 100644
>> index 0000000..adf57d1
>> --- /dev/null
>> +++ b/drivers/usb/host/ehci-faraday.c
>> @@ -0,0 +1,122 @@
>> +/*
>> + * Faraday USB 2.0 EHCI Controller
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for
>> details. + */
>> +
>> +#include <common.h>
>> +#include <asm/io.h>
>> +#include <usb.h>
>> +#include <usb/fusbh200.h>
>> +#include <usb/fotg210.h>
>> +
>> +#include "ehci.h"
>> +
>> +union ehci_faraday_regs {
>> +     struct fusbh200_regs usb;
>> +     struct fotg210_regs  otg;
>> +};
>> +
>> +static inline int ehci_hci_fotg2xx(struct ehci_hccr *hccr)
>> +{
>> +     union ehci_faraday_regs __iomem *regs = (void *)hccr;
>> +     return !readl(&regs->usb.easstr);
>> +}
>> +
>> +/*
>> + * Create the appropriate control structures to manage
>> + * a new EHCI host controller.
>> + */
>> +int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
>> +             struct ehci_hcor **ret_hcor)
>> +{
>> +     struct ehci_hccr *hccr;
>> +     struct ehci_hcor *hcor;
>> +     union ehci_faraday_regs __iomem *regs;
>> +#ifdef CONFIG_USB_EHCI_BASE_LIST
>> +     uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
>> +#else
>> +     uint32_t base_list[] = { CONFIG_USB_EHCI_BASE };
>> +#endif
>> +
>> +     if (index < 0 || index >= ARRAY_SIZE(base_list))
>> +             return -1;
>> +     regs = (void __iomem *)base_list[index];
>> +     hccr = (struct ehci_hccr *)&regs->usb.hccr;
>> +     hcor = (struct ehci_hcor *)&regs->usb.hcor;
>> +
>> +     if (ehci_hci_fotg2xx(hccr)) {
>> +             /* A-device bus reset */
>> +             /* ... Power off A-device */
>> +             setbits_le32(&regs->otg.otgcsr, BIT_MASK(5));
>
> Do these bits not have names?
>
> [...]
>

Sorry for my laziness, they'll be fixed later.

>> +int ehci_hcd_port_speed(struct ehci_hccr *hccr)
>> +{
>> +     int ret = 0;
>> +     int speed;
>> +     union ehci_faraday_regs __iomem *regs = (void *)hccr;
>> +
>> +     if (ehci_hci_fotg2xx(hccr))
>> +             speed = (readl(&regs->otg.otgcsr) >> 22) & 0x03;
>> +     else
>> +             speed = (readl(&regs->usb.bmcsr) >>  9) & 0x03;
>
> Same here, what're these magic numbers?
>

Sorry for my laziness, they'll be fixed later.

>> +     switch (speed) {
>> +     case 0:    /* full speed */
>> +             break;
>> +
>> +     case 1:    /* low  speed */
>> +             ret = USB_PORT_STAT_LOW_SPEED;
>> +             break;
>> +
>> +     case 2:    /* high speed */
>> +             ret = USB_PORT_STAT_HIGH_SPEED;
>> +             break;
>> +
>> +     default:
>> +             printf("ehci-faraday: invalid device speed\n");
>> +             break;
>> +     }
>> +
>> +     return ret;
>> +}
>> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>> index c816878..450d217 100644
>> --- a/drivers/usb/host/ehci-hcd.c
>> +++ b/drivers/usb/host/ehci-hcd.c
>> @@ -149,8 +149,10 @@ static int handshake(uint32_t *ptr, uint32_t mask,
>> uint32_t done, int usec) static int ehci_reset(int index)
>>  {
>>       uint32_t cmd;
>> +#ifndef CONFIG_USB_EHCI_FARADAY
>>       uint32_t tmp;
>>       uint32_t *reg_ptr;
>> +#endif
>>       int ret = 0;
>>
>>       cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
>> @@ -163,6 +165,7 @@ static int ehci_reset(int index)
>>               goto out;
>>       }
>>
>> +#ifndef CONFIG_USB_EHCI_FARADAY
>
> Wouldn't it suffice to set your EHCI is not TDI ?
>

No, it's surely a TDI design, although we use private registers for
speed detection
(see ehci_hcd_port_speed()) rather then BIT26-27 of PORTSC registers.

>>       if (ehci_is_TDI()) {
>>               reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
>>               tmp = ehci_readl(reg_ptr);
>> @@ -172,6 +175,7 @@ static int ehci_reset(int index)
>>  #endif
>>               ehci_writel(reg_ptr, tmp);
>>       }
>> +#endif       /* !CONFIG_USB_EHCI_FARADAY */
>
> [...]



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 09/11] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-04-26 12:21           ` Marek Vasut
@ 2013-04-29  3:11             ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-29  3:11 UTC (permalink / raw)
  To: u-boot

2013/4/26 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> The Faraday FOTG210 is an OTG chip which could operate
>> as either an EHCI Host or a USB Device as a time.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>
> Same rambling as for the other patch, bits should have proper names defined in
> the fotg_....h header file.

Got it, thanks

> You should avoid calling
> dcache_enable()/dcache_disable() throughout the driver, why do you need to do
> that? Rather implement proper cacheline flushing/invalidation.
>

Sorry, it's my debug codes in the old days, it would be cleanup later


> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-26 23:41           ` Scott Wood
@ 2013-04-29  3:28             ` Kuo-Jung Su
  2013-04-29 20:46               ` Scott Wood
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-29  3:28 UTC (permalink / raw)
  To: u-boot

2013/4/27 Scott Wood <scottwood@freescale.com>:
> On 04/26/2013 03:02:36 AM, Kuo-Jung Su wrote:
>>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday FTNANDC021 is a integrated NAND flash controller.
>> It use a build-in command table to abstract the underlying
>> NAND flash control logic.
>>
>> For example:
>>
>> Issuing a command 0x10 to FTNANDC021 would result in
>> a page write + a read status operation.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Scott Wood <scottwood@freescale.com>
>> ---
>>  README                        |    7 +
>>  drivers/mtd/nand/Makefile     |    1 +
>>  drivers/mtd/nand/ftnandc021.c |  724
>> +++++++++++++++++++++++++++++++++++++++++
>>  drivers/mtd/nand/ftnandc021.h |  137 ++++++++
>>  include/faraday/nand.h        |   34 ++
>>  5 files changed, 903 insertions(+)
>>  create mode 100644 drivers/mtd/nand/ftnandc021.c
>>  create mode 100644 drivers/mtd/nand/ftnandc021.h
>>  create mode 100644 include/faraday/nand.h
>>
>> diff --git a/README b/README
>> index 862bb3e..adc198f 100644
>> --- a/README
>> +++ b/README
>> @@ -3872,6 +3872,13 @@ Low Level (hardware related) configuration options:
>>                 - drivers/mtd/nand/ndfc.c
>>                 - drivers/mtd/nand/mxc_nand.c
>>
>> +- CONFIG_SYS_NAND_TIMING
>> +               Defined to tell the NAND controller that the NAND chip is
>> using
>> +               a customized timing parameters.
>> +               Not all NAND drivers use this symbol.
>> +               Example of drivers that use it:
>> +               - drivers/mtd/nand/ftnandc021.c
>
>
> This doesn't seem to have any standardized meaning (even if that meaning
> is applicable to only a subset of controllers), so please call it
> CONFIG_SYS_FTNANDC021_TIMING and document the ftnandc021-specific
> semantics.
>
>

Got it, thanks

>> diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
>> new file mode 100644
>> index 0000000..39c181f
>> --- /dev/null
>> +++ b/drivers/mtd/nand/ftnandc021.c
>> @@ -0,0 +1,724 @@
>> +/*
>> + * Faraday NAND Flash Controller
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for
>> details.
>> + */
>> +
>> +#include <common.h>
>> +#include <asm/errno.h>
>> +#include <asm/io.h>
>> +#include <asm/unaligned.h>
>> +#include <nand.h>
>> +#include <malloc.h>
>> +#include <faraday/nand.h>
>> +
>> +#include "ftnandc021.h"
>> +
>> +#define CFG_HWECC      /* Enable hardware ECC */
>
>
> If this is really to be optional, call it CONFIG_FTNANDC021_ECC (HWECC
> suggests the alternative is SW ECC, not no ECC) and define it in the
> board config file (or better, invert it to CONFIG_FTNANDC021_NO_ECC so
> ECC is the default).
>
> If it's not meant to be optional, just remove the non-ECC code.
>
> If the ECC doesn't cause major problems in a reasonable use case, I'd
> rather see the non-ECC code just removed.
>
>

Got it, thanks
I'll just remove the non-ECC codes later

>> +static struct nand_ecclayout ftnandc021_ecclayout[] = {
>> +       { /* page size = 512 (oob size = 16) */
>> +               .eccbytes = 6,
>> +               .eccpos = { 0, 1, 2, 3, 6, 7 },
>> +               .oobfree = {
>> +#ifdef CFG_HWECC
>> +                       { 9, 3 },
>> +#else
>> +                       { 8, 4 },
>> +#endif
>> +               }
>> +       },
>> +       { /* page size = 2048 (oob size = 64) */
>> +               .eccbytes = 24,
>> +               .eccpos = {
>> +                       40, 41, 42, 43, 44, 45, 46, 47,
>> +                       48, 49, 50, 51, 52, 53, 54, 55,
>> +                       56, 57, 58, 59, 60, 61, 62, 63
>> +               },
>> +               .oobfree = {
>> +#ifdef CFG_HWECC
>> +                       { 9, 3 },
>> +#else
>> +                       { 8, 4 },
>> +#endif
>> +               },
>> +       },
>> +       { /* page size = 4096 (oob size = 128) */
>> +               .eccbytes = 48,
>> +               .eccpos = {
>> +                       80, 81, 82, 83, 84, 85, 86, 87,
>> +                       88, 89, 90, 91, 92, 93, 94, 95,
>> +                       96, 97, 98, 99, 100, 101, 102, 103,
>> +                       104, 105, 106, 107, 108, 109, 110, 111,
>> +                       112, 113, 114, 115, 116, 117, 118, 119,
>> +                       120, 121, 122, 123, 124, 125, 126, 127
>> +               },
>> +               .oobfree = {
>> +#ifdef CFG_HWECC
>> +                       { 9, 7 },
>> +#else
>> +                       { 8, 8 },
>> +#endif
>> +               },
>> +       },
>> +};
>
>
> Shouldn't .eccpos depend on HWECC?
>
>

Actually it means nothing here, the ECC function is designed to be some kind of
a blackbox to users (i.e softwares), the actual position of ECC codes
are not documented
in the datasheet, I have to dig it out from RTL which I do not have
permission to access.

And there are only 5 bytes are free to users in 2K page flash, users
actually could only
control the 'value' of the 5 bytes, the actual position of these data
are hard-coded in RTL level.

P.S: The 5-bytes are:  1-byte Bad Block Info + 4-bytes data in OOB.

>> +static int ftnandc021_ecc_correct(struct mtd_info *mtd, uint8_t *dat,
>> +       uint8_t *read_ecc, uint8_t *calc_ecc)
>> +{
>> +       struct nand_chip *chip = mtd->priv;
>> +       struct faraday_nand_chip *info = chip->priv;
>> +       struct ftnandc021_chip *priv = info->priv;
>> +       struct ftnandc021_regs __iomem *regs = priv->regs;
>> +       uint32_t st = readl(&regs->ecc_sr);
>> +       int ret = 0;
>> +
>> +       if (st & ECC_SR_CERR) {
>> +               printf("ftnandc021: ecc corection error\n");
>> +               ret = -EIO;
>> +       } else if (st & ECC_SR_ERR) {
>> +               printf("ftnandc021: ecc error\n");
>> +               ret = -EIO;
>> +       }
>> +
>> +       return ret;
>
>
> Can you detect correctable errors?
>
>

No, the FTNANDC021 does not have this function.
Like I said, it was designed for SSD applications, which usually uses
some sort of
bare-metal software, and cares nothing about if it has encounter
correctable ECC error.

>> +#ifdef CFG_HWECC
>> +       chip->ecc.bytes          = chip->ecc.layout->eccbytes;
>> +       chip->ecc.size           = info->pgsz;
>> +       chip->ecc.steps          = 1;
>
>
> Is it really all in one step, regardless of page size?
>

Theoretical, NO.
It uses R-S or BCH for Forwarding Error Correction, which is selected
at RTL level.
Which means it actually 522 bytes per step at RS and 528 bytes per step at BCH.

However it's all blackbox to software, the FTNANDC021 simply supports only
page read, so looks like everything is done at 1 step.

> -Scott



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 04/11] i2c: add Faraday FTI2C010 I2C controller support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 04/11] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
@ 2013-04-29  3:34           ` Heiko Schocher
  2013-05-07  6:32           ` [U-Boot] [PATCH v4 03/16] " Kuo-Jung Su
  1 sibling, 0 replies; 311+ messages in thread
From: Heiko Schocher @ 2013-04-29  3:34 UTC (permalink / raw)
  To: u-boot

Hello Su,

On 26.04.2013 10:02, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTI2C010 is a multi-function I2C controller
> which supports both master and slave mode.
> This patch simplily implements the master mode only.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Heiko Schocher <hs@denx.de>
> ---
>  drivers/i2c/Makefile   |    1 +
>  drivers/i2c/fti2c010.c |  360 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/i2c/fti2c010.h |   71 ++++++++++
>  3 files changed, 432 insertions(+)
>  create mode 100644 drivers/i2c/fti2c010.c
>  create mode 100644 drivers/i2c/fti2c010.h

As this is in a patchserie I just Ack this patch:

Acked-by: Heiko Schocher <hs@denx.de>

Thanks!

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

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

* [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-29  3:28             ` Kuo-Jung Su
@ 2013-04-29 20:46               ` Scott Wood
  2013-04-30  1:33                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-04-29 20:46 UTC (permalink / raw)
  To: u-boot

On 04/28/2013 10:28:14 PM, Kuo-Jung Su wrote:
> 2013/4/27 Scott Wood <scottwood@freescale.com>:
> > Shouldn't .eccpos depend on HWECC?
> >
> >
> 
> Actually it means nothing here, the ECC function is designed to be  
> some kind of
> a blackbox to users (i.e softwares), the actual position of ECC codes
> are not documented
> in the datasheet, I have to dig it out from RTL which I do not have
> permission to access.

Maybe get rid of .eccpos altogether, and supply your own (much simpler)  
hwecc read/write_page functions -- similar to what fsl_elbc_nand, which  
also has transparent (but not hidden) ECC, does?  This would also let  
you get rid of hwctl/calculate/correct.

> > Is it really all in one step, regardless of page size?
> >
> 
> Theoretical, NO.
> It uses R-S or BCH for Forwarding Error Correction, which is selected
> at RTL level.
> Which means it actually 522 bytes per step at RS and 528 bytes per  
> step at BCH.
> 
> However it's all blackbox to software, the FTNANDC021 simply supports  
> only
> page read, so looks like everything is done at 1 step.

It would matter if you could detect correctable errors, but since you  
can't, it doesn't.

-Scott

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

* [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-29  3:10             ` Kuo-Jung Su
@ 2013-04-29 22:50               ` Marek Vasut
  2013-04-30  1:32                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-04-29 22:50 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> 2013/4/26 Marek Vasut <marex@denx.de>:
> > Dear Kuo-Jung Su,
> > 
> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> 
> >> This patch add supports to both Faraday FUSBH200 and FOTG210,
> >> these controllers slightly differ from standard EHCI specification.
> > 
> > How do they differ?
> 
> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
>     are not only un-implemented, but also removed from its register address
>     space, which means we have to update the 'struct ehci_hcor' of ehci.h
> 
> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
> implementations. (It should be a hardware bug, but no one wants to fix
> it.)
> 
> I'll add these description to commit log at next patch.

Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of poluting 
it with ifdefs ? Weak-aliased functions would probably work best to contain your 
weird stuff in your driver only.

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-29 22:50               ` Marek Vasut
@ 2013-04-30  1:32                 ` Kuo-Jung Su
  2013-05-01 19:34                   ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-30  1:32 UTC (permalink / raw)
  To: u-boot

2013/4/30 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/4/26 Marek Vasut <marex@denx.de>:
>> > Dear Kuo-Jung Su,
>> >
>> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >>
>> >> This patch add supports to both Faraday FUSBH200 and FOTG210,
>> >> these controllers slightly differ from standard EHCI specification.
>> >
>> > How do they differ?
>>
>> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
>>     are not only un-implemented, but also removed from its register address
>>     space, which means we have to update the 'struct ehci_hcor' of ehci.h
>>
>> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
>> implementations. (It should be a hardware bug, but no one wants to fix
>> it.)
>>
>> I'll add these description to commit log at next patch.
>
> Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of poluting
> it with ifdefs ? Weak-aliased functions would probably work best to contain your
> weird stuff in your driver only.
>

Did you mean 'Not poluting ehci.h with ifdefs' ?

It looks to me that the best way is to leave ehci.h untouched, and
update the ehci_submit_root() as following:
----------------------------
ehci_submit_root()
{
......
#ifdef CONFIG_USB_EHCI_FARADAY
    status_reg = (uint32_t *)((uint8_t *)&ctrl->hcor + 0x30);
#else
    status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
                 le16_to_cpu(req->index) - 1];
#endif
......
}
------------------------------

Would it be acceptable in this way?

If it's not, I'll make this patch as a separate patch with some hooks
into ehci-hcd.

> Best regards,
> Marek Vasut




--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support
  2013-04-29 20:46               ` Scott Wood
@ 2013-04-30  1:33                 ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-04-30  1:33 UTC (permalink / raw)
  To: u-boot

2013/4/30 Scott Wood <scottwood@freescale.com>:
> On 04/28/2013 10:28:14 PM, Kuo-Jung Su wrote:
>>
>> 2013/4/27 Scott Wood <scottwood@freescale.com>:
>>
>> > Shouldn't .eccpos depend on HWECC?
>> >
>> >
>>
>> Actually it means nothing here, the ECC function is designed to be some
>> kind of
>> a blackbox to users (i.e softwares), the actual position of ECC codes
>> are not documented
>> in the datasheet, I have to dig it out from RTL which I do not have
>> permission to access.
>
>
> Maybe get rid of .eccpos altogether, and supply your own (much simpler)
> hwecc read/write_page functions -- similar to what fsl_elbc_nand, which also
> has transparent (but not hidden) ECC, does?  This would also let you get rid
> of hwctl/calculate/correct.
>
>

Got it, thanks
I'll check it later.

>> > Is it really all in one step, regardless of page size?
>> >
>>
>> Theoretical, NO.
>> It uses R-S or BCH for Forwarding Error Correction, which is selected
>> at RTL level.
>> Which means it actually 522 bytes per step at RS and 528 bytes per step at
>> BCH.
>>
>> However it's all blackbox to software, the FTNANDC021 simply supports only
>> page read, so looks like everything is done at 1 step.
>
>
> It would matter if you could detect correctable errors, but since you can't,
> it doesn't.
>

Got it, thanks

> -Scott



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-04-30  1:32                 ` Kuo-Jung Su
@ 2013-05-01 19:34                   ` Marek Vasut
  2013-05-02  1:14                     ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-01 19:34 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> 2013/4/30 Marek Vasut <marex@denx.de>:
> > Dear Kuo-Jung Su,
> > 
> >> 2013/4/26 Marek Vasut <marex@denx.de>:
> >> > Dear Kuo-Jung Su,
> >> > 
> >> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> >> 
> >> >> This patch add supports to both Faraday FUSBH200 and FOTG210,
> >> >> these controllers slightly differ from standard EHCI specification.
> >> > 
> >> > How do they differ?
> >> 
> >> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
> >> 
> >>     are not only un-implemented, but also removed from its register
> >>     address space, which means we have to update the 'struct ehci_hcor'
> >>     of ehci.h
> >> 
> >> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
> >> implementations. (It should be a hardware bug, but no one wants to fix
> >> it.)
> >> 
> >> I'll add these description to commit log at next patch.
> > 
> > Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of
> > poluting it with ifdefs ? Weak-aliased functions would probably work
> > best to contain your weird stuff in your driver only.
> 
> Did you mean 'Not poluting ehci.h with ifdefs' ?
> 
> It looks to me that the best way is to leave ehci.h untouched, and
> update the ehci_submit_root() as following:
> ----------------------------
> ehci_submit_root()
> {
> ......
> #ifdef CONFIG_USB_EHCI_FARADAY
>     status_reg = (uint32_t *)((uint8_t *)&ctrl->hcor + 0x30);
> #else
>     status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
>                  le16_to_cpu(req->index) - 1];
> #endif
> ......
> }
> ------------------------------
> 
> Would it be acceptable in this way?
> 
> If it's not, I'll make this patch as a separate patch with some hooks
> into ehci-hcd.

What about defining a

__weak uint32_t get_status_register()
{
...
}

function and override it's implementation in your driver?

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-01 19:34                   ` Marek Vasut
@ 2013-05-02  1:14                     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-02  1:14 UTC (permalink / raw)
  To: u-boot

2013/5/2 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/4/30 Marek Vasut <marex@denx.de>:
>> > Dear Kuo-Jung Su,
>> >
>> >> 2013/4/26 Marek Vasut <marex@denx.de>:
>> >> > Dear Kuo-Jung Su,
>> >> >
>> >> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >> >>
>> >> >> This patch add supports to both Faraday FUSBH200 and FOTG210,
>> >> >> these controllers slightly differ from standard EHCI specification.
>> >> >
>> >> > How do they differ?
>> >>
>> >> 1. The reserved registers (0x1C - 0x3F) and CONFIGFLAG (0x40) register
>> >>
>> >>     are not only un-implemented, but also removed from its register
>> >>     address space, which means we have to update the 'struct ehci_hcor'
>> >>     of ehci.h
>> >>
>> >> 2. FUSBH200/FOTG210 doesn't properly follow the ECHI for ISOC
>> >> implementations. (It should be a hardware bug, but no one wants to fix
>> >> it.)
>> >>
>> >> I'll add these description to commit log at next patch.
>> >
>> > Mhmmm ... maybe you can add some hooks into ehci-hcd driver instead of
>> > poluting it with ifdefs ? Weak-aliased functions would probably work
>> > best to contain your weird stuff in your driver only.
>>
>> Did you mean 'Not poluting ehci.h with ifdefs' ?
>>
>> It looks to me that the best way is to leave ehci.h untouched, and
>> update the ehci_submit_root() as following:
>> ----------------------------
>> ehci_submit_root()
>> {
>> ......
>> #ifdef CONFIG_USB_EHCI_FARADAY
>>     status_reg = (uint32_t *)((uint8_t *)&ctrl->hcor + 0x30);
>> #else
>>     status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
>>                  le16_to_cpu(req->index) - 1];
>> #endif
>> ......
>> }
>> ------------------------------
>>
>> Would it be acceptable in this way?
>>
>> If it's not, I'll make this patch as a separate patch with some hooks
>> into ehci-hcd.
>
> What about defining a
>
> __weak uint32_t get_status_register()
> {
> ...
> }
>
> function and override it's implementation in your driver?
>

That's a great idea, I'll update it in this way at next version.

Thanks

> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
@ 2013-05-02 16:03           ` Tom Rini
  2013-05-03  6:01             ` Kuo-Jung Su
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Tom Rini @ 2013-05-02 16:03 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 26, 2013 at 04:02:32PM +0800, Kuo-Jung Su wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
[snip]
> +		| (phyaddr << PHYCR_ADDR_SHIFT)
> +		| (phyreg  << PHYCR_REG_SHIFT)
> +		| 0x30000000;

Magic number.

> +
> +	writel(tmp, &regs->phycr);
> +
> +	for (ts = get_timer(0); get_timer(ts) < 1000; ) {

Please define a TIMEOUT and use that insteadof 1000 all the time.

[snip]
> +	/* interrupt at every packet transmit/receive */
> +	writel(0x00001010, &regs->itc);
> +	/* tx/rx poll interval=5.12us; rx_poll_cnt=1 */
> +	writel(0x00000001, &regs->aptc);
> +	/* rx fifo: high=1536, low=512 */
> +	writel(0x00000390, &regs->dblac);
> +	/* clear all interrupt status */
> +	writel(0x000003FF, &regs->isr);

More magic numbers.  Please fix globally.  Thanks!

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130502/4b731b9a/attachment.pgp>

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

* [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support
  2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                           ` (10 preceding siblings ...)
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 11/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-05-02 22:27         ` Tom Rini
  2013-05-03  6:02           ` Kuo-Jung Su
  11 siblings, 1 reply; 311+ messages in thread
From: Tom Rini @ 2013-05-02 22:27 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 26, 2013 at 04:02:29PM +0800, Kuo-Jung Su wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> To: u-boot at lists.denx.de
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> 
> These patches introduce Faraday A36x SoC platform support.
> 
> Here are some public documents for your reference.
> 
>     http://www.faraday-tech.com/html/documentation/index.html
> 
> There is also a A369 QEMU emulator available at my github account:
> 
>     https://github.com/dantesu1218/qemu.git
> 
> Here is quick start for QEMU:
> 
> 1. Download the QEMU source tree
> 
>     $ git clone -b qemu-1.3.0 https://github.com/dantesu1218/qemu.git
> 
> 2. Build & Install the QEMU:
> 
>     $ ./configure --target-list=arm-softmmu
>     $ make
>     $ make install
> 
> 3. Launch u-boot with QEMU:
> 
>     $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-devel/u-boot
> 
> Changes for v3:
>    - Coding Style cleanup.
>      There is still one warnning reported by checkpatch.pl,
>      however it's too deep for me to fix it.
>      Here is the shapshot for it:
>      -----------------------------------------------------
>      WARNING: do not add new typedefs
>      #9735: FILE: include/lcd.h:258:
>      +typedef struct vidinfo {
>      -----------------------------------------------------
>    - Drop bit fields from c struct.
>    - Drop macros for wirtel()/readl(), call them directly.
>    - Always insert a blank line between declarations and code.
>    - Replace all the infinite wait loop with a timeout.
>    - Add '__iomem' to all the declaration of HW register pointers.
>    - cmd_boot.c: Make it a separate stand-alone patch.
>    - ftspi020: Make it a separate stand-alone patch.
>    - dma-mapping.h: Have the global data ptr declared outside functions.
>    - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
>    - MMU/D-Cache: Drop static non-cached region, now we use
>      map_physmem()/unmap_physmem() for dynamic mappings.
>    - ftmac110: Make a correction to multi-line comment style
>    - ftmac110: Use random MAC address while having trouble
>      to get one from environment variables.
>    - ftmac110: Add comments to timing control registers.
>    - ftnandc021: Re-write this driver with ECC enabled and
>      correct column address handling for OOB read/write,
>      and fixing issused addressed by Scott.
>    - a36x_config: No more static global network configurations.
>    - a36x_config: Add a common file for the redundant configurations.

I see a few:
/* --------------------
 * Comment
 */
in various places, and I pointed it out in the net changes, but I also
saw in the SPI block '100' being used as a timeout, rather than defined.
Please give everything a check for magic numbers and direct numbers used
as timeout, rather than a #define.

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130502/303fab73/attachment.pgp>

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

* [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-05-02 16:03           ` Tom Rini
@ 2013-05-03  6:01             ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-03  6:01 UTC (permalink / raw)
  To: u-boot

2013/5/3 Tom Rini <trini@ti.com>:
> On Fri, Apr 26, 2013 at 04:02:32PM +0800, Kuo-Jung Su wrote:
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> [snip]
>> +             | (phyaddr << PHYCR_ADDR_SHIFT)
>> +             | (phyreg  << PHYCR_REG_SHIFT)
>> +             | 0x30000000;
>
> Magic number.
>
It's the HW debug function, it would be removed at next version.

>> +
>> +     writel(tmp, &regs->phycr);
>> +
>> +     for (ts = get_timer(0); get_timer(ts) < 1000; ) {
>
> Please define a TIMEOUT and use that insteadof 1000 all the time.
>

Got it, thanks

> [snip]
>> +     /* interrupt at every packet transmit/receive */
>> +     writel(0x00001010, &regs->itc);
>> +     /* tx/rx poll interval=5.12us; rx_poll_cnt=1 */
>> +     writel(0x00000001, &regs->aptc);
>> +     /* rx fifo: high=1536, low=512 */
>> +     writel(0x00000390, &regs->dblac);
>> +     /* clear all interrupt status */
>> +     writel(0x000003FF, &regs->isr);
>
> More magic numbers.  Please fix globally.  Thanks!
>

Got it, thanks

> --
> Tom



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support
  2013-05-02 22:27         ` [U-Boot] [PATCH v3 00/11] " Tom Rini
@ 2013-05-03  6:02           ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-03  6:02 UTC (permalink / raw)
  To: u-boot

2013/5/3 Tom Rini <trini@ti.com>:
> On Fri, Apr 26, 2013 at 04:02:29PM +0800, Kuo-Jung Su wrote:
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> To: u-boot at lists.denx.de
>> CC: Albert Aribaud <albert.u.boot@aribaud.net>
>>
>> These patches introduce Faraday A36x SoC platform support.
>>
>> Here are some public documents for your reference.
>>
>>     http://www.faraday-tech.com/html/documentation/index.html
>>
>> There is also a A369 QEMU emulator available at my github account:
>>
>>     https://github.com/dantesu1218/qemu.git
>>
>> Here is quick start for QEMU:
>>
>> 1. Download the QEMU source tree
>>
>>     $ git clone -b qemu-1.3.0 https://github.com/dantesu1218/qemu.git
>>
>> 2. Build & Install the QEMU:
>>
>>     $ ./configure --target-list=arm-softmmu
>>     $ make
>>     $ make install
>>
>> 3. Launch u-boot with QEMU:
>>
>>     $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-devel/u-boot
>>
>> Changes for v3:
>>    - Coding Style cleanup.
>>      There is still one warnning reported by checkpatch.pl,
>>      however it's too deep for me to fix it.
>>      Here is the shapshot for it:
>>      -----------------------------------------------------
>>      WARNING: do not add new typedefs
>>      #9735: FILE: include/lcd.h:258:
>>      +typedef struct vidinfo {
>>      -----------------------------------------------------
>>    - Drop bit fields from c struct.
>>    - Drop macros for wirtel()/readl(), call them directly.
>>    - Always insert a blank line between declarations and code.
>>    - Replace all the infinite wait loop with a timeout.
>>    - Add '__iomem' to all the declaration of HW register pointers.
>>    - cmd_boot.c: Make it a separate stand-alone patch.
>>    - ftspi020: Make it a separate stand-alone patch.
>>    - dma-mapping.h: Have the global data ptr declared outside functions.
>>    - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
>>    - MMU/D-Cache: Drop static non-cached region, now we use
>>      map_physmem()/unmap_physmem() for dynamic mappings.
>>    - ftmac110: Make a correction to multi-line comment style
>>    - ftmac110: Use random MAC address while having trouble
>>      to get one from environment variables.
>>    - ftmac110: Add comments to timing control registers.
>>    - ftnandc021: Re-write this driver with ECC enabled and
>>      correct column address handling for OOB read/write,
>>      and fixing issused addressed by Scott.
>>    - a36x_config: No more static global network configurations.
>>    - a36x_config: Add a common file for the redundant configurations.
>
> I see a few:
> /* --------------------
>  * Comment
>  */

It's used in ftssp010_spi.c only, and it would be removed later.

> in various places, and I pointed it out in the net changes, but I also
> saw in the SPI block '100' being used as a timeout, rather than defined.
> Please give everything a check for magic numbers and direct numbers used
> as timeout, rather than a #define.
>

Got it, thanks

> --
> Tom



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue Kuo-Jung Su
@ 2013-05-03 22:35           ` Andy Fleming
  2013-05-06  6:44             ` Kuo-Jung Su
  2013-05-07  6:32           ` [U-Boot] [PATCH v4] mmc: update Faraday FTSDC010 for rw performance Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Andy Fleming @ 2013-05-03 22:35 UTC (permalink / raw)
  To: u-boot

On Fri, Apr 26, 2013 at 3:02 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> Faraday FTSDC010 is a MMC/SD host controller.
> Although there is already a driver in current u-boot release,
> which is modified from eSHDC and contributed by Andes Tech.
>
> Its performance is too terrible on Faraday A36x SoC platforms,
> so I turn to implement this new version of driver which is
> 10+ times faster than the old one.
>
> It's carefully designed to be compatible to Andes chips,
> so it should be safe to replace it.
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Andy Fleming <afleming@gmail.com>
>
>


> +
> +       if (chip->acmd) {
> +               cmd |= FTSDC010_CMD_APP_CMD;
> +               chip->acmd = 0;
> +       }
>

[...]


> +       if (ret) {
> +               debug("ftsdc010: cmd timeout (op code=%d)\n",
> +                       mmc_cmd->cmdidx);
> +       } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
> +               chip->acmd = 1;
> +       }
>


Interesting. I've not seen any other devices that needed to have the sub
command of the APP command flagged as such. I can't think of a better way
to do this right now, so it's fine. Perhaps if there were other examples,
we could implement a separate callback for APP cmds? Or we could modify the
higher-level code to set a flag for the subcommands? I feel like
maintaining this kind of state shouldn't be necessary, but possibly this
hardware is strange.



> +static void ftsdc010_set_ios(struct mmc *mmc)
> +{
> +       struct ftsdc010_chip *chip = mmc->priv;
> +       struct ftsdc010_mmc __iomem *regs = chip->regs;
> +
> +       ftsdc010_clkset(chip, mmc->clock);
> +
> +       if (mmc->clock > 25000000)
> +               setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
> +       else
> +               clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
>


Why not put this part in ftsdc010_clkset, and set ccr all at once?



> +int ftsdc010_mmc_init(int devid)
> +{
>

[...]


> +
> +       sprintf(mmc->name, "ftsdc010");
> +       mmc->send_cmd = ftsdc010_request;
> +       mmc->set_ios  = ftsdc010_set_ios;
> +       mmc->init     = ftsdc010_init;
> +
> +       switch ((readl(&regs->bwr) >> 3) & 3) {
>


Could we get named constants for those mask/shift numbers?



> +       case 1:
> +               mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz
> +                       | MMC_MODE_4BIT;
> +               break;
> +       case 2:
>

Andy

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

* [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue
  2013-05-03 22:35           ` Andy Fleming
@ 2013-05-06  6:44             ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-06  6:44 UTC (permalink / raw)
  To: u-boot

2013/5/4 Andy Fleming <afleming@gmail.com>:
>
>
>
> On Fri, Apr 26, 2013 at 3:02 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday FTSDC010 is a MMC/SD host controller.
>> Although there is already a driver in current u-boot release,
>> which is modified from eSHDC and contributed by Andes Tech.
>>
>> Its performance is too terrible on Faraday A36x SoC platforms,
>> so I turn to implement this new version of driver which is
>> 10+ times faster than the old one.
>>
>> It's carefully designed to be compatible to Andes chips,
>> so it should be safe to replace it.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Andy Fleming <afleming@gmail.com>
>>
>
>
>>
>> +
>>
>> +       if (chip->acmd) {
>> +               cmd |= FTSDC010_CMD_APP_CMD;
>> +               chip->acmd = 0;
>> +       }
>
>
> [...]
>
>>
>> +       if (ret) {
>> +               debug("ftsdc010: cmd timeout (op code=%d)\n",
>> +                       mmc_cmd->cmdidx);
>> +       } else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
>> +               chip->acmd = 1;
>> +       }
>
>
>
> Interesting. I've not seen any other devices that needed to have the sub
> command of the APP command flagged as such. I can't think of a better way to
> do this right now, so it's fine. Perhaps if there were other examples, we
> could implement a separate callback for APP cmds? Or we could modify the
> higher-level code to set a flag for the subcommands? I feel like maintaining
> this kind of state shouldn't be necessary, but possibly this hardware is
> strange.
>
>
>>
>> +static void ftsdc010_set_ios(struct mmc *mmc)
>> +{
>> +       struct ftsdc010_chip *chip = mmc->priv;
>> +       struct ftsdc010_mmc __iomem *regs = chip->regs;
>> +
>> +       ftsdc010_clkset(chip, mmc->clock);
>> +
>> +       if (mmc->clock > 25000000)
>> +               setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
>> +       else
>> +               clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
>
>
>
> Why not put this part in ftsdc010_clkset, and set ccr all at once?
>
>

Got it, thanks.
I'll merge it into ftsdc010_clkset().

>>
>> +int ftsdc010_mmc_init(int devid)
>> +{
>
>
> [...]
>
>>
>> +
>> +       sprintf(mmc->name, "ftsdc010");
>> +       mmc->send_cmd = ftsdc010_request;
>> +       mmc->set_ios  = ftsdc010_set_ios;
>> +       mmc->init     = ftsdc010_init;
>> +
>> +       switch ((readl(&regs->bwr) >> 3) & 3) {
>
>
>
> Could we get named constants for those mask/shift numbers?
>
>

Sure, it would be fixed in next version.

>>
>> +       case 1:
>> +               mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz
>> +                       | MMC_MODE_4BIT;
>> +               break;
>> +       case 2:
>
>
> Andy



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v3 10/11] video: add Faraday FTLCDC200 LCD controller support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 10/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
@ 2013-05-06 20:18           ` Anatolij Gustschin
  2013-05-07  6:34           ` [U-Boot] [PATCH v2] " Kuo-Jung Su
  1 sibling, 0 replies; 311+ messages in thread
From: Anatolij Gustschin @ 2013-05-06 20:18 UTC (permalink / raw)
  To: u-boot

Hi,

On Fri, 26 Apr 2013 16:02:39 +0800
Kuo-Jung Su <dantesu@gmail.com> wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTLCDC200 Color LCD controller performs translation of
> pixel-coded data into the required formats and timings to
> drive a variety of single/dual mono and color LCDs.
> 
> Depending on the LCD type and mode, the unpacked data can represent:
>    1. an actual true display gray or color value
>    2. an address to a 256 x 16 bit wide palette RAM gray or color value.
> 
> The FTLCDC200 generates 4 individual interrupts for:
>    1. DMA FIFO underflow
>    2. base address update
>    3. vertical status
>    4. bus error.
> 
> There is also a single combined interrupt that is raised when any of
> the individual interrupts become active.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Anatolij Gustschin <agust@denx.de>

Acked-by: Anatolij Gustschin <agust@denx.de>

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

* [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 01/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
@ 2013-05-07  6:25           ` Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
                               ` (6 more replies)
  0 siblings, 7 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

    http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

    https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU:

1. Download the QEMU source tree

    $ git clone -b qemu-1.3.0 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

    $ ./configure --target-list=arm-softmmu
    $ make
    $ make install

3. Launch u-boot with QEMU:

    $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-devel/u-boot

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (7):
  arm: add MMU/D-Cache support for Faraday cores
  arm: add Faraday common utilities
  arm: add Faraday FTINTC020 interrupt controller support
  arm: add Faraday FTTMR010 timer support
  arm: add Faraday FTPWMTMR010 timer support
  arm: add Faraday firmware image utility
  arm: add Faraday A36x SoC platform support

 arch/arm/cpu/faraday/Makefile             |   57 ++++
 arch/arm/cpu/faraday/a360/Makefile        |   49 +++
 arch/arm/cpu/faraday/a369/Makefile        |   50 +++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   77 +++++
 arch/arm/cpu/faraday/cmd_bootfa.c         |  132 ++++++++
 arch/arm/cpu/faraday/config.mk            |   33 ++
 arch/arm/cpu/faraday/cpu.c                |  280 +++++++++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  160 +++++++++
 arch/arm/cpu/faraday/fttmr010.c           |  160 +++++++++
 arch/arm/cpu/faraday/fwimage.h            |   38 +++
 arch/arm/cpu/faraday/fwimage2.h           |   70 ++++
 arch/arm/cpu/faraday/interrupts.c         |  151 +++++++++
 arch/arm/cpu/faraday/start.S              |  523 +++++++++++++++++++++++++++++
 arch/arm/cpu/u-boot.lds                   |   11 +
 arch/arm/include/asm/arch-a360/hardware.h |   73 ++++
 arch/arm/include/asm/arch-a360/pmu.h      |   39 +++
 arch/arm/include/asm/arch-a360/scu.h      |   27 ++
 arch/arm/include/asm/arch-a369/ahbc.h     |   23 ++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++
 arch/arm/include/asm/arch-a369/scu.h      |  213 ++++++++++++
 arch/arm/include/asm/dma-mapping.h        |   61 +++-
 arch/arm/include/asm/global_data.h        |    4 +
 arch/arm/include/asm/io.h                 |  160 ++++++++-
 arch/arm/include/asm/mach-types.h         |    1 +
 arch/arm/include/asm/system.h             |    7 +-
 arch/arm/lib/cache-cp15.c                 |   30 ++
 board/faraday/a360evb/Makefile            |   49 +++
 board/faraday/a360evb/board.c             |   73 ++++
 board/faraday/a360evb/clk.c               |   57 ++++
 board/faraday/a360evb/config.mk           |   33 ++
 board/faraday/a360evb/lowlevel_init.S     |   33 ++
 board/faraday/a369evb/Makefile            |   49 +++
 board/faraday/a369evb/board.c             |  184 ++++++++++
 board/faraday/a369evb/clk.c               |   80 +++++
 board/faraday/a369evb/config.mk           |   33 ++
 board/faraday/a369evb/lowlevel_init.S     |  136 ++++++++
 boards.cfg                                |    3 +
 drivers/mtd/cfi_flash.c                   |    2 +-
 include/common.h                          |   13 +
 include/configs/a360.h                    |   63 ++++
 include/configs/a369-common.h             |   74 ++++
 include/configs/a369.h                    |   33 ++
 include/configs/a369_fa606te.h            |   29 ++
 include/configs/faraday-common.h          |  304 +++++++++++++++++
 include/faraday/ftintc020.h               |   37 ++
 include/faraday/ftpwmtmr010.h             |   41 +++
 include/faraday/ftsmc020.h                |    1 +
 include/faraday/fttmr010.h                |   17 +
 48 files changed, 3847 insertions(+), 14 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/faraday/ftintc020.h
 create mode 100644 include/faraday/ftpwmtmr010.h

--
1.7.9.5

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

* [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-05-07  6:25             ` Kuo-Jung Su
  2013-06-10 17:59               ` Albert ARIBAUD
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 2/7] arm: add Faraday common utilities Kuo-Jung Su
                               ` (5 subsequent siblings)
  6 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch updates the map_physmem()/unmap_physmem(), and use
them to implement dma_alloc_coherent(), dma_free_coherent().

It uses 1MB section for each mapping, and thus waste lots of
address space, however this should still be good enough for
tiny systems (i.e. u-boot).

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - Drop static non-cached region, now we use map_physmem()/unmap_physmem()
     for dynamic mappings.

Changes for v2:
   - Coding Style cleanup.
   - cache-cp15: Enable write buffer in write-through mode.

 arch/arm/include/asm/dma-mapping.h |   61 +++++++++++++-
 arch/arm/include/asm/global_data.h |    4 +
 arch/arm/include/asm/io.h          |  160 ++++++++++++++++++++++++++++++++++--
 arch/arm/include/asm/system.h      |    7 +-
 arch/arm/lib/cache-cp15.c          |   30 +++++++
 drivers/mtd/cfi_flash.c            |    2 +-
 6 files changed, 250 insertions(+), 14 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..5a13af5 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -3,6 +3,9 @@
  * Stelian Pop <stelian@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
  *
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -24,22 +27,76 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };

-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	*handle = (unsigned long)malloc(len);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (va && gd->arch.cpu_mmu) {
+		invalidate_dcache_range((ulong)va, (ulong)va + len);
+		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
+		if (!map)
+			free(va);
+		va = map;
+	}
+
+	if (handle)
+		*handle = virt_to_phys(va);
+
+	return va;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+}
+
+static inline void dma_free_coherent(void *vaddr, ulong len)
+{
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *tmp = (void *)virt_to_phys(vaddr);
+	unmap_physmem(vaddr, len);
+	vaddr = tmp;
+#endif
+	free(vaddr);
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (unsigned long)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 37ac0da..bd18ff7 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -38,6 +38,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..37c737e 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/io.h
  *
  *  Copyright (C) 1996-2000 Russell King
+ *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -28,9 +29,36 @@
 #if 0	/* XXX###XXX */
 #include <asm/arch/hardware.h>
 #endif	/* XXX###XXX */
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/system.h>
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#ifndef CONFIG_MMAP_START
+#define CONFIG_MMAP_START   0xd0000000
+#endif
+
+#ifndef CONFIG_MMAP_END
+#define CONFIG_MMAP_END     0xfff00000
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
+/* arch/$(ARCH)/lib/cache.c */
+void invalidate_icache_all(void);
+void flush_dcache_all(void);
+void flush_dcache_range(ulong start, ulong stop);

 static inline void sync(void)
 {
+#ifndef CONFIG_SYS_DCACHE_OFF
+	flush_dcache_all();
+#endif
+#ifndef CONFIG_SYS_ICACHE_OFF
+	invalidate_icache_all();
+#endif
 }

 /*
@@ -39,27 +67,143 @@ static inline void sync(void)
  * properties specified by "flags".
  */
 #define MAP_NOCACHE	(0)
-#define MAP_WRCOMBINE	(0)
-#define MAP_WRBACK	(0)
-#define MAP_WRTHROUGH	(0)
+#define MAP_WRCOMBINE	(1)
+#define MAP_WRBACK	(2)
+#define MAP_WRTHROUGH	(3)
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+static inline void map_flush(ulong start, ulong end)
+{
+	flush_dcache_range(start, end);
+
+	/* invalidate D-TLB */
+	start &= 0xfff00000;
+	end = (end + 0x000fffff) & 0xfff00000;
+	__asm__ __volatile__ (
+		"mov r3, %0\n"
+		"1:\n"
+		"mcr p15, 0, r3, c8, c6, 1\n"
+		"add r3, r3, #4096\n"
+		"cmp r3, %1\n"
+		"blo 1b\n"
+		: /* output */
+		: "r"(start), "r"(end) /* input */
+		: "r3" /* clobber list */
+	);
+}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */

 static inline void *
-map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+map_physmem(phys_addr_t paddr, ulong len, ulong flags)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 vaddr, nattr, oattr, addr, size, end;
+
+	/* 1. check if we have to create a mapping for it */
+	vaddr = paddr;
+	addr  = page_table[vaddr >> 20] & 0xfff00000;
+	oattr = page_table[vaddr >> 20] & 0x1f;
+	switch (flags) {
+	case MAP_WRCOMBINE:
+		nattr = DCACHE_WRITECOMBINE;
+		break;
+	case MAP_WRTHROUGH:
+		nattr = DCACHE_WRITETHROUGH;
+		break;
+	case MAP_WRBACK:
+		nattr = DCACHE_WRITEBACK;
+		break;
+	default:
+		nattr = DCACHE_OFF;
+		break;
+	}
+	if ((nattr == oattr) && (vaddr == addr))
+		return (void *)paddr;
+
+	/* 2. find a contiguous region for it */
+	end = (paddr + len + 0x000fffff) & 0xfff00000;
+	len = end - (paddr & 0xfff00000);
+	size = 0;
+	addr = CONFIG_MMAP_START;
+	vaddr = addr;
+	while (addr < CONFIG_MMAP_END) {
+		/* if va == pa, then it's free to use */
+		if (addr == (page_table[addr >> 20] & 0xfff00000)) {
+			size += SZ_1M;
+		} else {
+			size = 0;
+			vaddr = addr + SZ_1M;
+		}
+		if (size >= len)
+			break;
+		addr += SZ_1M;
+	}
+	if (size < len)
+		return NULL;
+
+	/* 3. create the map */
+	map_flush(vaddr, vaddr + size);
+	addr = vaddr;
+	vaddr += paddr & 0x000fffff;
+	paddr &= 0xfff00000;
+	while (size) {
+		page_table[addr >> 20] = paddr | (3 << 10) | nattr;
+		size -= SZ_1M;
+		addr += SZ_1M;
+		paddr += SZ_1M;
+	}
+	return (void *)vaddr;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (void *)paddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
  * Take down a mapping set up by map_physmem().
  */
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
+static inline void unmap_physmem(void *vaddr, ulong len)
 {
-
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 addr, end;
+
+	/* 1. skip on NULL pointer */
+	if (!vaddr)
+		return;
+
+	/* 2. check if it's the right address map */
+	addr = (u32)vaddr;
+	if ((page_table[addr >> 20] & 0xfff00000) == addr)
+		return;
+
+	/* 3. reset the map */
+	end = (addr + len + 0x000fffff) & 0xfff00000;
+	addr &= 0xfff00000;
+	map_flush(addr, end);
+	while (addr < end) {
+		page_table[addr >> 20] = addr | (3 << 10) | DCACHE_OFF;
+		addr += SZ_1M;
+	}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

-static inline phys_addr_t virt_to_phys(void * vaddr)
+static inline phys_addr_t virt_to_phys(void *vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	phys_addr_t phys = (phys_addr_t)vaddr;
+
+	if (!gd->arch.cpu_mmu || !vaddr)
+		return phys;
+
+	phys = page_table[(u32)vaddr >> 20] & 0xfff00000;
+	phys += (u32)vaddr & 0x000fffff;
+
+	return phys;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	return (phys_addr_t)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 760345f..050b707 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -97,9 +97,10 @@ static inline void set_dacr(unsigned int val)

 /* options available for data cache on each page */
 enum dcache_option {
-	DCACHE_OFF = 0x12,
-	DCACHE_WRITETHROUGH = 0x1a,
-	DCACHE_WRITEBACK = 0x1e,
+	DCACHE_OFF = 0x12,          /* non-cached + non-buffered */
+	DCACHE_WRITECOMBINE = 0x16, /* non-cached + buffered */
+	DCACHE_WRITETHROUGH = 0x1a, /* cached + non-buffered */
+	DCACHE_WRITEBACK = 0x1e,    /* cached + buffered */
 };

 /* Size of an MMU section */
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 4abe1cf..ea29e83 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -1,6 +1,8 @@
 /*
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -98,6 +100,24 @@ __weak void dram_bank_mmu_setup(int bank)
 		set_section_dcache(i, DCACHE_WRITEBACK);
 #endif
 	}
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+
+# ifdef CONFIG_USE_IRQ
+	/* make sure the exception table is at 0x00000000 */
+	if (!bank && bd->bi_dram[bank].start) {
+		u32 pa = bd->bi_dram[bank].start;
+		u32 *page_table = (u32 *)gd->arch.tlb_addr;
+
+#  ifdef CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITETHROUGH;
+#  else
+		page_table[0] = pa | (3 << 10) | DCACHE_WRITEBACK;
+#  endif
+	}
+# endif /* # ifdef CONFIG_USE_IRQ */
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /* to activate the MMU we need to set up virtual memory: use 1M areas */
@@ -126,6 +146,10 @@ static inline void mmu_setup(void)

 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#ifdef CONFIG_FARADAY
+	reg |= CR_W;	/* enable write buffer */
+	reg |= CR_Z;	/* enable branch prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -140,9 +164,15 @@ static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;

+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
+
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | cache_bit);
diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 22d8440..49bdcff 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1818,7 +1818,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)
 					break;
 				else
 					unmap_physmem((void *)info->start[0],
-						      MAP_NOCACHE);
+						      info->portwidth);
 			}
 		}

--
1.7.9.5

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

* [U-Boot] [PATCH v4 2/7] arm: add Faraday common utilities
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
@ 2013-05-07  6:25             ` Kuo-Jung Su
  2013-06-10 18:05               ` Albert ARIBAUD
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 3/7] arm: add Faraday interrupt controller support Kuo-Jung Su
                               ` (4 subsequent siblings)
  6 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]
   - Drop reset.c and get the reset_cpu() merged into cpu.c
   - Add macro constants & bit/mask for cpu ids.
   - Disable MMU/D-cache only when FA606TE(no-mmu) detected.

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.

Changes for v2:
   - Coding Style cleanup.

 arch/arm/cpu/faraday/Makefile     |   55 ++++
 arch/arm/cpu/faraday/config.mk    |   33 +++
 arch/arm/cpu/faraday/cpu.c        |  280 ++++++++++++++++++++
 arch/arm/cpu/faraday/start.S      |  523 +++++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/mach-types.h |    1 +
 include/common.h                  |    8 +
 6 files changed, 900 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..ecb240a
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,55 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+src-y  := cpu.o
+
+START	= start.o
+COBJS	= $(src-y)
+
+ifdef	CONFIG_SPL_BUILD
+ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE
+START	:=
+endif
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f03030a
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
+
+PLATFORM_CPPFLAGS += -march=armv4
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..3ee5d08
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,280 @@
+/*
+ * arch/arm/cpu/faraday/cpu.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+
+	disable_interrupts();
+
+	/* turn off D-cache */
+	dcache_disable();
+
+	/* flush I-cache */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15, 0, r3, c7, c5, 0\n" /* invalidate i-cache all */
+		:      /* output */
+		:      /* input */
+		: "r3" /* clobber list */
+	);
+
+	return 0;
+}
+
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#else
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c14,0\n" /* clean & invalidate d-cache all */
+		"mcr p15,0,r3,c7,c10,4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n" /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c10,4\n" /* drain write buffer */
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)   /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n" /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start)    /* output */
+		: "r"(stop), "r"(align)  /* input */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c6,0\n" /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r3,#0\n"
+		"mcr p15,0,r3,c7,c5,0\n" /* invalidate i-cache all */
+		: /* output */
+		: /* input */
+		: "r3"    /* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
+
+void enable_caches(void)
+{
+	icache_enable();
+
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		puts("MMU:   on\n");
+		dcache_enable();
+	} else
+#endif
+		puts("MMU:   off\n");
+}
+
+#define CPUID_VID(x)        (((x) >> 24) & 0xff)
+#define CPUID_ISA(x)        (((x) >> 16) & 0xff)
+#define CPUID_PID(x)        (((x) >>  4) & 0x0fff)
+#define CPUID_REV(x)        ((x) & 0x0f) /* revision */
+#define CPUID_NOREV(x)      (((x) >>  4) & 0x0fffffff)
+
+/* Vendor ID */
+#define CPUID_VID_ARM       0x41
+#define CPUID_VID_FARADAY   0x66
+
+/* Instruction Set Architecture */
+#define CPUID_ISA_ARMV4     0x01
+#define CPUID_ISA_ARMV5TE   0x05
+#define CPUID_ISA_ARMV5TEJ  0x06
+
+/* Faraday ARMv4 cores */
+#define CPUID_FA526         0x6601526
+#define CPUID_FA626         0x6601626
+
+/* Faraday ARMv5TE cores */
+#define CPUID_FA606TE       0x6605606
+#define CPUID_FA616TE       0x6605616
+#define CPUID_FA626TE       0x6605626
+#define CPUID_FA726TE       0x6605726
+
+#ifdef CONFIG_ARCH_CPU_INIT
+
+int arch_cpu_init(void)
+{
+	unsigned int id, ctr;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		"mrc p15, 0, %1, c0, c0, 1\n"
+		: "=r"(id), "=r"(ctr) /* output */
+		: /* input */
+	);
+
+	gd->arch.cpu_id = id;
+
+	/* MMU/D-Cache */
+	switch (CPUID_NOREV(gd->arch.cpu_id)) {
+	case CPUID_FA606TE: /* FA606TE (no-mmu) */
+		/* Disable MMU/D-Cache */
+		gd->arch.cpu_mmu = 0;
+		break;
+	default:
+		/* Enable MMU/D-Cache */
+		gd->arch.cpu_mmu = 1;
+		break;
+	}
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+	uint vid = CPUID_VID(gd->arch.cpu_id);
+	uint pid = CPUID_PID(gd->arch.cpu_id);
+
+	/* build cpu_name */
+	switch (vid) {
+	case CPUID_VID_FARADAY:	/* Faraday */
+		switch (CPUID_ISA(gd->arch.cpu_id)) {
+		case CPUID_ISA_ARMV5TE:
+			sprintf(cpu_name, "FA%xTE", pid);
+			break;
+		default:
+			sprintf(cpu_name, "FA%x", pid);
+			break;
+		}
+		break;
+	case CPUID_VID_ARM:	/* ARM */
+		if ((pid & 0xff0) == 0xc00)
+			sprintf(cpu_name, "Cortex-A%u", (pid & 0x00f));
+		else if (pid >= 0xa00)
+			sprintf(cpu_name, "ARM%x", 0x1000 + (pid - 0xa00));
+		else
+			sprintf(cpu_name, "ARM%x", pid);
+		break;
+	default:
+		sprintf(cpu_name, "Unknown");
+		break;
+	}
+
+	/* print cpu_info */
+	printf("CPU:   %s %u MHz\n",
+		cpu_name, (unsigned int)(clk_get_rate("CPU") / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("AHB") / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("APB") / 1000000));
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_DISPLAY_CPUINFO */
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt __iomem *regs =
+		(struct ftwdt010_wdt __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with System Reset Function */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+	/* Kick it to make sure it's in running state */
+	writel(FTWDT010_WDRESTART_MAGIC, &regs->wdrestart);
+#endif
+}
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..577d900
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,523 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _image_copy_end_ofs
+_image_copy_end_ofs:
+	.word __image_copy_end - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * Relocate U-Boot to RAM
+	 * It's copied from the old u-boot release.
+	 */
+#if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD)
+	adr	r0, _start          /* r0 <- current position of code   */
+	ldr	r1, _TEXT_BASE		/* test if we run from flash or RAM */
+	teq     r0, r1          /* don't reloc during debug         */
+	bleq    rr_exit
+	ldr	r2, _end_ofs        /* r2 <- size of u-boot             */
+	add	r2, r0, r2          /* r2 <- source end address         */
+
+rr_loop:
+	ldmia r0!, {r3-r10}	/* copy from source address [r0]    */
+	stmia r1!, {r3-r10}	/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end addreee [r2]    */
+	blo	rr_loop
+
+	/* Adjust the pc to use the correct text address */
+	adr	r0, _start
+	ldr	r1, _TEXT_BASE
+	sub r2, pc, r0
+	add r2, r2, #4
+	add pc, r1, r2
+
+rr_exit:
+#endif  /* #if !defined(CONFIG_NAND_SPL) && !defined(CONFIG_SPL_BUILD) */
+
+	bl	_main
+
+/*---------------------------------------------------------------------*/
+
+/*
+ * void relocate_code(addr_moni)
+ *
+ * This function relocates the monitor code.
+ */
+	.globl	relocate_code
+relocate_code:
+	mov	r6, r0	/* save addr of destination */
+
+	adr	r0, _start
+	subs	r9, r6, r0		/* r9 <- relocation offset */
+	beq	relocate_done		/* skip relocation */
+	mov	r1, r6			/* r1 <- scratch for copy loop */
+	ldr	r3, _image_copy_end_ofs
+	add	r2, r0, r3		/* r2 <- source end address	    */
+
+copy_loop:
+	ldmia	r0!, {r10-r11}		/* copy from source address [r0]    */
+	stmia	r1!, {r10-r11}		/* copy to   target address [r1]    */
+	cmp	r0, r2			/* until source end address [r2]    */
+	blo	copy_loop
+
+#ifndef CONFIG_SPL_BUILD
+	/*
+	 * fix .rel.dyn relocations
+	 */
+	ldr	r0, _TEXT_BASE		/* r0 <- Text base */
+	ldr	r10, _dynsym_start_ofs	/* r10 <- sym table ofs */
+	add	r10, r10, r0		/* r10 <- sym table in FLASH */
+	ldr	r2, _rel_dyn_start_ofs	/* r2 <- rel dyn start ofs */
+	add	r2, r2, r0		/* r2 <- rel dyn start in FLASH */
+	ldr	r3, _rel_dyn_end_ofs	/* r3 <- rel dyn end ofs */
+	add	r3, r3, r0		/* r3 <- rel dyn end in FLASH */
+fixloop:
+	ldr	r0, [r2]   /* r0 <- location to fix up, IN FLASH! */
+	add	r0, r0, r9 /* r0 <- location to fix up in RAM */
+	ldr	r1, [r2, #4]
+	and	r7, r1, #0xff
+	cmp	r7, #23			/* relative fixup? */
+	beq	fixrel
+	cmp	r7, #2			/* absolute fixup? */
+	beq	fixabs
+	/* ignore unknown type of fixup */
+	b	fixnext
+fixabs:
+	/* absolute fix: set location to (offset) symbol value */
+	mov	r1, r1, LSR #4		/* r1 <- symbol index in .dynsym */
+	add	r1, r10, r1		/* r1 <- address of symbol in table */
+	ldr	r1, [r1, #4]		/* r1 <- symbol value */
+	add	r1, r1, r9		/* r1 <- relocated sym addr */
+	b	fixnext
+fixrel:
+	/* relative fix: increase location by offset */
+	ldr	r1, [r0]
+	add	r1, r1, r9
+fixnext:
+	str	r1, [r0]
+	add	r2, r2, #8		/* each rel.dyn entry is 8 bytes */
+	cmp	r2, r3
+	blo	fixloop
+#endif
+
+relocate_done:
+#if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ)
+	/* adjust exception table */
+	adr r0, _undefined_instruction
+	adr r2, _TEXT_BASE
+	ldr r1, [r2]
+adjustex:
+	ldr r3, [r0]
+	sub r3, r3, r1
+	add r3, r6, r3      /* r6 -> relocaddr */
+	str r3, [r0], #4
+	cmp r0, r2
+	blo adjustex
+
+	/* relocate exception table */
+	adr r0, _start
+	ldr	r1, =CONFIG_SYS_SDRAM_BASE
+	adr r2, _TEXT_BASE
+copyex:
+	ldr r3, [r0], #4 /* copy from source address [r0] */
+	str r3, [r1], #4 /* copy to   target address [r1] */
+	cmp	r0, r2       /* until source end addreee [r2] */
+	blo	copyex
+#endif	/* #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_USE_IRQ) */
+	bx	lr
+
+#ifndef CONFIG_SPL_BUILD
+
+_rel_dyn_start_ofs:
+	.word __rel_dyn_start - _start
+_rel_dyn_end_ofs:
+	.word __rel_dyn_end - _start
+_dynsym_start_ofs:
+	.word __dynsym_start - _start
+
+#endif
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
index 440b041..a103922 100644
--- a/arch/arm/include/asm/mach-types.h
+++ b/arch/arm/include/asm/mach-types.h
@@ -144,6 +144,7 @@ extern unsigned int __machine_arch_type;
 #define MACH_TYPE_AKITA                744
 #define MACH_TYPE_E330                 753
 #define MACH_TYPE_NOKIA770             755
+#define MACH_TYPE_FARADAY              758
 #define MACH_TYPE_CARMEVA              769
 #define MACH_TYPE_EDB9315A             772
 #define MACH_TYPE_STARGATE2            774
diff --git a/include/common.h b/include/common.h
index 8a1f3e4..17d9043 100644
--- a/include/common.h
+++ b/include/common.h
@@ -112,6 +112,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_FARADAY
+#include <asm/arch/hardware.h>
+#endif

 #include <part.h>
 #include <flash.h>
@@ -257,6 +260,11 @@ typedef void (interrupt_handler_t)(void *);
 	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
 	(type *)( (char *)__mptr - offsetof(type,member) );})

+#ifdef CONFIG_FARADAY
+/* board/faraday/xxx/clk.c */
+ulong clk_get_rate(char *id);
+#endif
+
 /*
  * Function Prototypes
  */
--
1.7.9.5

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

* [U-Boot] [PATCH v4 3/7] arm: add Faraday interrupt controller support
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 2/7] arm: add Faraday common utilities Kuo-Jung Su
@ 2013-05-07  6:25             ` Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 4/7] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
                               ` (3 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile     |    2 +-
 arch/arm/cpu/faraday/interrupts.c |  151 +++++++++++++++++++++++++++++++++++++
 include/common.h                  |    5 ++
 include/faraday/ftintc020.h       |   37 +++++++++
 4 files changed, 194 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/faraday/interrupts.c
 create mode 100644 include/faraday/ftintc020.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index ecb240a..77cc373 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk

 LIB	= $(obj)lib$(CPU).o

-src-y  := cpu.o
+src-y  := cpu.o interrupts.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/interrupts.c b/arch/arm/cpu/faraday/interrupts.c
new file mode 100644
index 0000000..25f6dec
--- /dev/null
+++ b/arch/arm/cpu/faraday/interrupts.c
@@ -0,0 +1,151 @@
+/*
+ * arch/arm/cpu/faraday/interrupts.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftintc020.h>
+
+#ifdef CONFIG_USE_IRQ
+
+static struct ftintc020_regs __iomem *regs
+	= (void __iomem *)CONFIG_PIC_BASE;
+
+struct _irq_handler {
+	void  *data;
+	void (*func)(void *data);
+};
+
+static struct _irq_handler IRQ_HANDLER[64];
+
+static inline void irq_acknowledge(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		writel(mask, &regs->irq32.scr);
+	else
+		writel(mask, &regs->irq64.scr);
+}
+
+void irq_enable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		setbits_le32(&regs->irq32.ena, mask);
+	else
+		setbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_disable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		clrbits_le32(&regs->irq32.ena, mask);
+	else
+		clrbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_set_trigger(int irq, int edge, int low)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (edge) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tmr, mask);
+		else
+			setbits_le32(&regs->irq64.tmr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tmr, mask);
+		else
+			clrbits_le32(&regs->irq64.tmr, mask);
+	}
+
+	if (low) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tlr, mask);
+		else
+			setbits_le32(&regs->irq64.tlr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tlr, mask);
+		else
+			clrbits_le32(&regs->irq64.tlr, mask);
+	}
+}
+
+void do_irq(struct pt_regs *pt_regs)
+{
+	int irq;
+	uint32_t stat;
+
+	irq  = 32;
+	stat = readl(&regs->irq64.sr);     /* IRQ 32 ~ 63 */
+	if (!stat) {
+		irq  = 0;
+		stat = readl(&regs->irq32.sr); /* IRQ  0 ~ 31 */
+	}
+	irq += ffs(stat) - 1;
+
+	if (irq < 0) {
+		printf("interrupts: no irq!?\n");
+	} else {
+		irq_acknowledge(irq);
+		IRQ_HANDLER[irq].func(IRQ_HANDLER[irq].data);
+	}
+}
+
+static void default_isr(void *data)
+{
+	printf("default_isr():  called for IRQ %d\n", (int)data);
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *hndl, void *data)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = hndl;
+		IRQ_HANDLER[irq].data = data;
+	}
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq >= 0 && irq < 64) {
+		IRQ_HANDLER[irq].func = default_isr;
+		IRQ_HANDLER[irq].data = (void *)irq;
+		irq_disable(irq);
+	}
+}
+
+int arch_interrupt_init(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(IRQ_HANDLER); ++i)
+		irq_free_handler(i);
+
+	/* hardware reset */
+	writel(0x00000000, &regs->irq32.ena);
+	writel(0xffffffff, &regs->irq32.scr);
+	writel(0x00000000, &regs->irq32.tmr);
+	writel(0x00000000, &regs->irq32.tlr);
+
+	writel(0x00000000, &regs->irq64.ena);
+	writel(0xffffffff, &regs->irq64.scr);
+	writel(0x00000000, &regs->irq64.tmr);
+	writel(0x00000000, &regs->irq64.tlr);
+
+	return 0;
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
diff --git a/include/common.h b/include/common.h
index 17d9043..2cdb7f3 100644
--- a/include/common.h
+++ b/include/common.h
@@ -263,6 +263,11 @@ typedef void (interrupt_handler_t)(void *);
 #ifdef CONFIG_FARADAY
 /* board/faraday/xxx/clk.c */
 ulong clk_get_rate(char *id);
+
+/* arch/arm/cpu/faraday/xxx/interrupt.c */
+void irq_set_trigger(int irq, int edge, int low);
+void irq_enable(int irq);
+void irq_disable(int irq);
 #endif

 /*
diff --git a/include/faraday/ftintc020.h b/include/faraday/ftintc020.h
new file mode 100644
index 0000000..e23d1e7
--- /dev/null
+++ b/include/faraday/ftintc020.h
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTINTC020_H
+#define ARCH_ARM_CPU_FARADAY_FTINTC020_H
+
+struct ftintc020_pic_regs {
+	uint32_t src; /* source register */
+	uint32_t ena; /* enable register */
+	uint32_t scr; /* status clear register */
+	uint32_t tmr; /* trigger mode register */
+	uint32_t tlr; /* trigger level register */
+	uint32_t sr;  /* status register */
+	uint32_t rsvd[2];
+};
+
+struct ftintc020_regs {
+	/* IRQ/FIQ:  0 ~ 31 */
+	struct ftintc020_pic_regs irq32; /* 0x00 - 0x1C: IRQ 0 ~ 31 */
+	struct ftintc020_pic_regs fiq32; /* 0x20 - 0x3C: FIQ 0 ~ 31 */
+	uint32_t rsvd1[4];               /* 0x40 - 0x4C: Reserved */
+	uint32_t revision;               /* 0x50: Revision Register */
+	uint32_t feature;                /* 0x54: Feature Register */
+	uint32_t rsvd2[2];               /* 0x58 - 0x5C: Reserved */
+	/* IRQ/FIQ: 32 ~ 63 */
+	struct ftintc020_pic_regs irq64; /* 0x60 - 0x7C: IRQ 32 ~ 63 */
+	struct ftintc020_pic_regs fiq64; /* 0x80 - 0x9C: FIQ 32 ~ 63 */
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v4 4/7] arm: add Faraday FTTMR010 timer support
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                               ` (2 preceding siblings ...)
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 3/7] arm: add Faraday interrupt controller support Kuo-Jung Su
@ 2013-05-07  6:25             ` Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 5/7] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
                               ` (2 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    1 +
 arch/arm/cpu/faraday/fttmr010.c |  160 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 +++++
 3 files changed, 178 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 77cc373..5de417c 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
 LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o interrupts.o
+src-$(CONFIG_FTTMR010)    += fttmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..39e170a
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,160 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+static struct fttmr010 __iomem *regs = (void __iomem *)CONFIG_TIMER_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((sclk / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	++ticks;
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+	/* Disable Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt init */
+	irq_set_trigger(CONFIG_TIMER_IRQ, 1, 0);
+	irq_install_handler(CONFIG_TIMER_IRQ, (void *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+#endif
+
+	/* timer1 setup */
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	writel(sclk / CONFIG_SYS_HZ, &regs->timer1_counter);
+	writel(sclk / CONFIG_SYS_HZ, &regs->timer1_load);
+#else
+	/* setup a 30 sec one-shot timer */
+	writel(30 * sclk, &regs->timer1_counter);
+	writel(0, &regs->timer1_load);
+#endif
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* start timer1 with overflow interrupt enabled */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = ((30 * sclk) - readl(&regs->timer1_counter)) / s;
+
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+#ifdef CONFIG_TIMER_FREQ
+	sclk  = CONFIG_TIMER_FREQ;
+#else
+	sclk  = clk_get_rate("APB");
+#endif
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (!readl(&regs->timer1_counter)) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 72abcb3..ef10f31 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -57,6 +57,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -70,4 +80,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v4 5/7] arm: add Faraday FTPWMTMR010 timer support
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                               ` (3 preceding siblings ...)
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 4/7] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
@ 2013-05-07  6:25             ` Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 6/7] arm: add Faraday firmware image utility Kuo-Jung Su
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 7/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    1 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  160 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 +++++++++
 3 files changed, 202 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 5de417c..290400a 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -27,6 +27,7 @@ LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o interrupts.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
+src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..e959d8b
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,160 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+#ifdef CONFIG_A369_FA606TE_PLATFORM
+#define TIMER_ID    4
+#else
+#define TIMER_ID    0
+#endif
+
+static ulong ticks;				/* U-Boot ticks since startup */
+static ulong sclk  = 66000000;	/* source clock (66MHz by default) */
+static struct ftpwmtmr010_regs __iomem *regs =
+	(void __iomem *)CONFIG_TIMER_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((sclk / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+#ifdef CONFIG_USE_IRQ
+
+void timer_interrupt(struct pt_regs *ctx)
+{
+	int id = TIMER_ID;
+
+	++ticks;
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+#endif    /* #ifdef CONFIG_USE_IRQ */
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+#ifdef CONFIG_USE_IRQ
+	/* setup a 1 sec periodic timer */
+	writel(0,
+		&regs->t[id].cmpb);
+	writel(sclk / CONFIG_SYS_HZ,
+		&regs->t[id].cntb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+	irq_install_handler(CONFIG_TIMER_IRQ, (void *)timer_interrupt, NULL);
+	irq_enable(CONFIG_TIMER_IRQ);
+	enable_interrupts();
+#else
+	/* setup a 30 sec one-shot timer */
+	writel(0,
+		&regs->t[id].cmpb);
+	writel(30 * sclk,
+		&regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+#endif    /* #ifdef CONFIG_USE_IRQ */
+}
+
+ulong get_timer_masked(void)
+{
+#ifdef CONFIG_USE_IRQ
+	return ticks;
+#else
+	ulong s = sclk / CONFIG_SYS_HZ;
+	ulong t = (30 * sclk - readl(&regs->t[TIMER_ID].cnto)) / s;
+
+	return ticks + t;
+#endif
+}
+
+int timer_init(void)
+{
+	ticks = 0;
+#ifdef CONFIG_TIMER_FREQ
+	sclk  = CONFIG_TIMER_FREQ;
+#else
+	sclk  = clk_get_rate("APB");
+#endif
+
+#ifdef CONFIG_USE_IRQ
+	/* interrupt is not yet initialized here */
+#else
+	reset_timer_masked();
+#endif
+
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+#ifndef CONFIG_USE_IRQ
+	if (!readl(&regs->t[TIMER_ID].cnto)) {
+		ticks += 30 * CONFIG_SYS_HZ;
+		reset_timer_masked();
+	}
+#endif
+	return get_timer_masked() - base;
+}
+
+void set_timer(ulong t)
+{
+	ticks = t;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..9455577
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v4 6/7] arm: add Faraday firmware image utility
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                               ` (4 preceding siblings ...)
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 5/7] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
@ 2013-05-07  6:25             ` Kuo-Jung Su
  2013-06-10 18:38               ` Albert ARIBAUD
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 7/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  6 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.

Changes for v2:
   - Coding Style cleanup.

 arch/arm/cpu/faraday/Makefile     |    2 +-
 arch/arm/cpu/faraday/cmd_bootfa.c |  132 +++++++++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/fwimage.h    |   38 +++++++++++
 arch/arm/cpu/faraday/fwimage2.h   |   70 ++++++++++++++++++++
 arch/arm/cpu/u-boot.lds           |   11 ++++
 5 files changed, 252 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 290400a..77899d9 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk

 LIB	= $(obj)lib$(CPU).o

-src-y  := cpu.o interrupts.o
+src-y  := cpu.o interrupts.o cmd_bootfa.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
 src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o

diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..bcced38
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,132 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would try to boot faraday image from MMC/SD/USB/SPI/NAND/NOR
+ */
+
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *part = hdr->part;
+
+	for (i = 0; part[i].length > 0 && i < 10; ++i) {
+		if (strcmp(name, part[i].name) == 0) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				part[i].name, part[i].offset, part[i].length);
+			return part + i;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400",
+			CONFIG_SYS_FLASH_BASE,
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x",
+			CONFIG_SYS_FLASH_BASE + part->offset,
+			CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400",
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..af4f2f9
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,38 @@
+/*
+ * arch/arm/cpu/faraday/fwimage.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t	count;
+	uint32_t	version; /* ycmo100525: for firmware image version */
+	uint32_t	addr[31];
+	uint32_t	data[31];
+};
+
+struct fwfile {
+	char		name[64];
+	uint32_t	size;
+	/* uint32_t	block[1]; */
+};
+
+struct fwimage {
+	/* 8 bytes */
+	uint32_t		magic;	/* Magic number */
+	uint32_t		length;	/* It shall not be greater than 2048 */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam	param;
+
+	struct fwfile	file[1];
+};
+
+#endif
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..27319a7
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,70 @@
+/*
+ * arch/arm/cpu/faraday/fwimage2.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+#define ARCH_ARM_CPU_FARADAY_FWIMAGE2_H
+
+#include <image.h>
+#include "fwimage.h"
+
+/* 8 bytes struct for generic 32-bit memory write */
+struct fwmw32 {
+	uint32_t addr;
+	uint32_t data;
+};
+
+/* 72 bytes */
+struct fwpart {
+	/* offset: 0 ~ 63 */
+	char     name[32];
+
+	uint32_t offset;
+	uint32_t length;
+
+	uint32_t load;
+	uint32_t qcrc; /* Quick CRC32 against 256KB on both TOP & BOTTOM */
+
+	uint32_t flag;
+#define FWIMAGE2_FLAG_UIMAGE		0x00000001 /* Is a uImage ? */
+#define FWIMAGE2_FLAG_FILESYSTEM	0x00000010 /* Is a filesystem ? */
+
+	uint8_t  rsvd[12];
+
+	/* offset: 64 ~ 71 */
+	uint32_t magic1000; /* It's always 0x00001000 */
+	uint32_t magic0001; /* It's always 0x00000001 */
+};
+
+struct fwimage2 {
+	/*   4 bytes, magic */
+	uint32_t magic; /* Image Header Magic Number */
+#define FWIMAGE2_MAGIC			0x00484946 /* "FIH\0" */
+
+	/*   4 bytes, header length */
+	uint32_t hlen;      /* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwmw32 mw32[32];
+
+	/* 720 bytes, firmware partition table */
+	struct fwpart part[10];
+
+	/*   4 bytes */
+	uint32_t hcrc;  /* Image Header Checksum (CRC32) */
+
+	/*   4 bytes, revision */
+	uint32_t revision; /* Image Header Revision Code */
+#define FWIMAGE2_REVISION		0x00000201		/* v2.1 */
+
+	/*  32 bytes */
+	char     build[32]; /* Build Date (yyyy/mm/dd HH:MM:SS) */
+};	/* Total 1024 bytes */
+
+#endif
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index d9bbee3..ac59fec 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -23,6 +23,8 @@
  * MA 02111-1307 USA
  */

+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -35,6 +37,15 @@ SECTIONS
 	{
 		__image_copy_start = .;
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}

--
1.7.9.5

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

* [U-Boot] [PATCH v4 7/7] arm: add Faraday A36x SoC platform support
  2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                               ` (5 preceding siblings ...)
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 6/7] arm: add Faraday firmware image utility Kuo-Jung Su
@ 2013-05-07  6:25             ` Kuo-Jung Su
  2013-06-10 18:39               ` Albert ARIBAUD
  6 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:25 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday A36x EVB is a Faraday SoC platform evalution board used for
Faraday IP functional verification based on the well-known ARM AMBA 2.0
architecture.

Faraday A360 EVB:
   CPU: FA626TE
   NET: FTMAC110
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC010
   WDT: FTWDT010
   TMR: FTTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC020

Faraday A369 EVB:
   CPU: FA626TE(Master)/FA606TE(Slave)
   NET: FTGMAC100
   USB: FUSBH200, FOTG210
   LCD: FTLCDC200
   I2C: FTI2C010
   SPI: FTSSP010 v1.18.0
   MMC: FTSDC010
   RTC: FTRTC011
   WDT: FTWDT010
   TMR: FTPWMTMR010
   PIC: FTINTC020
   UART: FTUART010
   NAND: FTNANDC021

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v4:
   - Coding Style cleanup.
   - Break-down the interrupt, timers and common utilties.

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/a360/Makefile        |   49 +++++
 arch/arm/cpu/faraday/a369/Makefile        |   50 +++++
 arch/arm/cpu/faraday/a369/cmd_fa606.c     |   77 ++++++++
 arch/arm/include/asm/arch-a360/hardware.h |   73 +++++++
 arch/arm/include/asm/arch-a360/pmu.h      |   39 ++++
 arch/arm/include/asm/arch-a360/scu.h      |   27 +++
 arch/arm/include/asm/arch-a369/ahbc.h     |   23 +++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++++
 arch/arm/include/asm/arch-a369/scu.h      |  213 ++++++++++++++++++++
 board/faraday/a360evb/Makefile            |   49 +++++
 board/faraday/a360evb/board.c             |   73 +++++++
 board/faraday/a360evb/clk.c               |   57 ++++++
 board/faraday/a360evb/config.mk           |   33 ++++
 board/faraday/a360evb/lowlevel_init.S     |   33 ++++
 board/faraday/a369evb/Makefile            |   49 +++++
 board/faraday/a369evb/board.c             |  184 +++++++++++++++++
 board/faraday/a369evb/clk.c               |   80 ++++++++
 board/faraday/a369evb/config.mk           |   33 ++++
 board/faraday/a369evb/lowlevel_init.S     |  136 +++++++++++++
 boards.cfg                                |    3 +
 include/configs/a360.h                    |   63 ++++++
 include/configs/a369-common.h             |   74 +++++++
 include/configs/a369.h                    |   33 ++++
 include/configs/a369_fa606te.h            |   29 +++
 include/configs/faraday-common.h          |  304 +++++++++++++++++++++++++++++
 include/faraday/ftsmc020.h                |    1 +
 26 files changed, 1873 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clk.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clk.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..7113f66
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..4dddd36
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+obj-$(CONFIG_CMD_FA606) += cmd_fa606.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/cmd_fa606.c b/arch/arm/cpu/faraday/a369/cmd_fa606.c
new file mode 100644
index 0000000..8a6d86c
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/cmd_fa606.c
@@ -0,0 +1,77 @@
+/*
+ * arch/arm/cpu/faraday/a369/cmd_fa606.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ *
+ * This command would start the A369 slave cpu - FA606TE, and also immediately
+ * halt the master cpu - FA626TE.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/ahbc.h>
+
+static struct a369scu_regs __iomem *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a369ahbc_regs __iomem *ahbc = (void __iomem *)CONFIG_AHBC2_BASE;
+
+static int do_fa606(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int addr = CONFIG_SYS_LOAD_ADDR;
+
+	if (argc >= 2)
+		addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("FA606TE Image at 0x%08X\n", addr);
+	printf("FA626TE is going to halt...\n");
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+	cleanup_before_linux();
+#endif
+
+	/* 1. FA606TE address offset = 0 */
+	printf("FA606 address shift disable.\n");
+	writel(0x00000000, &ahbc->cpusao);
+
+	/* 2. Generate a long-jump to 0x00000000 */
+	writel(0xEA00000A, 0x00); /* b   0x30 */
+	writel(addr,       0x20);
+	writel(0xE3A00020, 0x30); /* mov r0, #32 ; 0x20 */
+	writel(0xE590F000, 0x34); /* ldr pc, [r0] */
+
+	/* 3. Pinmux = ICE + LCD */
+	writel(GPMUX_DEFAULT, &scu->gpmux);
+	writel(SCCFG0_DEFAULT, &scu->sccfg[0]);
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+	writel(MFPMUX0_TS(1) | MFPMUX0_ISP(2) | MFPMUX0_SATA(1)
+		| MFPMUX0_EXTAHB(1), &scu->mfpmux[0]);
+	writel(MFPMUX1_SSP0(1), &scu->mfpmux[1]);
+	udelay(5000);
+
+	/* 4. FA606TE clock enable & reset */
+	writel(0x00000000, &scu->hclkgr);
+	udelay(5000);
+	writel(GPMUX_DEFAULT | GPMUX_CPUS_START, &scu->gpmux);
+
+	/* 5. FA626TE is going to halt... */
+	__asm__ __volatile__ (
+		"mov r3, #0\n"
+		"mcr p15,0,r3,c7,c0,4\n"
+		:
+		:
+		: "r3" /* clobber list */
+	);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	fa606, 2, 0, do_fa606,
+	"launch firmware with A369's built-in fa606te\n",
+	"fa606 [address] - mov pc of fa606te to the specified address.\n"
+);
diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..9ddefed
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,73 @@
+/*
+ * arch/arm/include/asm/arch-a360/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC020_BASE		0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+#define CONFIG_FTSSP010_GPIO_BASE	0x98700000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+#define CONFIG_FOTG210_BASE         0x90B00000
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/pmu.h b/arch/arm/include/asm/arch-a360/pmu.h
new file mode 100644
index 0000000..51b9391
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/pmu.h
@@ -0,0 +1,39 @@
+/*
+ * asm/arch-a360/pmu.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_PMU_H
+#define __ASM_ARCH_PMU_H
+
+struct a360pmu_regs {
+	uint32_t idr;      /* ID register */
+	uint32_t rsvd0;
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pmr;      /* Power mode register */
+
+	uint32_t pmcr;     /* Power manager control register */
+	uint32_t peer;     /* Power manager edge detect enable register */
+	uint32_t pesr;     /* Power manager edge detect status register */
+	uint32_t rsvd1;
+
+	uint32_t pmsr;     /* Power manager status register */
+	uint32_t pgsr;     /* Power manager GPIO sleep state register */
+	uint32_t rsvd2;
+	uint32_t mcr;      /* Misc. control register */
+
+	uint32_t pdcr;     /* PLL/DLL control register */
+	uint32_t rsvd3[7];
+
+	uint32_t pspr[16]; /* Power manager scratch pad register */
+
+	uint32_t rsvd4[3];
+	uint32_t jssr;     /* Jumper setting status register */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/scu.h b/arch/arm/include/asm/arch-a360/scu.h
new file mode 100644
index 0000000..6fbd1b8
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/scu.h
@@ -0,0 +1,27 @@
+/*
+ * asm/arch-a360/scu.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a360scu_regs {
+	uint32_t idr;      /* 0x00: ID Register */
+	uint32_t gcr;      /* 0x04: General Control Register */
+	uint32_t ccr;      /* 0x08: Clock Configuration Register */
+	uint32_t hcer;     /* 0x0C: AHB Clock Enable Register */
+	uint32_t pcer;     /* 0x10: APB Clock Enable Register */
+	uint32_t csr;      /* 0x14: Configuration Strap Register */
+	uint32_t iomcr[4]; /* IO Mux Control Register */
+	uint32_t iopcr[2]; /* IO Parameter Control Register */
+	uint32_t cescr;    /* CPU Edge Sync Control Register */
+	uint32_t expcr[3]; /* PCI-Express Control Register */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/ahbc.h b/arch/arm/include/asm/arch-a369/ahbc.h
new file mode 100644
index 0000000..606cedc
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/ahbc.h
@@ -0,0 +1,23 @@
+/*
+ * arch/arm/include/asm/arch-a369/ahbc.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_AHBC_H
+#define __ASM_ARCH_AHBC_H
+
+struct a369ahbc_regs {
+	uint32_t slave[32];/* Slave Device Configurations */
+	uint32_t priority; /* Priority */
+	uint32_t idle_cnt; /* IDLE Counter */
+	uint32_t control;  /* Control Register */
+	uint32_t revision; /* Revision ID */
+	uint32_t cpusao;   /* CPUS (FA606TE) Address Offset */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..4c9f105
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDR_BASE             0x93100000
+#define CONFIG_AHB_BASE             0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/scu.h b/arch/arm/include/asm/arch-a369/scu.h
new file mode 100644
index 0000000..93e3439
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/scu.h
@@ -0,0 +1,213 @@
+/*
+ * arch/arm/include/asm/arch-a369/scu.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a369scu_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)   (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x) ((((x) >> 3) & 0x3) > 2 ? 2 : (((x) >> 3) & 0x3))
+#define HWCFG_DLL_OFF     (1 << 2)
+#define HWCFG_PLL_OFF     (1 << 1)
+#define HWCFG_OSCHCNT_OFF (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 0x3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 0x3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 0x3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..02b9a47
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,73 @@
+/*
+ * board/faraday/a360evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <asm/arch/scu.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a360scu_regs __iomem *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+/*
+ * pinmux
+ */
+static void pinmux_init(void)
+{
+	writel(0x00555500, &scu->iomcr[3]);
+	setbits_le32(&scu->iomcr[0], 0x800002AA);
+	setbits_le32(&scu->iomcr[1], 0x82AAAAAA);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	pinmux_init();
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	return ftmac110_initialize(bd);
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a360evb/clk.c b/board/faraday/a360evb/clk.c
new file mode 100644
index 0000000..1a8a224
--- /dev/null
+++ b/board/faraday/a360evb/clk.c
@@ -0,0 +1,57 @@
+/*
+ * board/faraday/a360evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/pmu.h>
+
+static struct a360scu_regs __iomem *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a360pmu_regs __iomem *pmu = (void __iomem *)CONFIG_PMU_BASE;
+
+static ulong clk_get_rate_ahb(void)
+{
+	return CONFIG_MAIN_CLK * ((readl(&pmu->pdcr) >> 3) & 0x3f) / 8;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	uint32_t s = readl(&scu->csr);
+	uint32_t p = readl(&pmu->pmr);
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (s & 0x200) ? 2 : 4;
+
+	return (p & 0x02) ? (clk * mul) : clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a360evb/config.mk b/board/faraday/a360evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a360evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..1ead608
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,33 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..0b0ac84
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clk.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..ea86954
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,184 @@
+/*
+ * board/faraday/a369evb/board.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/scu.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftlcdc200.h>
+#include <faraday/ftsdc010.h>
+#include <faraday/ftnandc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a369scu_regs __iomem *scu
+	= (void __iomem *)CONFIG_SCU_BASE;
+
+static struct ftlcdc200_regs __iomem *lcd
+	= (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+static struct ftsmc020 __iomem *smc
+	= (void __iomem *)CONFIG_SMC_BASE;
+
+/*
+ * System Control Uint (pinmux)
+ */
+static void scu_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&scu->hclkgr);
+		setbits_le32(&scu->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_SUPP_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &scu->hclkgr);
+		writel(GPMUX_DEFAULT, &scu->gpmux);
+		clrbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &scu->mfpmux[0]);
+#endif
+	}
+
+	/* Clock Setup: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+
+	/* Enable LCD for I2C/TVEncode work-around */
+	/* ... Clock DIV=32 */
+	writel(PCR_DIV(32), &lcd->pcr);
+	/* ... Enable LCD */
+	writel(FER_EN | FER_ON, &lcd->fer);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	/* 1. NOR flash */
+	/* Bank 0: base=0x00000000, size=64MB, 16bits */
+	writel(FTSMC020_BANK_ENABLE | FTSMC020_BANK_BASE(0)
+		| FTSMC020_BANK_SIZE_64M | FTSMC020_BANK_MBW_16,
+		&smc->bank[0].cr);
+	/* Bank 0: worst timing */
+	writel(FTSMC020_TPR_WORST, &smc->bank[0].tpr);
+
+	/* 2. Unused Area */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	scu_init();
+	smc_init();
+	return 0;
+}
+
+int board_late_init(void)
+{
+	reset_timer();
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_SYS_NAND_SELF_INIT
+void board_nand_init(void)
+{
+	int alen, devnum = 0;
+	struct mtd_info *mtd = &nand_info[devnum];
+	struct nand_chip *chip;
+	uint32_t iobase = CONFIG_SYS_NAND_BASE;
+	uint32_t ehwcfg = readl(&scu->ehwcfg);
+
+	chip = calloc(1, sizeof(*chip));
+	if (!chip)
+		return;
+	mtd->priv = chip;
+
+	/* page size */
+	switch (EHWCFG_NAND_PS(ehwcfg)) {
+	case 0:
+		chip->page_shift = 9;	/* 512 */
+		break;
+	case 1:
+		chip->page_shift = 11;	/* 2048 */
+		break;
+	default:
+		chip->page_shift = 12;	/* 4096 */
+		break;
+	}
+
+	/* block size */
+	chip->phys_erase_shift = chip->page_shift + 4
+		+ EHWCFG_NAND_BK(ehwcfg);
+
+	/* address length/cycle */
+	alen = 3 + EHWCFG_NAND_AC(ehwcfg);
+
+	if (ftnandc021_init(chip, iobase, alen))
+		goto bni_err;
+
+	if (nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS))
+		goto bni_err;
+
+	nand_register(devnum);
+
+	return;
+
+bni_err:
+	free(chip);
+}
+#endif /* #ifdef CONFIG_SYS_NAND_SELF_INIT */
diff --git a/board/faraday/a369evb/clk.c b/board/faraday/a369evb/clk.c
new file mode 100644
index 0000000..4714a4b
--- /dev/null
+++ b/board/faraday/a369evb/clk.c
@@ -0,0 +1,80 @@
+/*
+ * board/faraday/a369evb/clk.c
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+
+#define CFG_PLL_TIMEOUT 10 /* ms */
+
+static struct a369scu_regs __iomem *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+static ulong clk_get_rate_ahb(void)
+{
+	uint32_t tmp = 0, mul = 4;
+	ulong ts;
+
+	/* Wait until PLL1 becomes stable or 10 ms timeout */
+	ts = get_timer(0);
+	do {
+		tmp = readl(&scu->pllcr);
+		if (tmp & PLLCR_STABLE)
+			break;
+	} while (get_timer(ts) < CFG_PLL_TIMEOUT);
+
+	mul = PLLCR_NS(tmp);
+
+	return (CONFIG_MAIN_CLK * mul) >> 3;
+}
+
+static ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+#ifndef CONFIG_A369_FA606TE_PLATFORM
+	/* If it's an internal CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after
+	 * kicking off slave cpu, so we could check the
+	 * GPMUX_CPUS_START to determine if it's a master.
+	 */
+	if (!(readl(&scu->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&scu->hwcfg));
+#endif
+
+	return clk;
+}
+
+ulong clk_get_rate(char *id)
+{
+	ulong clk = 0;
+
+	if (!strcmp(id, "AHB"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		clk = clk_get_rate_cpu();
+	else if (!strcmp(id, "SDC"))
+		clk = clk_get_rate_ahb();
+	else if (!strcmp(id, "I2C"))
+		clk = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		clk = clk_get_rate_apb();
+
+	return clk;
+}
diff --git a/board/faraday/a369evb/config.mk b/board/faraday/a369evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a369evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..a55fddb
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,136 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2010
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+	.macro	_v3_mw32
+
+	ldr r0, =0x1008
+	ldr r3, =0x1108
+_v3_mw32_loop:
+	cmp   r0, r3
+	movhs r1, #0
+	ldrlo r1, [r0, #0]
+	ldrlo r2, [r0, #4]
+	teq   r1, #0
+	strne r2, [r1, #0]
+	addne r0, #8
+	bne   _v3_mw32_loop
+
+	.endm	/* _v3_mw32 */
+
+	.macro	_sdram_enable
+
+	/* Clear SDRAM CKE, GPIO Hold, READ Hold */
+	ldr r0, =CONFIG_SCU_BASE
+	mov r1, #7
+	str r1, [r0, #0x14]
+
+	/* Wait until sdram ready */
+	ldr r0, =CONFIG_DDR_BASE
+_sdram_wait:
+	ldr r1, [r0, #0x04]
+	teq r1, #0x100
+	bne _sdram_wait
+
+	.endm	/* _sdram_enable */
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	/* Check image header */
+	ldr   r1, =0x1000
+	ldr   r0, [r1, #0]
+	ldr   r1, =0x00484946	/* "FIH\0" */
+	ldr   r2, =0x33333639	/* "3369" */
+	teq   r0, r1
+	teqne r0, r2
+	bne _exit
+	_v3_mw32
+	_sdram_enable
+
+#if 1
+	/* Create a shadow copy onto SDRAM (limited to 512K) */
+	mov	r0, #0               /* r0 <- start of source */
+	ldr	r1, =CONFIG_AHB_BASE
+	ldr r2, [r1,#0x18]
+	bic r1, r2, #0x000f0000  /* r1 <- SDRAM base */
+	mov	r2, #0x80000         /* r2 <- source end address (512KB) */
+
+_copy_loop:
+	ldmia	r0!, {r3-r10} /* copy from source address [r0] */
+	stmia	r1!, {r3-r10} /* copy to   target address [r1] */
+	cmp	r0, r2            /* until source end addreee [r2] */
+	ble	_copy_loop
+#else
+	/* Adjust lr(r14) to the remapped address */
+	ldr r0, =CONFIG_AHB_BASE
+	ldr r1, [r0,#0x18]    /* r1 = AHB slave 6 */
+	bic r1, r1, #0xff000000
+	bic r1, r1, #0x00f00000
+	lsr r1, r1, #16
+	add r1, r1, #20
+	mov r2, #1
+	lsl r2, r2, r1
+	add lr, lr, r2
+#endif
+
+	/* AHB remap */
+	mov r0, #0
+	ldr r1, =CONFIG_AHB_BASE
+	ldr r2, =CONFIG_DDR_BASE
+	/* magic (r5) = REG32(0x00) XOR 0xFFFFFFFF */
+	ldr r5, [r0, #0]
+	ldr r3, =0xffffffff
+	eor r5, r5, r3
+	/* r3 = REG32(CONFIG_IOBASE_DDR + 0x10) & 0x00FFFFFF */
+	ldr r3, [r2, #0x10]
+	bic r3, #0xff000000
+	/* r4 = 0x00100f01 */
+	ldr r4, =0x00100f01
+
+	/*
+	 * invalidate i-cache all to make sure the codes bellow
+	 * to be fetched into a single 32-bytes cache line
+	 */
+	mcr p15, 0, r0, c7, c5, 0
+
+	.align 5
+
+	str r3, [r2, #0x10] /* REG32(CONFIG_IOBASE_DDR + 0x10) &= 0x00FFFFFF */
+	str r4, [r1, #0x88] /* REG32(CONFIG_IOBASE_AHB + 0x88)  = 0x00100F01 */
+
+_remap_wait:
+	str r5, [r0, #0]
+	ldr r1, [r0, #0]
+	teq r1, r5
+	bne _remap_wait		/* while(magic != REG32(addr)) */
+
+_exit:
+	mov	pc, lr
diff --git a/boards.cfg b/boards.cfg
index 5d78064..891f7f3 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -73,6 +73,9 @@ mini2440                     arm         arm920t     mini2440            friendl
 VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
 smdk2410                     arm         arm920t     -                   samsung        s3c24x0
 omap1510inn                  arm         arm925t     -                   ti
+a360                         arm         faraday     a360evb             faraday        a360
+a369                         arm         faraday     a369evb             faraday        a369
+a369_fa606te                 arm         faraday     a369evb             faraday        a369
 integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap:CM926EJ_S
 integratorcp_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorcp:CM924EJ_S
 aspenite                     arm         arm926ejs   -                   Marvell        armada100
diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..6a25b0a
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,63 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Main oscillator (HZ) */
+#define CONFIG_MAIN_CLK             40000000
+
+/*
+ * Memory Configuration
+ */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_256M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_PIN    26
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369-common.h b/include/configs/a369-common.h
new file mode 100644
index 0000000..0099739
--- /dev/null
+++ b/include/configs/a369-common.h
@@ -0,0 +1,74 @@
+#ifndef __CONFIG_A369_COMMON_H
+#define __CONFIG_A369_COMMON_H
+
+#include <asm/hardware.h>
+
+/*
+ * A369 Platform Common Configuration
+ */
+
+/* Main oscillator (HZ) */
+#define CONFIG_MAIN_CLK             33000000
+
+/*
+ * Memory Configuration
+ */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_512M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* NAND Flash */
+#define CONFIG_SYS_MAX_NAND_DEVICE      1 /* Max. num. of devices */
+#define CONFIG_SYS_FTNANDC021_TIMING    { 0x02240264, 0x42054209 }
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_BASE   0x92600000 /* GPIO 1 */
+#define CONFIG_FTSSP010_GPIO_PIN    27
+
+/* NOR Flash */
+/*
+#define PHYS_FLASH_SIZE             SZ_64M
+#define CONFIG_SYS_FLASH_BASE       0x20000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH  FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS  1
+#define CONFIG_SYS_MAX_FLASH_SECT   1024
+*/
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_IN_NAND
+#define CONFIG_ENV_OFFSET           0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND    0x07FE0000
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..d4bb39a
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,33 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_PLATFORM
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Support runtime switching to built-in slave core: FA606TE */
+#define CONFIG_CMD_FA606
+
+/* Autoboot */
+#define CONFIG_BOOTDELAY            3
+#define CONFIG_BOOTCOMMAND          "bootfa nand linux"
+
+/*
+ * A369 Common Configuration
+ */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/a369_fa606te.h b/include/configs/a369_fa606te.h
new file mode 100644
index 0000000..ec29d50
--- /dev/null
+++ b/include/configs/a369_fa606te.h
@@ -0,0 +1,29 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_FA606TE_PLATFORM
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Disable I-CACHE */
+#define CONFIG_SYS_ICACHE_OFF
+
+/*
+ * A369 Common Configuration
+ */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..8291fa5
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,304 @@
+#ifndef __CONFIG_A36X_COMMON_H
+#define __CONFIG_A36X_COMMON_H
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+#define CONFIG_BOARD_LATE_INIT      1
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_8M
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+/*
+ * CPU
+ */
+#define CONFIG_FARADAY
+#define CONFIG_ARCH_CPU_INIT
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_SYS_CACHELINE_SIZE	32
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+/*
+ * Interrupt
+ */
+#ifdef CONFIG_USE_IRQ
+# define CONFIG_FTINTC020
+# ifdef CONFIG_A369_PLATFORM
+#  define CONFIG_PIC_BASE           CONFIG_FTINTC020_BASE
+# else
+#  define CONFIG_PIC_BASE           CONFIG_FTINTC020_BASE1
+# endif
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_SYS_HZ               1000
+
+#ifdef CONFIG_FTTMR010_BASE
+# define CONFIG_FTTMR010
+# define CONFIG_TIMER_BASE           CONFIG_FTTMR010_BASE
+# define CONFIG_TIMER_IRQ            CONFIG_FTTMR010_IRQ
+#endif /* CONFIG_FTTMR010_BASE */
+
+#ifdef CONFIG_FTPWMTMR010_BASE
+# define CONFIG_FTPWMTMR010
+# define CONFIG_TIMER_BASE           CONFIG_FTPWMTMR010_BASE
+# define CONFIG_TIMER_IRQ            CONFIG_FTPWMTMR010_IRQ
+#endif /* CONFIG_FTPWMTMR010_BASE */
+
+/*
+ * Serial Info
+ */
+#ifdef CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# ifndef CONFIG_SYS_NS16550_CLK
+#  define CONFIG_SYS_NS16550_CLK     18432000
+# endif
+# define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE -4
+# define CONFIG_CONS_INDEX           1
+# define CONFIG_BAUDRATE             38400
+# undef  CONFIG_HWFLOW
+# undef  CONFIG_MODEM_SUPPORT
+#endif /* #ifdef CONFIG_FTUART010_BASE */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTMAC110_BASE
+# define CONFIG_FTMAC110
+#endif
+#ifdef CONFIG_FTGMAC100_BASE
+# define CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA    /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR    32 /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT 20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif
+
+/*
+ * I2C Controller
+ */
+#ifdef CONFIG_FTI2C010_BASE3
+# define CONFIG_SYS_MAX_I2C_BUS      4
+#elif defined(CONFIG_FTI2C010_BASE2)
+# define CONFIG_SYS_MAX_I2C_BUS      3
+#elif defined(CONFIG_FTI2C010_BASE1)
+# define CONFIG_SYS_MAX_I2C_BUS      2
+#elif defined(CONFIG_FTI2C010_BASE)
+# define CONFIG_SYS_MAX_I2C_BUS      1
+#else
+# define CONFIG_SYS_MAX_I2C_BUS      0
+#endif
+#if CONFIG_SYS_MAX_I2C_BUS > 0
+# define CONFIG_FTI2C010
+# define CONFIG_HARD_I2C
+# define CONFIG_SYS_I2C_SPEED        5000
+# define CONFIG_SYS_I2C_SLAVE        0
+# define CONFIG_CMD_I2C
+# define CONFIG_I2C_CMD_TREE
+#endif
+#if CONFIG_SYS_MAX_I2C_BUS > 1
+# define CONFIG_I2C_MULTI_BUS
+#endif
+
+/*
+ * I2C-EEPROM
+ */
+#ifdef CONFIG_ENV_EEPROM_IS_ON_I2C
+# define CONFIG_CMD_EEPROM
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      3
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  5
+# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN         1
+# define CONFIG_SYS_I2C_MULTI_EEPROMS
+#endif
+
+/*
+ * SPI Bus
+ */
+#ifdef CONFIG_FTSSP010_BASE
+# define CONFIG_FTSSP010_SPI
+# define CONFIG_SPI
+# define CONFIG_HARD_SPI
+# define CONFIG_CMD_SPI
+# define CONFIG_ENV_SPI_BUS         0
+# define CONFIG_ENV_SPI_CS          0
+# define CONFIG_ENV_SPI_MAX_HZ      25000000
+# define CONFIG_DEFAULT_SPI_MODE    SPI_MODE_0
+#endif
+
+/*
+ * SPI Flash
+ */
+#ifdef CONFIG_FTSPI020_BASE
+# define CONFIG_FTSPI020
+#elif defined(CONFIG_SPI)
+# define CONFIG_SPI_FLASH
+# define CONFIG_SPI_FLASH_MACRONIX
+# define CONFIG_SPI_FLASH_WINBOND
+#endif
+
+#if defined(CONFIG_FTSPI020) || defined(CONFIG_SPI_FLASH)
+# define CONFIG_CMD_SF
+# define CONFIG_SF_DEFAULT_MODE     SPI_MODE_0
+# define CONFIG_SF_DEFAULT_SPEED    25000000
+#endif
+
+/*
+ * NOR Flash
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* print 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * NAND Flash
+ */
+#ifdef CONFIG_FTNANDC021_BASE
+# define CONFIG_SYS_NAND_SELF_INIT
+# define CONFIG_NAND_FTNANDC021
+# define CONFIG_SYS_NAND_BASE           CONFIG_FTNANDC021_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+#endif
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010_BASE
+# define CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* The hardware core supports SDIO */
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 0
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#if defined(CONFIG_SUPP_USB_RNDIS) && defined(CONFIG_FOTG210_BASE)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+#endif
+
+/*
+ * LCD
+ */
+#if defined(CONFIG_SUPP_VGA_CONSOLE) && defined(CONFIG_FTLCDC200_BASE)
+# define CONFIG_FTLCDC200
+# define CONFIG_FTLCDC200_800X480S_TPO
+# define LCD_BPP                    4 /* 16-bit per pixel */
+# define CONFIG_LCD
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+#ifndef CONFIG_SYS_LOAD_ADDR        /* Default load address */
+# define CONFIG_SYS_LOAD_ADDR       (CONFIG_SYS_SDRAM_BASE + SZ_1M)
+#endif
+/* Console Baud-Rate Table */
+#define CONFIG_SYS_BAUDRATE_TABLE   { 115200, 57600, 38400, 19200, 9600 }
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 59c6f8e..aa02717 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -82,5 +82,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_WORST	0x0f1ff3ff /* worst but safe */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v4 0/2] usb: ehci: add Faraday USB EHCI&Gadget support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-04-26 12:19           ` Marek Vasut
@ 2013-05-07  6:26           ` Kuo-Jung Su
  2013-05-07  6:26             ` [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-05-07  6:26             ` [U-Boot] [PATCH v4 2/2] " Kuo-Jung Su
  1 sibling, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:26 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch add supports to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI as
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. Since U-boot doesn't support ISOC,
   we don't have to worry that.

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device as a time.

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

Kuo-Jung Su (2):
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 common/usb_hub.c                  |   13 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  961 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/host/Makefile         |    1 +
 drivers/usb/host/ehci-faraday.c   |  146 ++++++
 drivers/usb/host/ehci-hcd.c       |  104 ++--
 include/usb/fotg210.h             |  358 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 9 files changed, 1616 insertions(+), 37 deletions(-)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-07  6:26           ` [U-Boot] [PATCH v4 0/2] usb: ehci: add Faraday USB EHCI&Gadget support Kuo-Jung Su
@ 2013-05-07  6:26             ` Kuo-Jung Su
  2013-05-07 21:42               ` Marek Vasut
  2013-05-09  3:20               ` [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-07  6:26             ` [U-Boot] [PATCH v4 2/2] " Kuo-Jung Su
  1 sibling, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:26 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch add supports to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI as
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. Since U-boot doesn't support ISOC,
   we don't have to worry that.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 common/usb_hub.c                |   13 +-
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |  104 ++++++++----
 include/usb/fotg210.h           |  358 +++++++++++++++++++++++++++++++++++++++
 include/usb/fusbh200.h          |   61 +++++++
 6 files changed, 646 insertions(+), 37 deletions(-)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index b5eeb62..3c6cb69 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device *dev)
 			portstatus = le16_to_cpu(portsts->wPortStatus);
 			portchange = le16_to_cpu(portsts->wPortChange);

+#ifdef CONFIG_USB_EHCI_FARADAY
+			/* Faraday EHCI needs a long long delay here */
+			if (!portchange && !portstatus) {
+				if (get_timer(start) < 250)
+					continue;
+			}
+#endif
+
 			if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
 				(portstatus & USB_PORT_STAT_CONNECTION))
 				break;
@@ -441,7 +449,9 @@ static int usb_hub_configure(struct usb_device *dev)
 					i + 1, portstatus);
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_ENABLE);
-
+			/* The following hack causes a ghost device problem
+			 * to Faraday EHCI */
+#ifndef CONFIG_USB_EHCI_FARADAY
 			/* EM interference sometimes causes bad shielded USB
 			 * devices to be shutdown by the hub, this hack enables
 			 * them again. Works at least with mouse driver */
@@ -453,6 +463,7 @@ static int usb_hub_configure(struct usb_device *dev)
 						"re-enabling...\n", i + 1);
 					usb_hub_port_connect_change(dev, i);
 			}
+#endif
 		}
 		if (portstatus & USB_PORT_STAT_SUSPEND) {
 			USB_HUB_PRINTF("port %d suspend change\n", i + 1);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..1be9369
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,146 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+/*
+ * This ehci_tdi_reset() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+void ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	/* nothing needs to be done */
+}
+
+/*
+ * This ehci_port_speed() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int spd, ret = 0;
+	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		break;
+	case 1:    /* low  speed */
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case 2:    /* high speed */
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This ehci_get_portsc_register() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/* Faraday EHCI has one and only one portsc register */
+	if (port > 0) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)hcor + 0x20);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..36ad897 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -117,10 +117,50 @@ static struct descriptor {
 };

 #if defined(CONFIG_EHCI_IS_TDI)
-#define ehci_is_TDI()	(1)
-#else
-#define ehci_is_TDI()	(0)
+# define ehci_is_TDI()	(1)
+
+/* put TDI/ARC silicon into EHCI mode */
+void __ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	uint32_t tmp, *reg_ptr;
+
+	reg_ptr = (uint32_t *)((uint8_t *) + USBMODE);
+	tmp = ehci_readl(reg_ptr);
+	tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+	tmp |= USBMODE_BE;
 #endif
+	ehci_writel(reg_ptr, tmp);
+}
+
+void ehci_tdi_reset(struct ehci_hcor *hcor)
+	__attribute__((weak, alias("__ehci_tdi_reset")));
+
+int __ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int ret = 0;
+
+	switch (PORTSC_PSPD(portsc)) {
+	case PORTSC_PSPD_FS:
+		break;
+	case PORTSC_PSPD_LS:
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case PORTSC_PSPD_HS:
+	default:
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	}
+
+	return ret;
+}
+
+int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+	__attribute__((weak, alias("__ehci_port_speed")));
+
+#else  /* CONFIG_EHCI_IS_TDI */
+# define ehci_is_TDI()	(0)
+#endif /* CONFIG_EHCI_IS_TDI */

 void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 {
@@ -149,8 +189,6 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
-	uint32_t tmp;
-	uint32_t *reg_ptr;
 	int ret = 0;

 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,15 +201,8 @@ static int ehci_reset(int index)
 		goto out;
 	}

-	if (ehci_is_TDI()) {
-		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
-		tmp = ehci_readl(reg_ptr);
-		tmp |= USBMODE_CM_HC;
-#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
-		tmp |= USBMODE_BE;
-#endif
-		ehci_writel(reg_ptr, tmp);
-	}
+	if (ehci_is_TDI())
+		ehci_tdi_reset(ehcic[index].hcor);

 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -573,10 +604,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
 		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
 		      ehci_readl(&ctrl->hcor->or_portsc[0]),
 		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
 	}

 	free(qtd);
@@ -597,6 +630,18 @@ static inline int min3(int a, int b, int c)
 	return a;
 }

+uint32_t *__ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+	__attribute__((weak, alias("__ehci_get_portsc_register")));
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
@@ -609,13 +654,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	uint32_t *status_reg;
 	struct ehci_ctrl *ctrl = dev->controller;

-	if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		printf("The request port(%d) is not configured\n",
-			le16_to_cpu(req->index) - 1);
+	status_reg = ehci_get_portsc_register(ctrl->hcor,
+		le16_to_cpu(req->index) - 1);
+	if (!status_reg)
 		return -1;
-	}
-	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
-						le16_to_cpu(req->index) - 1];
 	srclen = 0;

 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -709,23 +751,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[0] |= USB_PORT_STAT_RESET;
 		if (reg & EHCI_PS_PP)
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
-
-		if (ehci_is_TDI()) {
-			switch (PORTSC_PSPD(reg)) {
-			case PORTSC_PSPD_FS:
-				break;
-			case PORTSC_PSPD_LS:
-				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
-				break;
-			case PORTSC_PSPD_HS:
-			default:
-				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-				break;
-			}
-		} else {
+		if (ehci_is_TDI())
+			tmpbuf[1] |= ehci_port_speed(ctrl->hcor, reg) >> 8;
+		else
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-		}
-
 		if (reg & EHCI_PS_CSC)
 			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
 		if (reg & EHCI_PS_PEC)
@@ -950,10 +979,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..15b7f01
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,358 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t miscr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[2];
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */
+};
+
+/* Miscellaneous Register */
+#define MISCR_SUSPEND  (1 << 6) /* Put transceiver in suspend mode */
+#define MISCR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define MISCR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define MISCR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* OTG Control Status Register */
+#define OTGCSR_SPD_HIGH     (2 << 22) /* Speed of the attached device (host) */
+#define OTGCSR_SPD_LOW      (1 << 22)
+#define OTGCSR_SPD_FULL     (0 << 22)
+#define OTGCSR_SPD_MASK     (3 << 22)
+#define OTGCSR_SPD_SHIFT    22
+#define OTGCSR_SPD(x)       (((x) >> 22) & 0x03)
+#define OTGCSR_DEV_A        (0 << 21) /* Acts as A-device */
+#define OTGCSR_DEV_B        (1 << 21) /* Acts as B-device */
+#define OTGCSR_ROLE_H       (0 << 20) /* Acts as Host */
+#define OTGCSR_ROLE_D       (1 << 20) /* Acts as Device */
+#define OTGCSR_A_VBUS_VLD   (1 << 19) /* A-device VBUS Valid */
+#define OTGCSR_A_SESS_VLD   (1 << 18) /* A-device Session Valid */
+#define OTGCSR_B_SESS_VLD   (1 << 17) /* B-device Session Valid */
+#define OTGCSR_B_SESS_END   (1 << 16) /* B-device Session End */
+#define OTGCSR_HFT_LONG     (1 << 11) /* HDISCON noise filter = 270 us*/
+#define OTGCSR_HFT          (0 << 11) /* HDISCON noise filter = 135 us*/
+#define OTGCSR_VFT_LONG     (1 << 10) /* VBUS noise filter = 472 us*/
+#define OTGCSR_VFT          (0 << 10) /* VBUS noise filter = 135 us*/
+#define OTGCSR_IDFT_LONG    (1 << 9)  /* ID noise filter = 4 ms*/
+#define OTGCSR_IDFT         (0 << 9)  /* ID noise filter = 3 ms*/
+#define OTGCSR_A_SRPR_VBUS  (0 << 8)  /* A-device: SRP responds to VBUS */
+#define OTGCSR_A_SRPR_DATA  (1 << 8)  /* A-device: SRP responds to DATA-LINE */
+#define OTGCSR_A_SRP_EN     (1 << 7)  /* A-device SRP detection enabled */
+#define OTGCSR_A_HNP        (1 << 6)  /* Set role=A-device with HNP enabled */
+#define OTGCSR_A_BUSDROP    (1 << 5)  /* A-device drop bus (power-down) */
+#define OTGCSR_A_BUSREQ     (1 << 4)  /* A-device request bus */
+#define OTGCSR_B_VBUS_DISC  (1 << 2)  /* B-device discharges VBUS */
+#define OTGCSR_B_HNP        (1 << 1)  /* B-device enable HNP */
+#define OTGCSR_B_BUSREQ     (1 << 0)  /* B-device request bus */
+
+/* OTG Interrupt Status Register */
+#define OTGISR_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGISR_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGISR_OVD          (1 << 10) /* over-current detected */
+#define OTGISR_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGISR_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGISR_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGISR_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGISR_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGISR_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* OTG Interrupt Enable Register */
+#define OTGIER_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGIER_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGIER_OVD          (1 << 10) /* over-current detected */
+#define OTGIER_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGIER_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGIER_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGIER_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGIER_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGIER_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* Global Interrupt Status Register */
+#define ISR_HOST            (1 << 2)  /* USB Host interrupt */
+#define ISR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define ISR_DEV             (1 << 0)  /* USB Device interrupt */
+
+/* Global Interrupt Mask Register */
+#define IMR_IRQLH           (1 << 3)  /* Interrupt triggered at level-high */
+#define IMR_IRQLL           (0 << 3)  /* Interrupt triggered@level-low */
+#define IMR_HOST            (1 << 2)  /* USB Host interrupt */
+#define IMR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define IMR_DEV             (1 << 0)  /* USB Device interrupt */
+
+/* Device Control Register */
+#define DEVCTRL_FS_FORCED   (1 << 9)  /* Forced to be Full-Speed Mode */
+#define DEVCTRL_HS          (1 << 6)  /* High Speed Mode */
+#define DEVCTRL_FS          (0 << 6)  /* Full Speed Mode */
+#define DEVCTRL_EN          (1 << 5)  /* Chip Enable */
+#define DEVCTRL_RESET       (1 << 4)  /* Chip Software Reset */
+#define DEVCTRL_SUSPEND     (1 << 3)  /* Enter Suspend Mode */
+#define DEVCTRL_GIRQ_EN     (1 << 2)  /* Global Interrupt Enabled */
+#define DEVCTRL_HALFSPD     (1 << 1)  /* Half speed mode for FPGA test */
+#define DEVCTRL_RWAKEUP     (1 << 0)  /* Enable remote wake-up */
+
+/* Device Address Register */
+#define DEVADDR_CONF        (1 << 7)  /* SET_CONFIGURATION has been executed */
+#define DEVADDR_ADDR(x)     ((x) & 0x7f)
+#define DEVADDR_ADDR_MASK   0x7f
+
+/* Device Test Register */
+#define DEVTEST_NOSOF       (1 << 6)  /* Do not generate SOF */
+#define DEVTEST_TST_MODE    (1 << 5)  /* Enter Test Mode */
+#define DEVTEST_TST_NOTS    (1 << 4)  /* Do not toggle sequence */
+#define DEVTEST_TST_NOCRC   (1 << 3)  /* Do not append CRC */
+#define DEVTEST_TST_CLREA   (1 << 2)  /* Clear External Side Address */
+#define DEVTEST_TST_CXLP    (1 << 1)  /* EP0 loopback test */
+#define DEVTEST_TST_CLRFF   (1 << 0)  /* Clear FIFO */
+
+/* SOF Frame Number Register */
+#define SOFFNR_UFN(x)       (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */
+#define SOFFNR_FNR(x)       ((x) & 0x7ff) /* SOF Frame Number */
+
+/* SOF Mask Timer Register */
+#define SOFMTR_TMR(x)       ((x) & 0xffff)
+
+/* PHY Test Mode Selector Register */
+#define PHYTMSR_TST_PKT     (1 << 4) /* Packet send test */
+#define PHYTMSR_TST_SE0NAK  (1 << 3) /* High-Speed quiescent state */
+#define PHYTMSR_TST_KSTA    (1 << 2) /* High-Speed K state */
+#define PHYTMSR_TST_JSTA    (1 << 1) /* High-Speed J state */
+#define PHYTMSR_UNPLUG      (1 << 0) /* Enable soft-detachment */
+
+/* CX FIFO Register */
+#define CXFIFO_BYTES(x)     (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */
+#define CXFIFO_FIFOE(x)     (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */
+#define CXFIFO_FIFOE_FIFO0  (1 << 8)
+#define CXFIFO_FIFOE_FIFO1  (1 << 9)
+#define CXFIFO_FIFOE_FIFO2  (1 << 10)
+#define CXFIFO_FIFOE_FIFO3  (1 << 11)
+#define CXFIFO_FIFOE_MASK   (0x0f << 8)
+#define CXFIFO_CXFIFOE      (1 << 5) /* CX FIFO empty */
+#define CXFIFO_CXFIFOF      (1 << 4) /* CX FIFO full */
+#define CXFIFO_CXFIFOCLR    (1 << 3) /* CX FIFO clear */
+#define CXFIFO_CXSTALL      (1 << 2) /* CX Stall */
+#define CXFIFO_TSTPKTFIN    (1 << 1) /* Test packet data transfer finished */
+#define CXFIFO_CXFIN        (1 << 0) /* CX data transfer finished */
+
+/* IDLE Counter Register */
+#define IDLE_MS(x)          ((x) & 0x07) /* PHY suspend delay = x ms */
+
+/* Group Interrupt Mask(Disable) Register */
+#define GIMR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GIMR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GIMR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+
+/* Group Interrupt Mask(Disable) Register 0 (CX) */
+#define GIMR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GIMR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GIMR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GIMR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GIMR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GIMR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Mask(Disable) Register 1 (FIFO) */
+#define GIMR1_FIFO_IN(x)    (1 << (((x) & 3) + 16))    /* FIFOx IN */
+#define GIMR1_FIFO_TX(x)    GIMR1_FIFO_IN(x)
+#define GIMR1_FIFO_OUT(x)   (1 << (((x) & 3) * 2))     /* FIFOx OUT */
+#define GIMR1_FIFO_SPK(x)   (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */
+#define GIMR1_FIFO_RX(x)    (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x))
+
+/* Group Interrupt Mask(Disable) Register 2 (Device) */
+#define GIMR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GIMR2_IDLE          (1 << 9)  /* Device idle */
+#define GIMR2_DMAERR        (1 << 8)  /* DMA error */
+#define GIMR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GIMR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GIMR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GIMR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GIMR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GIMR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GIMR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GIMR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Group Interrupt Status Register */
+#define GISR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GISR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GISR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+
+/* Group Interrupt Status Register 0 (CX) */
+#define GISR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GISR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GISR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GISR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GISR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GISR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Status Register 1 (FIFO) */
+#define GISR1_IN_FIFO(x)    (1 << (((x) & 0x03) + 16))    /* FIFOx IN */
+#define GISR1_OUT_FIFO(x)   (1 << (((x) & 0x03) * 2))     /* FIFOx OUT */
+#define GISR1_SPK_FIFO(x)   (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */
+#define GISR1_RX_FIFO(x)    (3 << (((x) & 0x03) * 2))     /* FIFOx OUT/SPK */
+
+/* Group Interrupt Status Register 2 (Device) */
+#define GISR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GISR2_IDLE          (1 << 9)  /* Device idle */
+#define GISR2_DMAERR        (1 << 8)  /* DMA error */
+#define GISR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GISR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GISR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GISR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GISR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GISR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GISR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GISR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Receive Zero-Length-Packet Register */
+#define RXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP rx interrupt */
+
+/* Transfer Zero-Length-Packet Register */
+#define TXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP tx interrupt */
+
+/* ISOC Error/Abort Status Register */
+#define ISOEASR_EP(x)       (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */
+
+/* IN Endpoint Register */
+#define IEP_SENDZLP         (1 << 15)     /* Send Zero-Length-Packet */
+#define IEP_TNRHB(x)        (((x) & 0x03) << 13) \
+	/* Transaction Number for High-Bandwidth EP(ISOC) */
+#define IEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define IEP_STALL           (1 << 11)     /* Stall */
+#define IEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* OUT Endpoint Register */
+#define OEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define OEP_STALL           (1 << 11)     /* Stall */
+#define OEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* Endpoint Map Register (EP1 ~ EP4) */
+#define EPMAP14_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 0)
+#define EPMAP14_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 4)
+#define EPMAP14_SET(ep, in, out) \
+	do { \
+		EPMAP14_SET_IN(ep, in); \
+		EPMAP14_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP14_DEFAULT     0x33221100 /* EP1->FIFO0, EP2->FIFO1... */
+
+/* Endpoint Map Register (EP5 ~ EP8) */
+#define EPMAP58_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 0)
+#define EPMAP58_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 4)
+#define EPMAP58_SET(ep, in, out) \
+	do { \
+		EPMAP58_SET_IN(ep, in); \
+		EPMAP58_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP58_DEFAULT     0x00000000 /* All EPx->FIFO0 */
+
+/* FIFO Map Register */
+#define FIFOMAP_BIDIR       (2 << 4)
+#define FIFOMAP_IN          (1 << 4)
+#define FIFOMAP_OUT         (0 << 4)
+#define FIFOMAP_DIR_MASK    0x30
+#define FIFOMAP_EP(x)       ((x) & 0x0f)
+#define FIFOMAP_EP_MASK     0x0f
+#define FIFOMAP_CFG_MASK    0x3f
+#define FIFOMAP_DEFAULT     0x04030201 /* FIFO0->EP1, FIFO1->EP2... */
+#define FIFOMAP(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Configuration Register */
+#define FIFOCFG_EN          (1 << 5)
+#define FIFOCFG_BLKSZ_1024  (1 << 4)
+#define FIFOCFG_BLKSZ_512   (0 << 4)
+#define FIFOCFG_3BLK        (2 << 2)
+#define FIFOCFG_2BLK        (1 << 2)
+#define FIFOCFG_1BLK        (0 << 2)
+#define FIFOCFG_NBLK_MASK   3
+#define FIFOCFG_NBLK_SHIFT  2
+#define FIFOCFG_INTR        (3 << 0)
+#define FIFOCFG_BULK        (2 << 0)
+#define FIFOCFG_ISOC        (1 << 0)
+#define FIFOCFG_RSVD        (0 << 0)  /* Reserved */
+#define FIFOCFG_TYPE_MASK   3
+#define FIFOCFG_TYPE_SHIFT  0
+#define FIFOCFG_CFG_MASK    0x3f
+#define FIFOCFG(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Control Status Register */
+#define FIFOCSR_RESET       (1 << 12) /* FIFO Reset */
+#define FIFOCSR_BYTES(x)    ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */
+
+/* DMA Target FIFO Register */
+#define DMAFIFO_CX          (1 << 4) /* DMA FIFO = CX FIFO */
+#define DMAFIFO_FIFO(x)     (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */
+
+/* DMA Control Register */
+#define DMACTRL_LEN(x)      (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */
+#define DMACTRL_LEN_SHIFT   8
+#define DMACTRL_CLRFF       (1 << 4) /* Clear FIFO upon DMA abort */
+#define DMACTRL_ABORT       (1 << 3) /* DMA abort */
+#define DMACTRL_IO2IO       (1 << 2) /* IO to IO */
+#define DMACTRL_FIFO2MEM    (0 << 1) /* FIFO to Memory */
+#define DMACTRL_MEM2FIFO    (1 << 1) /* Memory to FIFO */
+#define DMACTRL_START       (1 << 0) /* DMA start */
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..8a9c488
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,61 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+/* EOF & Async. Schedule Sleep Timer Register */
+#define EASSTR_RUNNING  (1 << 6) /* Put transceiver in running/resume mode */
+#define EASSTR_SUSPEND  (0 << 6) /* Put transceiver in suspend mode */
+#define EASSTR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define EASSTR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define EASSTR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* Bus Monitor Control Status Register */
+#define BMCSR_SPD_HIGH  (2 << 9) /* Speed of the attached device */
+#define BMCSR_SPD_LOW   (1 << 9)
+#define BMCSR_SPD_FULL  (0 << 9)
+#define BMCSR_SPD_MASK  (3 << 9)
+#define BMCSR_SPD_SHIFT 9
+#define BMCSR_SPD(x)    ((x >> 9) & 0x03)
+#define BMCSR_VBUS      (1 << 8) /* VBUS Valid */
+#define BMCSR_VBUS_OFF  (1 << 4) /* VBUS Off */
+#define BMCSR_VBUS_ON   (0 << 4) /* VBUS On */
+#define BMCSR_IRQLH     (1 << 3) /* IRQ triggered at level-high */
+#define BMCSR_IRQLL     (0 << 3) /* IRQ triggered@level-low */
+#define BMCSR_HALFSPD   (1 << 2) /* Half speed mode for FPGA test */
+#define BMCSR_HFT_LONG  (1 << 1) /* HDISCON noise filter = 270 us*/
+#define BMCSR_HFT       (0 << 1) /* HDISCON noise filter = 135 us*/
+#define BMCSR_VFT_LONG  (1 << 1) /* VBUS noise filter = 472 us*/
+#define BMCSR_VFT       (0 << 1) /* VBUS noise filter = 135 us*/
+
+/* Bus Monitor Interrupt Status Register */
+/* Bus Monitor Interrupt Enable Register */
+#define BMISR_DMAERR    (1 << 4) /* DMA error */
+#define BMISR_DMA       (1 << 3) /* DMA complete */
+#define BMISR_DEVRM     (1 << 2) /* device removed */
+#define BMISR_OVD       (1 << 1) /* over-current detected */
+#define BMISR_VBUSERR   (1 << 0) /* VBUS error */
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v4 2/2] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-07  6:26           ` [U-Boot] [PATCH v4 0/2] usb: ehci: add Faraday USB EHCI&Gadget support Kuo-Jung Su
  2013-05-07  6:26             ` [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-05-07  6:26             ` Kuo-Jung Su
  2013-05-07 21:37               ` Marek Vasut
  1 sibling, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:26 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device as a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v4:
   - Use only macro constants and named bit/mask
   - Remove dcache_enable() from usb_gadget_register_driver()

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  961 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 970 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..70797ae
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,961 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+#define CFG_RST_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs __iomem *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType  = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes =    USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id % 4) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) % 4);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs __iomem *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], OEP_STALL);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+	uint32_t i, ts;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(DEVCTRL_EN, &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(chip->addr, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable interrupts */
+	writel(0x0f, &regs->imr);
+	writel(0x07, &regs->gimr);
+	writel(0x3f, &regs->gimr0);
+	writel(0xf00ff, &regs->gimr1);
+	writel(0x7ff, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(0x07, &regs->isr);
+	writel(0x00, &regs->gisr);
+	writel(0x00, &regs->gisr0);
+	writel(0x00, &regs->gisr1);
+	writel(0x00, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+		if (readl(&regs->dev_ctrl) & DEVCTRL_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+		if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR)
+			continue;
+		break;
+	}
+	if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(EPMAP14_DEFAULT, &regs->epmap14);
+	writel(EPMAP58_DEFAULT, &regs->epmap58);
+	writel(FIFOMAP_DEFAULT, &regs->fifomap);
+	writel(0, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+		for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+			if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET)
+				continue;
+			break;
+		}
+		if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(0x0e, &regs->imr);
+	writel(0x07, &regs->isr);
+
+	/* disable EP0 IN/OUT interrupt */
+	writel(0x06, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(0xf00ff, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(0x7e0, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0x00, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_GIRQ_EN);
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	uint32_t fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->dma_ctrl) & 0x01)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+#ifndef CONFIG_SYS_DCACHE_OFF
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+	else
+		invalidate_dcache_range((uint32_t)buf, (uint32_t)buf + len);
+#endif
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until cx fifo empty */
+			fotg210_cxwait(chip, CXFIFO_CXFIFOE);
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+		} else {
+			/* Wait until fifo empty */
+			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+		}
+		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+
+		if (ep->id == 0) {
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+			do {
+				blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+			} while (blen < len);
+		} else {
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+			blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+		}
+		len  = (len < blen) ? len : blen;
+		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & GISR2_DMAFIN) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & GISR2_DMAERR) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & 0x07) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(DMACTRL_ABORT | DMACTRL_CLRFF, &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs __iomem *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & OTGCSR_DEV_B) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				writel(0x044c, &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				writel(0x2710, &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(DMAFIFO_CX, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->ep0_data);
+	tmp[1] = readl(&regs->ep0_data);
+	/* release data port */
+	writel(0, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(DEVADDR_ADDR(chip->addr),
+					&regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(DEVADDR_ADDR(chip->addr) | DEVADDR_CONF,
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], IEP_STALL);
+				setbits_le32(&regs->oep[id - 1], OEP_STALL);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue)) {
+		setbits_le32(&regs->gimr1,
+			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+	}
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_IN));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+	clrbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs __iomem *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs __iomem *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return readl(&regs->sof_fnr) & 0x7ff;
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name    = "ep0",
+			.ops    = &fotg210_ep_ops,
+		},
+		.desc       = &ep0_desc,
+		.chip        = &controller,
+		.maxpacket    = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name    = "ep1",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name    = "ep2",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name    = "ep3",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name    = "ep4",
+			.ops    = &fotg210_ep_ops,
+		},
+		.chip        = &controller,
+		.maxpacket    = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs __iomem *regs = chip->regs;
+	uint32_t id, st, isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & ISR_DEV) || !gisr)
+		return 0;
+
+	writel(ISR_DEV, &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & GISR_GRP0) {
+		st = readl(&regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & GISR0_CXERR)
+			printf("fotg210: cmd error\n");
+
+		if (st & GISR0_CXABORT)
+			printf("fotg210: cmd abort\n");
+
+		if (st & GISR0_CXSETUP)    /* setup */
+			fotg210_setup(chip);
+		else if (st & GISR0_CXEND) /* command finish */
+			setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & GISR_GRP1) {
+		st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & GISR1_RX_FIFO(id))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & GISR_GRP2) {
+		st = readl(&regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & GISR2_RESET)
+			printf("fotg210: reset by host\n");
+		else if (st & GISR2_SUSPEND)
+			printf("fotg210: suspend/removed\n");
+		else if (st & GISR2_RESUME)
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & GISR2_ISOCERR)
+			printf("fotg210: iso error\n");
+		if (st & GISR2_ISOCABT)
+			printf("fotg210: iso abort\n");
+		if (st & GISR2_DMAERR)
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH v4 03/16] i2c: add Faraday FTI2C010 I2C controller support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 04/11] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
  2013-04-29  3:34           ` Heiko Schocher
@ 2013-05-07  6:32           ` Kuo-Jung Su
  2013-05-07 13:19             ` Heiko Schocher
  2013-05-08  7:36             ` [U-Boot] [PATCH v5] " Kuo-Jung Su
  1 sibling, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:32 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTI2C010 is a multi-function I2C controller
which supports both master and slave mode.
This patch simplily implements the master mode only.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Heiko Schocher <hs@denx.de>
---
Changes for v4:
   - Coding Style cleanup.
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 drivers/i2c/Makefile   |    1 +
 drivers/i2c/fti2c010.c |  371 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/fti2c010.h |   81 +++++++++++
 3 files changed, 453 insertions(+)
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 5dbdbe3..ed2b8c0 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
 COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
 COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
 COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
+COBJS-$(CONFIG_FTI2C010) += fti2c010.o
 COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
 COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
 COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
new file mode 100644
index 0000000..ef994a3
--- /dev/null
+++ b/drivers/i2c/fti2c010.c
@@ -0,0 +1,371 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+
+#include "fti2c010.h"
+
+#define I2C_RD              1
+#define I2C_WR              0
+
+#define CFG_I2C_TIMEOUT     CONFIG_SYS_HZ
+
+struct fti2c010_chip {
+	void __iomem *regs;
+	uint32_t bus;
+	uint32_t speed;
+};
+
+#if defined(CONFIG_HARD_I2C)
+
+static struct fti2c010_chip chip_list[] = {
+#ifdef CONFIG_I2C_MULTI_BUS
+# ifdef CONFIG_FTI2C010_BASE
+	{
+		.bus   = 0,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE1
+	{
+		.bus   = 1,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE1,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE2
+	{
+		.bus   = 2,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE2,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE3
+	{
+		.bus   = 3,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE3,
+	},
+# endif
+#else    /* #ifdef CONFIG_I2C_MULTI_BUS */
+	{
+		.bus   = 0,
+		.speed = 0,
+		.regs  = (void __iomem *)CONFIG_FTI2C010_BASE,
+	},
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+};
+
+static struct fti2c010_chip *priv = chip_list;
+
+static int fti2c010_wait(uint32_t mask)
+{
+	int ret = -1;
+	uint32_t stat, ts;
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_I2C_TIMEOUT; ) {
+		stat = readl(&regs->sr);
+		if ((stat & mask) == mask) {
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * u-boot I2C API
+ */
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+	if (speed || priv->speed == 0)
+		i2c_set_bus_speed(speed);
+}
+
+/*
+ * Probe the given I2C chip address.  Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uchar chip)
+{
+	int rc;
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	/* 1. Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_WR, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* 2. Select device register */
+	writel(0, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_WR, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+		writel(paddr[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Get register data
+	 */
+
+	/* B.1 Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_RD, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* B.2 Get register data */
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		uint32_t stat = SR_DR;
+
+		if (pos == len - 1) {
+			ctrl |= CR_NAK | CR_STOP;
+			stat |= SR_ACK;
+		}
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(stat);
+		if (rc)
+			break;
+		buf[pos] = (uchar)(readl(&regs->dr) & 0xFF);
+	}
+
+	return rc;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int rc, pos;
+	uchar paddr[4];
+	struct fti2c010_regs __iomem *regs = priv->regs;
+
+	i2c_init(0, chip);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	writel((chip << 1) + I2C_WR, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	rc = fti2c010_wait(SR_DT);
+	if (rc)
+		return rc;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+		writel(paddr[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			return rc;
+	}
+
+	/*
+	 * Phase B. Set register data
+	 */
+
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+		if (pos == len - 1)
+			ctrl |= CR_STOP;
+		writel(buf[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		rc = fti2c010_wait(SR_DT);
+		if (rc)
+			break;
+	}
+
+	return rc;
+}
+
+/*
+ * Functions for setting the current I2C bus and its speed
+ */
+#ifdef CONFIG_I2C_MULTI_BUS
+
+/*
+ * i2c_set_bus_num:
+ *
+ *  Change the active I2C bus.  Subsequent read/write calls will
+ *  go to this one.
+ *
+ *    bus - bus index, zero based
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_num(unsigned int bus)
+{
+	if (bus >= sizeof(chip_list) / sizeof(chip_list[0]))
+		return -1;
+	priv = chip_list + bus;
+	i2c_init(5000, 0);
+	return 0;
+}
+
+/*
+ * i2c_get_bus_num:
+ *
+ *  Returns index of currently active I2C bus.  Zero-based.
+ */
+
+unsigned int i2c_get_bus_num(void)
+{
+	return priv->bus;
+}
+
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+
+/*
+ * i2c_set_bus_speed:
+ *
+ *  Change the speed of the active I2C bus
+ *
+ *    speed - bus speed in Hz
+ *
+ *    Returns: 0 on success, not 0 on failure
+ *
+ */
+int i2c_set_bus_speed(unsigned int speed)
+{
+	struct fti2c010_regs __iomem *regs = priv->regs;
+#ifdef CONFIG_FTI2C010_SCLK
+	ulong apb = CONFIG_FTI2C010_SCLK;
+#else
+	ulong apb = clk_get_rate("I2C");
+#endif
+	ulong div = 0x640;
+	ulong gsr = 0;
+	ulong tsr = 0x20;
+	ulong ts;
+
+	writel(CR_I2CRST, &regs->cr);
+	for (ts = get_timer(0); get_timer(ts) < CFG_I2C_TIMEOUT; ) {
+		if (readl(&regs->cr) & CR_I2CRST)
+			continue;
+		break;
+	}
+	if (readl(&regs->cr) & CR_I2CRST) {
+		printf("fti2c010: reset timeout\n");
+		return -1;
+	}
+
+	/* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
+	priv->speed = apb / (2 * (div + 2) + gsr);
+
+	if (speed > 0) {
+		for (div = 0; div < 0x3ffff; ++div) {
+			priv->speed = apb / (2 * (div + 2) + gsr);
+			if (priv->speed < speed)
+				break;
+		}
+	}
+
+	writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), &regs->tgsr);
+	writel(CDR_DIV(div), &regs->cdr);
+
+	return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ *  Returns speed of currently active I2C bus in Hz
+ */
+
+unsigned int i2c_get_bus_speed(void)
+{
+	return priv->speed;
+}
+
+#endif /* CONFIG_HARD_I2C */
diff --git a/drivers/i2c/fti2c010.h b/drivers/i2c/fti2c010.h
new file mode 100644
index 0000000..18aec2c
--- /dev/null
+++ b/drivers/i2c/fti2c010.h
@@ -0,0 +1,81 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTI2C010_H
+#define __FTI2C010_H
+
+/*
+ * FTI2C010 registers
+ */
+struct fti2c010_regs {
+	uint32_t cr;  /* 0x00: control register */
+	uint32_t sr;  /* 0x04: status register */
+	uint32_t cdr; /* 0x08: clock division register */
+	uint32_t dr;  /* 0x0c: data register */
+	uint32_t sar; /* 0x10: slave address register */
+	uint32_t tgsr;/* 0x14: time & glitch suppression register */
+	uint32_t bmr; /* 0x18: bus monitor register */
+	uint32_t rsvd[5];
+	uint32_t revr;/* 0x30: revision register */
+};
+
+/*
+ * control register
+ */
+#define CR_ALIRQ      0x2000  /* arbitration lost interrupt (master) */
+#define CR_SAMIRQ     0x1000  /* slave address match interrupt (slave) */
+#define CR_STOPIRQ    0x800   /* stop condition interrupt (slave) */
+#define CR_NAKRIRQ    0x400   /* NACK response interrupt (master) */
+#define CR_DRIRQ      0x200   /* rx interrupt (both) */
+#define CR_DTIRQ      0x100   /* tx interrupt (both) */
+#define CR_TBEN       0x80    /* tx enable (both) */
+#define CR_NAK        0x40    /* NACK (both) */
+#define CR_STOP       0x20    /* stop (master) */
+#define CR_START      0x10    /* start (master) */
+#define CR_GCEN       0x8     /* general call support (slave) */
+#define CR_SCLEN      0x4     /* enable clock out (master) */
+#define CR_I2CEN      0x2     /* enable I2C (both) */
+#define CR_I2CRST     0x1     /* reset I2C (both) */
+#define CR_ENABLE     \
+	(CR_ALIRQ | CR_NAKRIRQ | CR_DRIRQ | CR_DTIRQ | CR_SCLEN | CR_I2CEN)
+
+/*
+ * status register
+ */
+#define SR_CLRAL      0x400    /* clear arbitration lost */
+#define SR_CLRGC      0x200    /* clear general call */
+#define SR_CLRSAM     0x100    /* clear slave address match */
+#define SR_CLRSTOP    0x80     /* clear stop */
+#define SR_CLRNAKR    0x40     /* clear NACK respond */
+#define SR_DR         0x20     /* rx ready */
+#define SR_DT         0x10     /* tx done */
+#define SR_BB         0x8      /* bus busy */
+#define SR_BUSY       0x4      /* chip busy */
+#define SR_ACK        0x2      /* ACK/NACK received */
+#define SR_RW         0x1      /* set when master-rx or slave-tx mode */
+
+/*
+ * clock division register
+ */
+#define CDR_DIV(n)    ((n) & 0x3ffff)
+
+/*
+ * time & glitch suppression register
+ */
+#define TGSR_GSR(n)   (((n) & 0x7) << 10)
+#define TGSR_TSR(n)   ((n) & 0x3ff)
+
+/*
+ * bus monitor register
+ */
+#define BMR_SCL       0x2      /* SCL is pull-up */
+#define BMR_SDA       0x1      /* SDA is pull-up */
+
+#endif /* __FTI2C010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v4] mmc: update Faraday FTSDC010 for rw performance
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue Kuo-Jung Su
  2013-05-03 22:35           ` Andy Fleming
@ 2013-05-07  6:32           ` Kuo-Jung Su
  1 sibling, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:32 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTSDC010 is a MMC/SD host controller.
Although there is already a driver in current u-boot release,
which is modified from eSHDC and contributed by Andes Tech.
Its performance is too terrible on Faraday A36x SoC platforms,
so I turn to implement this new version of driver which is
10+ times faster than the old one.

It's carefully designed to be compatible with Andes chips,
so it should be safe to replace it.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Andy Fleming <afleming@gmail.com>
---
Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Drop the faraday/mmc.h to remove dependency to
     Faraday A36x patch series.
   - Merge high clock (> 25MHz) setting for SD into ftsdc010_clkset()
   - Use only named constants for bit mask/shift
   - Use macro constants for timeout control

Changes for v3:
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Replace ftsdc010_esdhc.c with this patch.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 drivers/mmc/Makefile         |    2 +-
 drivers/mmc/ftsdc010_esdhc.c |  687 ------------------------------------------
 drivers/mmc/ftsdc010_mci.c   |  377 +++++++++++++++++++++++
 include/faraday/ftsdc010.h   |   31 +-
 4 files changed, 400 insertions(+), 697 deletions(-)
 delete mode 100644 drivers/mmc/ftsdc010_esdhc.c
 create mode 100644 drivers/mmc/ftsdc010_mci.c

diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 1d6faa2..2f07168 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -32,7 +32,7 @@ endif
 COBJS-$(CONFIG_BFIN_SDH) += bfin_sdh.o
 COBJS-$(CONFIG_DAVINCI_MMC) += davinci_mmc.o
 COBJS-$(CONFIG_FSL_ESDHC) += fsl_esdhc.o
-COBJS-$(CONFIG_FTSDC010) += ftsdc010_esdhc.o
+COBJS-$(CONFIG_FTSDC010) += ftsdc010_mci.o
 COBJS-$(CONFIG_GENERIC_MMC) += mmc.o
 COBJS-$(CONFIG_GENERIC_ATMEL_MCI) += gen_atmel_mci.o
 COBJS-$(CONFIG_MMC_SPI) += mmc_spi.o
diff --git a/drivers/mmc/ftsdc010_esdhc.c b/drivers/mmc/ftsdc010_esdhc.c
deleted file mode 100644
index 42f0e0c..0000000
--- a/drivers/mmc/ftsdc010_esdhc.c
+++ /dev/null
@@ -1,687 +0,0 @@
-/*
- * Copyright (C) 2011 Andes Technology Corporation
- * Macpaul Lin, Andes Technology Corporation <macpaul@andestech.com>
- *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * 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
- */
-
-#include <config.h>
-#include <common.h>
-#include <mmc.h>
-
-#include <asm/io.h>
-#include <faraday/ftsdc010.h>
-
-/*
- * supported mmc hosts
- * setting the number CONFIG_FTSDC010_NUMBER in your configuration file.
- */
-static struct mmc ftsdc010_dev[CONFIG_FTSDC010_NUMBER];
-static struct mmc_host ftsdc010_host[CONFIG_FTSDC010_NUMBER];
-
-static struct ftsdc010_mmc *ftsdc010_get_base_mmc(int dev_index)
-{
-	return (struct ftsdc010_mmc *)CONFIG_FTSDC010_BASE + dev_index;
-}
-
-#ifdef DEBUG
-static void ftsdc010_dump_reg(struct mmc_host *host)
-{
-	debug("cmd: %08x\n",		readl(&host->reg->cmd));
-	debug("argu: %08x\n",		readl(&host->reg->argu));
-	debug("rsp0: %08x\n",		readl(&host->reg->rsp0));
-	debug("rsp1: %08x\n",		readl(&host->reg->rsp1));
-	debug("rsp2: %08x\n",		readl(&host->reg->rsp2));
-	debug("rsp3: %08x\n",		readl(&host->reg->rsp3));
-	debug("rsp_cmd: %08x\n",	readl(&host->reg->rsp_cmd));
-	debug("dcr: %08x\n",		readl(&host->reg->dcr));
-	debug("dtr: %08x\n",		readl(&host->reg->dtr));
-	debug("dlr: %08x\n",		readl(&host->reg->dlr));
-	debug("status: %08x\n",		readl(&host->reg->status));
-	debug("clr: %08x\n",		readl(&host->reg->clr));
-	debug("int_mask: %08x\n",	readl(&host->reg->int_mask));
-	debug("pcr: %08x\n",		readl(&host->reg->pcr));
-	debug("ccr: %08x\n",		readl(&host->reg->ccr));
-	debug("bwr: %08x\n",		readl(&host->reg->bwr));
-	debug("dwr: %08x\n",		readl(&host->reg->dwr));
-	debug("feature: %08x\n",	readl(&host->reg->feature));
-	debug("rev: %08x\n",		readl(&host->reg->rev));
-}
-#endif
-
-static unsigned int enable_imask(struct ftsdc010_mmc *reg, unsigned int imask)
-{
-	unsigned int newmask;
-
-	newmask = readl(&reg->int_mask);
-	newmask |= imask;
-
-	writel(newmask, &reg->int_mask);
-
-	return newmask;
-}
-
-static void ftsdc010_pio_read(struct mmc_host *host, char *buf, unsigned int size)
-{
-	unsigned int fifo;
-	unsigned int fifo_words;
-	unsigned int *ptr;
-	unsigned int status;
-	unsigned int retry = 0;
-
-	/* get_data_buffer */
-	ptr = (unsigned int *)buf;
-
-	while (size) {
-		status = readl(&host->reg->status);
-		debug("%s: size: %08x\n", __func__, size);
-
-		if (status & FTSDC010_STATUS_FIFO_ORUN) {
-
-			debug("%s: FIFO OVERRUN: sta: %08x\n",
-					__func__, status);
-
-			fifo = host->fifo_len > size ?
-				size : host->fifo_len;
-
-			size -= fifo;
-
-			fifo_words = fifo >> 2;
-
-			while (fifo_words--)
-				*ptr++ = readl(&host->reg->dwr);
-
-			/*
-			 * for adding some delays for SD card to put
-			 * data into FIFO again
-			 */
-			udelay(4*FTSDC010_DELAY_UNIT);
-
-#ifdef CONFIG_FTSDC010_SDIO
-			/* sdio allow non-power-of-2 blksz */
-			if (fifo & 3) {
-				unsigned int n = fifo & 3;
-				unsigned int data = readl(&host->reg->dwr);
-
-				unsigned char *p = (unsigned char *)ptr;
-
-				while (n--) {
-					*p++ = data;
-					data >>= 8;
-				}
-			}
-#endif
-		} else {
-			udelay(1);
-			if (++retry >= FTSDC010_PIO_RETRY) {
-				debug("%s: PIO_RETRY timeout\n", __func__);
-				return;
-			}
-		}
-	}
-}
-
-static void ftsdc010_pio_write(struct mmc_host *host, const char *buf,
-			unsigned int size)
-{
-	unsigned int fifo;
-	unsigned int *ptr;
-	unsigned int status;
-	unsigned int retry = 0;
-
-	/* get data buffer */
-	ptr = (unsigned int *)buf;
-
-	while (size) {
-		status = readl(&host->reg->status);
-
-		if (status & FTSDC010_STATUS_FIFO_URUN) {
-			fifo = host->fifo_len > size ?
-				size : host->fifo_len;
-
-			size -= fifo;
-
-			fifo = (fifo + 3) >> 2;
-
-			while (fifo--) {
-				writel(*ptr, &host->reg->dwr);
-				ptr++;
-			}
-		} else {
-			udelay(1);
-			if (++retry >= FTSDC010_PIO_RETRY) {
-				debug("%s: PIO_RETRY timeout\n", __func__);
-				return;
-			}
-		}
-	}
-}
-
-static int ftsdc010_check_rsp(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int sta, clear;
-
-	sta = readl(&host->reg->status);
-	debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
-	/* check RSP TIMEOUT or FAIL */
-	if (sta & FTSDC010_STATUS_RSP_TIMEOUT) {
-		/* RSP TIMEOUT */
-		debug("%s: RSP timeout: sta: %08x\n", __func__, sta);
-
-		clear |= FTSDC010_CLR_RSP_TIMEOUT;
-		writel(clear, &host->reg->clr);
-
-		return TIMEOUT;
-	} else if (sta & FTSDC010_STATUS_RSP_CRC_FAIL) {
-		/* clear response fail bit */
-		debug("%s: RSP CRC FAIL: sta: %08x\n", __func__, sta);
-
-		clear |= FTSDC010_CLR_RSP_CRC_FAIL;
-		writel(clear, &host->reg->clr);
-
-		return COMM_ERR;
-	} else if (sta & FTSDC010_STATUS_RSP_CRC_OK) {
-
-		/* clear response CRC OK bit */
-		clear |= FTSDC010_CLR_RSP_CRC_OK;
-	}
-
-	writel(clear, &host->reg->clr);
-	return 0;
-}
-
-static int ftsdc010_check_data(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int sta, clear;
-
-	sta = readl(&host->reg->status);
-	debug("%s: sta: %08x cmd %d\n", __func__, sta, cmd->cmdidx);
-
-	/* check DATA TIMEOUT or FAIL */
-	if (data) {
-
-		/* Transfer Complete */
-		if (sta & FTSDC010_STATUS_DATA_END)
-			clear |= FTSDC010_STATUS_DATA_END;
-
-		/* Data CRC_OK */
-		if (sta & FTSDC010_STATUS_DATA_CRC_OK)
-			clear |= FTSDC010_STATUS_DATA_CRC_OK;
-
-		/* DATA TIMEOUT or DATA CRC FAIL */
-		if (sta & FTSDC010_STATUS_DATA_TIMEOUT) {
-			/* DATA TIMEOUT */
-			debug("%s: DATA TIMEOUT: sta: %08x\n", __func__, sta);
-
-			clear |= FTSDC010_STATUS_DATA_TIMEOUT;
-			writel(clear, &host->reg->clr);
-
-			return TIMEOUT;
-		} else if (sta & FTSDC010_STATUS_DATA_CRC_FAIL) {
-			/* DATA CRC FAIL */
-			debug("%s: DATA CRC FAIL: sta: %08x\n", __func__, sta);
-
-			clear |= FTSDC010_STATUS_DATA_CRC_FAIL;
-			writel(clear, &host->reg->clr);
-
-			return COMM_ERR;
-		}
-		writel(clear, &host->reg->clr);
-	}
-	return 0;
-}
-
-static int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-
-#ifdef CONFIG_FTSDC010_SDIO
-	unsigned int scon;
-#endif
-	unsigned int ccon;
-	unsigned int mask, tmpmask;
-	unsigned int ret;
-	unsigned int sta, i;
-
-	ret = 0;
-
-	if (data)
-		mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
-	else if (cmd->resp_type & MMC_RSP_PRESENT)
-		mask = FTSDC010_INT_MASK_RSP_TIMEOUT;
-	else
-		mask = FTSDC010_INT_MASK_CMD_SEND;
-
-	/* write argu reg */
-	debug("%s: argu: %08x\n", __func__, host->reg->argu);
-	writel(cmd->cmdarg, &host->reg->argu);
-
-	/* setup commnad */
-	ccon = FTSDC010_CMD_IDX(cmd->cmdidx);
-
-	/* setup command flags */
-	ccon |= FTSDC010_CMD_CMD_EN;
-
-	/*
-	 * This hardware didn't support specific commands for mapping
-	 * MMC_RSP_BUSY and MMC_RSP_OPCODE. Hence we don't deal with it.
-	 */
-	if (cmd->resp_type & MMC_RSP_PRESENT) {
-		ccon |= FTSDC010_CMD_NEED_RSP;
-		mask |= FTSDC010_INT_MASK_RSP_CRC_OK |
-			FTSDC010_INT_MASK_RSP_CRC_FAIL;
-	}
-
-	if (cmd->resp_type & MMC_RSP_136)
-		ccon |= FTSDC010_CMD_LONG_RSP;
-
-	/* In Linux driver, MMC_CMD_APP_CMD is checked in last_opcode */
-	if (host->last_opcode == MMC_CMD_APP_CMD)
-		ccon |= FTSDC010_CMD_APP_CMD;
-
-#ifdef CONFIG_FTSDC010_SDIO
-	scon = readl(&host->reg->sdio_ctrl1);
-	if (host->card_type == MMC_TYPE_SDIO)
-		scon |= FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
-	else
-		scon &= ~FTSDC010_SDIO_CTRL1_SDIO_ENABLE;
-	writel(scon, &host->reg->sdio_ctrl1);
-#endif
-
-	/* record last opcode for specifing the command type to hardware */
-	host->last_opcode = cmd->cmdidx;
-
-	/* write int_mask reg */
-	tmpmask = readl(&host->reg->int_mask);
-	tmpmask |= mask;
-	writel(tmpmask, &host->reg->int_mask);
-
-	/* write cmd reg */
-	debug("%s: ccon: %08x\n", __func__, ccon);
-	writel(ccon, &host->reg->cmd);
-
-	/* check CMD_SEND */
-	for (i = 0; i < FTSDC010_CMD_RETRY; i++) {
-		/*
-		 * If we read status register too fast
-		 * will lead hardware error and the RSP_TIMEOUT
-		 * flag will be raised incorrectly.
-		 */
-		udelay(16*FTSDC010_DELAY_UNIT);
-		sta = readl(&host->reg->status);
-
-		/* Command Complete */
-		/*
-		 * Note:
-		 *	Do not clear FTSDC010_CLR_CMD_SEND flag.
-		 *	(by writing FTSDC010_CLR_CMD_SEND bit to clear register)
-		 *	It will make the driver becomes very slow.
-		 *	If the operation hasn't been finished, hardware will
-		 *	clear this bit automatically.
-		 *	In origin, the driver will clear this flag if there is
-		 *	no data need to be read.
-		 */
-		if (sta & FTSDC010_STATUS_CMD_SEND)
-			break;
-	}
-
-	if (i > FTSDC010_CMD_RETRY) {
-		printf("%s: send command timeout\n", __func__);
-		return TIMEOUT;
-	}
-
-	/* check rsp status */
-	ret = ftsdc010_check_rsp(mmc, cmd, data);
-	if (ret)
-		return ret;
-
-	/* read response if we have RSP_OK */
-	if (ccon & FTSDC010_CMD_LONG_RSP) {
-		cmd->response[0] = readl(&host->reg->rsp3);
-		cmd->response[1] = readl(&host->reg->rsp2);
-		cmd->response[2] = readl(&host->reg->rsp1);
-		cmd->response[3] = readl(&host->reg->rsp0);
-	} else {
-		cmd->response[0] = readl(&host->reg->rsp0);
-	}
-
-	/* read/write data */
-	if (data && (data->flags & MMC_DATA_READ)) {
-		ftsdc010_pio_read(host, data->dest,
-				data->blocksize * data->blocks);
-	} else if (data && (data->flags & MMC_DATA_WRITE)) {
-		ftsdc010_pio_write(host, data->src,
-				data->blocksize * data->blocks);
-	}
-
-	/* check data status */
-	if (data) {
-		ret = ftsdc010_check_data(mmc, cmd, data);
-		if (ret)
-			return ret;
-	}
-
-	udelay(FTSDC010_DELAY_UNIT);
-	return ret;
-}
-
-static unsigned int cal_blksz(unsigned int blksz)
-{
-	unsigned int blksztwo = 0;
-
-	while (blksz >>= 1)
-		blksztwo++;
-
-	return blksztwo;
-}
-
-static int ftsdc010_setup_data(struct mmc *mmc, struct mmc_data *data)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int dcon, newmask;
-
-	/* configure data transfer paramter */
-	if (!data)
-		return 0;
-
-	if (((data->blocksize - 1) & data->blocksize) != 0) {
-		printf("%s: can't do non-power-of 2 sized block transfers"
-			" (blksz %d)\n", __func__, data->blocksize);
-		return -1;
-	}
-
-	/*
-	 * We cannot deal with unaligned blocks with more than
-	 * one block being transfered.
-	 */
-	if ((data->blocksize <= 2) && (data->blocks > 1)) {
-			printf("%s: can't do non-word sized block transfers"
-				" (blksz %d)\n", __func__, data->blocksize);
-			return -1;
-	}
-
-	/* data length */
-	dcon = data->blocksize * data->blocks;
-	writel(dcon, &host->reg->dlr);
-
-	/* write data control */
-	dcon = cal_blksz(data->blocksize);
-
-	/* add to IMASK register */
-	newmask = (FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT);
-
-	/*
-	 * enable UNDERRUN will trigger interrupt immediatedly
-	 * So setup it when rsp is received successfully
-	 */
-	if (data->flags & MMC_DATA_WRITE) {
-		dcon |= FTSDC010_DCR_DATA_WRITE;
-	} else {
-		dcon &= ~FTSDC010_DCR_DATA_WRITE;
-		newmask |= FTSDC010_STATUS_FIFO_ORUN;
-	}
-	enable_imask(host->reg, newmask);
-
-#ifdef CONFIG_FTSDC010_SDIO
-	/* always reset fifo since last transfer may fail */
-	dcon |= FTSDC010_DCR_FIFO_RST;
-
-	if (data->blocks > 1)
-		dcon |= FTSDC010_SDIO_CTRL1_SDIO_BLK_MODE;
-#endif
-
-	/* enable data transfer which will be pended until cmd is send */
-	dcon |= FTSDC010_DCR_DATA_EN;
-	writel(dcon, &host->reg->dcr);
-
-	return 0;
-}
-
-static int ftsdc010_send_request(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	int ret;
-
-	if (data) {
-		ret = ftsdc010_setup_data(mmc, data);
-
-		if (ret) {
-			printf("%s: setup data error\n", __func__);
-			return -1;
-		}
-
-		if ((data->flags & MMC_DATA_BOTH_DIR) == MMC_DATA_BOTH_DIR) {
-			printf("%s: data is both direction\n", __func__);
-			return -1;
-		}
-	}
-
-	/* Send command */
-	ret = ftsdc010_send_cmd(mmc, cmd, data);
-	return ret;
-}
-
-static int ftsdc010_card_detect(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int sta;
-
-	sta = readl(&host->reg->status);
-	debug("%s: card status: %08x\n", __func__, sta);
-
-	return (sta & FTSDC010_STATUS_CARD_DETECT) ? 0 : 1;
-}
-
-static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
-			struct mmc_data *data)
-{
-	int ret;
-
-	if (ftsdc010_card_detect(mmc) == 0) {
-		printf("%s: no medium present\n", __func__);
-		return -1;
-	} else {
-		ret = ftsdc010_send_request(mmc, cmd, data);
-		return ret;
-	}
-}
-
-static void ftsdc010_set_clk(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned char clk_div;
-	unsigned int real_rate;
-	unsigned int clock;
-
-	debug("%s: mmc_set_clock: %x\n", __func__, mmc->clock);
-	clock = readl(&host->reg->ccr);
-
-	if (mmc->clock == 0) {
-		real_rate = 0;
-		clock |= FTSDC010_CCR_CLK_DIS;
-	} else {
-		debug("%s, mmc->clock: %08x, origin clock: %08x\n",
-			 __func__, mmc->clock, clock);
-
-		for (clk_div = 0; clk_div <= 127; clk_div++) {
-			real_rate = (CONFIG_SYS_CLK_FREQ / 2) /
-					(2 * (clk_div + 1));
-
-			if (real_rate <= mmc->clock)
-				break;
-		}
-
-		debug("%s: computed real_rate: %x, clk_div: %x\n",
-			 __func__, real_rate, clk_div);
-
-		if (clk_div > 127)
-			debug("%s: no match clock rate, %x\n",
-				__func__, mmc->clock);
-
-		clock = (clock & ~FTSDC010_CCR_CLK_DIV(0x7f)) |
-				FTSDC010_CCR_CLK_DIV(clk_div);
-
-		clock &= ~FTSDC010_CCR_CLK_DIS;
-	}
-
-	debug("%s, set clock: %08x\n", __func__, clock);
-	writel(clock, &host->reg->ccr);
-}
-
-static void ftsdc010_set_ios(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int power;
-	unsigned long val;
-	unsigned int bus_width;
-
-	debug("%s: bus_width: %x, clock: %d\n",
-		__func__, mmc->bus_width, mmc->clock);
-
-	/* set pcr: power on */
-	power = readl(&host->reg->pcr);
-	power |= FTSDC010_PCR_POWER_ON;
-	writel(power, &host->reg->pcr);
-
-	if (mmc->clock)
-		ftsdc010_set_clk(mmc);
-
-	/* set bwr: bus width reg */
-	bus_width = readl(&host->reg->bwr);
-	bus_width &= ~(FTSDC010_BWR_WIDE_8_BUS | FTSDC010_BWR_WIDE_4_BUS |
-			FTSDC010_BWR_SINGLE_BUS);
-
-	if (mmc->bus_width == 8)
-		bus_width |= FTSDC010_BWR_WIDE_8_BUS;
-	else if (mmc->bus_width == 4)
-		bus_width |= FTSDC010_BWR_WIDE_4_BUS;
-	else
-		bus_width |= FTSDC010_BWR_SINGLE_BUS;
-
-	writel(bus_width, &host->reg->bwr);
-
-	/* set fifo depth */
-	val = readl(&host->reg->feature);
-	host->fifo_len = FTSDC010_FEATURE_FIFO_DEPTH(val) * 4; /* 4 bytes */
-
-	/* set data timeout register */
-	val = -1;
-	writel(val, &host->reg->dtr);
-}
-
-static void ftsdc010_reset(struct mmc_host *host)
-{
-	unsigned int timeout;
-	unsigned int sta;
-
-	/* Do SDC_RST: Software reset for all register */
-	writel(FTSDC010_CMD_SDC_RST, &host->reg->cmd);
-
-	host->clock = 0;
-
-	/* this hardware has no reset finish flag to read */
-	/* wait 100ms maximum */
-	timeout = 100;
-
-	/* hw clears the bit when it's done */
-	while (readl(&host->reg->dtr) != 0) {
-		if (timeout == 0) {
-			printf("%s: reset timeout error\n", __func__);
-			return;
-		}
-		timeout--;
-		udelay(10*FTSDC010_DELAY_UNIT);
-	}
-
-	sta = readl(&host->reg->status);
-	if (sta & FTSDC010_STATUS_CARD_CHANGE)
-		writel(FTSDC010_CLR_CARD_CHANGE, &host->reg->clr);
-}
-
-static int ftsdc010_core_init(struct mmc *mmc)
-{
-	struct mmc_host *host = mmc->priv;
-	unsigned int mask;
-	unsigned int major, minor, revision;
-
-	/* get hardware version */
-	host->version = readl(&host->reg->rev);
-
-	major = FTSDC010_REV_MAJOR(host->version);
-	minor = FTSDC010_REV_MINOR(host->version);
-	revision = FTSDC010_REV_REVISION(host->version);
-
-	printf("ftsdc010 hardware ver: %d_%d_r%d\n", major, minor, revision);
-
-	/* Interrupt MASK register init - mask all */
-	writel(0x0, &host->reg->int_mask);
-
-	mask = FTSDC010_INT_MASK_CMD_SEND |
-		FTSDC010_INT_MASK_DATA_END |
-		FTSDC010_INT_MASK_CARD_CHANGE;
-#ifdef CONFIG_FTSDC010_SDIO
-	mask |= FTSDC010_INT_MASK_CP_READY |
-		FTSDC010_INT_MASK_CP_BUF_READY |
-		FTSDC010_INT_MASK_PLAIN_TEXT_READY |
-		FTSDC010_INT_MASK_SDIO_IRPT;
-#endif
-
-	writel(mask, &host->reg->int_mask);
-
-	return 0;
-}
-
-int ftsdc010_mmc_init(int dev_index)
-{
-	struct mmc *mmc;
-	struct mmc_host *host;
-
-	mmc = &ftsdc010_dev[dev_index];
-
-	sprintf(mmc->name, "FTSDC010 SD/MMC");
-	mmc->priv = &ftsdc010_host[dev_index];
-	mmc->send_cmd = ftsdc010_request;
-	mmc->set_ios = ftsdc010_set_ios;
-	mmc->init = ftsdc010_core_init;
-	mmc->getcd = NULL;
-	mmc->getwp = NULL;
-
-	mmc->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
-
-	mmc->host_caps = MMC_MODE_4BIT | MMC_MODE_8BIT;
-
-	mmc->f_min = CONFIG_SYS_CLK_FREQ / 2 / (2*128);
-	mmc->f_max = CONFIG_SYS_CLK_FREQ / 2 / 2;
-
-	ftsdc010_host[dev_index].clock = 0;
-	ftsdc010_host[dev_index].reg = ftsdc010_get_base_mmc(dev_index);
-	mmc_register(mmc);
-
-	/* reset mmc */
-	host = (struct mmc_host *)mmc->priv;
-	ftsdc010_reset(host);
-
-	return 0;
-}
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
new file mode 100644
index 0000000..562b14a
--- /dev/null
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -0,0 +1,377 @@
+/*
+ * Faraday MMC/SD Host Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <part.h>
+#include <mmc.h>
+
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <asm/byteorder.h>
+#include <faraday/ftsdc010.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
+#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+
+struct ftsdc010_chip {
+	void __iomem *regs;
+	uint32_t wprot;   /* write protected (locked) */
+	uint32_t rate;    /* actual SD clock in Hz */
+	uint32_t sclk;    /* FTSDC010 source clock in Hz */
+	uint32_t fifo;    /* fifo depth in bytes */
+	uint32_t acmd;
+};
+
+static inline int ftsdc010_send_cmd(struct mmc *mmc, struct mmc_cmd *mmc_cmd)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	int ret = TIMEOUT;
+	uint32_t ts, st;
+	uint32_t cmd   = FTSDC010_CMD_IDX(mmc_cmd->cmdidx);
+	uint32_t arg   = mmc_cmd->cmdarg;
+	uint32_t flags = mmc_cmd->resp_type;
+
+	cmd |= FTSDC010_CMD_CMD_EN;
+
+	if (chip->acmd) {
+		cmd |= FTSDC010_CMD_APP_CMD;
+		chip->acmd = 0;
+	}
+
+	if (flags & MMC_RSP_PRESENT)
+		cmd |= FTSDC010_CMD_NEED_RSP;
+
+	if (flags & MMC_RSP_136)
+		cmd |= FTSDC010_CMD_LONG_RSP;
+
+	writel(FTSDC010_STATUS_RSP_MASK | FTSDC010_STATUS_CMD_SEND,
+		&regs->clr);
+	writel(arg, &regs->argu);
+	writel(cmd, &regs->cmd);
+
+	if (!(flags & (MMC_RSP_PRESENT | MMC_RSP_136))) {
+		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+			if (readl(&regs->status) & FTSDC010_STATUS_CMD_SEND) {
+				writel(FTSDC010_STATUS_CMD_SEND, &regs->clr);
+				ret = 0;
+				break;
+			}
+		}
+	} else {
+		st = 0;
+		for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+			st = readl(&regs->status);
+			writel(st & FTSDC010_STATUS_RSP_MASK, &regs->clr);
+			if (st & FTSDC010_STATUS_RSP_MASK)
+				break;
+		}
+		if (st & FTSDC010_STATUS_RSP_CRC_OK) {
+			if (flags & MMC_RSP_136) {
+				mmc_cmd->response[0] = readl(&regs->rsp3);
+				mmc_cmd->response[1] = readl(&regs->rsp2);
+				mmc_cmd->response[2] = readl(&regs->rsp1);
+				mmc_cmd->response[3] = readl(&regs->rsp0);
+			} else {
+				mmc_cmd->response[0] = readl(&regs->rsp0);
+			}
+			ret = 0;
+		} else {
+			debug("ftsdc010: rsp err (cmd=%d, st=0x%x)\n",
+				mmc_cmd->cmdidx, st);
+		}
+	}
+
+	if (ret) {
+		debug("ftsdc010: cmd timeout (op code=%d)\n",
+			mmc_cmd->cmdidx);
+	} else if (mmc_cmd->cmdidx == MMC_CMD_APP_CMD) {
+		chip->acmd = 1;
+	}
+
+	return ret;
+}
+
+static void ftsdc010_clkset(struct mmc *mmc, uint32_t rate)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	uint32_t div;
+
+	for (div = 0; div < 0x7f; ++div) {
+		if (rate >= chip->sclk / (2 * (div + 1)))
+			break;
+	}
+	chip->rate = chip->sclk / (2 * (div + 1));
+
+	writel(FTSDC010_CCR_CLK_DIV(div), &regs->ccr);
+
+	if (IS_SD(mmc)) {
+		setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_SD);
+
+		if (chip->rate > 25000000)
+			setbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+		else
+			clrbits_le32(&regs->ccr, FTSDC010_CCR_CLK_HISPD);
+	}
+}
+
+static inline int ftsdc010_is_ro(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	const uint8_t *csd = (const uint8_t *)mmc->csd;
+
+	return chip->wprot || (csd[1] & 0x30);
+}
+
+static int ftsdc010_wait(struct ftsdc010_mmc __iomem *regs, uint32_t mask)
+{
+	int ret = TIMEOUT;
+	uint32_t st, ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		st = readl(&regs->status);
+		if (!(st & mask))
+			continue;
+		writel(st & mask, &regs->clr);
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		debug("ftsdc010: wait st(0x%x) timeout\n", mask);
+
+	return ret;
+}
+
+/*
+ * u-boot mmc api
+ */
+
+static int ftsdc010_request(struct mmc *mmc, struct mmc_cmd *cmd,
+	struct mmc_data *data)
+{
+	int ret = UNUSABLE_ERR;
+	uint32_t len = 0;
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+	if (data && (data->flags & MMC_DATA_WRITE) && chip->wprot) {
+		printf("ftsdc010: the card is write protected!\n");
+		return ret;
+	}
+
+	if (data) {
+		uint32_t dcr;
+
+		len = data->blocksize * data->blocks;
+
+		/* 1. data disable + fifo reset */
+		writel(FTSDC010_DCR_FIFO_RST, &regs->dcr);
+
+		/* 2. clear status register */
+		writel(FTSDC010_STATUS_DATA_MASK | FTSDC010_STATUS_FIFO_URUN
+			| FTSDC010_STATUS_FIFO_ORUN, &regs->clr);
+
+		/* 3. data timeout (1 sec) */
+		writel(chip->rate, &regs->dtr);
+
+		/* 4. data length (bytes) */
+		writel(len, &regs->dlr);
+
+		/* 5. data enable */
+		dcr = (ffs(data->blocksize) - 1) | FTSDC010_DCR_DATA_EN;
+		if (data->flags & MMC_DATA_WRITE)
+			dcr |= FTSDC010_DCR_DATA_WRITE;
+		writel(dcr, &regs->dcr);
+	}
+
+	ret = ftsdc010_send_cmd(mmc, cmd);
+	if (ret) {
+		printf("ftsdc010: CMD%d failed\n", cmd->cmdidx);
+		return ret;
+	}
+
+	if (!data)
+		return ret;
+
+	if (data->flags & MMC_DATA_WRITE) {
+		const uint8_t *buf = (const uint8_t *)data->src;
+
+		while (len > 0) {
+			int wlen;
+
+			/* wait for tx ready */
+			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_URUN);
+			if (ret)
+				break;
+
+			/* write bytes to ftsdc010 */
+			for (wlen = 0; wlen < len && wlen < chip->fifo; ) {
+				writel(*(uint32_t *)buf, &regs->dwr);
+				buf  += 4;
+				wlen += 4;
+			}
+
+			len -= wlen;
+		}
+
+	} else {
+		uint8_t *buf = (uint8_t *)data->dest;
+
+		while (len > 0) {
+			int rlen;
+
+			/* wait for rx ready */
+			ret = ftsdc010_wait(regs, FTSDC010_STATUS_FIFO_ORUN);
+			if (ret)
+				break;
+
+			/* fetch bytes from ftsdc010 */
+			for (rlen = 0; rlen < len && rlen < chip->fifo; ) {
+				*(uint32_t *)buf = readl(&regs->dwr);
+				buf  += 4;
+				rlen += 4;
+			}
+
+			len -= rlen;
+		}
+
+	}
+
+	if (!ret) {
+		ret = ftsdc010_wait(regs,
+			FTSDC010_STATUS_DATA_END | FTSDC010_STATUS_DATA_ERROR);
+	}
+
+	return ret;
+}
+
+static void ftsdc010_set_ios(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+
+	ftsdc010_clkset(mmc, mmc->clock);
+
+	clrbits_le32(&regs->bwr, FTSDC010_BWR_MODE_MASK);
+	switch (mmc->bus_width) {
+	case 4:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_4BIT);
+		break;
+	case 8:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_8BIT);
+		break;
+	default:
+		setbits_le32(&regs->bwr, FTSDC010_BWR_MODE_1BIT);
+		break;
+	}
+}
+
+static int ftsdc010_init(struct mmc *mmc)
+{
+	struct ftsdc010_chip *chip = mmc->priv;
+	struct ftsdc010_mmc __iomem *regs = chip->regs;
+	uint32_t ts;
+
+	if (readl(&regs->status) & FTSDC010_STATUS_CARD_DETECT)
+		return NO_CARD_ERR;
+
+	if (readl(&regs->status) & FTSDC010_STATUS_WRITE_PROT) {
+		printf("ftsdc010: write protected\n");
+		chip->wprot = 1;
+	}
+
+	chip->fifo = (readl(&regs->feature) & 0xff) << 2;
+
+	/* 1. chip reset */
+	writel(FTSDC010_CMD_SDC_RST, &regs->cmd);
+	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+		if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST)
+			continue;
+		break;
+	}
+	if (readl(&regs->cmd) & FTSDC010_CMD_SDC_RST) {
+		printf("ftsdc010: reset failed\n");
+		return UNUSABLE_ERR;
+	}
+
+	/* 2. enter low speed mode (400k card detection) */
+	ftsdc010_clkset(mmc, 400000);
+
+	/* 3. interrupt disabled */
+	writel(0, &regs->int_mask);
+
+	return 0;
+}
+
+int ftsdc010_mmc_init(int devid)
+{
+	struct mmc *mmc;
+	struct ftsdc010_chip *chip;
+	struct ftsdc010_mmc __iomem *regs;
+#ifdef CONFIG_FTSDC010_BASE_LIST
+	uint32_t base_list[] = CONFIG_FTSDC010_BASE_LIST;
+
+	if (devid < 0 || devid >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[devid];
+#else
+	regs = (void __iomem *)(CONFIG_FTSDC010_BASE + (devid << 20));
+#endif
+
+	mmc = malloc(sizeof(struct mmc));
+	if (!mmc)
+		return -ENOMEM;
+	memset(mmc, 0, sizeof(struct mmc));
+
+	chip = malloc(sizeof(struct ftsdc010_chip));
+	if (!chip) {
+		free(mmc);
+		return -ENOMEM;
+	}
+	memset(chip, 0, sizeof(struct ftsdc010_chip));
+
+	chip->regs = regs;
+	mmc->priv  = chip;
+
+	sprintf(mmc->name, "ftsdc010");
+	mmc->send_cmd  = ftsdc010_request;
+	mmc->set_ios   = ftsdc010_set_ios;
+	mmc->init      = ftsdc010_init;
+
+	mmc->host_caps = MMC_MODE_HS | MMC_MODE_HS_52MHz;
+	switch (readl(&regs->bwr) & FTSDC010_BWR_CAPS_MASK) {
+	case FTSDC010_BWR_CAPS_4BIT:
+		mmc->host_caps |= MMC_MODE_4BIT;
+		break;
+	case FTSDC010_BWR_CAPS_8BIT:
+		mmc->host_caps |= MMC_MODE_4BIT | MMC_MODE_8BIT;
+		break;
+	default:
+		break;
+	}
+
+#ifdef CONFIG_SYS_CLK_FREQ
+	chip->sclk = CONFIG_SYS_CLK_FREQ;
+#else
+	chip->sclk = clk_get_rate("SDC");
+#endif
+
+	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
+	mmc->f_max     = chip->sclk / 2;
+	mmc->f_min     = chip->sclk / 0x100;
+	mmc->block_dev.part_type = PART_TYPE_DOS;
+
+	mmc_register(mmc);
+
+	return 0;
+}
diff --git a/include/faraday/ftsdc010.h b/include/faraday/ftsdc010.h
index c34dde7..8284f53 100644
--- a/include/faraday/ftsdc010.h
+++ b/include/faraday/ftsdc010.h
@@ -23,6 +23,7 @@
 #define __FTSDC010_H

 #ifndef __ASSEMBLY__
+
 /* sd controller register */
 struct ftsdc010_mmc {
 	unsigned int	cmd;		/* 0x00 - command reg		*/
@@ -143,6 +144,15 @@ int ftsdc010_mmc_init(int dev_index);
 #define FTSDC010_STATUS_SDIO_IRPT		(1 << 16) /* SDIO card intr */
 #define FTSDC010_STATUS_DATA0_STATUS		(1 << 17)
 #endif /* CONFIG_FTSDC010_SDIO */
+#define FTSDC010_STATUS_RSP_ERROR	\
+	(FTSDC010_STATUS_RSP_CRC_FAIL | FTSDC010_STATUS_RSP_TIMEOUT)
+#define FTSDC010_STATUS_RSP_MASK	\
+	(FTSDC010_STATUS_RSP_ERROR | FTSDC010_STATUS_RSP_CRC_OK)
+#define FTSDC010_STATUS_DATA_ERROR	\
+	(FTSDC010_STATUS_DATA_CRC_FAIL | FTSDC010_STATUS_DATA_TIMEOUT)
+#define FTSDC010_STATUS_DATA_MASK	\
+	(FTSDC010_STATUS_DATA_ERROR | FTSDC010_STATUS_DATA_CRC_OK \
+	| FTSDC010_STATUS_DATA_END)

 /* 0x2c - clear register */
 #define FTSDC010_CLR_RSP_CRC_FAIL		(1 << 0)
@@ -192,21 +202,24 @@ int ftsdc010_mmc_init(int dev_index);
 #define FTSDC010_CCR_CLK_DIV(x)			(((x) & 0x7f) << 0)
 #define FTSDC010_CCR_CLK_SD			(1 << 7) /* 0: MMC, 1: SD */
 #define FTSDC010_CCR_CLK_DIS			(1 << 8)
+#define FTSDC010_CCR_CLK_HISPD			(1 << 9) /* high speed */

 /* card type */
 #define FTSDC010_CARD_TYPE_SD			FTSDC010_CLOCK_REG_CARD_TYPE
 #define FTSDC010_CARD_TYPE_MMC			0x0

 /* 0x3c - bus width register */
-#define FTSDC010_BWR_SINGLE_BUS			(1 << 0)
-#define FTSDC010_BWR_WIDE_8_BUS			(1 << 1)
-#define FTSDC010_BWR_WIDE_4_BUS			(1 << 2)
-#define FTSDC010_BWR_WIDE_BUS_SUPPORT(x)	(((x) >> 3) & 0x3)
-#define FTSDC010_BWR_CARD_DETECT		(1 << 5)
-
-#define FTSDC010_BWR_1_BUS_SUPPORT		0x0
-#define FTSDC010_BWR_4_BUS_SUPPORT		0x1
-#define FTSDC010_BWR_8_BUS_SUPPORT		0x2
+#define FTSDC010_BWR_MODE_1BIT      (1 << 0) /* 1 bit mode enabled */
+#define FTSDC010_BWR_MODE_8BIT      (1 << 1) /* 8 bit mode enabled */
+#define FTSDC010_BWR_MODE_4BIT      (1 << 2) /* 4 bit mode enabled */
+#define FTSDC010_BWR_MODE_MASK      (7 << 0)
+#define FTSDC010_BWR_MODE_SHIFT     (0)
+#define FTSDC010_BWR_CAPS_1BIT      (0 << 3) /* 1 bits mode supported */
+#define FTSDC010_BWR_CAPS_4BIT      (1 << 3) /* 1,4 bits mode supported */
+#define FTSDC010_BWR_CAPS_8BIT      (2 << 3) /* 1,4,8 bits mode supported */
+#define FTSDC010_BWR_CAPS_MASK      (3 << 3)
+#define FTSDC010_BWR_CAPS_SHIFT     (3)
+#define FTSDC010_BWR_CARD_DETECT    (1 << 5)

 /* 0x44 or 0x9c - feature register */
 #define FTSDC010_FEATURE_FIFO_DEPTH(x)		(((x) >> 0) & 0xff)
--
1.7.9.5

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

* [U-Boot] [PATCH v4] nand: add Faraday FTNANDC021 NAND controller support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
  2013-04-26 23:41           ` Scott Wood
@ 2013-05-07  6:33           ` Kuo-Jung Su
  2013-05-09  0:43             ` Scott Wood
  2013-05-09  1:51             ` [U-Boot] [PATCH v5] " Kuo-Jung Su
  1 sibling, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:33 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is a integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Drop the faraday/nand.h to remove dependency to
     Faraday A36x patch series.
   - CONFIG_SYS_NAND_TIMING -> CONFIG_SYS_FTNANDC021_TIMING
   - Remove non-ECC code.
   - Implement private hwecc read/write_page functions
     to get rid of .eccpos & .eccbytes.
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Re-write this driver with ECC enabled and correct column address
     handling for OOB read/write,
   - Fix issuses addressed by Scott.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 README                        |    4 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  607 +++++++++++++++++++++++++++++++++++++++++
 include/faraday/ftnandc021.h  |  146 ++++++++++
 4 files changed, 758 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 include/faraday/ftnandc021.h

diff --git a/README b/README
index 0d37d56..883182d 100644
--- a/README
+++ b/README
@@ -3879,6 +3879,10 @@ Low Level (hardware related) configuration options:
 		- drivers/mtd/nand/ndfc.c
 		- drivers/mtd/nand/mxc_nand.c

+- CONFIG_SYS_FTNANDC021_TIMING
+		Defined to tell the FTNANDC021 controller that the NAND chip is
+		using customized timing parameters.
+
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
 		a default value will be used.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 35769c5..f6f89f0 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -63,6 +63,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..5cb8941
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,607 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <nand.h>
+#include <malloc.h>
+
+#include <faraday/ftnandc021.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
+
+struct ftnandc021_chip {
+	void __iomem *regs;
+	int alen;
+	int pgsz;
+	int bksz;
+
+	int col;    /* current column address */
+	int page;   /* current row address/page index */
+	int cmd;    /* current NAND command code */
+	int cmd_hc; /* current FTNANDC021 command code */
+};
+
+static struct nand_ecclayout ftnandc021_ecclayout[] = {
+	{ /* page size = 512 (oob size = 16) */
+		.oobfree = {
+			{ 9, 3 },
+		}
+	},
+	{ /* page size = 2048 (oob size = 64) */
+		.oobfree = {
+			{ 9, 3 },
+		},
+	},
+	{ /* page size = 4096 (oob size = 128) */
+		.oobfree = {
+			{ 9, 7 },
+		},
+	},
+};
+
+static inline int ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t st = readl(&regs->idr[1]);
+
+	if (st & NAND_STATUS_FAIL)
+		return -EIO;
+
+	if (!(st & NAND_STATUS_READY))
+		return -EBUSY;
+
+	if (!(st & NAND_STATUS_WP))
+		return -EIO;
+
+	return 0;
+}
+
+static inline int ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	char rc = 'c';
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			rc = 'e';
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	switch (rc) {
+	case 'e':
+		printf("ftnandc021: ecc timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	case 'c':
+		printf("ftnandc021: cmd timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	default:
+		break;
+	}
+
+	return rc ? -ETIMEDOUT : 0;
+}
+
+static int ftnandc021_read_page(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	/*
+	 * OOB has been read at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it here.
+	 */
+	chip->read_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static void ftnandc021_write_page(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	/*
+	 * OOB has been written at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it here.
+	 */
+	chip->write_buf(mtd, buf, mtd->writesize);
+}
+
+static int ftnandc021_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	printf("ftnandc021: read_page_raw is not supported\n");
+	return -EIO;
+}
+
+static void ftnandc021_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	printf("ftnandc021: write_page_raw is not supported\n");
+}
+
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = 0;
+
+	priv->cmd_hc = cmd;
+
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : (We have queued data at the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+	case FTNANDC021_CMD_WRPG:
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+static int ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t ts, bk, pg, ac, mask;
+#ifdef CONFIG_SYS_FTNANDC021_TIMING
+	uint32_t timing[] = CONFIG_SYS_FTNANDC021_TIMING;
+
+	writel(timing[0], &regs->atr[0]);
+	writel(timing[1], &regs->atr[1]);
+#endif
+
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	mask = SRR_CHIP_RESET | SRR_ECC_EN;
+	writel(mask, &regs->srr);
+	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+		if (readl(&regs->srr) & SRR_CHIP_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->srr) & SRR_CHIP_RESET) {
+		printf("ftnandc021: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* sanity check on page size */
+	if (priv->pgsz != 512 && priv->pgsz != 2048 && priv->pgsz != 4096) {
+		printf("ftnandc021: invalid page size=%d\n", priv->pgsz);
+		return -EINVAL;
+	}
+
+	bk = ffs(priv->bksz / priv->pgsz) - 5;
+	pg = (priv->pgsz < 2048) ? 0 : (ffs(priv->pgsz) - 11);
+	ac = priv->alen - 3;
+
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* IO mode = PIO */
+	writel(0, &regs->bcr);
+
+	/* ECC mode */
+	chip->ecc.layout         = ftnandc021_ecclayout + pg;
+	chip->ecc.size           = priv->pgsz;
+	chip->ecc.steps          = 1;
+	chip->ecc.read_page      = ftnandc021_read_page;
+	chip->ecc.write_page     = ftnandc021_write_page;
+	chip->ecc.read_page_raw  = ftnandc021_read_page_raw;
+	chip->ecc.write_page_raw = ftnandc021_write_page_raw;
+	chip->ecc.mode           = NAND_ECC_HW;
+
+	/* reset the attached flash */
+	if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+		return -ENXIO;
+
+	return 0;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv))
+		ret = 0;
+	else if (!(readl(&regs->sr) & SR_READY))
+		ret = 0;
+
+	return ret;
+}
+
+static int ftnandc021_pio_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = -ETIMEDOUT;
+	uint32_t ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
+		if (!(readl(&regs->ior) & IOR_READY))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftnandc021: pio timeout\n");
+
+	return ret;
+}
+
+static void ftnandc021_read_oob(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t tmp;
+
+	memset(buf, 0xff, len);
+
+	/* bad block */
+	buf[chip->badblockpos] = readl(&regs->bbird) & 0xff;
+
+	/* data */
+	tmp = readl(&regs->crcrd);
+	buf[8] = (tmp >> 0) & 0xff;
+	buf[9] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >=  4096) {
+		buf[12] = (tmp >> 16) & 0xff;
+		buf[13] = (tmp >> 24) & 0xff;
+	}
+
+	tmp = readl(&regs->lsnrd);
+	buf[10] = (tmp >> 0) & 0xff;
+	buf[11] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[14] = (tmp >> 16) & 0xff;
+		buf[15] = (tmp >> 24) & 0xff;
+	}
+}
+
+static void ftnandc021_write_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t tmp;
+
+	/* bad block */
+	tmp = buf[chip->badblockpos];
+	writel(tmp, &regs->bbiwr);
+
+	/* mark it as 'not blank' */
+	tmp = 'W' | (buf[9] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	writel(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	writel(tmp, &regs->lsnwr);
+}
+
+static uint8_t ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+		if (priv->col < 8) {
+			uint32_t idx = priv->col >> 2;
+			uint32_t pos = priv->col & 0x3;
+			uint32_t tmp = readl(&regs->idr[idx]);
+
+			ret = (uint8_t)(tmp >> (pos << 3));
+			priv->col += 1;
+		}
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint8_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: unknown cmd=0x%x in read_byte\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t ret = 0xffff;
+	uint8_t *buf = (uint8_t *)&ret;
+
+	/* LSB format */
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return ret;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void ftnandc021_read_buf(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int off;
+
+	if (priv->col >= mtd->writesize)
+		return;
+
+	if (priv->cmd == NAND_CMD_READOOB)
+		BUG();	/* should never happen */
+
+	/* skip if it's a blank page */
+	if (chip->oob_poi[8] != 'W') {
+		memset(buf, 0xff, len);
+		return;
+	}
+
+	off = 0;
+	while (off < len && priv->col < mtd->writesize) {
+		ftnandc021_pio_wait(priv);
+		*(uint32_t *)(buf + off) = readl(&regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void ftnandc021_write_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int off;
+
+	/*
+	 * FTNANDC021 HW design issues:
+	 *
+	 * 1. OOB data must be set before issuing write command,
+	 *    so it's too late to do it right here
+	 * 2. Only after command issued, the data register
+	 *    could accept data.
+	 */
+	if (priv->col >= mtd->writesize)
+		return;
+
+	for (off = 0; off < len && priv->col < mtd->writesize; ) {
+		ftnandc021_pio_wait(priv);
+		writel(*(uint32_t *)(buf + off), &regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int ftnandc021_verify_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	int ret = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021: out of memory\n");
+		return -ENOMEM;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			ret = -EINVAL;
+	}
+
+	free(tmp);
+	return ret;
+}
+
+static void ftnandc021_cmdfunc(struct mtd_info *mtd,
+	unsigned cmd, int col, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+
+	priv->cmd = cmd;
+	priv->col = col;
+	priv->page = page;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		priv->col = 0;
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID))
+			printf("ftnandc021: RDID failed.\n");
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		priv->col = mtd->writesize;
+		/* fall-through */
+	case NAND_CMD_READ0:	/* 0x00 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* fetch oob to check if it's a blank page */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+			break;
+		}
+		ftnandc021_read_oob(mtd, chip->oob_poi, mtd->oobsize);
+		/* skip if we don't need page data */
+		if (priv->col >= mtd->writesize)
+			break;
+		/* skip if it's a blank page */
+		if (chip->oob_poi[8] != 'W') {
+			debug("ftnandc021: skip page %d\n", page);
+			break;
+		}
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG))
+			printf("ftnandc021: RDPG failed.\n");
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK))
+			printf("ftnandc021: ERBLK failed\n");
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDST))
+			printf("ftnandc021: RDST failed\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* OOB data must be set before issuing command */
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->oobsize);
+		priv->cmd_hc = (priv->col >= mtd->writesize)
+			? FTNANDC021_CMD_WROOB : FTNANDC021_CMD_WRPG;
+		if (ftnandc021_command(priv, priv->cmd_hc))
+			printf("ftnandc021: CMD_HC=%d failed\n", priv->cmd_hc);
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		/* nothing needs to be done */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+			printf("ftnandc021: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021: unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void ftnandc021_hwcontrol(struct mtd_info *mtd,
+	int cmd, unsigned int ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen)
+{
+	struct ftnandc021_chip *priv;
+
+	priv = calloc(1, sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regs = (void __iomem *)iobase;
+	priv->pgsz = 1 << chip->page_shift;
+	priv->bksz = 1 << chip->phys_erase_shift;
+	priv->alen = alen;
+
+	chip->priv = priv;
+
+	debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n",
+		   priv->pgsz, priv->bksz, priv->alen);
+
+	/* hardware reset */
+	if (ftnandc021_reset(chip))
+		return -EINVAL;
+
+	/* hwcontrol always must be implemented */
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	return 0;
+}
diff --git a/include/faraday/ftnandc021.h b/include/faraday/ftnandc021.h
new file mode 100644
index 0000000..c70e91e
--- /dev/null
+++ b/include/faraday/ftnandc021.h
@@ -0,0 +1,146 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTNANDC021_H
+#define __FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+	/* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4];/* ECC Parity Register */
+	uint32_t ecc_sr;   /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+	/* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsn;	 /* LSN Initialize */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+	/* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+	/* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* ECC Status Register */
+#define ECC_SR_CERR      (1 << 3)  /* correction error */
+#define ECC_SR_ERR       (1 << 2)  /* ecc error */
+#define ECC_SR_DEC       (1 << 1)  /* ecc decode finished */
+#define ECC_SR_ENC       (1 << 0)  /* ecc encode finished */
+
+/* Status Register */
+#define SR_BLANK         (1 << 7)  /* blanking check failed */
+#define SR_ECC           (1 << 6)  /* ecc timeout */
+#define SR_STS           (1 << 4)  /* status error */
+#define SR_CRC           (1 << 3)  /* crc error */
+#define SR_CMD           (1 << 2)  /* command finished */
+#define SR_READY         (1 << 1)  /* chip ready/busy */
+#define SR_ENA           (1 << 0)  /* chip enabled */
+
+/* Access Control Register */
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        (1 << 7)  /* command start */
+
+/* Flow Control Register */
+#define FCR_SWCRC        (1 << 8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       (1 << 7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        (1 << 4)  /* 16 bit data bus */
+#define FCR_WPROT        (1 << 3)  /* write protected */
+#define FCR_NOSC         (1 << 2)  /* bypass status check error */
+#define FCR_MICRON       (1 << 1)  /* Micron 2-plane command */
+#define FCR_NOBC         (1 << 0)  /* skip blanking check error */
+
+/* Interrupt Enable Register */
+#define IER_ENA          (1 << 7)  /* interrupt enabled */
+#define IER_ECC          (1 << 3)  /* ecc error timeout */
+#define IER_STS          (1 << 2)  /* status error */
+#define IER_CRC          (1 << 1)  /* crc error */
+#define IER_CMD          (1 << 0)  /* command finished */
+
+/* BMC PIO Status Register */
+#define IOR_READY        (1 << 0)  /* PIO ready */
+
+/* MLC Software Reset Register */
+#define SRR_ECC_EN       (1 << 8)  /* ECC enabled */
+#define SRR_NANDC_RESET  (1 << 2)  /* NANDC reset */
+#define SRR_BMC_RESET    (1 << 1)  /* BMC reset */
+#define SRR_ECC_RESET    (1 << 0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+/* Memory Configuration Register */
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* FTNANDC021 built-in command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02   /* reset flash */
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen);
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v4] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
  2013-05-02 16:03           ` Tom Rini
@ 2013-05-07  6:33           ` Kuo-Jung Su
  2013-07-08 16:19             ` Joe Hershberger
  1 sibling, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:33 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTMAC110 10/100Mbps supports half-word data transfer for Linux.
However it has a weird DMA alignment issue:

(1) Tx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: O.K

(2) Rx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: Invalid!!!

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Joe Hershberger <joe.hershberger@gmail.com>
CC: Tom Rini <trini@ti.com>
---
Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Use macro constants for timeout control
   - Use only named constants for bit mask/shift and values
   - Drop the magic number from mdio read/write.

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Make a correction to multi-line comment style
   - Use random MAC address while having trouble
     to get one from environment variables.
   - Add comments to timing control registers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - ftmac110: Remove debug codes.

 drivers/net/Makefile   |    1 +
 drivers/net/ftmac110.c |  473 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ftmac110.h |  177 ++++++++++++++++++
 include/netdev.h       |    1 +
 4 files changed, 652 insertions(+)
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 786a656..0e23817 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
 COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
+COBJS-$(CONFIG_FTMAC110) += ftmac110.o
 COBJS-$(CONFIG_FTMAC100) += ftmac100.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
new file mode 100644
index 0000000..35f8633
--- /dev/null
+++ b/drivers/net/ftmac110.c
@@ -0,0 +1,473 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#define CFG_RXDES_NUM   8
+#define CFG_TXDES_NUM   2
+#define CFG_XBUF_SIZE   1536
+
+#define CFG_MDIORD_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_MDIOWR_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_LINKUP_TIMEOUT  (CONFIG_SYS_HZ << 2) /* 4 sec */
+
+/*
+ * FTMAC110 DMA design issue
+ *
+ * Its DMA engine has a weird restriction that its Rx DMA engine
+ * accepts only 16-bits aligned address, 32-bits aligned is not
+ * acceptable. However this restriction does not apply to Tx DMA.
+ *
+ * Conclusion:
+ * (1) Tx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
+ * (2) Rx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: Invalid
+ */
+
+struct ftmac110_chip {
+	void __iomem *regs;
+	uint32_t imr;
+	uint32_t maccr;
+	uint32_t lnkup;
+	uint32_t phy_addr;
+
+	struct ftmac110_rxd *rxd;
+	ulong                rxd_dma;
+	uint32_t             rxd_idx;
+
+	struct ftmac110_txd *txd;
+	ulong                txd_dma;
+	uint32_t             txd_idx;
+};
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint16_t ret = 0xffff;
+
+	tmp = PHYCR_READ
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT);
+
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
+		tmp = readl(&regs->phycr);
+		if (tmp & PHYCR_READ)
+			continue;
+		break;
+	}
+
+	if (tmp & PHYCR_READ)
+		printf("ftmac110: mdio read timeout\n");
+	else
+		ret = (uint16_t)(tmp & 0xffff);
+
+	return ret;
+}
+
+static void mdio_write(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	uint32_t tmp, ts;
+
+	tmp = PHYCR_WRITE
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT);
+
+	writel(phydata, &regs->phydr);
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
+		if (readl(&regs->phycr) & PHYCR_WRITE)
+			continue;
+		break;
+	}
+
+	if (readl(&regs->phycr) & PHYCR_WRITE)
+		printf("ftmac110: mdio write timeout\n");
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+	ulong ts;
+	uint32_t maccr;
+	uint16_t pa, tmp, bmsr, bmcr;
+	struct ftmac110_chip *chip = dev->priv;
+
+	/* Default = 100Mbps Full */
+	maccr = MACCR_100M | MACCR_FD;
+
+	/* 1. find the phy device  */
+	for (pa = 0; pa < 32; ++pa) {
+		tmp = mdio_read(dev, pa, MII_PHYSID1);
+		if (tmp == 0xFFFF || tmp == 0x0000)
+			continue;
+		chip->phy_addr = pa;
+		break;
+	}
+	if (pa >= 32) {
+		puts("ftmac110: phy device not found!\n");
+		goto exit;
+	}
+
+	/* 2. wait until link-up & auto-negotiation complete */
+	chip->lnkup = 0;
+	bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR);
+	ts = get_timer(0);
+	do {
+		bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR);
+		chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0;
+		if (!chip->lnkup)
+			continue;
+		if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE))
+			break;
+	} while (get_timer(ts) < CFG_LINKUP_TIMEOUT);
+	if (!chip->lnkup) {
+		puts("ftmac110: link down\n");
+		goto exit;
+	}
+	if (!(bmcr & BMCR_ANENABLE))
+		puts("ftmac110: auto negotiation disabled\n");
+	else if (!(bmsr & BMSR_ANEGCOMPLETE))
+		puts("ftmac110: auto negotiation timeout\n");
+
+	/* 3. derive MACCR */
+	if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) {
+		tmp  = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
+		tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
+		if (tmp & LPA_100FULL)      /* 100Mbps full-duplex */
+			maccr = MACCR_100M | MACCR_FD;
+		else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */
+			maccr = MACCR_100M;
+		else if (tmp & LPA_10FULL)  /* 10Mbps full-duplex */
+			maccr = MACCR_FD;
+		else if (tmp & LPA_10HALF)  /* 10Mbps half-duplex */
+			maccr = 0;
+	} else {
+		if (bmcr & BMCR_SPEED100)
+			maccr = MACCR_100M;
+		else
+			maccr = 0;
+		if (bmcr & BMCR_FULLDPLX)
+			maccr |= MACCR_FD;
+	}
+
+exit:
+	printf("ftmac110: %d Mbps, %s\n",
+		   (maccr & MACCR_100M) ? 100 : 10,
+		   (maccr & MACCR_FD) ? "Full" : "half");
+	return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+	uint8_t *a;
+	uint32_t i, maccr;
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+
+	/* 1. MAC reset */
+	writel(MACCR_RESET, &regs->maccr);
+	for (i = get_timer(0); get_timer(i) < 1000; ) {
+		if (readl(&regs->maccr) & MACCR_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->maccr) & MACCR_RESET) {
+		printf("ftmac110: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* 1-1. Init tx ring */
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		/* owned by SW */
+		chip->txd[i].ct[0] = 0;
+	}
+	chip->txd_idx = 0;
+
+	/* 1-2. Init rx ring */
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		/* owned by HW */
+		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+	}
+	chip->rxd_idx = 0;
+
+	/* 2. PHY status query */
+	maccr = ftmac110_phyqry(dev);
+
+	/* 3. Fix up the MACCR value */
+	chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+		| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+
+	/* 4. MAC address setup */
+	a = dev->enetaddr;
+	writel(a[1] | (a[0] << 8), &regs->mac[0]);
+	writel(a[5] | (a[4] << 8) | (a[3] << 16)
+		| (a[2] << 24), &regs->mac[1]);
+
+	/* 5. MAC registers setup */
+	writel(chip->rxd_dma, &regs->rxba);
+	writel(chip->txd_dma, &regs->txba);
+	/* interrupt at each tx/rx */
+	writel(ITC_DEFAULT, &regs->itc);
+	/* no tx pool, rx poll = 1 normal cycle */
+	writel(APTC_DEFAULT, &regs->aptc);
+	/* rx threshold = [6/8 fifo, 2/8 fifo] */
+	writel(DBLAC_DEFAULT, &regs->dblac);
+	/* disable & clear all interrupt status */
+	chip->imr = 0;
+	writel(ISR_ALL, &regs->isr);
+	writel(chip->imr, &regs->imr);
+	/* enable mac */
+	writel(chip->maccr, &regs->maccr);
+
+	return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+	debug("ftmac110: probe\n");
+
+	if (ftmac110_reset(dev))
+		return -1;
+
+	return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+
+	writel(0, &regs->imr);
+	writel(0, &regs->maccr);
+
+	debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *pkt, int len)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs __iomem *regs = chip->regs;
+	struct ftmac110_txd *des;
+
+	if (!chip->lnkup)
+		return 0;
+
+	if (len <= 0 || len > CFG_XBUF_SIZE) {
+		printf("ftmac110: bad tx pkt len(%d)\n", len);
+		return 0;
+	}
+
+	len = max(60, len);
+
+	des = &chip->txd[chip->txd_idx];
+	if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) {
+		/* kick-off Tx DMA */
+		writel(0xffffffff, &regs->txpd);
+		printf("ftmac110: out of txd\n");
+		return 0;
+	}
+
+	memcpy(des->vbuf, (void *)pkt, len);
+	dma_map_single(des->vbuf, len, DMA_TO_DEVICE);
+
+	/* update len, fts and lts */
+	des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END);
+	des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len)
+		| FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS);
+
+	/* set owner bit and clear others */
+	des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER);
+
+	/* kick-off Tx DMA */
+	writel(0xffffffff, &regs->txpd);
+
+	chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
+
+	return len;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_rxd *des;
+	uint32_t ct0, len, rlen = 0;
+	uint8_t *buf;
+
+	if (!chip->lnkup)
+		return 0;
+
+	do {
+		des = &chip->rxd[chip->rxd_idx];
+		ct0 = le32_to_cpu(des->ct[0]);
+		if (ct0 & FTMAC110_RXCT0_OWNER)
+			break;
+
+		len = FTMAC110_RXCT0_LEN(ct0);
+		buf = des->vbuf;
+
+		if (ct0 & FTMAC110_RXCT0_ERRMASK) {
+			printf("ftmac110: rx error\n");
+		} else {
+			dma_map_single(buf, len, DMA_FROM_DEVICE);
+			NetReceive(buf, len);
+			rlen += len;
+		}
+
+		/* owned by hardware */
+		des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+
+		chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
+	} while (0);
+
+	return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		*value = mdio_read(dev, addr, reg);
+	}
+
+	return ret;
+}
+
+static int ftmac110_mdio_write(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		mdio_write(dev, addr, reg, value);
+	}
+
+	return ret;
+}
+
+#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+	int i, card_nr = 0;
+	struct eth_device *dev;
+	struct ftmac110_chip *chip;
+
+	dev = malloc(sizeof(*dev) + sizeof(*chip));
+	if (dev == NULL) {
+		panic("ftmac110: out of memory 1\n");
+		return -1;
+	}
+	chip = (struct ftmac110_chip *)(dev + 1);
+	memset(dev, 0, sizeof(*dev) + sizeof(*chip));
+
+	sprintf(dev->name, "FTMAC110#%d", card_nr);
+
+	dev->iobase = CONFIG_FTMAC110_BASE;
+	chip->regs = (void __iomem *)dev->iobase;
+	dev->priv = chip;
+	dev->init = ftmac110_probe;
+	dev->halt = ftmac110_halt;
+	dev->send = ftmac110_send;
+	dev->recv = ftmac110_recv;
+
+	if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
+		eth_random_enetaddr(dev->enetaddr);
+
+	/* allocate tx descriptors (it must be 16 bytes aligned) */
+	chip->txd = dma_alloc_coherent(
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
+	if (!chip->txd)
+		panic("ftmac110: out of memory 3\n");
+	memset(chip->txd, 0,
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+		if (!va)
+			panic("ftmac110: out of memory 4\n");
+		chip->txd[i].vbuf  = va;
+		chip->txd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->txd[i].ct[1] = 0;
+		chip->txd[i].ct[0] = 0; /* owned by SW */
+	}
+	chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END);
+	chip->txd_idx = 0;
+
+	/* allocate rx descriptors (it must be 16 bytes aligned) */
+	chip->rxd = dma_alloc_coherent(
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
+	if (!chip->rxd)
+		panic("ftmac110: out of memory 4\n");
+	memset((void *)chip->rxd, 0,
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+		if (!va)
+			panic("ftmac110: out of memory 5\n");
+		/* it needs to be exactly 2 bytes aligned */
+		va = ((uint8_t *)va + 2);
+		chip->rxd[i].vbuf  = va;
+		chip->rxd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE);
+		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+	}
+	chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END);
+	chip->rxd_idx = 0;
+
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+	card_nr++;
+
+	return card_nr;
+}
diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h
new file mode 100644
index 0000000..5b2d23b
--- /dev/null
+++ b/drivers/net/ftmac110.h
@@ -0,0 +1,177 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTMAC110_H
+#define _FTMAC110_H
+
+struct ftmac110_regs {
+	uint32_t isr;    /* 0x00: Interrups Status Register */
+	uint32_t imr;    /* 0x04: Interrupt Mask Register */
+	uint32_t mac[2]; /* 0x08: MAC Address */
+	uint32_t mht[2]; /* 0x10: Multicast Hash Table Register */
+	uint32_t txpd;   /* 0x18: Tx Poll Demand Register */
+	uint32_t rxpd;   /* 0x1c: Rx Poll Demand Register */
+	uint32_t txba;   /* 0x20: Tx Ring Base Address Register */
+	uint32_t rxba;   /* 0x24: Rx Ring Base Address Register */
+	uint32_t itc;    /* 0x28: Interrupt Timer Control Register */
+	uint32_t aptc;   /* 0x2C: Automatic Polling Timer Control Register */
+	uint32_t dblac;  /* 0x30: DMA Burst Length&Arbitration Control */
+	uint32_t revr;   /* 0x34: Revision Register */
+	uint32_t fear;   /* 0x38: Feature Register */
+	uint32_t rsvd[19];
+	uint32_t maccr;  /* 0x88: MAC Control Register */
+	uint32_t macsr;  /* 0x8C: MAC Status Register */
+	uint32_t phycr;  /* 0x90: PHY Control Register */
+	uint32_t phydr;  /* 0x94: PHY Data Register */
+	uint32_t fcr;    /* 0x98: Flow Control Register */
+	uint32_t bpr;    /* 0x9C: Back Pressure Register */
+};
+
+/*
+ * Interrupt status/mask register(ISR/IMR) bits
+ */
+#define ISR_ALL          0x3ff
+#define ISR_PHYSTCHG     (1 << 9) /* phy status change */
+#define ISR_AHBERR       (1 << 8) /* bus error */
+#define ISR_RXLOST       (1 << 7) /* rx lost */
+#define ISR_RXFIFO       (1 << 6) /* rx to fifo */
+#define ISR_TXLOST       (1 << 5) /* tx lost */
+#define ISR_TXOK         (1 << 4) /* tx to ethernet */
+#define ISR_NOTXBUF      (1 << 3) /* out of tx buffer */
+#define ISR_TXFIFO       (1 << 2) /* tx to fifo */
+#define ISR_NORXBUF      (1 << 1) /* out of rx buffer */
+#define ISR_RXOK         (1 << 0) /* rx to buffer */
+
+/*
+ * MACCR control bits
+ */
+#define MACCR_100M       (1 << 18) /* 100Mbps mode */
+#define MACCR_RXBCST     (1 << 17) /* rx broadcast packet */
+#define MACCR_RXMCST     (1 << 16) /* rx multicast packet */
+#define MACCR_FD         (1 << 15) /* full duplex */
+#define MACCR_CRCAPD     (1 << 14) /* tx crc append */
+#define MACCR_RXALL      (1 << 12) /* rx all packets */
+#define MACCR_RXFTL      (1 << 11) /* rx packet even it's > 1518 byte */
+#define MACCR_RXRUNT     (1 << 10) /* rx packet even it's < 64 byte */
+#define MACCR_RXMCSTHT   (1 << 9)  /* rx multicast hash table */
+#define MACCR_RXEN       (1 << 8)  /* rx enable */
+#define MACCR_RXINHDTX   (1 << 6)  /* rx in half duplex tx */
+#define MACCR_TXEN       (1 << 5)  /* tx enable */
+#define MACCR_CRCDIS     (1 << 4)  /* tx packet even it's crc error */
+#define MACCR_LOOPBACK   (1 << 3)  /* loop-back */
+#define MACCR_RESET      (1 << 2)  /* reset */
+#define MACCR_RXDMAEN    (1 << 1)  /* rx dma enable */
+#define MACCR_TXDMAEN    (1 << 0)  /* tx dma enable */
+
+/*
+ * PHYCR control bits
+ */
+#define PHYCR_READ       (1 << 26)
+#define PHYCR_WRITE      (1 << 27)
+#define PHYCR_REG_SHIFT  21
+#define PHYCR_ADDR_SHIFT 16
+
+/*
+ * ITC control bits
+ */
+
+/* Tx Cycle Length */
+#define ITC_TX_CYCLONG   (1 << 15) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_TX_CYCNORM   (0 << 15) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_TX_THR(n)    (((n) & 0x7) << 12)
+/* Tx Interrupt Timeout = n * Tx Cycle */
+#define ITC_TX_ITMO(n)   (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define ITC_RX_CYCLONG   (1 << 7)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_RX_CYCNORM   (0 << 7)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_RX_THR(n)    (((n) & 0x7) << 4)
+/* Rx Interrupt Timeout = n * Rx Cycle */
+#define ITC_RX_ITMO(n)   (((n) & 0xf) << 0)
+
+#define ITC_DEFAULT \
+	(ITC_TX_THR(1) | ITC_TX_ITMO(0) | ITC_RX_THR(1) | ITC_RX_ITMO(0))
+
+/*
+ * APTC contrl bits
+ */
+
+/* Tx Cycle Length */
+#define APTC_TX_CYCLONG  (1 << 12) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_TX_CYCNORM  (0 << 12) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Poll Timeout = n * Tx Cycle, 0=No auto polling */
+#define APTC_TX_PTMO(n)  (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define APTC_RX_CYCLONG  (1 << 4)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_RX_CYCNORM  (0 << 4)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Poll Timeout = n * Rx Cycle, 0=No auto polling */
+#define APTC_RX_PTMO(n)  (((n) & 0xf) << 0)
+
+#define APTC_DEFAULT     (APTC_TX_PTMO(0) | APTC_RX_PTMO(1))
+
+/*
+ * DBLAC contrl bits
+ */
+#define DBLAC_BURST_MAX_ANY  (0 << 14) /* un-limited */
+#define DBLAC_BURST_MAX_32X4 (2 << 14) /* max = 32 x 4 bytes */
+#define DBLAC_BURST_MAX_64X4 (3 << 14) /* max = 64 x 4 bytes */
+#define DBLAC_RXTHR_EN       (1 << 9)  /* enable rx threshold arbitration */
+#define DBLAC_RXTHR_HIGH(n)  (((n) & 0x7) << 6) /* upper bound = n/8 fifo */
+#define DBLAC_RXTHR_LOW(n)   (((n) & 0x7) << 3) /* lower bound = n/8 fifo */
+#define DBLAC_BURST_CAP16    (1 << 2)  /* support burst 16 */
+#define DBLAC_BURST_CAP8     (1 << 1)  /* support burst 8 */
+#define DBLAC_BURST_CAP4     (1 << 0)  /* support burst 4 */
+
+#define DBLAC_DEFAULT \
+	(DBLAC_RXTHR_EN | DBLAC_RXTHR_HIGH(6) | DBLAC_RXTHR_LOW(2))
+
+/*
+ * descriptor structure
+ */
+struct ftmac110_rxd {
+	uint32_t ct[2];
+	uint32_t buf;
+	void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_RXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_RXCT0_FRS         BIT_MASK(29) /* first pkt desc */
+#define FTMAC110_RXCT0_LRS         BIT_MASK(28) /* last pkt desc */
+#define FTMAC110_RXCT0_ODDNB       BIT_MASK(22) /* odd nibble */
+#define FTMAC110_RXCT0_RUNT        BIT_MASK(21) /* runt pkt */
+#define FTMAC110_RXCT0_FTL         BIT_MASK(20) /* frame too long */
+#define FTMAC110_RXCT0_CRC         BIT_MASK(19) /* pkt crc error */
+#define FTMAC110_RXCT0_ERR         BIT_MASK(18) /* bus error */
+#define FTMAC110_RXCT0_ERRMASK     (0x1f << 18) /* all errors */
+#define FTMAC110_RXCT0_BCST        BIT_MASK(17) /* Bcst pkt */
+#define FTMAC110_RXCT0_MCST        BIT_MASK(16) /* Mcst pkt */
+#define FTMAC110_RXCT0_LEN(x)      ((x) & 0x7ff)
+
+#define FTMAC110_RXCT1_END         BIT_MASK(31)
+#define FTMAC110_RXCT1_BUFSZ(x)    ((x) & 0x7ff)
+
+struct ftmac110_txd {
+	uint32_t ct[2];
+	uint32_t buf;
+	void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_TXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_TXCT0_COL         0x00000003   /* collision */
+
+#define FTMAC110_TXCT1_END         BIT_MASK(31) /* end of ring */
+#define FTMAC110_TXCT1_TXIC        BIT_MASK(30) /* tx done interrupt */
+#define FTMAC110_TXCT1_TX2FIC      BIT_MASK(29) /* tx fifo interrupt */
+#define FTMAC110_TXCT1_FTS         BIT_MASK(28) /* first pkt desc */
+#define FTMAC110_TXCT1_LTS         BIT_MASK(27) /* last pkt desc */
+#define FTMAC110_TXCT1_LEN(x)      ((x) & 0x7ff)
+
+#endif  /* FTMAC110_H */
diff --git a/include/netdev.h b/include/netdev.h
index fd3e243..48c2fe5 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -67,6 +67,7 @@ int fecmxc_initialize(bd_t *bis);
 int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
 int ftgmac100_initialize(bd_t *bits);
 int ftmac100_initialize(bd_t *bits);
+int ftmac110_initialize(bd_t *bits);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
--
1.7.9.5

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

* [U-Boot] [PATCH v4] net: update FTGMAC100 for MMU/D-cache support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 02/11] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
@ 2013-05-07  6:33           ` Kuo-Jung Su
  2013-07-08 16:21             ` Joe Hershberger
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:33 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Joe Hershberger <joe.hershberger@gmail.com>
CC: Tom Rini <trini@ti.com>
---
Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series

Changes for v3:
   - Coding Style cleanup

Changes for v2:
   - Coding Style cleanup
   - Cleanup (Drop cosmetic patch)

 drivers/net/ftgmac100.c |   70 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 69ba57d..2dbb328 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -27,11 +27,13 @@
 #include <malloc.h>
 #include <net.h>
 #include <asm/io.h>
+#include <asm/dma-mapping.h>
 #include <linux/mii.h>

 #include "ftgmac100.h"

 #define ETH_ZLEN	60
+#define CFG_XBUF_SIZE	1536

 /* RBSR - hw default init value is also 0x640 */
 #define RBSR_DEFAULT_VALUE	0x640
@@ -40,8 +42,10 @@
 #define PKTBUFSTX	4	/* must be power of 2 */

 struct ftgmac100_data {
-	struct ftgmac100_txdes txdes[PKTBUFSTX];
-	struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+	ulong txdes_dma;
+	struct ftgmac100_txdes *txdes;
+	ulong rxdes_dma;
+	struct ftgmac100_rxdes *rxdes;
 	int tx_index;
 	int rx_index;
 	int phy_addr;
@@ -375,13 +379,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 {
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
-	struct ftgmac100_txdes *txdes = priv->txdes;
-	struct ftgmac100_rxdes *rxdes = priv->rxdes;
+	struct ftgmac100_txdes *txdes;
+	struct ftgmac100_rxdes *rxdes;
 	unsigned int maccr;
+	void *buf;
 	int i;

 	debug("%s()\n", __func__);

+	if (!priv->txdes) {
+		txdes = dma_alloc_coherent(
+			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+		if (!txdes)
+			panic("ftgmac100: out of memory\n");
+		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+		priv->txdes = txdes;
+	}
+	txdes = priv->txdes;
+
+	if (!priv->rxdes) {
+		rxdes = dma_alloc_coherent(
+			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+		if (!rxdes)
+			panic("ftgmac100: out of memory\n");
+		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+		priv->rxdes = rxdes;
+	}
+	rxdes = priv->rxdes;
+
 	/* set the ethernet address */
 	ftgmac100_set_mac_from_env(dev);

@@ -397,21 +422,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)

 	for (i = 0; i < PKTBUFSTX; i++) {
 		/* TXBUF_BADR */
-		txdes[i].txdes3 = 0;
+		if (!txdes[i].txdes2) {
+			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+			if (!buf)
+				panic("ftgmac100: out of memory\n");
+			txdes[i].txdes3 = virt_to_phys(buf);
+			txdes[i].txdes2 = (uint)buf;
+		}
 		txdes[i].txdes1 = 0;
 	}

 	for (i = 0; i < PKTBUFSRX; i++) {
 		/* RXBUF_BADR */
-		rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i];
+		if (!rxdes[i].rxdes2) {
+			buf = NetRxPackets[i];
+			rxdes[i].rxdes3 = virt_to_phys(buf);
+			rxdes[i].rxdes2 = (uint)buf;
+		}
 		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
 	}

 	/* transmit ring */
-	writel((unsigned int)txdes, &ftgmac100->txr_badr);
+	writel(priv->txdes_dma, &ftgmac100->txr_badr);

 	/* receive ring */
-	writel((unsigned int)rxdes, &ftgmac100->rxr_badr);
+	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);

 	/* poll receive descriptor automatically */
 	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -466,8 +501,11 @@ static int ftgmac100_recv(struct eth_device *dev)
 	debug("%s(): RX buffer %d, %x received\n",
 	       __func__, priv->rx_index, rxlen);

+	/* invalidate d-cache */
+	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
 	/* pass the packet up to the protocol layers. */
-	NetReceive((void *)curr_des->rxdes3, rxlen);
+	NetReceive((void *)curr_des->rxdes2, rxlen);

 	/* release buffer to DMA */
 	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
@@ -485,7 +523,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
 	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
-	int start;

 	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
 		debug("%s(): no TX descriptor available\n", __func__);
@@ -496,8 +533,8 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)

 	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;

-	/* initiate a transmit sequence */
-	curr_des->txdes3 = (unsigned int)packet;	/* TXBUF_BADR */
+	memcpy((void *)curr_des->txdes2, (void *)packet, length);
+	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);

 	/* only one descriptor on TXBUF */
 	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
@@ -509,15 +546,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	/* start transmit */
 	writel(1, &ftgmac100->txpd);

-	/* wait for transfer to succeed */
-	start = get_timer(0);
-	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
-		if (get_timer(0) >= 5) {
-			debug("%s(): timed out\n", __func__);
-			return -1;
-		}
-	}
-
 	debug("%s(): packet sent\n", __func__);

 	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
--
1.7.9.5

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

* [U-Boot] [PATCH v4] spi: add Faraday FTSPI010 SPI controller support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 05/11] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
@ 2013-05-07  6:34           ` Kuo-Jung Su
  2013-06-12 18:56             ` [U-Boot] [U-Boot, " Jagan Teki
                               ` (2 more replies)
  0 siblings, 3 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:34 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FTSSP010 is a multi-function controller
which supports I2S/SPI/SSP/AC97/SPDIF. However This
patch implements only the SPI mode.

NOTE:
The DMA and CS/Clock control logic has been altered
since hardware revision 1.19.0. So this patch
would first detects the revision id of the underlying
chip, and then switch to the corresponding software
control routines.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Tom Rini <trini@ti.com>
---
Changes for v4:
   - Coding Style cleanup.
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 drivers/spi/Makefile        |    1 +
 drivers/spi/ftssp010_spi.c  |  385 +++++++++++++++++++++++++++++++++++++++++++
 drivers/spi/ftssp010_spi.h  |   86 ++++++++++
 include/faraday/ftgpio010.h |   25 +++
 4 files changed, 497 insertions(+)
 create mode 100644 drivers/spi/ftssp010_spi.c
 create mode 100644 drivers/spi/ftssp010_spi.h
 create mode 100644 include/faraday/ftgpio010.h

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index d08609e..947d60e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
 COBJS-$(CONFIG_CF_SPI) += cf_spi.o
 COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
 COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
+COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
 COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
 COBJS-$(CONFIG_ICH_SPI) +=  ich.o
 COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
new file mode 100644
index 0000000..d401ecc
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.c
@@ -0,0 +1,385 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <malloc.h>
+#include <faraday/ftgpio010.h>
+#include "ftssp010_spi.h"
+
+#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
+#define CFG_CS_TIMEOUT  (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct ftssp010_chip {
+	void __iomem *regs;
+	uint32_t fifo;
+	uint32_t rev;
+	uint32_t div;
+	uint32_t mode;
+
+	struct {
+		void __iomem *regs;
+		uint32_t      pin;
+	} gpio;
+};
+
+static struct ftssp010_chip chip_list[] = {
+#ifdef CONFIG_FTSSP010_BASE
+	{
+		.regs = (void __iomem *)CONFIG_FTSSP010_BASE,
+# ifdef CONFIG_FTSSP010_GPIO_BASE
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE,
+			CONFIG_FTSSP010_GPIO_PIN
+		},
+# endif
+	},
+#endif /* #ifdef CONFIG_FTSSP010_BASE */
+#ifdef CONFIG_FTSSP010_BASE1
+	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE1, },
+# ifdef CONFIG_FTSSP010_GPIO_BASE1
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE1,
+			CONFIG_FTSSP010_GPIO_PIN1
+		},
+# endif
+#endif
+#ifdef CONFIG_FTSSP010_BASE2
+	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE2, },
+# ifdef CONFIG_FTSSP010_GPIO_BASE2
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE2,
+			CONFIG_FTSSP010_GPIO_PIN2
+		},
+# endif
+#endif
+#ifdef CONFIG_FTSSP010_BASE3
+	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE3, },
+# ifdef CONFIG_FTSSP010_GPIO_BASE3
+		.gpio = {
+			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE3,
+			CONFIG_FTSSP010_GPIO_PIN3
+		},
+# endif
+#endif
+};
+
+static inline int ftssp010_wait_tx(struct ftssp010_chip *chip)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
+		if (!(readl(&regs->sr) & SR_TFNF))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftssp010: tx timeout\n");
+
+	return ret;
+}
+
+static inline int ftssp010_wait_rx(struct ftssp010_chip *chip)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
+		if (!SR_RFVE(readl(&regs->sr)))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftssp010: rx timeout\n");
+
+	return ret;
+}
+
+static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t xmsk = 0;
+
+		if (tx_buf) {
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_tx(chip);
+				writel(*txb++, &regs->dr);
+			}
+			xmsk |= CR2_TXEN | CR2_TXDOE;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+		}
+		if (rx_buf) {
+			xmsk |= CR2_RXEN;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_rx(chip);
+				*rxb++ = (uint8_t)readl(&regs->dr);
+			}
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t tmp;
+
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_tx(chip);
+			writel(txb ? (*txb++) : 0, &regs->dr);
+		}
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_rx(chip);
+			tmp = readl(&regs->dr);
+			if (rxb)
+				*rxb++ = (uint8_t)tmp;
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+/*
+ * Determine if a SPI chipselect is valid.
+ * This function is provided by the board if the low-level SPI driver
+ * needs it to determine if a given chipselect is actually valid.
+ *
+ * Returns: 1 if bus:cs identifies a valid chip on this board, 0
+ * otherwise.
+ */
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	int ret = 0;
+	struct ftssp010_chip *chip;
+	struct ftssp010_regs __iomem *regs;
+	uint32_t txfifo, rxfifo;
+
+	if (bus >= ARRAY_SIZE(chip_list))
+		return ret;
+
+	chip = chip_list + bus;
+	regs = chip->regs;
+	chip->rev = readl(&regs->revr);
+	txfifo = FEAR_TXFIFO(readl(&regs->fear));
+	rxfifo = FEAR_RXFIFO(readl(&regs->fear));
+	chip->fifo = min(txfifo, rxfifo);
+
+	debug("ftssp010: rev=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
+
+	if (chip->rev >= 0x00011900) {
+		if (cs < 4)
+			ret = 1;
+	} else if (!cs) {
+		struct ftgpio010_regs *gpio = chip->gpio.regs;
+		uint32_t mask = BIT_MASK(chip->gpio.pin);
+
+		if (gpio) {
+			/* setup gpio pin as an output pin */
+			setbits_le32(&gpio->dir, mask);
+			ret = 1;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * Activate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should activate the chip select
+ * to the device identified by "slave".
+ */
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+
+	/* cs pull low */
+	if (chip->rev >= 0x00011900) {
+		writel((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
+			| CR2_RXFCLR, &regs->cr[2]);
+	} else {
+		struct ftgpio010_regs *gpio = chip->gpio.regs;
+		uint32_t mask = BIT_MASK(chip->gpio.pin);
+
+		if (gpio)
+			setbits_le32(&gpio->clr, mask);
+	}
+	udelay_masked(1);
+}
+
+/*
+ * Deactivate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should deactivate the chip
+ * select to the device identified by "slave".
+ */
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+	ulong ts;
+
+	/* wait until device idle */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CS_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_BUSY)
+			continue;
+		break;
+	}
+	if (readl(&regs->sr) & SR_BUSY)
+		printf("ftspi010: busy timeout at cs deactivate\n");
+
+	/* cs pull high */
+	if (chip->rev >= 0x00011900) {
+		writel((slave->cs << 10) | CR2_FS, &regs->cr[2]);
+	} else {
+		struct ftgpio010_regs *gpio = chip->gpio.regs;
+		uint32_t mask = BIT_MASK(chip->gpio.pin);
+
+		if (gpio)
+			setbits_le32(&gpio->set, mask);
+	}
+	udelay_masked(1);
+}
+
+void spi_init(void)
+{
+}
+
+struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
+{
+	uint32_t clk, div;
+	struct spi_slave *ss;
+	struct ftssp010_chip *chip;
+
+	if (!spi_cs_is_valid(bus, cs))
+		return NULL;
+
+	if (mode != SPI_MODE_0) {
+		printf("ftssp010: MODE%d is not supported\n", mode);
+		return NULL;
+	}
+
+	ss = malloc(sizeof(struct spi_slave));
+	if (!ss)
+		return NULL;
+
+	ss->bus = bus;
+	ss->cs  = cs;
+
+#ifdef CONFIG_FTSSP010_SCLK
+	clk = CONFIG_FTSSP010_SCLK;
+#else
+	clk = clk_get_rate("SSP");
+#endif
+	if (max_hz > 0) {
+		for (div = 0; div < 0xFFFF; ++div) {
+			if ((clk / (2 * (div + 1))) <= max_hz)
+				break;
+		}
+	} else {
+		div = 7;
+	}
+
+	chip = chip_list + bus;
+	chip->div  = div;
+	chip->mode = mode;
+
+	debug("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
+
+	return ss;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+
+	writel(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
+
+	if (chip->rev >= 0x00011900) {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
+			&regs->cr[0]);
+		writel(CR2_TXFCLR | CR2_RXFCLR,
+			&regs->cr[2]);
+	} else {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
+			&regs->cr[0]);
+		writel(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
+			&regs->cr[2]);
+	}
+
+	spi_cs_deactivate(slave);
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	struct ftssp010_regs __iomem *regs = chip->regs;
+
+	writel(0, &regs->cr[2]);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+			 const void *dout, void *din, unsigned long flags)
+{
+	struct ftssp010_chip *chip = chip_list + slave->bus;
+	uint32_t len = bitlen >> 3;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(slave);
+
+	if (chip->rev >= 0x00011900)
+		ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags);
+	else
+		ftssp010_spi_work_transfer(chip, dout, din, len, flags);
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(slave);
+
+	return 0;
+}
diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
new file mode 100644
index 0000000..5258edc
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.h
@@ -0,0 +1,86 @@
+/*
+ * Faraday Multi-function Controller - SPI Mode
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FTSSP010_H
+#define _FTSSP010_H
+
+/* FTSSP010 HW Registers */
+struct ftssp010_regs {
+	uint32_t cr[3];/* control register */
+	uint32_t sr;   /* status register */
+	uint32_t icr;  /* interrupt control register */
+	uint32_t isr;  /* interrupt status register */
+	uint32_t dr;   /* data register */
+	uint32_t rsvd[17];
+	uint32_t revr; /* revision register */
+	uint32_t fear; /* feature register */
+};
+
+/* Control Register 0  */
+#define CR0_FFMT_MASK       (7 << 12)
+#define CR0_FFMT_SSP        (0 << 12)
+#define CR0_FFMT_SPI        (1 << 12)
+#define CR0_FFMT_MICROWIRE  (2 << 12)
+#define CR0_FFMT_I2S        (3 << 12)
+#define CR0_FFMT_AC97       (4 << 12)
+#define CR0_FLASH           (1 << 11)
+#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
+#define CR0_LBM             (1 << 7)  /* Loopback mode */
+#define CR0_LSB             (1 << 6)  /* LSB first */
+#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
+#define CR0_FSJUSTIFY       (1 << 4)
+#define CR0_OPM_SLAVE       (0 << 2)
+#define CR0_OPM_MASTER      (3 << 2)
+#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
+#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
+#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
+#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
+#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
+#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
+
+/* Control Register 1 */
+
+#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
+#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
+#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
+
+/* Control Register 2 */
+#define CR2_FSOS(x)         (((x) & 0x03) << 10)	/* FS/CS Select */
+#define CR2_FS              (1 << 9)	/* FS/CS Signal Level */
+#define CR2_TXEN            (1 << 8)	/* Tx Enable */
+#define CR2_RXEN            (1 << 7)	/* Rx Enable */
+#define CR2_SSPRST          (1 << 6)	/* SSP reset */
+#define CR2_TXFCLR          (1 << 3)	/* TX FIFO Clear */
+#define CR2_RXFCLR          (1 << 2)	/* RX FIFO Clear */
+#define CR2_TXDOE           (1 << 1)	/* TX Data Output Enable */
+#define CR2_SSPEN           (1 << 0)	/* SSP Enable */
+
+/*
+ * Status Register
+ */
+#define SR_RFF       (1 << 0) /* receive FIFO full */
+#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
+#define SR_BUSY      (1 << 2) /* bus is busy */
+#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid entries */
+#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */
+
+/*
+ * Feature Register
+ */
+#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
+#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
+#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
+#define FEAR_AC97        (1 << 24)
+#define FEAR_I2S         (1 << 25)
+#define FEAR_SPI_MWR     (1 << 26)
+#define FEAR_SSP         (1 << 27)
+#define FEAR_SPDIF       (1 << 28)
+
+#endif /* EOF */
diff --git a/include/faraday/ftgpio010.h b/include/faraday/ftgpio010.h
new file mode 100644
index 0000000..2dc45f2
--- /dev/null
+++ b/include/faraday/ftgpio010.h
@@ -0,0 +1,25 @@
+/*
+ * Faraday GPIO Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTGPIO010_H
+#define __FTGPIO010_H
+
+struct ftgpio010_regs {
+	uint32_t out;     /* 0x00: Data Output */
+	uint32_t in;      /* 0x04: Data Input */
+	uint32_t dir;     /* 0x08: Pin Direction */
+	uint32_t bypass;  /* 0x0c: Bypass */
+	uint32_t set;     /* 0x10: Data Set */
+	uint32_t clr;     /* 0x14: Data Clear */
+	uint32_t pull_up; /* 0x18: Pull-Up Enabled */
+	uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */
+};
+
+#endif /* __FTGPIO010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v2] video: add Faraday FTLCDC200 LCD controller support
  2013-04-26  8:02         ` [U-Boot] [PATCH v3 10/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
  2013-05-06 20:18           ` Anatolij Gustschin
@ 2013-05-07  6:34           ` Kuo-Jung Su
  1 sibling, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-07  6:34 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTLCDC200 Color LCD controller performs translation of
pixel-coded data into the required formats and timings to
drive a variety of single/dual mono and color LCDs.

Depending on the LCD type and mode, the unpacked data can represent:
   1. an actual true display gray or color value
   2. an address to a 256 x 16 bit wide palette RAM gray or color value.

The FTLCDC200 generates 4 individual interrupts for:
   1. DMA FIFO underflow
   2. base address update
   3. vertical status
   4. bus error.

There is also a single combined interrupt that is raised when any of
the individual interrupts become active.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Anatolij Gustschin <agust@denx.de>
---
Changes for v2:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series

 drivers/video/Makefile          |    1 +
 drivers/video/ftlcdc200.c       |  134 +++++++++++++++++++++++++
 drivers/video/ftlcdc200_panel.c |  210 +++++++++++++++++++++++++++++++++++++++
 include/faraday/ftlcdc200.h     |  179 +++++++++++++++++++++++++++++++++
 include/lcd.h                   |   33 ++++++
 5 files changed, 557 insertions(+)
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/faraday/ftlcdc200.h

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 53952ab..ec8df26 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
 				exynos_mipi_dsi_lowlevel.o
 COBJS-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o
 COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
+COBJS-$(CONFIG_FTLCDC200) += ftlcdc200.o ftlcdc200_panel.o
 COBJS-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o
 COBJS-$(CONFIG_PXA_LCD) += pxa_lcd.o
 COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o
diff --git a/drivers/video/ftlcdc200.c b/drivers/video/ftlcdc200.c
new file mode 100644
index 0000000..70473f8
--- /dev/null
+++ b/drivers/video/ftlcdc200.c
@@ -0,0 +1,134 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+static struct ftlcdc200_regs __iomem *regs
+	= (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+static void ftlcdc2xx_fixup(struct vidinfo *panel)
+{
+	u_long ht, vt;
+	u_long div, clk;
+	long fps = 60;
+	long upper = 32767;
+	long lower = -32767;
+
+	if (panel->vl_fps)
+		return;
+
+	/* If it's serial mode */
+	if (panel->vl_serial & SPPR_SERIAL)
+		clk = clk_get_rate("AHB") / 3;
+	else
+		clk = clk_get_rate("AHB");
+
+	/* Derive clock divisor */
+	ht = panel->vl_col + panel->vl_hbp + panel->vl_hfp + panel->vl_hsw;
+	vt = panel->vl_row + panel->vl_vbp + panel->vl_vfp + panel->vl_vsw;
+	for (div = 1; div <= 0x7f; ++div) {
+		long tmp = (clk / div / ht / vt);
+		if (fps > tmp) {
+			lower = tmp;
+			break;
+		}
+		upper = tmp;
+	}
+	if ((upper - fps) > (fps - lower))
+		div += 1;
+	div = (div > 1) ? (div - 1) : div;
+
+	/* Update hardware register cache */
+	panel->vl_polarity = (panel->vl_polarity & (~0x7f00))
+		| ((div - 1) << 8);
+
+	/* Derive real frame rate */
+	panel->vl_fps = (u_long)(clk / div / ht / vt);
+
+	debug("ftlcdc200: %s\n", panel->vl_name);
+	debug("ftlcdc200: fps=%u (%u < FPS < %u)\n",
+		   (unsigned int)panel->vl_fps,
+		   (unsigned int)lower,
+		   (unsigned int)upper);
+	debug("ftlcdc200: div=%u (ahb=%u MHz)\n",
+		   (unsigned int)div,
+		   (unsigned int)clk_get_rate("AHB") / 1000000);
+}
+
+/* setcolreg used in 8bpp/16bpp */
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+/* initcolregs used in monochrome */
+void lcd_initcolregs(void)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+	uint32_t i, v;
+
+	/*
+	 * initialize the contrast lookup table and the Red, Green, Blue
+	 * gamma lookup table, fill the straight line x-y=0 to the contrast
+	 * and gamma lookup table
+	 */
+	for (i = 0; i < 64; i++) {
+		v = 0x03020100 + 0x04040404 * i;
+		writel(v, &regs->gamma_r[i]);
+		writel(v, &regs->gamma_g[i]);
+		writel(v, &regs->gamma_b[i]);
+	}
+
+	writel(virt_to_phys(lcdbase), &regs->fb0);
+
+	debug("ftlcdc200: fb_base=0x%08X at 0x%08X\n",
+		(uint32_t)lcdbase, readl(&regs->fb0));
+}
+
+void lcd_enable(void)
+{
+	struct vidinfo *panel = &panel_info;
+
+	/* 1. derive the clock parameters at runtime */
+	ftlcdc2xx_fixup(panel);
+	/* 2. disable lcd */
+	writel(0, &regs->fer);
+	/* 3. setup panel parameters */
+	writel(panel->vl_pixel, &regs->ppr);
+	writel(HTCR_PL(panel->vl_col) | HTCR_HSYNC(panel->vl_hsw)
+		| HTCR_HBP(panel->vl_hbp) | HTCR_HFP(panel->vl_hfp),
+		&regs->htcr);
+	writel(VTCR0_LF(panel->vl_row) | VTCR0_VSYNC(panel->vl_vsw)
+		| VTCR0_VFP(panel->vl_vfp), &regs->vtcr[0]);
+	writel(VTCR1_VBP(panel->vl_vbp), &regs->vtcr[1]);
+	writel(panel->vl_polarity, &regs->pcr);
+	writel(panel->vl_serial, &regs->sppr);
+	writel(panel->vl_ccir656, &regs->ccir);
+	/* 4. default 4 cycles delay for all framebuffer */
+	writel(0x04040404, &regs->fifo);
+	/* 5. disable & clean interrupts */
+	writel(0x00, &regs->ier);
+	writel(0x0f, &regs->iscr);
+	/* 6. enable lcd */
+	writel(panel->vl_enable, &regs->fer);
+}
+
+ulong calc_fbsize(void)
+{
+	return ((panel_info.vl_col * panel_info.vl_row *
+			 NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
+}
diff --git a/drivers/video/ftlcdc200_panel.c b/drivers/video/ftlcdc200_panel.c
new file mode 100644
index 0000000..ca1a091
--- /dev/null
+++ b/drivers/video/ftlcdc200_panel.c
@@ -0,0 +1,210 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+struct vidinfo panel_info = {
+#if defined(CONFIG_FTLCDC200_320X240P_SHARP)
+	.vl_name  = "SHARP-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x10,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x10,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0f,
+	.vl_vbp   = 0x07,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBLP,
+	.vl_polarity = POL_DIV(23) | POL_IHS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240P_AUO)
+	.vl_name  = "AUO-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PWROFF,
+	.vl_polarity = POL_DIV(21) | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240S_AUO)
+	.vl_name  = "AUO-320x240s",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(1),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_640X480P_PV)
+	.vl_name  = "PV-640x480p",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x63,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2D,
+	.vl_vsw   = 0x44,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(6) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480S_TPO)
+	.vl_name  = "TPO-800x480s",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x01,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(1) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(0),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_TPO)
+	.vl_name  = "TPO-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x04,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0xD4,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x0A,
+	.vl_vbp   = 0x22,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_CPT)
+	/* Chunghwa Picture Tubes - CLAA048LA0BCT */
+	.vl_name  = "CPT-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x32,
+	.vl_hbp   = 0x31,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0E,
+	.vl_vbp   = 0x05,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X600_VGA)
+	.vl_name  = "D-SUB: VGA-800x600",
+	.vl_col   = 800,
+	.vl_row   = 600,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(3) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_1024X768_VGA)
+	.vl_name  = "D-SUB: VGA-1024x768",
+	.vl_col   = 1024,
+	.vl_row   = 768,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(2) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_720X480_NTSC)
+	.vl_name  = "A/V: NTSC-720x480",
+	.vl_col   = 720,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x06,
+	.vl_hfp   = 0x7D,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x0F,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1A,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 3,
+#elif defined(CONFIG_FTLCDC200_640X480_NTSC)
+	.vl_name  = "A/V: NTSC-640x480",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x02,
+	.vl_hfp   = 0xD1,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x10,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x19,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 1,
+#else
+#error "Please specific target LCD panel."
+#endif
+};
diff --git a/include/faraday/ftlcdc200.h b/include/faraday/ftlcdc200.h
new file mode 100644
index 0000000..35f19b7
--- /dev/null
+++ b/include/faraday/ftlcdc200.h
@@ -0,0 +1,179 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTLCDC200_H
+#define __FTLCDC200_H
+
+/* FTLCDC200 Registers */
+struct ftlcdc200_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t fer;  /* 0x000: Function Enable Register */
+	uint32_t ppr;  /* 0x004: Panel Pixel Register */
+	uint32_t ier;  /* 0x008: Interrupt Enable Register */
+	uint32_t iscr; /* 0x00C: Interrupt Status Clear Register */
+	uint32_t isr;  /* 0x010: Interrupt Status Register */
+	uint32_t rsvd0[1];
+	uint32_t fb0;  /* 0x018: Framebuffer Base Register 0 */
+	uint32_t rsvd1[2];
+	uint32_t fb1;  /* 0x024: Framebuffer Base Register 1 */
+	uint32_t rsvd2[2];
+	uint32_t fb2;  /* 0x030: Framebuffer Base Register 2 */
+	uint32_t rsvd3[2];
+	uint32_t fb3;  /* 0x03C: Framebuffer Base Register 3 */
+	uint32_t rsvd4[2];
+	uint32_t patg; /* 0x048: Pattern Generator */
+	uint32_t fifo; /* 0x04C: FIFO Threshold */
+	uint32_t gpio; /* 0x050: GPIO */
+	uint32_t rsvd5[43];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t htcr;    /* Horizontal Timing Control Register */
+	uint32_t vtcr[2]; /* Vertical Timing Control Register */
+	uint32_t pcr;     /* Polarity Control Register */
+	uint32_t rsvd6[60];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t sppr;    /* Serial Panel Pixel Register */
+	uint32_t ccir;    /* CCIR565 Register */
+	uint32_t rsvd7[62];
+
+	/* 0x300 ~ 0x3ff */
+	uint32_t pipr;    /* Picture-In-Picture Register */
+	uint32_t pip1pos; /* Sub-picture 1 position */
+	uint32_t pip1dim; /* Sub-picture 1 dimension */
+	uint32_t pip2pos; /* Sub-picture 2 position */
+	uint32_t pip2dim; /* Sub-picture 2 dimension */
+	uint32_t rsvd8[59];
+
+	/* 0x400 ~ 0x5ff */
+	uint32_t cmnt[4]; /* Color Management */
+	uint32_t rsvd9[124];
+
+	/* 0x600 ~ 0x6ff */
+	uint32_t gamma_r[64]; /* RED - Gamma Correct */
+
+	/* 0x700 ~ 0x7ff */
+	uint32_t gamma_g[64]; /* GREEN - Gamma Correct */
+
+	/* 0x800 ~ 0x8ff */
+	uint32_t gamma_b[64]; /* BLUE - Gamma Correct */
+
+	/* 0x900 ~ 0x9ff */
+	uint32_t rsvd10[64];
+
+	/* 0xa00 ~ 0xbff */
+	uint32_t palette[128];  /* Palette Write Port */
+
+	/* 0xc00 ~ 0xcff */
+	uint32_t cstn_cr;       /* CSTN Control Register */
+	uint32_t cstn_pr;       /* CSTN Parameter Register */
+	uint32_t rsvd11[62];
+
+	/* 0xd00 ~ 0xdff */
+	uint32_t cstn_bmap[16]; /* CSTN bitmap write port */
+	uint32_t rsvd12[48];
+};
+
+/* LCD Function Enable Register */
+#define FER_EN          (1 << 0)    /* chip enabled */
+#define FER_ON          (1 << 1)    /* screen on */
+#define FER_YUV420      (3 << 2)
+#define FER_YUV422      (2 << 2)
+#define FER_YUV         (1 << 3)    /* 1:YUV, 0:RGB */
+
+/* LCD Panel Pixel Register */
+#define PPR_BPP_1       (0 << 0)
+#define PPR_BPP_2       (1 << 0)
+#define PPR_BPP_4       (2 << 0)
+#define PPR_BPP_8       (3 << 0)
+#define PPR_BPP_16      (4 << 0)
+#define PPR_BPP_24      (5 << 0)
+#define PPR_BPP_MASK    (7 << 0)
+#define PPR_PWROFF      (1 << 3)
+#define PPR_BGR         (1 << 4)
+#define PPR_ENDIAN_LBLP (0 << 5)
+#define PPR_ENDIAN_BBBP (1 << 5)
+#define PPR_ENDIAN_LBBP (2 << 5)
+#define PPR_ENDIAN_MASK (3 << 5)
+#define PPR_RGB1        (PPR_BPP_1)
+#define PPR_RGB2        (PPR_BPP_2)
+#define PPR_RGB4        (PPR_BPP_4)
+#define PPR_RGB8        (PPR_BPP_8)
+#define PPR_RGB12       (PPR_BPP_16 | (2 << 7))
+#define PPR_RGB16_555   (PPR_BPP_16 | (1 << 7))
+#define PPR_RGB16_565   (PPR_BPP_16 | (0 << 7))
+#define PPR_RGB24       (PPR_BPP_24)
+#define PPR_RGB32       (PPR_BPP_24)
+#define PPR_RGB_MASK    (PPR_BPP_MASK | (3 << 7))
+#define PPR_VCOMP_VSYNC (0 << 9)
+#define PPR_VCOMP_VBP   (1 << 9)
+#define PPR_VCOMP_VAIMG (2 << 9)
+#define PPR_VCOMP_VFP   (3 << 9)
+#define PPR_VCOMP_MASK  (3 << 9)
+#define	PPR_PANEL_6BIT  (0 << 11)
+#define	PPR_PANEL_8BIT  (1 << 11)
+#define	PPR_DITHER565   (0 << 12)
+#define	PPR_DITHER555   (1 << 12)
+#define	PPR_DITHER444   (2 << 12)
+#define	PPR_HCLK_RESET  (1 << 14)
+#define	PPR_LCCLK_RESET (1 << 15)
+
+/* LCD Interrupt Enable Register */
+#define IER_FIFOUR      (1 << 0)
+#define IER_NEXTFB      (1 << 1)
+#define IER_VCOMP       (1 << 2)
+#define IER_BUSERR      (1 << 3)
+
+/* LCD Interrupt Status Register */
+#define ISR_FIFOUR      (1 << 0)
+#define ISR_NEXTFB      (1 << 1)
+#define ISR_VCOMP       (1 << 2)
+#define ISR_BUSERR      (1 << 3)
+
+/* LCD Horizontal Timing Control Register */
+#define HTCR_HBP(x)     ((((x) - 1) & 0xff) << 24)
+#define HTCR_HFP(x)     ((((x) - 1) & 0xff) << 16)
+#define HTCR_HSYNC(x)   ((((x) - 1) & 0xff) << 8)
+#define HTCR_PL(x)      (((x >> 4) - 1) & 0xff)
+
+/* LCD Vertical Timing Control Register 0 */
+#define VTCR0_VFP(x)    (((x) & 0xff) << 24)
+#define VTCR0_VSYNC(x)  ((((x) - 1) & 0x3f) << 16)
+#define VTCR0_LF(x)     (((x) - 1) & 0xfff)
+
+/* LCD Vertical Timing Control Register 1 */
+#define VTCR1_VBP(x)    ((x) & 0xff)
+
+/* LCD Polarity Control Register */
+#define PCR_IVS         (1 << 0)
+#define PCR_IHS         (1 << 1)
+#define PCR_ICK         (1 << 2)
+#define PCR_IDE         (1 << 3)
+#define PCR_IPWR        (1 << 4)
+#define PCR_DIV(x)      ((((x) - 1) & 0x7f) << 8)
+
+/* LCD Serial Panel Pixel Register */
+#define SPPR_SERIAL     (1 << 0)
+#define SPPR_DELTA      (1 << 1)
+#define SPPR_CS(x)      ((x) << 2)
+#define SPPR_CS_RGB     (0 << 2)
+#define SPPR_CS_BRG     (1 << 2)
+#define SPPR_CS_GBR     (2 << 2)
+#define SPPR_LSR        (1 << 4)
+#define SPPR_AUO052     (1 << 5)
+
+/* LCD CCIR656 Register */
+#define CCIR_PAL        (0 << 0)
+#define CCIR_NTSC       (1 << 0)
+#define CCIR_P640       (0 << 1)
+#define CCIR_P720       (1 << 1)
+#define CCIR_PHASE(x)   ((x) << 2)
+
+#endif /* __FTLCDC200_H */
diff --git a/include/lcd.h b/include/lcd.h
index c6e7fc5..1d9e584 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -253,6 +253,39 @@ typedef struct vidinfo {

 void init_panel_info(vidinfo_t *vid);

+#elif defined(CONFIG_FTLCDC200)
+
+typedef struct vidinfo {
+	ushort	vl_col;		/* Number of columns (i.e. 800) */
+	ushort	vl_row;		/* Number of rows (i.e. 600) */
+
+	u_char	vl_bpix;	/* Bits per pixel, 0 = 1, 1 = 2 ... 4 = 16 */
+
+	/* Timing Parameters */
+	u_char	vl_fps;		/* Frame per second */
+
+	u_char	vl_hsw;
+	u_char	vl_hbp;
+	u_char	vl_hfp;
+
+	u_char	vl_vsw;
+	u_char	vl_vbp;
+	u_char	vl_vfp;
+
+	/* Pre-defined FTLCDC200 register values */
+	u_long	vl_enable;	/* LCDEnable */
+	u_long	vl_pixel;	/* PanelPixel */
+	u_long	vl_polarity;/* Polarity */
+	u_long	vl_serial;	/* SerialPanelPixel */
+	u_long	vl_ccir656;	/* CCIR656 */
+
+	/* Panel name */
+	char	*vl_name;
+
+	ushort	*cmap;		/* Pointer to the colormap */
+	void	*priv;		/* Pointer to driver-specific data */
+} vidinfo_t;
+
 #else

 typedef struct vidinfo {
--
1.7.9.5

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

* [U-Boot] [PATCH v4 03/16] i2c: add Faraday FTI2C010 I2C controller support
  2013-05-07  6:32           ` [U-Boot] [PATCH v4 03/16] " Kuo-Jung Su
@ 2013-05-07 13:19             ` Heiko Schocher
  2013-05-08  1:51               ` Kuo-Jung Su
  2013-05-08  7:36             ` [U-Boot] [PATCH v5] " Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Heiko Schocher @ 2013-05-07 13:19 UTC (permalink / raw)
  To: u-boot

Hello Kuo-Jung,

Am 07.05.2013 08:32, schrieb Kuo-Jung Su:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTI2C010 is a multi-function I2C controller
> which supports both master and slave mode.
> This patch simplily implements the master mode only.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Heiko Schocher <hs@denx.de>
> ---
> Changes for v4:
>    - Coding Style cleanup.
>    - Make it a separate patch, rather then a part of
>      Faraday A36x patch series
>    - Use macro constants for timeout control
> 
> Changes for v3:
>    - Coding Style cleanup.
>    - Drop macros for wirtel()/readl(), call them directly.
>    - Always insert a blank line between declarations and code.
>    - Replace all the infinite wait loop with a timeout.
>    - Add '__iomem' to all the declaration of HW register pointers.
> 
> Changes for v2:
>    - Coding Style cleanup.
>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>    - Use structure based hardware registers to replace the macro constants.
>    - Replace BIT() with BIT_MASK().
> 
>  drivers/i2c/Makefile   |    1 +
>  drivers/i2c/fti2c010.c |  371 ++++++++++++++++++++++++++++++++++++++++++++++++
>  drivers/i2c/fti2c010.h |   81 +++++++++++
>  3 files changed, 453 insertions(+)
>  create mode 100644 drivers/i2c/fti2c010.c
>  create mode 100644 drivers/i2c/fti2c010.h

As I posted the new i2c multibus/multiadapter framework:

http://lists.denx.de/pipermail/u-boot/2013-May/153452.html

maybe it is possible you can adapt your i2c driver based on
this patches?

> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
> index 5dbdbe3..ed2b8c0 100644
> --- a/drivers/i2c/Makefile
> +++ b/drivers/i2c/Makefile
> @@ -29,6 +29,7 @@ COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
>  COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
>  COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
>  COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
> +COBJS-$(CONFIG_FTI2C010) += fti2c010.o

For the new framework this should be something like
CONFIG_SYS_I2C_FTI2C010 ... and as I think, this
name would be good also for the old framework.

>  COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
>  COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
>  COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
[...]

Rest of your patch looks good to me ...

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

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

* [U-Boot] [PATCH v4 2/2] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-07  6:26             ` [U-Boot] [PATCH v4 2/2] " Kuo-Jung Su
@ 2013-05-07 21:37               ` Marek Vasut
  2013-05-08  2:30                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-07 21:37 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> The Faraday FOTG210 is an OTG chip which could operate
> as either an EHCI Host or a USB Device as a time.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
> Changes for v4:
>    - Use only macro constants and named bit/mask
>    - Remove dcache_enable() from usb_gadget_register_driver()
> 
> Changes for v3:
>    - Coding Style cleanup.
>    - Drop bit fields from c struct.
>    - Drop macros for wirtel()/readl(), call them directly.
>    - Always insert a blank line between declarations and code.
>    - Replace all the infinite wait loop with a timeout.
>    - Add '__iomem' to all the declaration of HW register pointers.
> 
> Changes for v2:
>    - Coding Style cleanup.
>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>    - Use structure based hardware registers to replace the macro constants.
>    - Replace BIT() with BIT_MASK().
>    - echi-faraday: Remove debug codes.
> 
>  drivers/usb/gadget/Makefile       |    1 +
>  drivers/usb/gadget/fotg210.c      |  961
> +++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/gadget_chips.h | 
>   8 +
>  3 files changed, 970 insertions(+)
>  create mode 100644 drivers/usb/gadget/fotg210.c
> 
> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
> index e545b6b..432cf17 100644
> --- a/drivers/usb/gadget/Makefile
> +++ b/drivers/usb/gadget/Makefile
> @@ -35,6 +35,7 @@ endif
>  # new USB gadget layer dependencies
>  ifdef CONFIG_USB_GADGET
>  COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
> +COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
>  COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
>  COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
>  endif
> diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
> new file mode 100644
> index 0000000..70797ae
> --- /dev/null
> +++ b/drivers/usb/gadget/fotg210.c
> @@ -0,0 +1,961 @@
> +/*
> + * Faraday USB 2.0 OTG Controller
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later version.
> + * See the file COPYING in the root directory of the source tree for
> details. + */
> +
> +#include <common.h>
> +#include <command.h>
> +#include <config.h>
> +#include <net.h>
> +#include <malloc.h>
> +#include <asm/io.h>
> +#include <asm/errno.h>
> +#include <linux/types.h>
> +#include <linux/usb/ch9.h>
> +#include <linux/usb/gadget.h>
> +
> +#include <usb/fotg210.h>
> +
> +#define CFG_NUM_ENDPOINTS		4
> +#define CFG_EP0_MAX_PACKET_SIZE	64
> +#define CFG_EPX_MAX_PACKET_SIZE	512
> +
> +#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
> +#define CFG_RST_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */

Uh, how's this supposed to work? Why don't you just use mdelay(250) with those?

[...]

> +static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
> +{
> +	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
> +	struct fotg210_regs __iomem *regs = chip->regs;

No need for __iomem here.

[...]

> +	/* 3. DMA target setup */
> +#ifndef CONFIG_SYS_DCACHE_OFF
> +	if (ep->desc->bEndpointAddress & USB_DIR_IN)
> +		flush_dcache_range((uint32_t)buf, (uint32_t)buf + len);
> +	else
> +		invalidate_dcache_range((uint32_t)buf, (uint32_t)buf + len);
> +#endif

The cache stuff will be optimized out anyway, no ?

[...]

> +			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
> +				puts("fotg210: HS\n");
> +				chip->gadget.speed = USB_SPEED_HIGH;
> +				writel(0x044c, &regs->sof_mtr);
> +			} else {
> +				puts("fotg210: FS\n");
> +				chip->gadget.speed = USB_SPEED_FULL;
> +				writel(0x2710, &regs->sof_mtr);

Magic values, please fix globally as previously asked.

[...]

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

* [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-07  6:26             ` [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-05-07 21:42               ` Marek Vasut
  2013-05-08  2:18                 ` Kuo-Jung Su
  2013-05-09  3:20               ` [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-07 21:42 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch add supports to both Faraday FUSBH200 and FOTG210,
> the differences between Faraday EHCI and standard EHCI as
> listed bellow:
> 
> 1. The PORTSC starts at 0x30 instead of 0x44.
> 2. The CONFIGFLAG(0x40) is not only un-implemented, and
>    also has its address removed.
> 3. Faraday EHCI is a TDI design, but it doesn't
>    compatible with the general TDI implementation
>    found at both U-Boot and Linux.
> 4. The ISOC descriptors differs from standard EHCI in
>    several ways. Since U-boot doesn't support ISOC,
>    we don't have to worry that.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
> Changes for v4:
>    - Use only macro constants and named bit/mask
>    - Use weak-aliased functions for tdi implementation and
>      also portsc registers to avoid poluting ehci.h with ifdefs
> 
> Changes for v3:
>    - Coding Style cleanup.
>    - Drop bit fields from c struct.
>    - Drop macros for wirtel()/readl(), call them directly.
>    - Always insert a blank line between declarations and code.
>    - Replace all the infinite wait loop with a timeout.
>    - Add '__iomem' to all the declaration of HW register pointers.
> 
> Changes for v2:
>    - Coding Style cleanup.
>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>    - Use structure based hardware registers to replace the macro constants.
>    - Replace BIT() with BIT_MASK().
>    - echi-faraday: Remove debug codes.
> 
>  common/usb_hub.c                |   13 +-
>  drivers/usb/host/Makefile       |    1 +
>  drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
>  drivers/usb/host/ehci-hcd.c     |  104 ++++++++----
>  include/usb/fotg210.h           |  358
> +++++++++++++++++++++++++++++++++++++++ include/usb/fusbh200.h          | 
>  61 +++++++
>  6 files changed, 646 insertions(+), 37 deletions(-)
>  create mode 100644 drivers/usb/host/ehci-faraday.c
>  create mode 100644 include/usb/fotg210.h
>  create mode 100644 include/usb/fusbh200.h
> 
> diff --git a/common/usb_hub.c b/common/usb_hub.c
> index b5eeb62..3c6cb69 100644

Please split the EHCI changes from this patch.

> --- a/common/usb_hub.c
> +++ b/common/usb_hub.c
> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device *dev)
>  			portstatus = le16_to_cpu(portsts->wPortStatus);
>  			portchange = le16_to_cpu(portsts->wPortChange);
> 
> +#ifdef CONFIG_USB_EHCI_FARADAY
> +			/* Faraday EHCI needs a long long delay here */
> +			if (!portchange && !portstatus) {
> +				if (get_timer(start) < 250)
> +					continue;
> +			}
> +#endif

I'd say just call a weak function here, in case some other non-EHCI compliant 
controller happened to need this too. btw. does it need to be 250 ms or can you 
poll for readiness somehow ?

>  			if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
>  				(portstatus & USB_PORT_STAT_CONNECTION))
>  				break;
> @@ -441,7 +449,9 @@ static int usb_hub_configure(struct usb_device *dev)
>  					i + 1, portstatus);
>  			usb_clear_port_feature(dev, i + 1,
>  						USB_PORT_FEAT_C_ENABLE);
> -
> +			/* The following hack causes a ghost device problem
> +			 * to Faraday EHCI */

Invalid multiline comment style (not that the one right below is a shining 
example of a valid one :-( ).

/*
 * This is how you
 * do multiline comments.
 */

> +#ifndef CONFIG_USB_EHCI_FARADAY
>  			/* EM interference sometimes causes bad shielded USB
>  			 * devices to be shutdown by the hub, this hack enables
>  			 * them again. Works at least with mouse driver */
> @@ -453,6 +463,7 @@ static int usb_hub_configure(struct usb_device *dev)
>  						"re-enabling...\n", i + 1);
>  					usb_hub_port_connect_change(dev, i);
>  			}
> +#endif
>  		}
>  		if (portstatus & USB_PORT_STAT_SUSPEND) {
>  			USB_HUB_PRINTF("port %d suspend change\n", i + 1);

[...]

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

* [U-Boot] [PATCH v4 03/16] i2c: add Faraday FTI2C010 I2C controller support
  2013-05-07 13:19             ` Heiko Schocher
@ 2013-05-08  1:51               ` Kuo-Jung Su
  2013-05-08  4:30                 ` Heiko Schocher
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-08  1:51 UTC (permalink / raw)
  To: u-boot

2013/5/7 Heiko Schocher <hs@denx.de>:
> Hello Kuo-Jung,
>
> Am 07.05.2013 08:32, schrieb Kuo-Jung Su:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday FTI2C010 is a multi-function I2C controller
>> which supports both master and slave mode.
>> This patch simplily implements the master mode only.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Heiko Schocher <hs@denx.de>
>> ---
>> Changes for v4:
>>    - Coding Style cleanup.
>>    - Make it a separate patch, rather then a part of
>>      Faraday A36x patch series
>>    - Use macro constants for timeout control
>>
>> Changes for v3:
>>    - Coding Style cleanup.
>>    - Drop macros for wirtel()/readl(), call them directly.
>>    - Always insert a blank line between declarations and code.
>>    - Replace all the infinite wait loop with a timeout.
>>    - Add '__iomem' to all the declaration of HW register pointers.
>>
>> Changes for v2:
>>    - Coding Style cleanup.
>>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>>    - Use structure based hardware registers to replace the macro constants.
>>    - Replace BIT() with BIT_MASK().
>>
>>  drivers/i2c/Makefile   |    1 +
>>  drivers/i2c/fti2c010.c |  371 ++++++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/i2c/fti2c010.h |   81 +++++++++++
>>  3 files changed, 453 insertions(+)
>>  create mode 100644 drivers/i2c/fti2c010.c
>>  create mode 100644 drivers/i2c/fti2c010.h
>
> As I posted the new i2c multibus/multiadapter framework:
>
> http://lists.denx.de/pipermail/u-boot/2013-May/153452.html
>
> maybe it is possible you can adapt your i2c driver based on
> this patches?
>

Sure, why not?
But it looks to me that the new i2c framework has not yet committed
into the mainline u-boot git repository, so I'll only update the fti2c010 driver
and postpone the board related stuff until the new i2c framework get accepted.

>> diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
>> index 5dbdbe3..ed2b8c0 100644
>> --- a/drivers/i2c/Makefile
>> +++ b/drivers/i2c/Makefile
>> @@ -29,6 +29,7 @@ COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
>>  COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
>>  COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
>>  COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
>> +COBJS-$(CONFIG_FTI2C010) += fti2c010.o
>
> For the new framework this should be something like
> CONFIG_SYS_I2C_FTI2C010 ... and as I think, this
> name would be good also for the old framework.
>

Got it, thanks

>>  COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
>>  COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
>>  COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
> [...]
>
> Rest of your patch looks good to me ...
>

I think it would be better to update the 'CONFIG_HARD_I2C' ifdef statement
of the fti2c010 as bellow:

#if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_HARD_I2C)
#error "fti2c010: either CONFIG_SYS_I2C or CONFIG_HARD_I2C would be defined"
#endif

> bye,
> Heiko
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-07 21:42               ` Marek Vasut
@ 2013-05-08  2:18                 ` Kuo-Jung Su
  2013-05-08  3:09                   ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-08  2:18 UTC (permalink / raw)
  To: u-boot

2013/5/8 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch add supports to both Faraday FUSBH200 and FOTG210,
>> the differences between Faraday EHCI and standard EHCI as
>> listed bellow:
>>
>> 1. The PORTSC starts at 0x30 instead of 0x44.
>> 2. The CONFIGFLAG(0x40) is not only un-implemented, and
>>    also has its address removed.
>> 3. Faraday EHCI is a TDI design, but it doesn't
>>    compatible with the general TDI implementation
>>    found at both U-Boot and Linux.
>> 4. The ISOC descriptors differs from standard EHCI in
>>    several ways. Since U-boot doesn't support ISOC,
>>    we don't have to worry that.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>> Changes for v4:
>>    - Use only macro constants and named bit/mask
>>    - Use weak-aliased functions for tdi implementation and
>>      also portsc registers to avoid poluting ehci.h with ifdefs
>>
>> Changes for v3:
>>    - Coding Style cleanup.
>>    - Drop bit fields from c struct.
>>    - Drop macros for wirtel()/readl(), call them directly.
>>    - Always insert a blank line between declarations and code.
>>    - Replace all the infinite wait loop with a timeout.
>>    - Add '__iomem' to all the declaration of HW register pointers.
>>
>> Changes for v2:
>>    - Coding Style cleanup.
>>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>>    - Use structure based hardware registers to replace the macro constants.
>>    - Replace BIT() with BIT_MASK().
>>    - echi-faraday: Remove debug codes.
>>
>>  common/usb_hub.c                |   13 +-
>>  drivers/usb/host/Makefile       |    1 +
>>  drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
>>  drivers/usb/host/ehci-hcd.c     |  104 ++++++++----
>>  include/usb/fotg210.h           |  358
>> +++++++++++++++++++++++++++++++++++++++ include/usb/fusbh200.h          |
>>  61 +++++++
>>  6 files changed, 646 insertions(+), 37 deletions(-)
>>  create mode 100644 drivers/usb/host/ehci-faraday.c
>>  create mode 100644 include/usb/fotg210.h
>>  create mode 100644 include/usb/fusbh200.h
>>
>> diff --git a/common/usb_hub.c b/common/usb_hub.c
>> index b5eeb62..3c6cb69 100644
>
> Please split the EHCI changes from this patch.
>

Got it, thanks

>> --- a/common/usb_hub.c
>> +++ b/common/usb_hub.c
>> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device *dev)
>>                       portstatus = le16_to_cpu(portsts->wPortStatus);
>>                       portchange = le16_to_cpu(portsts->wPortChange);
>>
>> +#ifdef CONFIG_USB_EHCI_FARADAY
>> +                     /* Faraday EHCI needs a long long delay here */
>> +                     if (!portchange && !portstatus) {
>> +                             if (get_timer(start) < 250)
>> +                                     continue;
>> +                     }
>> +#endif
>
> I'd say just call a weak function here, in case some other non-EHCI compliant
> controller happened to need this too. btw. does it need to be 250 ms or can you
> poll for readiness somehow ?
>

Got it, thanks. I'll add a weak function later,
and about the 250 ms is actually an estimated value.
The delay time is actually board specific, it looks to me
that it's somehow related to the number of usb host controllers
and the attached usb flash drivers.

For example:

1.  A369 - FUSBH200: a usb flash driver attached
     A369 - FOTG210: nothing attached
=> no extra delay required.

2.  A369 - FUSBH200: nothing attached
     A369 - FOTG210: a usb flash driver attached
=> no extra delay required.

3. A369 - FUSBH200: a usb flash driver attached
    A369 - FOTG210: a usb flash driver attached
=> The 2nd ehci host requires 200 ms extra delay to detect the attached device.
     So I put a 250ms here for safe.

>>                       if ((portchange & USB_PORT_STAT_C_CONNECTION) ==
>>                               (portstatus & USB_PORT_STAT_CONNECTION))
>>                               break;
>> @@ -441,7 +449,9 @@ static int usb_hub_configure(struct usb_device *dev)
>>                                       i + 1, portstatus);
>>                       usb_clear_port_feature(dev, i + 1,
>>                                               USB_PORT_FEAT_C_ENABLE);
>> -
>> +                     /* The following hack causes a ghost device problem
>> +                      * to Faraday EHCI */
>
> Invalid multiline comment style (not that the one right below is a shining
> example of a valid one :-( ).
>
> /*
>  * This is how you
>  * do multiline comments.
>  */
>

Got it, thanks!

>> +#ifndef CONFIG_USB_EHCI_FARADAY
>>                       /* EM interference sometimes causes bad shielded USB
>>                        * devices to be shutdown by the hub, this hack enables
>>                        * them again. Works at least with mouse driver */
>> @@ -453,6 +463,7 @@ static int usb_hub_configure(struct usb_device *dev)
>>                                               "re-enabling...\n", i + 1);
>>                                       usb_hub_port_connect_change(dev, i);
>>                       }
>> +#endif
>>               }
>>               if (portstatus & USB_PORT_STAT_SUSPEND) {
>>                       USB_HUB_PRINTF("port %d suspend change\n", i + 1);
>
> [...]



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 2/2] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-07 21:37               ` Marek Vasut
@ 2013-05-08  2:30                 ` Kuo-Jung Su
  2013-05-08  3:07                   ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-08  2:30 UTC (permalink / raw)
  To: u-boot

2013/5/8 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> The Faraday FOTG210 is an OTG chip which could operate
>> as either an EHCI Host or a USB Device as a time.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>> Changes for v4:
>>    - Use only macro constants and named bit/mask
>>    - Remove dcache_enable() from usb_gadget_register_driver()
>>
>> Changes for v3:
>>    - Coding Style cleanup.
>>    - Drop bit fields from c struct.
>>    - Drop macros for wirtel()/readl(), call them directly.
>>    - Always insert a blank line between declarations and code.
>>    - Replace all the infinite wait loop with a timeout.
>>    - Add '__iomem' to all the declaration of HW register pointers.
>>
>> Changes for v2:
>>    - Coding Style cleanup.
>>    - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>>    - Use structure based hardware registers to replace the macro constants.
>>    - Replace BIT() with BIT_MASK().
>>    - echi-faraday: Remove debug codes.
>>
>>  drivers/usb/gadget/Makefile       |    1 +
>>  drivers/usb/gadget/fotg210.c      |  961
>> +++++++++++++++++++++++++++++++++++++ drivers/usb/gadget/gadget_chips.h |
>>   8 +
>>  3 files changed, 970 insertions(+)
>>  create mode 100644 drivers/usb/gadget/fotg210.c
>>
>> diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
>> index e545b6b..432cf17 100644
>> --- a/drivers/usb/gadget/Makefile
>> +++ b/drivers/usb/gadget/Makefile
>> @@ -35,6 +35,7 @@ endif
>>  # new USB gadget layer dependencies
>>  ifdef CONFIG_USB_GADGET
>>  COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
>> +COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
>>  COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
>>  COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
>>  endif
>> diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
>> new file mode 100644
>> index 0000000..70797ae
>> --- /dev/null
>> +++ b/drivers/usb/gadget/fotg210.c
>> @@ -0,0 +1,961 @@
>> +/*
>> + * Faraday USB 2.0 OTG Controller
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for
>> details. + */
>> +
>> +#include <common.h>
>> +#include <command.h>
>> +#include <config.h>
>> +#include <net.h>
>> +#include <malloc.h>
>> +#include <asm/io.h>
>> +#include <asm/errno.h>
>> +#include <linux/types.h>
>> +#include <linux/usb/ch9.h>
>> +#include <linux/usb/gadget.h>
>> +
>> +#include <usb/fotg210.h>
>> +
>> +#define CFG_NUM_ENDPOINTS            4
>> +#define CFG_EP0_MAX_PACKET_SIZE      64
>> +#define CFG_EPX_MAX_PACKET_SIZE      512
>> +
>> +#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
>> +#define CFG_RST_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
>
> Uh, how's this supposed to work? Why don't you just use mdelay(250) with those?
>

1. The CFG_CMD_TIMEOUT is used for polling dma or ep0 fifo ready,
    put a permanent delay (i.e. mdelay()) here would slow down the
    overall performance.

2. The CFG_RST_TIMEOUT is used for polling chip reset or fifo reset.
    It's definitely O.K to replace it with a permanent delay, so I'll
do it later

> [...]
>
>> +static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
>> +{
>> +     int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
>> +     struct fotg210_regs __iomem *regs = chip->regs;
>
> No need for __iomem here.
>

Got it, thanks

> [...]
>
>> +     /* 3. DMA target setup */
>> +#ifndef CONFIG_SYS_DCACHE_OFF
>> +     if (ep->desc->bEndpointAddress & USB_DIR_IN)
>> +             flush_dcache_range((uint32_t)buf, (uint32_t)buf + len);
>> +     else
>> +             invalidate_dcache_range((uint32_t)buf, (uint32_t)buf + len);
>> +#endif
>
> The cache stuff will be optimized out anyway, no ?
>

That's right, I'll have the #ifdef statement removed later

> [...]
>
>> +                     if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
>> +                             puts("fotg210: HS\n");
>> +                             chip->gadget.speed = USB_SPEED_HIGH;
>> +                             writel(0x044c, &regs->sof_mtr);
>> +                     } else {
>> +                             puts("fotg210: FS\n");
>> +                             chip->gadget.speed = USB_SPEED_FULL;
>> +                             writel(0x2710, &regs->sof_mtr);
>
> Magic values, please fix globally as previously asked.
>

Sorry, I forget to fix this one.

> [...]
>



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 2/2] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-08  2:30                 ` Kuo-Jung Su
@ 2013-05-08  3:07                   ` Marek Vasut
  0 siblings, 0 replies; 311+ messages in thread
From: Marek Vasut @ 2013-05-08  3:07 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

[...]

> > Uh, how's this supposed to work? Why don't you just use mdelay(250) with
> > those?
> 
> 1. The CFG_CMD_TIMEOUT is used for polling dma or ep0 fifo ready,
>     put a permanent delay (i.e. mdelay()) here would slow down the
>     overall performance.

Understood

> 2. The CFG_RST_TIMEOUT is used for polling chip reset or fifo reset.
>     It's definitely O.K to replace it with a permanent delay, so I'll
> do it later

Agreed,  nice to see we're getting real close with this patchset.

[...]

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-08  2:18                 ` Kuo-Jung Su
@ 2013-05-08  3:09                   ` Marek Vasut
  2013-05-08  5:41                     ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-08  3:09 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

[...]

> >> --- a/common/usb_hub.c
> >> +++ b/common/usb_hub.c
> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
> >> *dev)
> >> 
> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
> >>                       portchange = le16_to_cpu(portsts->wPortChange);
> >> 
> >> +#ifdef CONFIG_USB_EHCI_FARADAY
> >> +                     /* Faraday EHCI needs a long long delay here */
> >> +                     if (!portchange && !portstatus) {
> >> +                             if (get_timer(start) < 250)
> >> +                                     continue;
> >> +                     }
> >> +#endif
> > 
> > I'd say just call a weak function here, in case some other non-EHCI
> > compliant controller happened to need this too. btw. does it need to be
> > 250 ms or can you poll for readiness somehow ?
> 
> Got it, thanks. I'll add a weak function later,
> and about the 250 ms is actually an estimated value.
> The delay time is actually board specific, it looks to me
> that it's somehow related to the number of usb host controllers
> and the attached usb flash drivers.
> 
> For example:
> 
> 1.  A369 - FUSBH200: a usb flash driver attached
>      A369 - FOTG210: nothing attached
> => no extra delay required.
> 
> 2.  A369 - FUSBH200: nothing attached
>      A369 - FOTG210: a usb flash driver attached
> => no extra delay required.
> 
> 3. A369 - FUSBH200: a usb flash driver attached
>     A369 - FOTG210: a usb flash driver attached
> => The 2nd ehci host requires 200 ms extra delay to detect the attached
> device. So I put a 250ms here for safe.

Urgh, isn't it a PHY problem then? Or can this not be solved like 
board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such 
function?

[...]

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v4 03/16] i2c: add Faraday FTI2C010 I2C controller support
  2013-05-08  1:51               ` Kuo-Jung Su
@ 2013-05-08  4:30                 ` Heiko Schocher
  2013-05-08  5:47                   ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Heiko Schocher @ 2013-05-08  4:30 UTC (permalink / raw)
  To: u-boot

Hello Kuo-Jung,

Am 08.05.2013 03:51, schrieb Kuo-Jung Su:
> 2013/5/7 Heiko Schocher <hs@denx.de>:
>> Hello Kuo-Jung,
>>
>> Am 07.05.2013 08:32, schrieb Kuo-Jung Su:
>>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>
>>> Faraday FTI2C010 is a multi-function I2C controller
>>> which supports both master and slave mode.
>>> This patch simplily implements the master mode only.
>>>
>>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>> CC: Heiko Schocher <hs@denx.de>
>>> ---
[...]
>>>  drivers/i2c/Makefile   |    1 +
>>>  drivers/i2c/fti2c010.c |  371 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>  drivers/i2c/fti2c010.h |   81 +++++++++++
>>>  3 files changed, 453 insertions(+)
>>>  create mode 100644 drivers/i2c/fti2c010.c
>>>  create mode 100644 drivers/i2c/fti2c010.h
>>
>> As I posted the new i2c multibus/multiadapter framework:
>>
>> http://lists.denx.de/pipermail/u-boot/2013-May/153452.html
>>
>> maybe it is possible you can adapt your i2c driver based on
>> this patches?
>>
> 
> Sure, why not?
> But it looks to me that the new i2c framework has not yet committed
> into the mainline u-boot git repository, so I'll only update the fti2c010 driver
> and postpone the board related stuff until the new i2c framework get accepted.

Ok, thanks! Hope to get the new framework ASAP into mainline.

[...]

>>>  COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
>>>  COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
>>>  COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
>> [...]
>>
>> Rest of your patch looks good to me ...
>>
> 
> I think it would be better to update the 'CONFIG_HARD_I2C' ifdef statement
> of the fti2c010 as bellow:
> 
> #if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_HARD_I2C)
> #error "fti2c010: either CONFIG_SYS_I2C or CONFIG_HARD_I2C would be defined"
> #endif

No! If you convert to the new i2c framework, you not longer need
the old (CONFIG_HARD_I2C) style. If all i2c drivers are ported to
the new framework, CONFIG_HARD_I2C will be dropped. So please delete
the CONFIG_HARD_I2C define completely when switching to the new
framework. Also the CONFIG_I2C_MULTI_BUS define is no longer needed.

bye,
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

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

* [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-08  3:09                   ` Marek Vasut
@ 2013-05-08  5:41                     ` Kuo-Jung Su
  2013-05-08 11:52                       ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-08  5:41 UTC (permalink / raw)
  To: u-boot

2013/5/8 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
> [...]
>
>> >> --- a/common/usb_hub.c
>> >> +++ b/common/usb_hub.c
>> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
>> >> *dev)
>> >>
>> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
>> >>                       portchange = le16_to_cpu(portsts->wPortChange);
>> >>
>> >> +#ifdef CONFIG_USB_EHCI_FARADAY
>> >> +                     /* Faraday EHCI needs a long long delay here */
>> >> +                     if (!portchange && !portstatus) {
>> >> +                             if (get_timer(start) < 250)
>> >> +                                     continue;
>> >> +                     }
>> >> +#endif
>> >
>> > I'd say just call a weak function here, in case some other non-EHCI
>> > compliant controller happened to need this too. btw. does it need to be
>> > 250 ms or can you poll for readiness somehow ?
>>
>> Got it, thanks. I'll add a weak function later,
>> and about the 250 ms is actually an estimated value.
>> The delay time is actually board specific, it looks to me
>> that it's somehow related to the number of usb host controllers
>> and the attached usb flash drivers.
>>
>> For example:
>>
>> 1.  A369 - FUSBH200: a usb flash driver attached
>>      A369 - FOTG210: nothing attached
>> => no extra delay required.
>>
>> 2.  A369 - FUSBH200: nothing attached
>>      A369 - FOTG210: a usb flash driver attached
>> => no extra delay required.
>>
>> 3. A369 - FUSBH200: a usb flash driver attached
>>     A369 - FOTG210: a usb flash driver attached
>> => The 2nd ehci host requires 200 ms extra delay to detect the attached
>> device. So I put a 250ms here for safe.
>
> Urgh, isn't it a PHY problem then? Or can this not be solved like
> board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such
> function?
>

It looks to me that it's something related to root hub reset.
And now I've found that adding a extra delay to usb_hub_power_on()
would help to resolve this issue.
So I plan to add a new macro constant for it.
For example:

1. Add this to README:
CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
interval for usb hub power-on delay.(minimum 100msec)

2. Update usb_hub.c as bellow:
static void usb_hub_power_on(struct usb_hub_device *hub)
{
......
    /* Wait at least 100 msec for power to become stable */
    mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
}

> [...]
>
> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 03/16] i2c: add Faraday FTI2C010 I2C controller support
  2013-05-08  4:30                 ` Heiko Schocher
@ 2013-05-08  5:47                   ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-08  5:47 UTC (permalink / raw)
  To: u-boot

2013/5/8 Heiko Schocher <hs@denx.de>:
> Hello Kuo-Jung,
>
> Am 08.05.2013 03:51, schrieb Kuo-Jung Su:
>> 2013/5/7 Heiko Schocher <hs@denx.de>:
>>> Hello Kuo-Jung,
>>>
>>> Am 07.05.2013 08:32, schrieb Kuo-Jung Su:
>>>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>>
>>>> Faraday FTI2C010 is a multi-function I2C controller
>>>> which supports both master and slave mode.
>>>> This patch simplily implements the master mode only.
>>>>
>>>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>> CC: Heiko Schocher <hs@denx.de>
>>>> ---
> [...]
>>>>  drivers/i2c/Makefile   |    1 +
>>>>  drivers/i2c/fti2c010.c |  371 ++++++++++++++++++++++++++++++++++++++++++++++++
>>>>  drivers/i2c/fti2c010.h |   81 +++++++++++
>>>>  3 files changed, 453 insertions(+)
>>>>  create mode 100644 drivers/i2c/fti2c010.c
>>>>  create mode 100644 drivers/i2c/fti2c010.h
>>>
>>> As I posted the new i2c multibus/multiadapter framework:
>>>
>>> http://lists.denx.de/pipermail/u-boot/2013-May/153452.html
>>>
>>> maybe it is possible you can adapt your i2c driver based on
>>> this patches?
>>>
>>
>> Sure, why not?
>> But it looks to me that the new i2c framework has not yet committed
>> into the mainline u-boot git repository, so I'll only update the fti2c010 driver
>> and postpone the board related stuff until the new i2c framework get accepted.
>
> Ok, thanks! Hope to get the new framework ASAP into mainline.
>
> [...]
>
>>>>  COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
>>>>  COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
>>>>  COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
>>> [...]
>>>
>>> Rest of your patch looks good to me ...
>>>
>>
>> I think it would be better to update the 'CONFIG_HARD_I2C' ifdef statement
>> of the fti2c010 as bellow:
>>
>> #if !defined(CONFIG_SYS_I2C) && !defined(CONFIG_HARD_I2C)
>> #error "fti2c010: either CONFIG_SYS_I2C or CONFIG_HARD_I2C would be defined"
>> #endif
>
> No! If you convert to the new i2c framework, you not longer need
> the old (CONFIG_HARD_I2C) style. If all i2c drivers are ported to
> the new framework, CONFIG_HARD_I2C will be dropped. So please delete
> the CONFIG_HARD_I2C define completely when switching to the new
> framework. Also the CONFIG_I2C_MULTI_BUS define is no longer needed.
>

Got it, thanks.
So I'll leave the CONFIG_HARD_I2C & CONFIG_I2C_MULTI_BUS ifdef statement
untouched until the new i2c framework get accepted.

> bye,
> Heiko
> --
> DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v5] i2c: add Faraday FTI2C010 I2C controller support
  2013-05-07  6:32           ` [U-Boot] [PATCH v4 03/16] " Kuo-Jung Su
  2013-05-07 13:19             ` Heiko Schocher
@ 2013-05-08  7:36             ` Kuo-Jung Su
  1 sibling, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-08  7:36 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTI2C010 is a multi-function I2C controller
which supports both master and slave mode.
This patch simplily implements the master mode only.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Heiko Schocher <hs@denx.de>
---
Changes for v5:
   - Coding Style cleanup.
   - Use CONFIG_SYS_I2C_SPEED for default speed.
   - Put a permanent 100 ms delay to chip reset.
   - Makefile: CONFIG_FTI2C010 -> CONFIG_SYS_I2C_FTI2C010

Changes for v4:
   - Coding Style cleanup.
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 drivers/i2c/Makefile   |    1 +
 drivers/i2c/fti2c010.c |  369 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/i2c/fti2c010.h |   81 +++++++++++
 3 files changed, 451 insertions(+)
 create mode 100644 drivers/i2c/fti2c010.c
 create mode 100644 drivers/i2c/fti2c010.h

diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 5dbdbe3..9654607 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -29,6 +29,7 @@ COBJS-$(CONFIG_BFIN_TWI_I2C) += bfin-twi_i2c.o
 COBJS-$(CONFIG_DRIVER_DAVINCI_I2C) += davinci_i2c.o
 COBJS-$(CONFIG_DW_I2C) += designware_i2c.o
 COBJS-$(CONFIG_FSL_I2C) += fsl_i2c.o
+COBJS-$(CONFIG_SYS_I2C_FTI2C010) += fti2c010.o
 COBJS-$(CONFIG_I2C_MVTWSI) += mvtwsi.o
 COBJS-$(CONFIG_I2C_MV) += mv_i2c.o
 COBJS-$(CONFIG_I2C_MXC) += mxc_i2c.o
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
new file mode 100644
index 0000000..f639854
--- /dev/null
+++ b/drivers/i2c/fti2c010.c
@@ -0,0 +1,369 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <i2c.h>
+
+#include "fti2c010.h"
+
+#ifndef CONFIG_HARD_I2C
+#error "fti2c010: CONFIG_HARD_I2C is not defined"
+#endif
+
+#ifndef CONFIG_SYS_I2C_SPEED
+#define CONFIG_SYS_I2C_SPEED    50000
+#endif
+
+#ifndef CONFIG_FTI2C010_FREQ
+#define CONFIG_FTI2C010_FREQ    clk_get_rate("I2C")
+#endif
+
+/* command timeout */
+#define CFG_CMD_TIMEOUT         10 /* ms */
+
+/* 7-bit chip address + 1-bit read/write */
+#define I2C_RD(chip)            ((((chip) << 1) & 0xff) | 1)
+#define I2C_WR(chip)            (((chip) << 1) & 0xff)
+
+struct fti2c010_chip {
+	void __iomem *regs;
+	uint bus;
+	uint speed;
+};
+
+static struct fti2c010_chip chip_list[] = {
+	{
+		.bus  = 0,
+		.regs = (void __iomem *)CONFIG_FTI2C010_BASE,
+	},
+#ifdef CONFIG_I2C_MULTI_BUS
+# ifdef CONFIG_FTI2C010_BASE1
+	{
+		.bus  = 1,
+		.regs = (void __iomem *)CONFIG_FTI2C010_BASE1,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE2
+	{
+		.bus  = 2,
+		.regs = (void __iomem *)CONFIG_FTI2C010_BASE2,
+	},
+# endif
+# ifdef CONFIG_FTI2C010_BASE3
+	{
+		.bus  = 3,
+		.regs = (void __iomem *)CONFIG_FTI2C010_BASE3,
+	},
+# endif
+#endif  /* #ifdef CONFIG_I2C_MULTI_BUS */
+};
+
+static struct fti2c010_chip *curr = chip_list;
+
+static int fti2c010_wait(uint32_t mask)
+{
+	int ret = -1;
+	uint32_t stat, ts;
+	struct fti2c010_regs *regs = curr->regs;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		stat = readl(&regs->sr);
+		if ((stat & mask) == mask) {
+			ret = 0;
+			break;
+		}
+	}
+
+	return ret;
+}
+
+/*
+ * u-boot I2C API
+ */
+
+/*
+ * Initialization, must be called once on start up, may be called
+ * repeatedly to change the speed and slave addresses.
+ */
+void i2c_init(int speed, int slaveaddr)
+{
+	if (speed || !curr->speed)
+		i2c_set_bus_speed(speed);
+
+	/* if slave mode disabled */
+	if (!slaveaddr)
+		return;
+
+	/*
+	 * TODO:
+	 * Implement slave mode, but is it really necessary?
+	 */
+}
+
+/*
+ * Probe the given I2C chip address.  Returns 0 if a chip responded,
+ * not 0 on failure.
+ */
+int i2c_probe(uchar chip)
+{
+	int ret;
+	struct fti2c010_regs *regs = curr->regs;
+
+	i2c_init(0, 0);
+
+	/* 1. Select slave device (7bits Address + 1bit R/W) */
+	writel(I2C_WR(chip), &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	ret = fti2c010_wait(SR_DT);
+	if (ret)
+		return ret;
+
+	/* 2. Select device register */
+	writel(0, &regs->dr);
+	writel(CR_ENABLE | CR_TBEN, &regs->cr);
+	ret = fti2c010_wait(SR_DT);
+
+	return ret;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_read(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int ret, pos;
+	uchar paddr[4];
+	struct fti2c010_regs *regs = curr->regs;
+
+	i2c_init(0, 0);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 */
+
+	/* A.1 Select slave device (7bits Address + 1bit R/W) */
+	writel(I2C_WR(chip), &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	ret = fti2c010_wait(SR_DT);
+	if (ret)
+		return ret;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+		writel(paddr[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		ret = fti2c010_wait(SR_DT);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Phase B. Get register data
+	 */
+
+	/* B.1 Select slave device (7bits Address + 1bit R/W) */
+	writel(I2C_RD(chip), &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	ret = fti2c010_wait(SR_DT);
+	if (ret)
+		return ret;
+
+	/* B.2 Get register data */
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+		uint32_t stat = SR_DR;
+
+		if (pos == len - 1) {
+			ctrl |= CR_NAK | CR_STOP;
+			stat |= SR_ACK;
+		}
+		writel(ctrl, &regs->cr);
+		ret = fti2c010_wait(stat);
+		if (ret)
+			break;
+		buf[pos] = (uchar)(readl(&regs->dr) & 0xFF);
+	}
+
+	return ret;
+}
+
+/*
+ * Read/Write interface:
+ *   chip:    I2C chip address, range 0..127
+ *   addr:    Memory (register) address within the chip
+ *   alen:    Number of bytes to use for addr (typically 1, 2 for larger
+ *              memories, 0 for register type devices with only one
+ *              register)
+ *   buffer:  Where to read/write the data
+ *   len:     How many bytes to read/write
+ *
+ *   Returns: 0 on success, not 0 on failure
+ */
+int i2c_write(uchar chip, uint addr, int alen, uchar *buf, int len)
+{
+	int ret, pos;
+	uchar paddr[4];
+	struct fti2c010_regs *regs = curr->regs;
+
+	i2c_init(0, 0);
+
+	paddr[0] = (addr >> 0)  & 0xFF;
+	paddr[1] = (addr >> 8)  & 0xFF;
+	paddr[2] = (addr >> 16) & 0xFF;
+	paddr[3] = (addr >> 24) & 0xFF;
+
+	/*
+	 * Phase A. Set register address
+	 *
+	 * A.1 Select slave device (7bits Address + 1bit R/W)
+	 */
+	writel(I2C_WR(chip), &regs->dr);
+	writel(CR_ENABLE | CR_TBEN | CR_START, &regs->cr);
+	ret = fti2c010_wait(SR_DT);
+	if (ret)
+		return ret;
+
+	/* A.2 Select device register */
+	for (pos = 0; pos < alen; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+		writel(paddr[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		ret = fti2c010_wait(SR_DT);
+		if (ret)
+			return ret;
+	}
+
+	/*
+	 * Phase B. Set register data
+	 */
+	for (pos = 0; pos < len; ++pos) {
+		uint32_t ctrl = CR_ENABLE | CR_TBEN;
+
+		if (pos == len - 1)
+			ctrl |= CR_STOP;
+		writel(buf[pos], &regs->dr);
+		writel(ctrl, &regs->cr);
+		ret = fti2c010_wait(SR_DT);
+		if (ret)
+			break;
+	}
+
+	return ret;
+}
+
+/*
+ * Functions for setting the current I2C bus and its speed
+ */
+#ifdef CONFIG_I2C_MULTI_BUS
+
+/*
+ * i2c_set_bus_num:
+ *
+ *  Change the active I2C bus.  Subsequent read/write calls will
+ *  go to this one.
+ *
+ *    bus - bus index, zero based
+ *
+ *    Returns: 0 on success, not 0 on failure
+ */
+int i2c_set_bus_num(uint bus)
+{
+	if (bus >= ARRAY_SIZE(chip_list))
+		return -1;
+	curr = chip_list + bus;
+	i2c_init(0, 0);
+	return 0;
+}
+
+/*
+ * i2c_get_bus_num:
+ *
+ *  Returns index of currently active I2C bus.  Zero-based.
+ */
+
+uint i2c_get_bus_num(void)
+{
+	return curr->bus;
+}
+
+#endif    /* #ifdef CONFIG_I2C_MULTI_BUS */
+
+/*
+ * i2c_set_bus_speed:
+ *
+ *  Change the speed of the active I2C bus
+ *
+ *    speed - bus speed in Hz
+ *
+ *    Returns: 0 on success, not 0 on failure
+ */
+int i2c_set_bus_speed(uint speed)
+{
+	struct fti2c010_regs *regs = curr->regs;
+	uint clk = CONFIG_FTI2C010_FREQ;
+	uint gsr = 0, tsr = 32;
+	uint spd, div;
+
+	if (!speed)
+		speed = CONFIG_SYS_I2C_SPEED;
+
+	for (div = 0; div < 0x3ffff; ++div) {
+		/* SCLout = PCLK/(2*(COUNT + 2) + GSR) */
+		spd = clk / (2 * (div + 2) + gsr);
+		if (spd <= speed)
+			break;
+	}
+
+	if (curr->speed == spd)
+		return 0;
+
+	writel(CR_I2CRST, &regs->cr);
+	mdelay(100);
+	if (readl(&regs->cr) & CR_I2CRST) {
+		printf("fti2c010: reset timeout\n");
+		return -1;
+	}
+
+	curr->speed = spd;
+
+	writel(TGSR_GSR(gsr) | TGSR_TSR(tsr), &regs->tgsr);
+	writel(CDR_DIV(div), &regs->cdr);
+
+	return 0;
+}
+
+/*
+ * i2c_get_bus_speed:
+ *
+ *  Returns speed of currently active I2C bus in Hz
+ */
+
+uint i2c_get_bus_speed(void)
+{
+	return curr->speed;
+}
diff --git a/drivers/i2c/fti2c010.h b/drivers/i2c/fti2c010.h
new file mode 100644
index 0000000..18aec2c
--- /dev/null
+++ b/drivers/i2c/fti2c010.h
@@ -0,0 +1,81 @@
+/*
+ * Faraday I2C Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTI2C010_H
+#define __FTI2C010_H
+
+/*
+ * FTI2C010 registers
+ */
+struct fti2c010_regs {
+	uint32_t cr;  /* 0x00: control register */
+	uint32_t sr;  /* 0x04: status register */
+	uint32_t cdr; /* 0x08: clock division register */
+	uint32_t dr;  /* 0x0c: data register */
+	uint32_t sar; /* 0x10: slave address register */
+	uint32_t tgsr;/* 0x14: time & glitch suppression register */
+	uint32_t bmr; /* 0x18: bus monitor register */
+	uint32_t rsvd[5];
+	uint32_t revr;/* 0x30: revision register */
+};
+
+/*
+ * control register
+ */
+#define CR_ALIRQ      0x2000  /* arbitration lost interrupt (master) */
+#define CR_SAMIRQ     0x1000  /* slave address match interrupt (slave) */
+#define CR_STOPIRQ    0x800   /* stop condition interrupt (slave) */
+#define CR_NAKRIRQ    0x400   /* NACK response interrupt (master) */
+#define CR_DRIRQ      0x200   /* rx interrupt (both) */
+#define CR_DTIRQ      0x100   /* tx interrupt (both) */
+#define CR_TBEN       0x80    /* tx enable (both) */
+#define CR_NAK        0x40    /* NACK (both) */
+#define CR_STOP       0x20    /* stop (master) */
+#define CR_START      0x10    /* start (master) */
+#define CR_GCEN       0x8     /* general call support (slave) */
+#define CR_SCLEN      0x4     /* enable clock out (master) */
+#define CR_I2CEN      0x2     /* enable I2C (both) */
+#define CR_I2CRST     0x1     /* reset I2C (both) */
+#define CR_ENABLE     \
+	(CR_ALIRQ | CR_NAKRIRQ | CR_DRIRQ | CR_DTIRQ | CR_SCLEN | CR_I2CEN)
+
+/*
+ * status register
+ */
+#define SR_CLRAL      0x400    /* clear arbitration lost */
+#define SR_CLRGC      0x200    /* clear general call */
+#define SR_CLRSAM     0x100    /* clear slave address match */
+#define SR_CLRSTOP    0x80     /* clear stop */
+#define SR_CLRNAKR    0x40     /* clear NACK respond */
+#define SR_DR         0x20     /* rx ready */
+#define SR_DT         0x10     /* tx done */
+#define SR_BB         0x8      /* bus busy */
+#define SR_BUSY       0x4      /* chip busy */
+#define SR_ACK        0x2      /* ACK/NACK received */
+#define SR_RW         0x1      /* set when master-rx or slave-tx mode */
+
+/*
+ * clock division register
+ */
+#define CDR_DIV(n)    ((n) & 0x3ffff)
+
+/*
+ * time & glitch suppression register
+ */
+#define TGSR_GSR(n)   (((n) & 0x7) << 10)
+#define TGSR_TSR(n)   ((n) & 0x3ff)
+
+/*
+ * bus monitor register
+ */
+#define BMR_SCL       0x2      /* SCL is pull-up */
+#define BMR_SDA       0x1      /* SDA is pull-up */
+
+#endif /* __FTI2C010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-08  5:41                     ` Kuo-Jung Su
@ 2013-05-08 11:52                       ` Marek Vasut
  2013-05-09  1:51                         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-08 11:52 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> 2013/5/8 Marek Vasut <marex@denx.de>:
> > Dear Kuo-Jung Su,
> > 
> > [...]
> > 
> >> >> --- a/common/usb_hub.c
> >> >> +++ b/common/usb_hub.c
> >> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
> >> >> *dev)
> >> >> 
> >> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
> >> >>                       portchange = le16_to_cpu(portsts->wPortChange);
> >> >> 
> >> >> +#ifdef CONFIG_USB_EHCI_FARADAY
> >> >> +                     /* Faraday EHCI needs a long long delay here */
> >> >> +                     if (!portchange && !portstatus) {
> >> >> +                             if (get_timer(start) < 250)
> >> >> +                                     continue;
> >> >> +                     }
> >> >> +#endif
> >> > 
> >> > I'd say just call a weak function here, in case some other non-EHCI
> >> > compliant controller happened to need this too. btw. does it need to
> >> > be 250 ms or can you poll for readiness somehow ?
> >> 
> >> Got it, thanks. I'll add a weak function later,
> >> and about the 250 ms is actually an estimated value.
> >> The delay time is actually board specific, it looks to me
> >> that it's somehow related to the number of usb host controllers
> >> and the attached usb flash drivers.
> >> 
> >> For example:
> >> 
> >> 1.  A369 - FUSBH200: a usb flash driver attached
> >> 
> >>      A369 - FOTG210: nothing attached
> >> 
> >> => no extra delay required.
> >> 
> >> 2.  A369 - FUSBH200: nothing attached
> >> 
> >>      A369 - FOTG210: a usb flash driver attached
> >> 
> >> => no extra delay required.
> >> 
> >> 3. A369 - FUSBH200: a usb flash driver attached
> >> 
> >>     A369 - FOTG210: a usb flash driver attached
> >> 
> >> => The 2nd ehci host requires 200 ms extra delay to detect the attached
> >> device. So I put a 250ms here for safe.
> > 
> > Urgh, isn't it a PHY problem then? Or can this not be solved like
> > board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such
> > function?
> 
> It looks to me that it's something related to root hub reset.
> And now I've found that adding a extra delay to usb_hub_power_on()
> would help to resolve this issue.
> So I plan to add a new macro constant for it.
> For example:
> 
> 1. Add this to README:
> CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
> interval for usb hub power-on delay.(minimum 100msec)
> 
> 2. Update usb_hub.c as bellow:
> static void usb_hub_power_on(struct usb_hub_device *hub)
> {
> ......
>     /* Wait at least 100 msec for power to become stable */
>     mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
> }

Let's try it.

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v4] nand: add Faraday FTNANDC021 NAND controller support
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
@ 2013-05-09  0:43             ` Scott Wood
  2013-05-09  1:45               ` Kuo-Jung Su
  2013-05-09  1:51             ` [U-Boot] [PATCH v5] " Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-05-09  0:43 UTC (permalink / raw)
  To: u-boot

On 05/07/2013 01:33:11 AM, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTNANDC021 is a integrated NAND flash controller.
> It use a build-in command table to abstract the underlying
> NAND flash control logic.
> 
> For example:
> 
> Issuing a command 0x10 to FTNANDC021 would result in
> a page write + a read status operation.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Scott Wood <scottwood@freescale.com>

Looks mostly OK, just a couple nits:

> diff --git a/README b/README
> index 0d37d56..883182d 100644
> --- a/README
> +++ b/README
> @@ -3879,6 +3879,10 @@ Low Level (hardware related) configuration  
> options:
>  		- drivers/mtd/nand/ndfc.c
>  		- drivers/mtd/nand/mxc_nand.c
> 
> +- CONFIG_SYS_FTNANDC021_TIMING
> +		Defined to tell the FTNANDC021 controller that the NAND  
> chip is
> +		using customized timing parameters.

This makes it sound like a boolean option, but it's actually an array --
would be nice to mention what's actually expected.

> +	if (mtd->writesize >=  4096) {

Whitespace

-Scott

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

* [U-Boot] [PATCH v4] nand: add Faraday FTNANDC021 NAND controller support
  2013-05-09  0:43             ` Scott Wood
@ 2013-05-09  1:45               ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  1:45 UTC (permalink / raw)
  To: u-boot

2013/5/9 Scott Wood <scottwood@freescale.com>:
> On 05/07/2013 01:33:11 AM, Kuo-Jung Su wrote:
>>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday FTNANDC021 is a integrated NAND flash controller.
>> It use a build-in command table to abstract the underlying
>> NAND flash control logic.
>>
>> For example:
>>
>> Issuing a command 0x10 to FTNANDC021 would result in
>> a page write + a read status operation.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Scott Wood <scottwood@freescale.com>
>
>
> Looks mostly OK, just a couple nits:
>
>
>> diff --git a/README b/README
>> index 0d37d56..883182d 100644
>> --- a/README
>> +++ b/README
>> @@ -3879,6 +3879,10 @@ Low Level (hardware related) configuration options:
>>                 - drivers/mtd/nand/ndfc.c
>>                 - drivers/mtd/nand/mxc_nand.c
>>
>> +- CONFIG_SYS_FTNANDC021_TIMING
>> +               Defined to tell the FTNANDC021 controller that the NAND
>> chip is
>> +               using customized timing parameters.
>
>
> This makes it sound like a boolean option, but it's actually an array --
> would be nice to mention what's actually expected.
>
>

Got it, thanks

>> +       if (mtd->writesize >=  4096) {
>

Got it, thanks

>
> Whitespace
>
> -Scott



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-08 11:52                       ` Marek Vasut
@ 2013-05-09  1:51                         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  1:51 UTC (permalink / raw)
  To: u-boot

2013/5/8 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/5/8 Marek Vasut <marex@denx.de>:
>> > Dear Kuo-Jung Su,
>> >
>> > [...]
>> >
>> >> >> --- a/common/usb_hub.c
>> >> >> +++ b/common/usb_hub.c
>> >> >> @@ -419,6 +419,14 @@ static int usb_hub_configure(struct usb_device
>> >> >> *dev)
>> >> >>
>> >> >>                       portstatus = le16_to_cpu(portsts->wPortStatus);
>> >> >>                       portchange = le16_to_cpu(portsts->wPortChange);
>> >> >>
>> >> >> +#ifdef CONFIG_USB_EHCI_FARADAY
>> >> >> +                     /* Faraday EHCI needs a long long delay here */
>> >> >> +                     if (!portchange && !portstatus) {
>> >> >> +                             if (get_timer(start) < 250)
>> >> >> +                                     continue;
>> >> >> +                     }
>> >> >> +#endif
>> >> >
>> >> > I'd say just call a weak function here, in case some other non-EHCI
>> >> > compliant controller happened to need this too. btw. does it need to
>> >> > be 250 ms or can you poll for readiness somehow ?
>> >>
>> >> Got it, thanks. I'll add a weak function later,
>> >> and about the 250 ms is actually an estimated value.
>> >> The delay time is actually board specific, it looks to me
>> >> that it's somehow related to the number of usb host controllers
>> >> and the attached usb flash drivers.
>> >>
>> >> For example:
>> >>
>> >> 1.  A369 - FUSBH200: a usb flash driver attached
>> >>
>> >>      A369 - FOTG210: nothing attached
>> >>
>> >> => no extra delay required.
>> >>
>> >> 2.  A369 - FUSBH200: nothing attached
>> >>
>> >>      A369 - FOTG210: a usb flash driver attached
>> >>
>> >> => no extra delay required.
>> >>
>> >> 3. A369 - FUSBH200: a usb flash driver attached
>> >>
>> >>     A369 - FOTG210: a usb flash driver attached
>> >>
>> >> => The 2nd ehci host requires 200 ms extra delay to detect the attached
>> >> device. So I put a 250ms here for safe.
>> >
>> > Urgh, isn't it a PHY problem then? Or can this not be solved like
>> > board/genesi/mx51_efikamx/efikamx-usb.c board_ehci_hcd_postinit() or such
>> > function?
>>
>> It looks to me that it's something related to root hub reset.
>> And now I've found that adding a extra delay to usb_hub_power_on()
>> would help to resolve this issue.
>> So I plan to add a new macro constant for it.
>> For example:
>>
>> 1. Add this to README:
>> CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
>> interval for usb hub power-on delay.(minimum 100msec)
>>
>> 2. Update usb_hub.c as bellow:
>> static void usb_hub_power_on(struct usb_hub_device *hub)
>> {
>> ......
>>     /* Wait at least 100 msec for power to become stable */
>>     mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
>> }
>
> Let's try it.
>

Got it, thanks

> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v5] nand: add Faraday FTNANDC021 NAND controller support
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  2013-05-09  0:43             ` Scott Wood
@ 2013-05-09  1:51             ` Kuo-Jung Su
  1 sibling, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  1:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is a integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v5:
   - Update README for the description of CONFIG_SYS_FTNANDC021_TIMING.
   - Drop redundant white space. (i.e. if (mtd->writesize >= ' '4096))

Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Drop the faraday/nand.h to remove dependency to
     Faraday A36x patch series.
   - CONFIG_SYS_NAND_TIMING -> CONFIG_SYS_FTNANDC021_TIMING
   - Remove non-ECC code.
   - Implement private hwecc read/write_page functions
     to get rid of .eccpos & .eccbytes.
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Re-write this driver with ECC enabled and correct column address
     handling for OOB read/write,
   - Fix issuses addressed by Scott.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 README                        |    6 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  607 +++++++++++++++++++++++++++++++++++++++++
 include/faraday/ftnandc021.h  |  146 ++++++++++
 4 files changed, 760 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 include/faraday/ftnandc021.h

diff --git a/README b/README
index 0d37d56..94c15e0 100644
--- a/README
+++ b/README
@@ -3879,6 +3879,12 @@ Low Level (hardware related) configuration options:
 		- drivers/mtd/nand/ndfc.c
 		- drivers/mtd/nand/mxc_nand.c

+- CONFIG_SYS_FTNANDC021_TIMING
+		This option specifies an array of customized timing parameters
+		for Faraday FTNANDC021 NAND flash controller.
+		e.g.
+		#define CONFIG_SYS_FTNANDC021_TIMING { 0x02240264, 0x42054209 }
+
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
 		a default value will be used.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 35769c5..f6f89f0 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -63,6 +63,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..213b67a
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,607 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <nand.h>
+#include <malloc.h>
+
+#include <faraday/ftnandc021.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
+
+struct ftnandc021_chip {
+	void __iomem *regs;
+	int alen;
+	int pgsz;
+	int bksz;
+
+	int col;    /* current column address */
+	int page;   /* current row address/page index */
+	int cmd;    /* current NAND command code */
+	int cmd_hc; /* current FTNANDC021 command code */
+};
+
+static struct nand_ecclayout ftnandc021_ecclayout[] = {
+	{ /* page size = 512 (oob size = 16) */
+		.oobfree = {
+			{ 9, 3 },
+		}
+	},
+	{ /* page size = 2048 (oob size = 64) */
+		.oobfree = {
+			{ 9, 3 },
+		},
+	},
+	{ /* page size = 4096 (oob size = 128) */
+		.oobfree = {
+			{ 9, 7 },
+		},
+	},
+};
+
+static inline int ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t st = readl(&regs->idr[1]);
+
+	if (st & NAND_STATUS_FAIL)
+		return -EIO;
+
+	if (!(st & NAND_STATUS_READY))
+		return -EBUSY;
+
+	if (!(st & NAND_STATUS_WP))
+		return -EIO;
+
+	return 0;
+}
+
+static inline int ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	char rc = 'c';
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			rc = 'e';
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	switch (rc) {
+	case 'e':
+		printf("ftnandc021: ecc timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	case 'c':
+		printf("ftnandc021: cmd timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	default:
+		break;
+	}
+
+	return rc ? -ETIMEDOUT : 0;
+}
+
+static int ftnandc021_read_page(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	/*
+	 * OOB has been read at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it here.
+	 */
+	chip->read_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static void ftnandc021_write_page(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	/*
+	 * OOB has been written at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it here.
+	 */
+	chip->write_buf(mtd, buf, mtd->writesize);
+}
+
+static int ftnandc021_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	printf("ftnandc021: read_page_raw is not supported\n");
+	return -EIO;
+}
+
+static void ftnandc021_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	printf("ftnandc021: write_page_raw is not supported\n");
+}
+
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = 0;
+
+	priv->cmd_hc = cmd;
+
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : (We have queued data at the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+	case FTNANDC021_CMD_WRPG:
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+static int ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t ts, bk, pg, ac, mask;
+#ifdef CONFIG_SYS_FTNANDC021_TIMING
+	uint32_t timing[] = CONFIG_SYS_FTNANDC021_TIMING;
+
+	writel(timing[0], &regs->atr[0]);
+	writel(timing[1], &regs->atr[1]);
+#endif
+
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	mask = SRR_CHIP_RESET | SRR_ECC_EN;
+	writel(mask, &regs->srr);
+	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+		if (readl(&regs->srr) & SRR_CHIP_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->srr) & SRR_CHIP_RESET) {
+		printf("ftnandc021: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* sanity check on page size */
+	if (priv->pgsz != 512 && priv->pgsz != 2048 && priv->pgsz != 4096) {
+		printf("ftnandc021: invalid page size=%d\n", priv->pgsz);
+		return -EINVAL;
+	}
+
+	bk = ffs(priv->bksz / priv->pgsz) - 5;
+	pg = (priv->pgsz < 2048) ? 0 : (ffs(priv->pgsz) - 11);
+	ac = priv->alen - 3;
+
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* IO mode = PIO */
+	writel(0, &regs->bcr);
+
+	/* ECC mode */
+	chip->ecc.layout         = ftnandc021_ecclayout + pg;
+	chip->ecc.size           = priv->pgsz;
+	chip->ecc.steps          = 1;
+	chip->ecc.read_page      = ftnandc021_read_page;
+	chip->ecc.write_page     = ftnandc021_write_page;
+	chip->ecc.read_page_raw  = ftnandc021_read_page_raw;
+	chip->ecc.write_page_raw = ftnandc021_write_page_raw;
+	chip->ecc.mode           = NAND_ECC_HW;
+
+	/* reset the attached flash */
+	if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+		return -ENXIO;
+
+	return 0;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv))
+		ret = 0;
+	else if (!(readl(&regs->sr) & SR_READY))
+		ret = 0;
+
+	return ret;
+}
+
+static int ftnandc021_pio_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int ret = -ETIMEDOUT;
+	uint32_t ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
+		if (!(readl(&regs->ior) & IOR_READY))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftnandc021: pio timeout\n");
+
+	return ret;
+}
+
+static void ftnandc021_read_oob(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t tmp;
+
+	memset(buf, 0xff, len);
+
+	/* bad block */
+	buf[chip->badblockpos] = readl(&regs->bbird) & 0xff;
+
+	/* data */
+	tmp = readl(&regs->crcrd);
+	buf[8] = (tmp >> 0) & 0xff;
+	buf[9] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[12] = (tmp >> 16) & 0xff;
+		buf[13] = (tmp >> 24) & 0xff;
+	}
+
+	tmp = readl(&regs->lsnrd);
+	buf[10] = (tmp >> 0) & 0xff;
+	buf[11] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[14] = (tmp >> 16) & 0xff;
+		buf[15] = (tmp >> 24) & 0xff;
+	}
+}
+
+static void ftnandc021_write_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint32_t tmp;
+
+	/* bad block */
+	tmp = buf[chip->badblockpos];
+	writel(tmp, &regs->bbiwr);
+
+	/* mark it as 'not blank' */
+	tmp = 'W' | (buf[9] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	writel(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	writel(tmp, &regs->lsnwr);
+}
+
+static uint8_t ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+		if (priv->col < 8) {
+			uint32_t idx = priv->col >> 2;
+			uint32_t pos = priv->col & 0x3;
+			uint32_t tmp = readl(&regs->idr[idx]);
+
+			ret = (uint8_t)(tmp >> (pos << 3));
+			priv->col += 1;
+		}
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint8_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: unknown cmd=0x%x in read_byte\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t ret = 0xffff;
+	uint8_t *buf = (uint8_t *)&ret;
+
+	/* LSB format */
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return ret;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void ftnandc021_read_buf(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int off;
+
+	if (priv->col >= mtd->writesize)
+		return;
+
+	if (priv->cmd == NAND_CMD_READOOB)
+		BUG();	/* should never happen */
+
+	/* skip if it's a blank page */
+	if (chip->oob_poi[8] != 'W') {
+		memset(buf, 0xff, len);
+		return;
+	}
+
+	off = 0;
+	while (off < len && priv->col < mtd->writesize) {
+		ftnandc021_pio_wait(priv);
+		*(uint32_t *)(buf + off) = readl(&regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void ftnandc021_write_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+	int off;
+
+	/*
+	 * FTNANDC021 HW design issues:
+	 *
+	 * 1. OOB data must be set before issuing write command,
+	 *    so it's too late to do it right here
+	 * 2. Only after command issued, the data register
+	 *    could accept data.
+	 */
+	if (priv->col >= mtd->writesize)
+		return;
+
+	for (off = 0; off < len && priv->col < mtd->writesize; ) {
+		ftnandc021_pio_wait(priv);
+		writel(*(uint32_t *)(buf + off), &regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int ftnandc021_verify_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	int ret = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021: out of memory\n");
+		return -ENOMEM;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			ret = -EINVAL;
+	}
+
+	free(tmp);
+	return ret;
+}
+
+static void ftnandc021_cmdfunc(struct mtd_info *mtd,
+	unsigned cmd, int col, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs __iomem *regs = priv->regs;
+
+	priv->cmd = cmd;
+	priv->col = col;
+	priv->page = page;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		priv->col = 0;
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID))
+			printf("ftnandc021: RDID failed.\n");
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		priv->col = mtd->writesize;
+		/* fall-through */
+	case NAND_CMD_READ0:	/* 0x00 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* fetch oob to check if it's a blank page */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+			break;
+		}
+		ftnandc021_read_oob(mtd, chip->oob_poi, mtd->oobsize);
+		/* skip if we don't need page data */
+		if (priv->col >= mtd->writesize)
+			break;
+		/* skip if it's a blank page */
+		if (chip->oob_poi[8] != 'W') {
+			debug("ftnandc021: skip page %d\n", page);
+			break;
+		}
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG))
+			printf("ftnandc021: RDPG failed.\n");
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK))
+			printf("ftnandc021: ERBLK failed\n");
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDST))
+			printf("ftnandc021: RDST failed\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* OOB data must be set before issuing command */
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->oobsize);
+		priv->cmd_hc = (priv->col >= mtd->writesize)
+			? FTNANDC021_CMD_WROOB : FTNANDC021_CMD_WRPG;
+		if (ftnandc021_command(priv, priv->cmd_hc))
+			printf("ftnandc021: CMD_HC=%d failed\n", priv->cmd_hc);
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		/* nothing needs to be done */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+			printf("ftnandc021: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021: unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void ftnandc021_hwcontrol(struct mtd_info *mtd,
+	int cmd, unsigned int ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen)
+{
+	struct ftnandc021_chip *priv;
+
+	priv = calloc(1, sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regs = (void __iomem *)iobase;
+	priv->pgsz = 1 << chip->page_shift;
+	priv->bksz = 1 << chip->phys_erase_shift;
+	priv->alen = alen;
+
+	chip->priv = priv;
+
+	debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n",
+		   priv->pgsz, priv->bksz, priv->alen);
+
+	/* hardware reset */
+	if (ftnandc021_reset(chip))
+		return -EINVAL;
+
+	/* hwcontrol always must be implemented */
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	return 0;
+}
diff --git a/include/faraday/ftnandc021.h b/include/faraday/ftnandc021.h
new file mode 100644
index 0000000..c70e91e
--- /dev/null
+++ b/include/faraday/ftnandc021.h
@@ -0,0 +1,146 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTNANDC021_H
+#define __FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+	/* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4];/* ECC Parity Register */
+	uint32_t ecc_sr;   /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+	/* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsn;	 /* LSN Initialize */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+	/* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+	/* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* ECC Status Register */
+#define ECC_SR_CERR      (1 << 3)  /* correction error */
+#define ECC_SR_ERR       (1 << 2)  /* ecc error */
+#define ECC_SR_DEC       (1 << 1)  /* ecc decode finished */
+#define ECC_SR_ENC       (1 << 0)  /* ecc encode finished */
+
+/* Status Register */
+#define SR_BLANK         (1 << 7)  /* blanking check failed */
+#define SR_ECC           (1 << 6)  /* ecc timeout */
+#define SR_STS           (1 << 4)  /* status error */
+#define SR_CRC           (1 << 3)  /* crc error */
+#define SR_CMD           (1 << 2)  /* command finished */
+#define SR_READY         (1 << 1)  /* chip ready/busy */
+#define SR_ENA           (1 << 0)  /* chip enabled */
+
+/* Access Control Register */
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        (1 << 7)  /* command start */
+
+/* Flow Control Register */
+#define FCR_SWCRC        (1 << 8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       (1 << 7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        (1 << 4)  /* 16 bit data bus */
+#define FCR_WPROT        (1 << 3)  /* write protected */
+#define FCR_NOSC         (1 << 2)  /* bypass status check error */
+#define FCR_MICRON       (1 << 1)  /* Micron 2-plane command */
+#define FCR_NOBC         (1 << 0)  /* skip blanking check error */
+
+/* Interrupt Enable Register */
+#define IER_ENA          (1 << 7)  /* interrupt enabled */
+#define IER_ECC          (1 << 3)  /* ecc error timeout */
+#define IER_STS          (1 << 2)  /* status error */
+#define IER_CRC          (1 << 1)  /* crc error */
+#define IER_CMD          (1 << 0)  /* command finished */
+
+/* BMC PIO Status Register */
+#define IOR_READY        (1 << 0)  /* PIO ready */
+
+/* MLC Software Reset Register */
+#define SRR_ECC_EN       (1 << 8)  /* ECC enabled */
+#define SRR_NANDC_RESET  (1 << 2)  /* NANDC reset */
+#define SRR_BMC_RESET    (1 << 1)  /* BMC reset */
+#define SRR_ECC_RESET    (1 << 0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+/* Memory Configuration Register */
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* FTNANDC021 built-in command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02   /* reset flash */
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen);
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support
  2013-05-07  6:26             ` [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-05-07 21:42               ` Marek Vasut
@ 2013-05-09  3:20               ` Kuo-Jung Su
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
                                   ` (3 more replies)
  1 sibling, 4 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  3:20 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. And since U-boot doesn't support ISOC,
   we don't have to worry about that.

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device as a time.

Changes for v5:
   - Split up EHCI changeset
   - usb_hub: replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.
   - ehci-faraday: fix the invalid multi-line comment style.
   - gadget-fotg210: coding style cleanup.
   - gadget-fotg210: drop postfix '__iomem' from struct fotg210_regs
   - gadget-fotg210: use permanent delay for hardware reset
   - gadget-fotg210: drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - gadget-fotg210: drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

Kuo-Jung Su (4):
  usb: make usb hub minimum power-on delay configurable
  usb: add weak-aliased functions EHCI portsc & tdi routines
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 README                            |    3 +
 common/usb_hub.c                  |   15 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/host/Makefile         |    1 +
 drivers/usb/host/ehci-faraday.c   |  146 ++++++
 drivers/usb/host/ehci-hcd.c       |  104 ++--
 include/usb/fotg210.h             |  364 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 10 files changed, 1613 insertions(+), 38 deletions(-)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-09  3:20               ` [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
@ 2013-05-09  3:20                 ` Kuo-Jung Su
  2013-05-10 11:41                   ` Marek Vasut
  2013-05-13  2:07                   ` [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
                                   ` (2 subsequent siblings)
  3 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  3:20 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch makes the minimum power-on delay for USB HUB
become configurable. The original design waits at least
100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
are known to require much longer delay interval.

NOTE:
The minimal delay is still 100 msec, a small value defined
in CONFIG_USB_HUB_MIN_POWER_ON_DELAY would be automatically
justified in common/usb_hub.c.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v5:
   - Split up from Faraday EHCI patch
   - Replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 README           |    3 +++
 common/usb_hub.c |    8 +++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/README b/README
index 0d37d56..c70a59b 100644
--- a/README
+++ b/README
@@ -1244,6 +1244,9 @@ The following options need to be configured:
 		CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
 		txfilltuning field in the EHCI controller on reset.

+		CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
+		interval for usb hub power-on delay.(minimum 100msec)
+
 - USB Device:
 		Define the below if you wish to use the USB console.
 		Once firmware is rebuilt from a serial console issue the
diff --git a/common/usb_hub.c b/common/usb_hub.c
index b5eeb62..0db3530 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -61,6 +61,12 @@
 #define USB_HUB_DEBUG	0
 #endif

+#if CONFIG_USB_HUB_MIN_POWER_ON_DELAY > 100
+# define USB_HUB_MIN_POWER_ON_DELAY	CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+#else
+# define USB_HUB_MIN_POWER_ON_DELAY	100
+#endif
+
 #define USB_PRINTF(fmt, args...)	debug_cond(USB_DEBUG, fmt, ##args)
 #define USB_HUB_PRINTF(fmt, args...)	debug_cond(USB_HUB_DEBUG, fmt, ##args)

@@ -121,7 +127,7 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
 	}

 	/* Wait at least 100 msec for power to become stable */
-	mdelay(max(pgood_delay, (unsigned)100));
+	mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
 }

 void usb_hub_reset(void)
--
1.7.9.5

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

* [U-Boot] [PATCH v5 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-09  3:20               ` [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-09  3:20                 ` Kuo-Jung Su
  2013-05-10 11:44                   ` Marek Vasut
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  3:20 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
known to implement a non-standard TDI stuff.
Futhermore, it not only leave reserved and CONFIGFLAG registers
un-implemented but also has their address spaces removed.

And thus, we need weak-aliased functions to both TDI stuff
and PORTSC registers for interface abstraction.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v5:
   - Split up from Faraday EHCI patch

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 drivers/usb/host/ehci-hcd.c |  100 +++++++++++++++++++++++++++----------------
 1 file changed, 64 insertions(+), 36 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..b334173 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -117,10 +117,50 @@ static struct descriptor {
 };

 #if defined(CONFIG_EHCI_IS_TDI)
-#define ehci_is_TDI()	(1)
-#else
-#define ehci_is_TDI()	(0)
+# define ehci_is_TDI()	(1)
+
+/* put TDI/ARC silicon into EHCI mode */
+void __ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	uint32_t tmp, *reg_ptr;
+
+	reg_ptr = (uint32_t *)((uint8_t *) + USBMODE);
+	tmp = ehci_readl(reg_ptr);
+	tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+	tmp |= USBMODE_BE;
 #endif
+	ehci_writel(reg_ptr, tmp);
+}
+
+void ehci_tdi_reset(struct ehci_hcor *hcor)
+	__attribute__((weak, alias("__ehci_tdi_reset")));
+
+int __ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int ret = 0;
+
+	switch (PORTSC_PSPD(portsc)) {
+	case PORTSC_PSPD_FS:
+		break;
+	case PORTSC_PSPD_LS:
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case PORTSC_PSPD_HS:
+	default:
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	}
+
+	return ret;
+}
+
+int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+	__attribute__((weak, alias("__ehci_port_speed")));
+
+#else  /* CONFIG_EHCI_IS_TDI */
+# define ehci_is_TDI()	(0)
+#endif /* CONFIG_EHCI_IS_TDI */

 void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 {
@@ -149,8 +189,6 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
-	uint32_t tmp;
-	uint32_t *reg_ptr;
 	int ret = 0;

 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,15 +201,8 @@ static int ehci_reset(int index)
 		goto out;
 	}

-	if (ehci_is_TDI()) {
-		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
-		tmp = ehci_readl(reg_ptr);
-		tmp |= USBMODE_CM_HC;
-#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
-		tmp |= USBMODE_BE;
-#endif
-		ehci_writel(reg_ptr, tmp);
-	}
+	if (ehci_is_TDI())
+		ehci_tdi_reset(ehcic[index].hcor);

 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -597,6 +628,18 @@ static inline int min3(int a, int b, int c)
 	return a;
 }

+uint32_t *__ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+	__attribute__((weak, alias("__ehci_get_portsc_register")));
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
@@ -609,13 +652,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	uint32_t *status_reg;
 	struct ehci_ctrl *ctrl = dev->controller;

-	if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		printf("The request port(%d) is not configured\n",
-			le16_to_cpu(req->index) - 1);
+	status_reg = ehci_get_portsc_register(ctrl->hcor,
+		le16_to_cpu(req->index) - 1);
+	if (!status_reg)
 		return -1;
-	}
-	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
-						le16_to_cpu(req->index) - 1];
 	srclen = 0;

 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -709,23 +749,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[0] |= USB_PORT_STAT_RESET;
 		if (reg & EHCI_PS_PP)
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
-
-		if (ehci_is_TDI()) {
-			switch (PORTSC_PSPD(reg)) {
-			case PORTSC_PSPD_FS:
-				break;
-			case PORTSC_PSPD_LS:
-				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
-				break;
-			case PORTSC_PSPD_HS:
-			default:
-				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-				break;
-			}
-		} else {
+		if (ehci_is_TDI())
+			tmpbuf[1] |= ehci_port_speed(ctrl->hcor, reg) >> 8;
+		else
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-		}
-
 		if (reg & EHCI_PS_CSC)
 			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
 		if (reg & EHCI_PS_PEC)
@@ -954,6 +981,7 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
--
1.7.9.5

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

* [U-Boot] [PATCH v5 3/4] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-09  3:20               ` [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
@ 2013-05-09  3:20                 ` Kuo-Jung Su
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  3:20 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address space removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. And since U-boot doesn't support ISOC,
   we don't have to worry about that.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v5:
   - Break down EHCI changes as seperate changesets.
   - Fix the invalid multi-line comment style.

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 common/usb_hub.c                |    7 +-
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |    4 +
 include/usb/fotg210.h           |  364 +++++++++++++++++++++++++++++++++++++++
 include/usb/fusbh200.h          |   61 +++++++
 6 files changed, 582 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index 0db3530..6513abe 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -447,7 +447,11 @@ static int usb_hub_configure(struct usb_device *dev)
 					i + 1, portstatus);
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_ENABLE);
-
+			/*
+			 * The following hack causes a ghost device problem
+			 * to Faraday EHCI
+			 */
+#ifndef CONFIG_USB_EHCI_FARADAY
 			/* EM interference sometimes causes bad shielded USB
 			 * devices to be shutdown by the hub, this hack enables
 			 * them again. Works at least with mouse driver */
@@ -459,6 +463,7 @@ static int usb_hub_configure(struct usb_device *dev)
 						"re-enabling...\n", i + 1);
 					usb_hub_port_connect_change(dev, i);
 			}
+#endif
 		}
 		if (portstatus & USB_PORT_STAT_SUSPEND) {
 			USB_HUB_PRINTF("port %d suspend change\n", i + 1);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..1be9369
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,146 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+/*
+ * This ehci_tdi_reset() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+void ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	/* nothing needs to be done */
+}
+
+/*
+ * This ehci_port_speed() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int spd, ret = 0;
+	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		break;
+	case 1:    /* low  speed */
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case 2:    /* high speed */
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This ehci_get_portsc_register() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/* Faraday EHCI has one and only one portsc register */
+	if (port > 0) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)hcor + 0x20);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index b334173..36ad897 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -604,10 +604,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
 		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
 		      ehci_readl(&ctrl->hcor->or_portsc[0]),
 		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
 	}

 	free(qtd);
@@ -977,10 +979,12 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif

 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..2d2d243
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,364 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t miscr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[2];
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */
+};
+
+/* Miscellaneous Register */
+#define MISCR_SUSPEND  (1 << 6) /* Put transceiver in suspend mode */
+#define MISCR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define MISCR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define MISCR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* OTG Control Status Register */
+#define OTGCSR_SPD_HIGH     (2 << 22) /* Speed of the attached device (host) */
+#define OTGCSR_SPD_LOW      (1 << 22)
+#define OTGCSR_SPD_FULL     (0 << 22)
+#define OTGCSR_SPD_MASK     (3 << 22)
+#define OTGCSR_SPD_SHIFT    22
+#define OTGCSR_SPD(x)       (((x) >> 22) & 0x03)
+#define OTGCSR_DEV_A        (0 << 21) /* Acts as A-device */
+#define OTGCSR_DEV_B        (1 << 21) /* Acts as B-device */
+#define OTGCSR_ROLE_H       (0 << 20) /* Acts as Host */
+#define OTGCSR_ROLE_D       (1 << 20) /* Acts as Device */
+#define OTGCSR_A_VBUS_VLD   (1 << 19) /* A-device VBUS Valid */
+#define OTGCSR_A_SESS_VLD   (1 << 18) /* A-device Session Valid */
+#define OTGCSR_B_SESS_VLD   (1 << 17) /* B-device Session Valid */
+#define OTGCSR_B_SESS_END   (1 << 16) /* B-device Session End */
+#define OTGCSR_HFT_LONG     (1 << 11) /* HDISCON noise filter = 270 us*/
+#define OTGCSR_HFT          (0 << 11) /* HDISCON noise filter = 135 us*/
+#define OTGCSR_VFT_LONG     (1 << 10) /* VBUS noise filter = 472 us*/
+#define OTGCSR_VFT          (0 << 10) /* VBUS noise filter = 135 us*/
+#define OTGCSR_IDFT_LONG    (1 << 9)  /* ID noise filter = 4 ms*/
+#define OTGCSR_IDFT         (0 << 9)  /* ID noise filter = 3 ms*/
+#define OTGCSR_A_SRPR_VBUS  (0 << 8)  /* A-device: SRP responds to VBUS */
+#define OTGCSR_A_SRPR_DATA  (1 << 8)  /* A-device: SRP responds to DATA-LINE */
+#define OTGCSR_A_SRP_EN     (1 << 7)  /* A-device SRP detection enabled */
+#define OTGCSR_A_HNP        (1 << 6)  /* Set role=A-device with HNP enabled */
+#define OTGCSR_A_BUSDROP    (1 << 5)  /* A-device drop bus (power-down) */
+#define OTGCSR_A_BUSREQ     (1 << 4)  /* A-device request bus */
+#define OTGCSR_B_VBUS_DISC  (1 << 2)  /* B-device discharges VBUS */
+#define OTGCSR_B_HNP        (1 << 1)  /* B-device enable HNP */
+#define OTGCSR_B_BUSREQ     (1 << 0)  /* B-device request bus */
+
+/* OTG Interrupt Status Register */
+#define OTGISR_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGISR_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGISR_OVD          (1 << 10) /* over-current detected */
+#define OTGISR_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGISR_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGISR_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGISR_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGISR_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGISR_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* OTG Interrupt Enable Register */
+#define OTGIER_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGIER_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGIER_OVD          (1 << 10) /* over-current detected */
+#define OTGIER_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGIER_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGIER_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGIER_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGIER_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGIER_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* Global Interrupt Status Register (W1C) */
+#define ISR_HOST            (1 << 2)  /* USB Host interrupt */
+#define ISR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define ISR_DEV             (1 << 0)  /* USB Device interrupt */
+#define ISR_MASK            0x07
+
+/* Global Interrupt Mask Register */
+#define IMR_IRQLH           (1 << 3)  /* Interrupt triggered at level-high */
+#define IMR_IRQLL           (0 << 3)  /* Interrupt triggered@level-low */
+#define IMR_HOST            (1 << 2)  /* USB Host interrupt */
+#define IMR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define IMR_DEV             (1 << 0)  /* USB Device interrupt */
+#define IMR_MASK            0x0f
+
+/* Device Control Register */
+#define DEVCTRL_FS_FORCED   (1 << 9)  /* Forced to be Full-Speed Mode */
+#define DEVCTRL_HS          (1 << 6)  /* High Speed Mode */
+#define DEVCTRL_FS          (0 << 6)  /* Full Speed Mode */
+#define DEVCTRL_EN          (1 << 5)  /* Chip Enable */
+#define DEVCTRL_RESET       (1 << 4)  /* Chip Software Reset */
+#define DEVCTRL_SUSPEND     (1 << 3)  /* Enter Suspend Mode */
+#define DEVCTRL_GIRQ_EN     (1 << 2)  /* Global Interrupt Enabled */
+#define DEVCTRL_HALFSPD     (1 << 1)  /* Half speed mode for FPGA test */
+#define DEVCTRL_RWAKEUP     (1 << 0)  /* Enable remote wake-up */
+
+/* Device Address Register */
+#define DEVADDR_CONF        (1 << 7)  /* SET_CONFIGURATION has been executed */
+#define DEVADDR_ADDR(x)     ((x) & 0x7f)
+#define DEVADDR_ADDR_MASK   0x7f
+
+/* Device Test Register */
+#define DEVTEST_NOSOF       (1 << 6)  /* Do not generate SOF */
+#define DEVTEST_TST_MODE    (1 << 5)  /* Enter Test Mode */
+#define DEVTEST_TST_NOTS    (1 << 4)  /* Do not toggle sequence */
+#define DEVTEST_TST_NOCRC   (1 << 3)  /* Do not append CRC */
+#define DEVTEST_TST_CLREA   (1 << 2)  /* Clear External Side Address */
+#define DEVTEST_TST_CXLP    (1 << 1)  /* EP0 loopback test */
+#define DEVTEST_TST_CLRFF   (1 << 0)  /* Clear FIFO */
+
+/* SOF Frame Number Register */
+#define SOFFNR_UFN(x)       (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */
+#define SOFFNR_FNR(x)       ((x) & 0x7ff) /* SOF Frame Number */
+
+/* SOF Mask Timer Register */
+#define SOFMTR_TMR(x)       ((x) & 0xffff)
+
+/* PHY Test Mode Selector Register */
+#define PHYTMSR_TST_PKT     (1 << 4) /* Packet send test */
+#define PHYTMSR_TST_SE0NAK  (1 << 3) /* High-Speed quiescent state */
+#define PHYTMSR_TST_KSTA    (1 << 2) /* High-Speed K state */
+#define PHYTMSR_TST_JSTA    (1 << 1) /* High-Speed J state */
+#define PHYTMSR_UNPLUG      (1 << 0) /* Enable soft-detachment */
+
+/* CX FIFO Register */
+#define CXFIFO_BYTES(x)     (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */
+#define CXFIFO_FIFOE(x)     (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */
+#define CXFIFO_FIFOE_FIFO0  (1 << 8)
+#define CXFIFO_FIFOE_FIFO1  (1 << 9)
+#define CXFIFO_FIFOE_FIFO2  (1 << 10)
+#define CXFIFO_FIFOE_FIFO3  (1 << 11)
+#define CXFIFO_FIFOE_MASK   (0x0f << 8)
+#define CXFIFO_CXFIFOE      (1 << 5) /* CX FIFO empty */
+#define CXFIFO_CXFIFOF      (1 << 4) /* CX FIFO full */
+#define CXFIFO_CXFIFOCLR    (1 << 3) /* CX FIFO clear */
+#define CXFIFO_CXSTALL      (1 << 2) /* CX Stall */
+#define CXFIFO_TSTPKTFIN    (1 << 1) /* Test packet data transfer finished */
+#define CXFIFO_CXFIN        (1 << 0) /* CX data transfer finished */
+
+/* IDLE Counter Register */
+#define IDLE_MS(x)          ((x) & 0x07) /* PHY suspend delay = x ms */
+
+/* Group Interrupt Mask(Disable) Register */
+#define GIMR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GIMR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GIMR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+#define GIMR_MASK           0x07
+
+/* Group Interrupt Mask(Disable) Register 0 (CX) */
+#define GIMR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GIMR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GIMR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GIMR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GIMR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GIMR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+#define GIMR0_MASK          0x3f
+
+/* Group Interrupt Mask(Disable) Register 1 (FIFO) */
+#define GIMR1_FIFO_IN(x)    (1 << (((x) & 3) + 16))    /* FIFOx IN */
+#define GIMR1_FIFO_TX(x)    GIMR1_FIFO_IN(x)
+#define GIMR1_FIFO_OUT(x)   (1 << (((x) & 3) * 2))     /* FIFOx OUT */
+#define GIMR1_FIFO_SPK(x)   (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */
+#define GIMR1_FIFO_RX(x)    (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x))
+#define GIMR1_MASK          0xf00ff
+
+/* Group Interrupt Mask(Disable) Register 2 (Device) */
+#define GIMR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GIMR2_IDLE          (1 << 9)  /* Device idle */
+#define GIMR2_DMAERR        (1 << 8)  /* DMA error */
+#define GIMR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GIMR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GIMR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GIMR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GIMR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GIMR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GIMR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GIMR2_RESET         (1 << 0)  /* Reset Interrupt */
+#define GIMR2_MASK          0x7ff
+
+/* Group Interrupt Status Register */
+#define GISR_GRP2           (1 << 2) /* Interrupt group 2 */
+#define GISR_GRP1           (1 << 1) /* Interrupt group 1 */
+#define GISR_GRP0           (1 << 0) /* Interrupt group 0 */
+
+/* Group Interrupt Status Register 0 (CX) */
+#define GISR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GISR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GISR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GISR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GISR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GISR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Status Register 1 (FIFO) */
+#define GISR1_IN_FIFO(x)    (1 << (((x) & 0x03) + 16))    /* FIFOx IN */
+#define GISR1_OUT_FIFO(x)   (1 << (((x) & 0x03) * 2))     /* FIFOx OUT */
+#define GISR1_SPK_FIFO(x)   (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */
+#define GISR1_RX_FIFO(x)    (3 << (((x) & 0x03) * 2))     /* FIFOx OUT/SPK */
+
+/* Group Interrupt Status Register 2 (Device) */
+#define GISR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GISR2_IDLE          (1 << 9)  /* Device idle */
+#define GISR2_DMAERR        (1 << 8)  /* DMA error */
+#define GISR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GISR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GISR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GISR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GISR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GISR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GISR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GISR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Receive Zero-Length-Packet Register */
+#define RXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP rx interrupt */
+
+/* Transfer Zero-Length-Packet Register */
+#define TXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP tx interrupt */
+
+/* ISOC Error/Abort Status Register */
+#define ISOEASR_EP(x)       (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */
+
+/* IN Endpoint Register */
+#define IEP_SENDZLP         (1 << 15)     /* Send Zero-Length-Packet */
+#define IEP_TNRHB(x)        (((x) & 0x03) << 13) \
+	/* Transaction Number for High-Bandwidth EP(ISOC) */
+#define IEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define IEP_STALL           (1 << 11)     /* Stall */
+#define IEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* OUT Endpoint Register */
+#define OEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define OEP_STALL           (1 << 11)     /* Stall */
+#define OEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* Endpoint Map Register (EP1 ~ EP4) */
+#define EPMAP14_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 0)
+#define EPMAP14_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 4)
+#define EPMAP14_SET(ep, in, out) \
+	do { \
+		EPMAP14_SET_IN(ep, in); \
+		EPMAP14_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP14_DEFAULT     0x33221100 /* EP1->FIFO0, EP2->FIFO1... */
+
+/* Endpoint Map Register (EP5 ~ EP8) */
+#define EPMAP58_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 0)
+#define EPMAP58_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 4)
+#define EPMAP58_SET(ep, in, out) \
+	do { \
+		EPMAP58_SET_IN(ep, in); \
+		EPMAP58_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP58_DEFAULT     0x00000000 /* All EPx->FIFO0 */
+
+/* FIFO Map Register */
+#define FIFOMAP_BIDIR       (2 << 4)
+#define FIFOMAP_IN          (1 << 4)
+#define FIFOMAP_OUT         (0 << 4)
+#define FIFOMAP_DIR_MASK    0x30
+#define FIFOMAP_EP(x)       ((x) & 0x0f)
+#define FIFOMAP_EP_MASK     0x0f
+#define FIFOMAP_CFG_MASK    0x3f
+#define FIFOMAP_DEFAULT     0x04030201 /* FIFO0->EP1, FIFO1->EP2... */
+#define FIFOMAP(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Configuration Register */
+#define FIFOCFG_EN          (1 << 5)
+#define FIFOCFG_BLKSZ_1024  (1 << 4)
+#define FIFOCFG_BLKSZ_512   (0 << 4)
+#define FIFOCFG_3BLK        (2 << 2)
+#define FIFOCFG_2BLK        (1 << 2)
+#define FIFOCFG_1BLK        (0 << 2)
+#define FIFOCFG_NBLK_MASK   3
+#define FIFOCFG_NBLK_SHIFT  2
+#define FIFOCFG_INTR        (3 << 0)
+#define FIFOCFG_BULK        (2 << 0)
+#define FIFOCFG_ISOC        (1 << 0)
+#define FIFOCFG_RSVD        (0 << 0)  /* Reserved */
+#define FIFOCFG_TYPE_MASK   3
+#define FIFOCFG_TYPE_SHIFT  0
+#define FIFOCFG_CFG_MASK    0x3f
+#define FIFOCFG(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Control Status Register */
+#define FIFOCSR_RESET       (1 << 12) /* FIFO Reset */
+#define FIFOCSR_BYTES(x)    ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */
+
+/* DMA Target FIFO Register */
+#define DMAFIFO_CX          (1 << 4) /* DMA FIFO = CX FIFO */
+#define DMAFIFO_FIFO(x)     (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */
+
+/* DMA Control Register */
+#define DMACTRL_LEN(x)      (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */
+#define DMACTRL_LEN_SHIFT   8
+#define DMACTRL_CLRFF       (1 << 4) /* Clear FIFO upon DMA abort */
+#define DMACTRL_ABORT       (1 << 3) /* DMA abort */
+#define DMACTRL_IO2IO       (1 << 2) /* IO to IO */
+#define DMACTRL_FIFO2MEM    (0 << 1) /* FIFO to Memory */
+#define DMACTRL_MEM2FIFO    (1 << 1) /* Memory to FIFO */
+#define DMACTRL_START       (1 << 0) /* DMA start */
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..8a9c488
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,61 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+/* EOF & Async. Schedule Sleep Timer Register */
+#define EASSTR_RUNNING  (1 << 6) /* Put transceiver in running/resume mode */
+#define EASSTR_SUSPEND  (0 << 6) /* Put transceiver in suspend mode */
+#define EASSTR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define EASSTR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define EASSTR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* Bus Monitor Control Status Register */
+#define BMCSR_SPD_HIGH  (2 << 9) /* Speed of the attached device */
+#define BMCSR_SPD_LOW   (1 << 9)
+#define BMCSR_SPD_FULL  (0 << 9)
+#define BMCSR_SPD_MASK  (3 << 9)
+#define BMCSR_SPD_SHIFT 9
+#define BMCSR_SPD(x)    ((x >> 9) & 0x03)
+#define BMCSR_VBUS      (1 << 8) /* VBUS Valid */
+#define BMCSR_VBUS_OFF  (1 << 4) /* VBUS Off */
+#define BMCSR_VBUS_ON   (0 << 4) /* VBUS On */
+#define BMCSR_IRQLH     (1 << 3) /* IRQ triggered at level-high */
+#define BMCSR_IRQLL     (0 << 3) /* IRQ triggered@level-low */
+#define BMCSR_HALFSPD   (1 << 2) /* Half speed mode for FPGA test */
+#define BMCSR_HFT_LONG  (1 << 1) /* HDISCON noise filter = 270 us*/
+#define BMCSR_HFT       (0 << 1) /* HDISCON noise filter = 135 us*/
+#define BMCSR_VFT_LONG  (1 << 1) /* VBUS noise filter = 472 us*/
+#define BMCSR_VFT       (0 << 1) /* VBUS noise filter = 135 us*/
+
+/* Bus Monitor Interrupt Status Register */
+/* Bus Monitor Interrupt Enable Register */
+#define BMISR_DMAERR    (1 << 4) /* DMA error */
+#define BMISR_DMA       (1 << 3) /* DMA complete */
+#define BMISR_DEVRM     (1 << 2) /* device removed */
+#define BMISR_OVD       (1 << 1) /* over-current detected */
+#define BMISR_VBUSERR   (1 << 0) /* VBUS error */
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v5 4/4] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-09  3:20               ` [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
                                   ` (2 preceding siblings ...)
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-05-09  3:20                 ` Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-09  3:20 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device as a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v5:
   - Coding Style cleanup.
   - Drop postfix '__iomem' from struct fotg210_regs
   - Use permanent delay for hardware reset
   - Drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - Drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Remove dcache_enable() from usb_gadget_register_driver()

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 957 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..d003331
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,948 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs      *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id & 0x03) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) & 0x03);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], OEP_STALL);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t i;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(DEVCTRL_EN, &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(0, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable all interrupts */
+	writel(IMR_MASK, &regs->imr);
+	writel(GIMR_MASK, &regs->gimr);
+	writel(GIMR0_MASK, &regs->gimr0);
+	writel(GIMR1_MASK, &regs->gimr1);
+	writel(GIMR2_MASK, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(ISR_MASK, &regs->isr);
+	writel(0, &regs->gisr);
+	writel(0, &regs->gisr0);
+	writel(0, &regs->gisr1);
+	writel(0, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+	mdelay(10);
+	if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+	mdelay(10);
+	if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(EPMAP14_DEFAULT, &regs->epmap14);
+	writel(EPMAP58_DEFAULT, &regs->epmap58);
+	writel(FIFOMAP_DEFAULT, &regs->fifomap);
+	writel(0, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+		mdelay(10);
+		if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(IMR_IRQLH | IMR_HOST | IMR_OTG, &regs->imr);
+	writel(ISR_MASK, &regs->isr);
+	/* disable EP0 IN/OUT interrupt */
+	writel(GIMR0_CXOUT | GIMR0_CXIN, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(GIMR1_MASK, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN
+		| GIMR2_ZLPRX | GIMR2_ZLPTX, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_GIRQ_EN);
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	int fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->dma_ctrl) & DMACTRL_START)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((ulong)buf, (ulong)buf + len);
+	else
+		invalidate_dcache_range((ulong)buf, (ulong)buf + len);
+
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until cx/ep0 fifo empty */
+			fotg210_cxwait(chip, CXFIFO_CXFIFOE);
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+		} else {
+			/* Wait until epx fifo empty */
+			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+		}
+		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+
+		if (ep->id == 0) {
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+			do {
+				blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+			} while (blen < len);
+		} else {
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+			blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+		}
+		len  = (len < blen) ? len : blen;
+		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & GISR2_DMAFIN) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & GISR2_DMAERR) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(DMACTRL_ABORT | DMACTRL_CLRFF, &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & OTGCSR_DEV_B) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				/* SOF mask timer = 1100 ticks */
+				writel(SOFMTR_TMR(1100), &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				/* SOF mask timer = 10000 ticks */
+				writel(SOFMTR_TMR(10000), &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(DMAFIFO_CX, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->ep0_data);
+	tmp[1] = readl(&regs->ep0_data);
+	/* release data port */
+	writel(0, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(chip->addr | DEVADDR_CONF,
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue & DEVADDR_ADDR_MASK;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], IEP_STALL);
+				setbits_le32(&regs->oep[id - 1], OEP_STALL);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue)) {
+		setbits_le32(&regs->gimr1,
+			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+	}
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_IN));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+	clrbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return SOFFNR_FNR(readl(&regs->sof_fnr));
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name  = "ep0",
+			.ops   = &fotg210_ep_ops,
+		},
+		.desc      = &ep0_desc,
+		.chip      = &controller,
+		.maxpacket = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name  = "ep1",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name  = "ep2",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name  = "ep3",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name  = "ep4",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t id, st, isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & ISR_DEV) || !gisr)
+		return 0;
+
+	writel(ISR_DEV, &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & GISR_GRP0) {
+		st = readl(&regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & GISR0_CXERR)
+			printf("fotg210: cmd error\n");
+
+		if (st & GISR0_CXABORT)
+			printf("fotg210: cmd abort\n");
+
+		if (st & GISR0_CXSETUP)    /* setup */
+			fotg210_setup(chip);
+		else if (st & GISR0_CXEND) /* command finish */
+			setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & GISR_GRP1) {
+		st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & GISR1_RX_FIFO(id))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & GISR_GRP2) {
+		st = readl(&regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & GISR2_RESET)
+			printf("fotg210: reset by host\n");
+		else if (st & GISR2_SUSPEND)
+			printf("fotg210: suspend/removed\n");
+		else if (st & GISR2_RESUME)
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & GISR2_ISOCERR)
+			printf("fotg210: iso error\n");
+		if (st & GISR2_ISOCABT)
+			printf("fotg210: iso abort\n");
+		if (st & GISR2_DMAERR)
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-10 11:41                   ` Marek Vasut
  2013-05-13  1:11                     ` Kuo-Jung Su
  2013-05-13  2:07                   ` [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-10 11:41 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch makes the minimum power-on delay for USB HUB
> become configurable. The original design waits at least
> 100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
> are known to require much longer delay interval.
> 
> NOTE:
> The minimal delay is still 100 msec, a small value defined
> in CONFIG_USB_HUB_MIN_POWER_ON_DELAY would be automatically
> justified in common/usb_hub.c.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
> Changes for v5:
>    - Split up from Faraday EHCI patch
>    - Replace the Faraday EHCI ifdef for the long delay
>      in usb_hub_configure() with the new configuration option:
>      USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
>      to control the minimum usb hub power-on delay.
> 
> Changes for v2 - v4:
>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
> 
>  README           |    3 +++
>  common/usb_hub.c |    8 +++++++-
>  2 files changed, 10 insertions(+), 1 deletion(-)
> 
> diff --git a/README b/README
> index 0d37d56..c70a59b 100644
> --- a/README
> +++ b/README
> @@ -1244,6 +1244,9 @@ The following options need to be configured:
>  		CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
>  		txfilltuning field in the EHCI controller on reset.
> 
> +		CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
> +		interval for usb hub power-on delay.(minimum 100msec)
> +
>  - USB Device:
>  		Define the below if you wish to use the USB console.
>  		Once firmware is rebuilt from a serial console issue the
> diff --git a/common/usb_hub.c b/common/usb_hub.c
> index b5eeb62..0db3530 100644
> --- a/common/usb_hub.c
> +++ b/common/usb_hub.c
> @@ -61,6 +61,12 @@
>  #define USB_HUB_DEBUG	0
>  #endif
> 
> +#if CONFIG_USB_HUB_MIN_POWER_ON_DELAY > 100
> +# define USB_HUB_MIN_POWER_ON_DELAY	CONFIG_USB_HUB_MIN_POWER_ON_DELAY
> +#else
> +# define USB_HUB_MIN_POWER_ON_DELAY	100
> +#endif

Even better (and easier) solution here would be:

ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
#define CONFIG_USB_HUB_MIN_POWER_ON_DELAY 100
#endif

no ? ;-)

>  #define USB_PRINTF(fmt, args...)	debug_cond(USB_DEBUG, fmt, ##args)
>  #define USB_HUB_PRINTF(fmt, args...)	debug_cond(USB_HUB_DEBUG, fmt,
> ##args)
> 
> @@ -121,7 +127,7 @@ static void usb_hub_power_on(struct usb_hub_device
> *hub) }
> 
>  	/* Wait at least 100 msec for power to become stable */
> -	mdelay(max(pgood_delay, (unsigned)100));
> +	mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
>  }
> 
>  void usb_hub_reset(void)
> --
> 1.7.9.5

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v5 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
@ 2013-05-10 11:44                   ` Marek Vasut
  2013-05-13  1:10                     ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-10 11:44 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
> known to implement a non-standard TDI stuff.
> Futhermore, it not only leave reserved and CONFIGFLAG registers
> un-implemented but also has their address spaces removed.
> 
> And thus, we need weak-aliased functions to both TDI stuff
> and PORTSC registers for interface abstraction.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
> Changes for v5:
>    - Split up from Faraday EHCI patch
> 
> Changes for v2 - v4:
>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
> 
>  drivers/usb/host/ehci-hcd.c |  100
> +++++++++++++++++++++++++++---------------- 1 file changed, 64
> insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index c816878..b334173 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -117,10 +117,50 @@ static struct descriptor {
>  };
> 
>  #if defined(CONFIG_EHCI_IS_TDI)
> -#define ehci_is_TDI()	(1)
> -#else
> -#define ehci_is_TDI()	(0)
> +# define ehci_is_TDI()	(1)
> +
> +/* put TDI/ARC silicon into EHCI mode */
> +void __ehci_tdi_reset(struct ehci_hcor *hcor)
> +{
> +	uint32_t tmp, *reg_ptr;
> +
> +	reg_ptr = (uint32_t *)((uint8_t *) + USBMODE);
> +	tmp = ehci_readl(reg_ptr);
> +	tmp |= USBMODE_CM_HC;
> +#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
> +	tmp |= USBMODE_BE;
>  #endif
> +	ehci_writel(reg_ptr, tmp);
> +}
> +
> +void ehci_tdi_reset(struct ehci_hcor *hcor)
> +	__attribute__((weak, alias("__ehci_tdi_reset")));

Just wrap this into simple

__weak void ehci_tdi_reset(struct ehci_hcor *hcor)
{
	...body of __ehci_tdi_reset() above ...
}

it's the same thing as those two functions above, but without so much code ;-)

if it doesn't work, include <linux/compiler.h>, same below.

> +int __ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
> +{
> +	int ret = 0;
> +
> +	switch (PORTSC_PSPD(portsc)) {
> +	case PORTSC_PSPD_FS:
> +		break;
> +	case PORTSC_PSPD_LS:
> +		ret = USB_PORT_STAT_LOW_SPEED;
> +		break;
> +	case PORTSC_PSPD_HS:
> +	default:
> +		ret = USB_PORT_STAT_HIGH_SPEED;
> +		break;
> +	}
> +
> +	return ret;
> +}
> +
> +int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
> +	__attribute__((weak, alias("__ehci_port_speed")));
> +
> +#else  /* CONFIG_EHCI_IS_TDI */
> +# define ehci_is_TDI()	(0)
> +#endif /* CONFIG_EHCI_IS_TDI */
> 
>  void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
>  {
> @@ -149,8 +189,6 @@ static int handshake(uint32_t *ptr, uint32_t mask,
> uint32_t done, int usec) static int ehci_reset(int index)
>  {
>  	uint32_t cmd;
> -	uint32_t tmp;
> -	uint32_t *reg_ptr;
>  	int ret = 0;
> 
>  	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
> @@ -163,15 +201,8 @@ static int ehci_reset(int index)
>  		goto out;
>  	}
> 
> -	if (ehci_is_TDI()) {
> -		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
> -		tmp = ehci_readl(reg_ptr);
> -		tmp |= USBMODE_CM_HC;
> -#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
> -		tmp |= USBMODE_BE;
> -#endif
> -		ehci_writel(reg_ptr, tmp);
> -	}
> +	if (ehci_is_TDI())
> +		ehci_tdi_reset(ehcic[index].hcor);
> 
>  #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
>  	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
> @@ -597,6 +628,18 @@ static inline int min3(int a, int b, int c)
>  	return a;
>  }
> 
> +uint32_t *__ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
> +{
> +	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
> +		printf("The request port(%d) is not configured\n", port);
> +		return NULL;
> +	}
> +
> +	return (uint32_t *)&hcor->or_portsc[port];
> +}
> +uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
> +	__attribute__((weak, alias("__ehci_get_portsc_register")));
> +
>  int
>  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
>  		 int length, struct devrequest *req)
> @@ -609,13 +652,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
> long pipe, void *buffer, uint32_t *status_reg;
>  	struct ehci_ctrl *ctrl = dev->controller;
> 
> -	if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
> -		printf("The request port(%d) is not configured\n",
> -			le16_to_cpu(req->index) - 1);
> +	status_reg = ehci_get_portsc_register(ctrl->hcor,
> +		le16_to_cpu(req->index) - 1);
> +	if (!status_reg)
>  		return -1;
> -	}
> -	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
> -						le16_to_cpu(req->index) - 1];
>  	srclen = 0;
> 
>  	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
> @@ -709,23 +749,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
> long pipe, void *buffer, tmpbuf[0] |= USB_PORT_STAT_RESET;
>  		if (reg & EHCI_PS_PP)
>  			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
> -
> -		if (ehci_is_TDI()) {
> -			switch (PORTSC_PSPD(reg)) {
> -			case PORTSC_PSPD_FS:
> -				break;
> -			case PORTSC_PSPD_LS:
> -				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
> -				break;
> -			case PORTSC_PSPD_HS:
> -			default:
> -				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
> -				break;
> -			}
> -		} else {
> +		if (ehci_is_TDI())
> +			tmpbuf[1] |= ehci_port_speed(ctrl->hcor, reg) >> 8;
> +		else
>  			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
> -		}
> -
>  		if (reg & EHCI_PS_CSC)
>  			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
>  		if (reg & EHCI_PS_PEC)
> @@ -954,6 +981,7 @@ int usb_lowlevel_init(int index, void **controller)
>  	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
>  	cmd |= FLAG_CF;
>  	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
> +

This is redundant ;-)

>  	/* unblock posted write */
>  	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
>  	mdelay(5);
> --
> 1.7.9.5

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v5 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-10 11:44                   ` Marek Vasut
@ 2013-05-13  1:10                     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  1:10 UTC (permalink / raw)
  To: u-boot

2013/5/10 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
>> known to implement a non-standard TDI stuff.
>> Futhermore, it not only leave reserved and CONFIGFLAG registers
>> un-implemented but also has their address spaces removed.
>>
>> And thus, we need weak-aliased functions to both TDI stuff
>> and PORTSC registers for interface abstraction.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>> Changes for v5:
>>    - Split up from Faraday EHCI patch
>>
>> Changes for v2 - v4:
>>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
>>
>>  drivers/usb/host/ehci-hcd.c |  100
>> +++++++++++++++++++++++++++---------------- 1 file changed, 64
>> insertions(+), 36 deletions(-)
>>
>> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>> index c816878..b334173 100644
>> --- a/drivers/usb/host/ehci-hcd.c
>> +++ b/drivers/usb/host/ehci-hcd.c
>> @@ -117,10 +117,50 @@ static struct descriptor {
>>  };
>>
>>  #if defined(CONFIG_EHCI_IS_TDI)
>> -#define ehci_is_TDI()        (1)
>> -#else
>> -#define ehci_is_TDI()        (0)
>> +# define ehci_is_TDI()       (1)
>> +
>> +/* put TDI/ARC silicon into EHCI mode */
>> +void __ehci_tdi_reset(struct ehci_hcor *hcor)
>> +{
>> +     uint32_t tmp, *reg_ptr;
>> +
>> +     reg_ptr = (uint32_t *)((uint8_t *) + USBMODE);
>> +     tmp = ehci_readl(reg_ptr);
>> +     tmp |= USBMODE_CM_HC;
>> +#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
>> +     tmp |= USBMODE_BE;
>>  #endif
>> +     ehci_writel(reg_ptr, tmp);
>> +}
>> +
>> +void ehci_tdi_reset(struct ehci_hcor *hcor)
>> +     __attribute__((weak, alias("__ehci_tdi_reset")));
>
> Just wrap this into simple
>
> __weak void ehci_tdi_reset(struct ehci_hcor *hcor)
> {
>         ...body of __ehci_tdi_reset() above ...
> }
>
> it's the same thing as those two functions above, but without so much code ;-)
>
> if it doesn't work, include <linux/compiler.h>, same below.
>

Got it, thanks

>> +int __ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
>> +{
>> +     int ret = 0;
>> +
>> +     switch (PORTSC_PSPD(portsc)) {
>> +     case PORTSC_PSPD_FS:
>> +             break;
>> +     case PORTSC_PSPD_LS:
>> +             ret = USB_PORT_STAT_LOW_SPEED;
>> +             break;
>> +     case PORTSC_PSPD_HS:
>> +     default:
>> +             ret = USB_PORT_STAT_HIGH_SPEED;
>> +             break;
>> +     }
>> +
>> +     return ret;
>> +}
>> +
>> +int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
>> +     __attribute__((weak, alias("__ehci_port_speed")));
>> +
>> +#else  /* CONFIG_EHCI_IS_TDI */
>> +# define ehci_is_TDI()       (0)
>> +#endif /* CONFIG_EHCI_IS_TDI */
>>
>>  void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
>>  {
>> @@ -149,8 +189,6 @@ static int handshake(uint32_t *ptr, uint32_t mask,
>> uint32_t done, int usec) static int ehci_reset(int index)
>>  {
>>       uint32_t cmd;
>> -     uint32_t tmp;
>> -     uint32_t *reg_ptr;
>>       int ret = 0;
>>
>>       cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
>> @@ -163,15 +201,8 @@ static int ehci_reset(int index)
>>               goto out;
>>       }
>>
>> -     if (ehci_is_TDI()) {
>> -             reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
>> -             tmp = ehci_readl(reg_ptr);
>> -             tmp |= USBMODE_CM_HC;
>> -#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
>> -             tmp |= USBMODE_BE;
>> -#endif
>> -             ehci_writel(reg_ptr, tmp);
>> -     }
>> +     if (ehci_is_TDI())
>> +             ehci_tdi_reset(ehcic[index].hcor);
>>
>>  #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
>>       cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
>> @@ -597,6 +628,18 @@ static inline int min3(int a, int b, int c)
>>       return a;
>>  }
>>
>> +uint32_t *__ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
>> +{
>> +     if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
>> +             printf("The request port(%d) is not configured\n", port);
>> +             return NULL;
>> +     }
>> +
>> +     return (uint32_t *)&hcor->or_portsc[port];
>> +}
>> +uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
>> +     __attribute__((weak, alias("__ehci_get_portsc_register")));
>> +
>>  int
>>  ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
>>                int length, struct devrequest *req)
>> @@ -609,13 +652,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
>> long pipe, void *buffer, uint32_t *status_reg;
>>       struct ehci_ctrl *ctrl = dev->controller;
>>
>> -     if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
>> -             printf("The request port(%d) is not configured\n",
>> -                     le16_to_cpu(req->index) - 1);
>> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
>> +             le16_to_cpu(req->index) - 1);
>> +     if (!status_reg)
>>               return -1;
>> -     }
>> -     status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
>> -                                             le16_to_cpu(req->index) - 1];
>>       srclen = 0;
>>
>>       debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
>> @@ -709,23 +749,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
>> long pipe, void *buffer, tmpbuf[0] |= USB_PORT_STAT_RESET;
>>               if (reg & EHCI_PS_PP)
>>                       tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
>> -
>> -             if (ehci_is_TDI()) {
>> -                     switch (PORTSC_PSPD(reg)) {
>> -                     case PORTSC_PSPD_FS:
>> -                             break;
>> -                     case PORTSC_PSPD_LS:
>> -                             tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
>> -                             break;
>> -                     case PORTSC_PSPD_HS:
>> -                     default:
>> -                             tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
>> -                             break;
>> -                     }
>> -             } else {
>> +             if (ehci_is_TDI())
>> +                     tmpbuf[1] |= ehci_port_speed(ctrl->hcor, reg) >> 8;
>> +             else
>>                       tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
>> -             }
>> -
>>               if (reg & EHCI_PS_CSC)
>>                       tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
>>               if (reg & EHCI_PS_PEC)
>> @@ -954,6 +981,7 @@ int usb_lowlevel_init(int index, void **controller)
>>       cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
>>       cmd |= FLAG_CF;
>>       ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
>> +
>
> This is redundant ;-)
>

Got it, thanks

>>       /* unblock posted write */
>>       cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
>>       mdelay(5);
>> --
>> 1.7.9.5
>
> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-10 11:41                   ` Marek Vasut
@ 2013-05-13  1:11                     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  1:11 UTC (permalink / raw)
  To: u-boot

2013/5/10 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch makes the minimum power-on delay for USB HUB
>> become configurable. The original design waits at least
>> 100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
>> are known to require much longer delay interval.
>>
>> NOTE:
>> The minimal delay is still 100 msec, a small value defined
>> in CONFIG_USB_HUB_MIN_POWER_ON_DELAY would be automatically
>> justified in common/usb_hub.c.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>> Changes for v5:
>>    - Split up from Faraday EHCI patch
>>    - Replace the Faraday EHCI ifdef for the long delay
>>      in usb_hub_configure() with the new configuration option:
>>      USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
>>      to control the minimum usb hub power-on delay.
>>
>> Changes for v2 - v4:
>>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
>>
>>  README           |    3 +++
>>  common/usb_hub.c |    8 +++++++-
>>  2 files changed, 10 insertions(+), 1 deletion(-)
>>
>> diff --git a/README b/README
>> index 0d37d56..c70a59b 100644
>> --- a/README
>> +++ b/README
>> @@ -1244,6 +1244,9 @@ The following options need to be configured:
>>               CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
>>               txfilltuning field in the EHCI controller on reset.
>>
>> +             CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
>> +             interval for usb hub power-on delay.(minimum 100msec)
>> +
>>  - USB Device:
>>               Define the below if you wish to use the USB console.
>>               Once firmware is rebuilt from a serial console issue the
>> diff --git a/common/usb_hub.c b/common/usb_hub.c
>> index b5eeb62..0db3530 100644
>> --- a/common/usb_hub.c
>> +++ b/common/usb_hub.c
>> @@ -61,6 +61,12 @@
>>  #define USB_HUB_DEBUG        0
>>  #endif
>>
>> +#if CONFIG_USB_HUB_MIN_POWER_ON_DELAY > 100
>> +# define USB_HUB_MIN_POWER_ON_DELAY  CONFIG_USB_HUB_MIN_POWER_ON_DELAY
>> +#else
>> +# define USB_HUB_MIN_POWER_ON_DELAY  100
>> +#endif
>
> Even better (and easier) solution here would be:
>
> ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
> #define CONFIG_USB_HUB_MIN_POWER_ON_DELAY 100
> #endif
>
> no ? ;-)
>

Yep, it looks better, I'll have it fixed.

>>  #define USB_PRINTF(fmt, args...)     debug_cond(USB_DEBUG, fmt, ##args)
>>  #define USB_HUB_PRINTF(fmt, args...) debug_cond(USB_HUB_DEBUG, fmt,
>> ##args)
>>
>> @@ -121,7 +127,7 @@ static void usb_hub_power_on(struct usb_hub_device
>> *hub) }
>>
>>       /* Wait at least 100 msec for power to become stable */
>> -     mdelay(max(pgood_delay, (unsigned)100));
>> +     mdelay(max(pgood_delay, USB_HUB_MIN_POWER_ON_DELAY));
>>  }
>>
>>  void usb_hub_reset(void)
>> --
>> 1.7.9.5
>
> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support
  2013-05-09  3:20                 ` [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
  2013-05-10 11:41                   ` Marek Vasut
@ 2013-05-13  2:07                   ` Kuo-Jung Su
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
                                       ` (3 more replies)
  1 sibling, 4 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  2:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Changes for v6:
   - usb_hub: Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY
     default value setup.
   - ehci-hcd: Simplify weak aliased function declaration
   - ehci-hcd: Drop redundant line feed

Changes for v5:
   - Split up EHCI changeset
   - usb_hub: replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.
   - ehci-faraday: fix the invalid multi-line comment style.
   - gadget-fotg210: coding style cleanup.
   - gadget-fotg210: drop postfix '__iomem' from struct fotg210_regs
   - gadget-fotg210: use permanent delay for hardware reset
   - gadget-fotg210: drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - gadget-fotg210: drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

Kuo-Jung Su (4):
  usb: hub: make minimum power-on delay configurable
  usb: ehci: add weak-aliased functions to portsc & tdi
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 README                            |    3 +
 common/usb_hub.c                  |   15 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/host/Makefile         |    1 +
 drivers/usb/host/ehci-faraday.c   |  146 ++++++
 drivers/usb/host/ehci-hcd.c       |   96 ++--
 include/usb/fotg210.h             |  364 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 10 files changed, 1604 insertions(+), 39 deletions(-)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-13  2:07                   ` [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
@ 2013-05-13  2:07                     ` Kuo-Jung Su
  2013-05-13  2:36                       ` Marek Vasut
  2013-05-13  8:28                       ` [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
                                       ` (2 subsequent siblings)
  3 siblings, 2 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  2:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch makes the minimum power-on delay for USB HUB
become configurable. The original design waits at least
100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
are known to require much longer delay interval.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v6:
   - Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY default value setup.

Changes for v5:
   - Split up from Faraday EHCI patch
   - Replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 README           |    3 +++
 common/usb_hub.c |    8 ++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/README b/README
index 0d37d56..455163b 100644
--- a/README
+++ b/README
@@ -1244,6 +1244,9 @@ The following options need to be configured:
 		CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
 		txfilltuning field in the EHCI controller on reset.

+		CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
+		interval for usb hub power-on delay.(100msec by default)
+
 - USB Device:
 		Define the below if you wish to use the USB console.
 		Once firmware is rebuilt from a serial console issue the
diff --git a/common/usb_hub.c b/common/usb_hub.c
index b5eeb62..f240d8c 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -61,6 +61,10 @@
 #define USB_HUB_DEBUG	0
 #endif

+#ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+#define CONFIG_USB_HUB_MIN_POWER_ON_DELAY	100
+#endif
+
 #define USB_PRINTF(fmt, args...)	debug_cond(USB_DEBUG, fmt, ##args)
 #define USB_HUB_PRINTF(fmt, args...)	debug_cond(USB_HUB_DEBUG, fmt, ##args)

@@ -120,8 +124,8 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
 		USB_HUB_PRINTF("port %d returns %lX\n", i + 1, dev->status);
 	}

-	/* Wait at least 100 msec for power to become stable */
-	mdelay(max(pgood_delay, (unsigned)100));
+	/* Wait for power to become stable */
+	mdelay(max(pgood_delay, CONFIG_USB_HUB_MIN_POWER_ON_DELAY));
 }

 void usb_hub_reset(void)
--
1.7.9.5

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-13  2:07                   ` [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-13  2:07                     ` Kuo-Jung Su
  2013-05-13  2:32                       ` Marek Vasut
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  2:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
known to implement a non-standard TDI stuff.
Futhermore, it not only leave reserved and CONFIGFLAG registers
un-implemented but also has their address spaces removed.

And thus, we need weak-aliased functions to both TDI stuff
and PORTSC registers for interface abstraction.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v6:
   - Simplify weak aliased function declaration
   - Drop redundant line feed

Changes for v5:
   - Split up from Faraday EHCI patch

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 drivers/usb/host/ehci-hcd.c |   91 ++++++++++++++++++++++++++-----------------
 1 file changed, 55 insertions(+), 36 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index c816878..ae3f2a4 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -117,10 +117,44 @@ static struct descriptor {
 };

 #if defined(CONFIG_EHCI_IS_TDI)
-#define ehci_is_TDI()	(1)
-#else
-#define ehci_is_TDI()	(0)
+# define ehci_is_TDI()	(1)
+
+/* put TDI/ARC silicon into EHCI mode */
+__weak void ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	uint32_t tmp, *reg_ptr;
+
+	reg_ptr = (uint32_t *)((uint8_t *) + USBMODE);
+	tmp = ehci_readl(reg_ptr);
+	tmp |= USBMODE_CM_HC;
+#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
+	tmp |= USBMODE_BE;
 #endif
+	ehci_writel(reg_ptr, tmp);
+}
+
+__weak int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int ret = 0;
+
+	switch (PORTSC_PSPD(portsc)) {
+	case PORTSC_PSPD_FS:
+		break;
+	case PORTSC_PSPD_LS:
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case PORTSC_PSPD_HS:
+	default:
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	}
+
+	return ret;
+}
+
+#else  /* CONFIG_EHCI_IS_TDI */
+# define ehci_is_TDI()	(0)
+#endif /* CONFIG_EHCI_IS_TDI */

 void __ehci_powerup_fixup(uint32_t *status_reg, uint32_t *reg)
 {
@@ -149,8 +183,6 @@ static int handshake(uint32_t *ptr, uint32_t mask, uint32_t done, int usec)
 static int ehci_reset(int index)
 {
 	uint32_t cmd;
-	uint32_t tmp;
-	uint32_t *reg_ptr;
 	int ret = 0;

 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
@@ -163,15 +195,8 @@ static int ehci_reset(int index)
 		goto out;
 	}

-	if (ehci_is_TDI()) {
-		reg_ptr = (uint32_t *)((u8 *)ehcic[index].hcor + USBMODE);
-		tmp = ehci_readl(reg_ptr);
-		tmp |= USBMODE_CM_HC;
-#if defined(CONFIG_EHCI_MMIO_BIG_ENDIAN)
-		tmp |= USBMODE_BE;
-#endif
-		ehci_writel(reg_ptr, tmp);
-	}
+	if (ehci_is_TDI())
+		ehci_tdi_reset(ehcic[index].hcor);

 #ifdef CONFIG_USB_EHCI_TXFIFO_THRESH
 	cmd = ehci_readl(&ehcic[index].hcor->or_txfilltuning);
@@ -597,6 +622,16 @@ static inline int min3(int a, int b, int c)
 	return a;
 }

+__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
@@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	uint32_t *status_reg;
 	struct ehci_ctrl *ctrl = dev->controller;

-	if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		printf("The request port(%d) is not configured\n",
-			le16_to_cpu(req->index) - 1);
+	status_reg = ehci_get_portsc_register(ctrl->hcor,
+		le16_to_cpu(req->index) - 1);
+	if (!status_reg)
 		return -1;
-	}
-	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
-						le16_to_cpu(req->index) - 1];
 	srclen = 0;

 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -709,23 +741,10 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 			tmpbuf[0] |= USB_PORT_STAT_RESET;
 		if (reg & EHCI_PS_PP)
 			tmpbuf[1] |= USB_PORT_STAT_POWER >> 8;
-
-		if (ehci_is_TDI()) {
-			switch (PORTSC_PSPD(reg)) {
-			case PORTSC_PSPD_FS:
-				break;
-			case PORTSC_PSPD_LS:
-				tmpbuf[1] |= USB_PORT_STAT_LOW_SPEED >> 8;
-				break;
-			case PORTSC_PSPD_HS:
-			default:
-				tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-				break;
-			}
-		} else {
+		if (ehci_is_TDI())
+			tmpbuf[1] |= ehci_port_speed(ctrl->hcor, reg) >> 8;
+		else
 			tmpbuf[1] |= USB_PORT_STAT_HIGH_SPEED >> 8;
-		}
-
 		if (reg & EHCI_PS_CSC)
 			tmpbuf[2] |= USB_PORT_STAT_C_CONNECTION;
 		if (reg & EHCI_PS_PEC)
--
1.7.9.5

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

* [U-Boot] [PATCH v6 3/4] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-13  2:07                   ` [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
@ 2013-05-13  2:07                     ` Kuo-Jung Su
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  2:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address space removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differ from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Break down EHCI changes as seperate changesets.
   - Fix the invalid multi-line comment style.

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 common/usb_hub.c                |    7 +-
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  146 ++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |    5 +
 include/usb/fotg210.h           |  364 +++++++++++++++++++++++++++++++++++++++
 include/usb/fusbh200.h          |   61 +++++++
 6 files changed, 583 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index f240d8c..25821a5 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -445,7 +445,11 @@ static int usb_hub_configure(struct usb_device *dev)
 					i + 1, portstatus);
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_ENABLE);
-
+			/*
+			 * The following hack causes a ghost device problem
+			 * to Faraday EHCI
+			 */
+#ifndef CONFIG_USB_EHCI_FARADAY
 			/* EM interference sometimes causes bad shielded USB
 			 * devices to be shutdown by the hub, this hack enables
 			 * them again. Works at least with mouse driver */
@@ -457,6 +461,7 @@ static int usb_hub_configure(struct usb_device *dev)
 						"re-enabling...\n", i + 1);
 					usb_hub_port_connect_change(dev, i);
 			}
+#endif
 		}
 		if (portstatus & USB_PORT_STAT_SUSPEND) {
 			USB_HUB_PRINTF("port %d suspend change\n", i + 1);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..1be9369
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,146 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+/*
+ * This ehci_tdi_reset() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+void ehci_tdi_reset(struct ehci_hcor *hcor)
+{
+	/* nothing needs to be done */
+}
+
+/*
+ * This ehci_port_speed() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+int ehci_port_speed(struct ehci_hcor *hcor, unsigned int portsc)
+{
+	int spd, ret = 0;
+	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		break;
+	case 1:    /* low  speed */
+		ret = USB_PORT_STAT_LOW_SPEED;
+		break;
+	case 2:    /* high speed */
+		ret = USB_PORT_STAT_HIGH_SPEED;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This ehci_get_portsc_register() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/* Faraday EHCI has one and only one portsc register */
+	if (port > 0) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)hcor + 0x20);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index ae3f2a4..37e5424 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -598,10 +598,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
 		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
 		      ehci_readl(&ctrl->hcor->or_portsc[0]),
 		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
 	}

 	free(qtd);
@@ -969,10 +971,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..2d2d243
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,364 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t miscr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[2];
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */
+};
+
+/* Miscellaneous Register */
+#define MISCR_SUSPEND  (1 << 6) /* Put transceiver in suspend mode */
+#define MISCR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define MISCR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define MISCR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* OTG Control Status Register */
+#define OTGCSR_SPD_HIGH     (2 << 22) /* Speed of the attached device (host) */
+#define OTGCSR_SPD_LOW      (1 << 22)
+#define OTGCSR_SPD_FULL     (0 << 22)
+#define OTGCSR_SPD_MASK     (3 << 22)
+#define OTGCSR_SPD_SHIFT    22
+#define OTGCSR_SPD(x)       (((x) >> 22) & 0x03)
+#define OTGCSR_DEV_A        (0 << 21) /* Acts as A-device */
+#define OTGCSR_DEV_B        (1 << 21) /* Acts as B-device */
+#define OTGCSR_ROLE_H       (0 << 20) /* Acts as Host */
+#define OTGCSR_ROLE_D       (1 << 20) /* Acts as Device */
+#define OTGCSR_A_VBUS_VLD   (1 << 19) /* A-device VBUS Valid */
+#define OTGCSR_A_SESS_VLD   (1 << 18) /* A-device Session Valid */
+#define OTGCSR_B_SESS_VLD   (1 << 17) /* B-device Session Valid */
+#define OTGCSR_B_SESS_END   (1 << 16) /* B-device Session End */
+#define OTGCSR_HFT_LONG     (1 << 11) /* HDISCON noise filter = 270 us*/
+#define OTGCSR_HFT          (0 << 11) /* HDISCON noise filter = 135 us*/
+#define OTGCSR_VFT_LONG     (1 << 10) /* VBUS noise filter = 472 us*/
+#define OTGCSR_VFT          (0 << 10) /* VBUS noise filter = 135 us*/
+#define OTGCSR_IDFT_LONG    (1 << 9)  /* ID noise filter = 4 ms*/
+#define OTGCSR_IDFT         (0 << 9)  /* ID noise filter = 3 ms*/
+#define OTGCSR_A_SRPR_VBUS  (0 << 8)  /* A-device: SRP responds to VBUS */
+#define OTGCSR_A_SRPR_DATA  (1 << 8)  /* A-device: SRP responds to DATA-LINE */
+#define OTGCSR_A_SRP_EN     (1 << 7)  /* A-device SRP detection enabled */
+#define OTGCSR_A_HNP        (1 << 6)  /* Set role=A-device with HNP enabled */
+#define OTGCSR_A_BUSDROP    (1 << 5)  /* A-device drop bus (power-down) */
+#define OTGCSR_A_BUSREQ     (1 << 4)  /* A-device request bus */
+#define OTGCSR_B_VBUS_DISC  (1 << 2)  /* B-device discharges VBUS */
+#define OTGCSR_B_HNP        (1 << 1)  /* B-device enable HNP */
+#define OTGCSR_B_BUSREQ     (1 << 0)  /* B-device request bus */
+
+/* OTG Interrupt Status Register */
+#define OTGISR_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGISR_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGISR_OVD          (1 << 10) /* over-current detected */
+#define OTGISR_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGISR_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGISR_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGISR_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGISR_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGISR_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* OTG Interrupt Enable Register */
+#define OTGIER_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGIER_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGIER_OVD          (1 << 10) /* over-current detected */
+#define OTGIER_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGIER_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGIER_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGIER_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGIER_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGIER_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* Global Interrupt Status Register (W1C) */
+#define ISR_HOST            (1 << 2)  /* USB Host interrupt */
+#define ISR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define ISR_DEV             (1 << 0)  /* USB Device interrupt */
+#define ISR_MASK            0x07
+
+/* Global Interrupt Mask Register */
+#define IMR_IRQLH           (1 << 3)  /* Interrupt triggered at level-high */
+#define IMR_IRQLL           (0 << 3)  /* Interrupt triggered@level-low */
+#define IMR_HOST            (1 << 2)  /* USB Host interrupt */
+#define IMR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define IMR_DEV             (1 << 0)  /* USB Device interrupt */
+#define IMR_MASK            0x0f
+
+/* Device Control Register */
+#define DEVCTRL_FS_FORCED   (1 << 9)  /* Forced to be Full-Speed Mode */
+#define DEVCTRL_HS          (1 << 6)  /* High Speed Mode */
+#define DEVCTRL_FS          (0 << 6)  /* Full Speed Mode */
+#define DEVCTRL_EN          (1 << 5)  /* Chip Enable */
+#define DEVCTRL_RESET       (1 << 4)  /* Chip Software Reset */
+#define DEVCTRL_SUSPEND     (1 << 3)  /* Enter Suspend Mode */
+#define DEVCTRL_GIRQ_EN     (1 << 2)  /* Global Interrupt Enabled */
+#define DEVCTRL_HALFSPD     (1 << 1)  /* Half speed mode for FPGA test */
+#define DEVCTRL_RWAKEUP     (1 << 0)  /* Enable remote wake-up */
+
+/* Device Address Register */
+#define DEVADDR_CONF        (1 << 7)  /* SET_CONFIGURATION has been executed */
+#define DEVADDR_ADDR(x)     ((x) & 0x7f)
+#define DEVADDR_ADDR_MASK   0x7f
+
+/* Device Test Register */
+#define DEVTEST_NOSOF       (1 << 6)  /* Do not generate SOF */
+#define DEVTEST_TST_MODE    (1 << 5)  /* Enter Test Mode */
+#define DEVTEST_TST_NOTS    (1 << 4)  /* Do not toggle sequence */
+#define DEVTEST_TST_NOCRC   (1 << 3)  /* Do not append CRC */
+#define DEVTEST_TST_CLREA   (1 << 2)  /* Clear External Side Address */
+#define DEVTEST_TST_CXLP    (1 << 1)  /* EP0 loopback test */
+#define DEVTEST_TST_CLRFF   (1 << 0)  /* Clear FIFO */
+
+/* SOF Frame Number Register */
+#define SOFFNR_UFN(x)       (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */
+#define SOFFNR_FNR(x)       ((x) & 0x7ff) /* SOF Frame Number */
+
+/* SOF Mask Timer Register */
+#define SOFMTR_TMR(x)       ((x) & 0xffff)
+
+/* PHY Test Mode Selector Register */
+#define PHYTMSR_TST_PKT     (1 << 4) /* Packet send test */
+#define PHYTMSR_TST_SE0NAK  (1 << 3) /* High-Speed quiescent state */
+#define PHYTMSR_TST_KSTA    (1 << 2) /* High-Speed K state */
+#define PHYTMSR_TST_JSTA    (1 << 1) /* High-Speed J state */
+#define PHYTMSR_UNPLUG      (1 << 0) /* Enable soft-detachment */
+
+/* CX FIFO Register */
+#define CXFIFO_BYTES(x)     (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */
+#define CXFIFO_FIFOE(x)     (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */
+#define CXFIFO_FIFOE_FIFO0  (1 << 8)
+#define CXFIFO_FIFOE_FIFO1  (1 << 9)
+#define CXFIFO_FIFOE_FIFO2  (1 << 10)
+#define CXFIFO_FIFOE_FIFO3  (1 << 11)
+#define CXFIFO_FIFOE_MASK   (0x0f << 8)
+#define CXFIFO_CXFIFOE      (1 << 5) /* CX FIFO empty */
+#define CXFIFO_CXFIFOF      (1 << 4) /* CX FIFO full */
+#define CXFIFO_CXFIFOCLR    (1 << 3) /* CX FIFO clear */
+#define CXFIFO_CXSTALL      (1 << 2) /* CX Stall */
+#define CXFIFO_TSTPKTFIN    (1 << 1) /* Test packet data transfer finished */
+#define CXFIFO_CXFIN        (1 << 0) /* CX data transfer finished */
+
+/* IDLE Counter Register */
+#define IDLE_MS(x)          ((x) & 0x07) /* PHY suspend delay = x ms */
+
+/* Group Interrupt Mask(Disable) Register */
+#define GIMR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GIMR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GIMR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+#define GIMR_MASK           0x07
+
+/* Group Interrupt Mask(Disable) Register 0 (CX) */
+#define GIMR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GIMR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GIMR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GIMR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GIMR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GIMR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+#define GIMR0_MASK          0x3f
+
+/* Group Interrupt Mask(Disable) Register 1 (FIFO) */
+#define GIMR1_FIFO_IN(x)    (1 << (((x) & 3) + 16))    /* FIFOx IN */
+#define GIMR1_FIFO_TX(x)    GIMR1_FIFO_IN(x)
+#define GIMR1_FIFO_OUT(x)   (1 << (((x) & 3) * 2))     /* FIFOx OUT */
+#define GIMR1_FIFO_SPK(x)   (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */
+#define GIMR1_FIFO_RX(x)    (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x))
+#define GIMR1_MASK          0xf00ff
+
+/* Group Interrupt Mask(Disable) Register 2 (Device) */
+#define GIMR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GIMR2_IDLE          (1 << 9)  /* Device idle */
+#define GIMR2_DMAERR        (1 << 8)  /* DMA error */
+#define GIMR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GIMR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GIMR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GIMR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GIMR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GIMR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GIMR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GIMR2_RESET         (1 << 0)  /* Reset Interrupt */
+#define GIMR2_MASK          0x7ff
+
+/* Group Interrupt Status Register */
+#define GISR_GRP2           (1 << 2) /* Interrupt group 2 */
+#define GISR_GRP1           (1 << 1) /* Interrupt group 1 */
+#define GISR_GRP0           (1 << 0) /* Interrupt group 0 */
+
+/* Group Interrupt Status Register 0 (CX) */
+#define GISR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GISR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GISR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GISR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GISR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GISR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Status Register 1 (FIFO) */
+#define GISR1_IN_FIFO(x)    (1 << (((x) & 0x03) + 16))    /* FIFOx IN */
+#define GISR1_OUT_FIFO(x)   (1 << (((x) & 0x03) * 2))     /* FIFOx OUT */
+#define GISR1_SPK_FIFO(x)   (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */
+#define GISR1_RX_FIFO(x)    (3 << (((x) & 0x03) * 2))     /* FIFOx OUT/SPK */
+
+/* Group Interrupt Status Register 2 (Device) */
+#define GISR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GISR2_IDLE          (1 << 9)  /* Device idle */
+#define GISR2_DMAERR        (1 << 8)  /* DMA error */
+#define GISR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GISR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GISR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GISR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GISR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GISR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GISR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GISR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Receive Zero-Length-Packet Register */
+#define RXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP rx interrupt */
+
+/* Transfer Zero-Length-Packet Register */
+#define TXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP tx interrupt */
+
+/* ISOC Error/Abort Status Register */
+#define ISOEASR_EP(x)       (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */
+
+/* IN Endpoint Register */
+#define IEP_SENDZLP         (1 << 15)     /* Send Zero-Length-Packet */
+#define IEP_TNRHB(x)        (((x) & 0x03) << 13) \
+	/* Transaction Number for High-Bandwidth EP(ISOC) */
+#define IEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define IEP_STALL           (1 << 11)     /* Stall */
+#define IEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* OUT Endpoint Register */
+#define OEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define OEP_STALL           (1 << 11)     /* Stall */
+#define OEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* Endpoint Map Register (EP1 ~ EP4) */
+#define EPMAP14_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 0)
+#define EPMAP14_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 4)
+#define EPMAP14_SET(ep, in, out) \
+	do { \
+		EPMAP14_SET_IN(ep, in); \
+		EPMAP14_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP14_DEFAULT     0x33221100 /* EP1->FIFO0, EP2->FIFO1... */
+
+/* Endpoint Map Register (EP5 ~ EP8) */
+#define EPMAP58_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 0)
+#define EPMAP58_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 4)
+#define EPMAP58_SET(ep, in, out) \
+	do { \
+		EPMAP58_SET_IN(ep, in); \
+		EPMAP58_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP58_DEFAULT     0x00000000 /* All EPx->FIFO0 */
+
+/* FIFO Map Register */
+#define FIFOMAP_BIDIR       (2 << 4)
+#define FIFOMAP_IN          (1 << 4)
+#define FIFOMAP_OUT         (0 << 4)
+#define FIFOMAP_DIR_MASK    0x30
+#define FIFOMAP_EP(x)       ((x) & 0x0f)
+#define FIFOMAP_EP_MASK     0x0f
+#define FIFOMAP_CFG_MASK    0x3f
+#define FIFOMAP_DEFAULT     0x04030201 /* FIFO0->EP1, FIFO1->EP2... */
+#define FIFOMAP(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Configuration Register */
+#define FIFOCFG_EN          (1 << 5)
+#define FIFOCFG_BLKSZ_1024  (1 << 4)
+#define FIFOCFG_BLKSZ_512   (0 << 4)
+#define FIFOCFG_3BLK        (2 << 2)
+#define FIFOCFG_2BLK        (1 << 2)
+#define FIFOCFG_1BLK        (0 << 2)
+#define FIFOCFG_NBLK_MASK   3
+#define FIFOCFG_NBLK_SHIFT  2
+#define FIFOCFG_INTR        (3 << 0)
+#define FIFOCFG_BULK        (2 << 0)
+#define FIFOCFG_ISOC        (1 << 0)
+#define FIFOCFG_RSVD        (0 << 0)  /* Reserved */
+#define FIFOCFG_TYPE_MASK   3
+#define FIFOCFG_TYPE_SHIFT  0
+#define FIFOCFG_CFG_MASK    0x3f
+#define FIFOCFG(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Control Status Register */
+#define FIFOCSR_RESET       (1 << 12) /* FIFO Reset */
+#define FIFOCSR_BYTES(x)    ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */
+
+/* DMA Target FIFO Register */
+#define DMAFIFO_CX          (1 << 4) /* DMA FIFO = CX FIFO */
+#define DMAFIFO_FIFO(x)     (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */
+
+/* DMA Control Register */
+#define DMACTRL_LEN(x)      (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */
+#define DMACTRL_LEN_SHIFT   8
+#define DMACTRL_CLRFF       (1 << 4) /* Clear FIFO upon DMA abort */
+#define DMACTRL_ABORT       (1 << 3) /* DMA abort */
+#define DMACTRL_IO2IO       (1 << 2) /* IO to IO */
+#define DMACTRL_FIFO2MEM    (0 << 1) /* FIFO to Memory */
+#define DMACTRL_MEM2FIFO    (1 << 1) /* Memory to FIFO */
+#define DMACTRL_START       (1 << 0) /* DMA start */
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..8a9c488
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,61 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+/* EOF & Async. Schedule Sleep Timer Register */
+#define EASSTR_RUNNING  (1 << 6) /* Put transceiver in running/resume mode */
+#define EASSTR_SUSPEND  (0 << 6) /* Put transceiver in suspend mode */
+#define EASSTR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define EASSTR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define EASSTR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* Bus Monitor Control Status Register */
+#define BMCSR_SPD_HIGH  (2 << 9) /* Speed of the attached device */
+#define BMCSR_SPD_LOW   (1 << 9)
+#define BMCSR_SPD_FULL  (0 << 9)
+#define BMCSR_SPD_MASK  (3 << 9)
+#define BMCSR_SPD_SHIFT 9
+#define BMCSR_SPD(x)    ((x >> 9) & 0x03)
+#define BMCSR_VBUS      (1 << 8) /* VBUS Valid */
+#define BMCSR_VBUS_OFF  (1 << 4) /* VBUS Off */
+#define BMCSR_VBUS_ON   (0 << 4) /* VBUS On */
+#define BMCSR_IRQLH     (1 << 3) /* IRQ triggered at level-high */
+#define BMCSR_IRQLL     (0 << 3) /* IRQ triggered@level-low */
+#define BMCSR_HALFSPD   (1 << 2) /* Half speed mode for FPGA test */
+#define BMCSR_HFT_LONG  (1 << 1) /* HDISCON noise filter = 270 us*/
+#define BMCSR_HFT       (0 << 1) /* HDISCON noise filter = 135 us*/
+#define BMCSR_VFT_LONG  (1 << 1) /* VBUS noise filter = 472 us*/
+#define BMCSR_VFT       (0 << 1) /* VBUS noise filter = 135 us*/
+
+/* Bus Monitor Interrupt Status Register */
+/* Bus Monitor Interrupt Enable Register */
+#define BMISR_DMAERR    (1 << 4) /* DMA error */
+#define BMISR_DMA       (1 << 3) /* DMA complete */
+#define BMISR_DEVRM     (1 << 2) /* device removed */
+#define BMISR_OVD       (1 << 1) /* over-current detected */
+#define BMISR_VBUSERR   (1 << 0) /* VBUS error */
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v6 4/4] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-13  2:07                   ` [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
                                       ` (2 preceding siblings ...)
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-05-13  2:07                     ` Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  2:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup.
   - Drop postfix '__iomem' from struct fotg210_regs
   - Use permanent delay for hardware reset
   - Drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - Drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Remove dcache_enable() from usb_gadget_register_driver()

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 957 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..d003331
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,948 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs      *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id & 0x03) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) & 0x03);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], OEP_STALL);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t i;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(DEVCTRL_EN, &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(0, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable all interrupts */
+	writel(IMR_MASK, &regs->imr);
+	writel(GIMR_MASK, &regs->gimr);
+	writel(GIMR0_MASK, &regs->gimr0);
+	writel(GIMR1_MASK, &regs->gimr1);
+	writel(GIMR2_MASK, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(ISR_MASK, &regs->isr);
+	writel(0, &regs->gisr);
+	writel(0, &regs->gisr0);
+	writel(0, &regs->gisr1);
+	writel(0, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+	mdelay(10);
+	if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+	mdelay(10);
+	if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(EPMAP14_DEFAULT, &regs->epmap14);
+	writel(EPMAP58_DEFAULT, &regs->epmap58);
+	writel(FIFOMAP_DEFAULT, &regs->fifomap);
+	writel(0, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+		mdelay(10);
+		if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(IMR_IRQLH | IMR_HOST | IMR_OTG, &regs->imr);
+	writel(ISR_MASK, &regs->isr);
+	/* disable EP0 IN/OUT interrupt */
+	writel(GIMR0_CXOUT | GIMR0_CXIN, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(GIMR1_MASK, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN
+		| GIMR2_ZLPRX | GIMR2_ZLPTX, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_GIRQ_EN);
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	int fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->dma_ctrl) & DMACTRL_START)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((ulong)buf, (ulong)buf + len);
+	else
+		invalidate_dcache_range((ulong)buf, (ulong)buf + len);
+
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until cx/ep0 fifo empty */
+			fotg210_cxwait(chip, CXFIFO_CXFIFOE);
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+		} else {
+			/* Wait until epx fifo empty */
+			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+		}
+		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+
+		if (ep->id == 0) {
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+			do {
+				blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+			} while (blen < len);
+		} else {
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+			blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+		}
+		len  = (len < blen) ? len : blen;
+		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & GISR2_DMAFIN) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & GISR2_DMAERR) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(DMACTRL_ABORT | DMACTRL_CLRFF, &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & OTGCSR_DEV_B) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				/* SOF mask timer = 1100 ticks */
+				writel(SOFMTR_TMR(1100), &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				/* SOF mask timer = 10000 ticks */
+				writel(SOFMTR_TMR(10000), &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(DMAFIFO_CX, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->ep0_data);
+	tmp[1] = readl(&regs->ep0_data);
+	/* release data port */
+	writel(0, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(chip->addr | DEVADDR_CONF,
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue & DEVADDR_ADDR_MASK;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], IEP_STALL);
+				setbits_le32(&regs->oep[id - 1], OEP_STALL);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue)) {
+		setbits_le32(&regs->gimr1,
+			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+	}
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_IN));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+	clrbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return SOFFNR_FNR(readl(&regs->sof_fnr));
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name  = "ep0",
+			.ops   = &fotg210_ep_ops,
+		},
+		.desc      = &ep0_desc,
+		.chip      = &controller,
+		.maxpacket = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name  = "ep1",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name  = "ep2",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name  = "ep3",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name  = "ep4",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t id, st, isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & ISR_DEV) || !gisr)
+		return 0;
+
+	writel(ISR_DEV, &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & GISR_GRP0) {
+		st = readl(&regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & GISR0_CXERR)
+			printf("fotg210: cmd error\n");
+
+		if (st & GISR0_CXABORT)
+			printf("fotg210: cmd abort\n");
+
+		if (st & GISR0_CXSETUP)    /* setup */
+			fotg210_setup(chip);
+		else if (st & GISR0_CXEND) /* command finish */
+			setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & GISR_GRP1) {
+		st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & GISR1_RX_FIFO(id))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & GISR_GRP2) {
+		st = readl(&regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & GISR2_RESET)
+			printf("fotg210: reset by host\n");
+		else if (st & GISR2_SUSPEND)
+			printf("fotg210: suspend/removed\n");
+		else if (st & GISR2_RESUME)
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & GISR2_ISOCERR)
+			printf("fotg210: iso error\n");
+		if (st & GISR2_ISOCABT)
+			printf("fotg210: iso abort\n");
+		if (st & GISR2_DMAERR)
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
@ 2013-05-13  2:32                       ` Marek Vasut
  2013-05-13  8:09                         ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-13  2:32 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
> known to implement a non-standard TDI stuff.
> Futhermore, it not only leave reserved and CONFIGFLAG registers
> un-implemented but also has their address spaces removed.
> 
> And thus, we need weak-aliased functions to both TDI stuff
> and PORTSC registers for interface abstraction.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>
> ---
> Changes for v6:
>    - Simplify weak aliased function declaration
>    - Drop redundant line feed
> 
> Changes for v5:
>    - Split up from Faraday EHCI patch
> 
> Changes for v2 - v4:
>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
> 
>  drivers/usb/host/ehci-hcd.c |   91
> ++++++++++++++++++++++++++----------------- 1 file changed, 55
> insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> index c816878..ae3f2a4 100644
> --- a/drivers/usb/host/ehci-hcd.c
> +++ b/drivers/usb/host/ehci-hcd.c
> @@ -117,10 +117,44 @@ static struct descriptor {
>  };
> 
>  #if defined(CONFIG_EHCI_IS_TDI)
> -#define ehci_is_TDI()	(1)
> -#else
> -#define ehci_is_TDI()	(0)
> +# define ehci_is_TDI()	(1)

btw you can remove those braces around (1) and (0) below. But I have one more 
question ...

[...]

> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
> long pipe, void *buffer, uint32_t *status_reg;
>  	struct ehci_ctrl *ctrl = dev->controller;
> 
> -	if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
> -		printf("The request port(%d) is not configured\n",
> -			le16_to_cpu(req->index) - 1);
> +	status_reg = ehci_get_portsc_register(ctrl->hcor,
> +		le16_to_cpu(req->index) - 1);
> +	if (!status_reg)

What happens here if req->index is zero ?

Hint: the above code always does unsigned comparison ...

I think you should make the second argument of ehci_get_portsc_register() 
unsigned short too (as is req->index in struct devrequest).

>  		return -1;
> -	}
> -	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
> -						le16_to_cpu(req->index) - 1];
>  	srclen = 0;
> 
>  	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",

[...]

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-13  2:36                       ` Marek Vasut
  2013-05-13  8:12                         ` Kuo-Jung Su
  2013-05-13  8:28                       ` [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-13  2:36 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> This patch makes the minimum power-on delay for USB HUB
> become configurable. The original design waits at least
> 100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
> are known to require much longer delay interval.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>

The rest of the patches are good, just 2/4 needs minor tweak.

I'd do it myself, but they don't apply to u-boot-usb/master , can you please 
adjust, rebase them and repost? Then I'll pick them.

Thanks!

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-13  2:32                       ` Marek Vasut
@ 2013-05-13  8:09                         ` Kuo-Jung Su
  2013-05-13 15:10                           ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  8:09 UTC (permalink / raw)
  To: u-boot

2013/5/13 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
>> known to implement a non-standard TDI stuff.
>> Futhermore, it not only leave reserved and CONFIGFLAG registers
>> un-implemented but also has their address spaces removed.
>>
>> And thus, we need weak-aliased functions to both TDI stuff
>> and PORTSC registers for interface abstraction.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>> ---
>> Changes for v6:
>>    - Simplify weak aliased function declaration
>>    - Drop redundant line feed
>>
>> Changes for v5:
>>    - Split up from Faraday EHCI patch
>>
>> Changes for v2 - v4:
>>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
>>
>>  drivers/usb/host/ehci-hcd.c |   91
>> ++++++++++++++++++++++++++----------------- 1 file changed, 55
>> insertions(+), 36 deletions(-)
>>
>> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>> index c816878..ae3f2a4 100644
>> --- a/drivers/usb/host/ehci-hcd.c
>> +++ b/drivers/usb/host/ehci-hcd.c
>> @@ -117,10 +117,44 @@ static struct descriptor {
>>  };
>>
>>  #if defined(CONFIG_EHCI_IS_TDI)
>> -#define ehci_is_TDI()        (1)
>> -#else
>> -#define ehci_is_TDI()        (0)
>> +# define ehci_is_TDI()       (1)
>
> btw you can remove those braces around (1) and (0) below. But I have one more
> question ...
>

Got it, thanks

> [...]
>
>> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
>> long pipe, void *buffer, uint32_t *status_reg;
>>       struct ehci_ctrl *ctrl = dev->controller;
>>
>> -     if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
>> -             printf("The request port(%d) is not configured\n",
>> -                     le16_to_cpu(req->index) - 1);
>> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
>> +             le16_to_cpu(req->index) - 1);
>> +     if (!status_reg)
>
> What happens here if req->index is zero ?
>
> Hint: the above code always does unsigned comparison ...
>
> I think you should make the second argument of ehci_get_portsc_register()
> unsigned short too (as is req->index in struct devrequest).
>

Sorry, but I'll prefer 'int' over 'unsigned short', since it looks to me that
the u-boot would set 'req->index' to 0 at startup, which results in
a 'port = -1' to be passed to ehci_get_portsc_register().

And I think '-1' is a better self-explain value, so I'd like to stick with 'int'

>>               return -1;
>> -     }
>> -     status_reg = (uint32_t *)&ctrl->hcor->or_portsc[
>> -                                             le16_to_cpu(req->index) - 1];
>>       srclen = 0;
>>
>>       debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
>
> [...]
>
> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-13  2:36                       ` Marek Vasut
@ 2013-05-13  8:12                         ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  8:12 UTC (permalink / raw)
  To: u-boot

2013/5/13 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This patch makes the minimum power-on delay for USB HUB
>> become configurable. The original design waits at least
>> 100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
>> are known to require much longer delay interval.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>
> The rest of the patches are good, just 2/4 needs minor tweak.
>
> I'd do it myself, but they don't apply to u-boot-usb/master , can you please
> adjust, rebase them and repost? Then I'll pick them.
>

Sorry about that, I didn't notice that the usb ehci had been updated 7 days ago.
I'll rebase my patches and repost later.

> Thanks!
>
> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support
  2013-05-13  2:07                     ` [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
  2013-05-13  2:36                       ` Marek Vasut
@ 2013-05-13  8:28                       ` Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
                                           ` (3 more replies)
  1 sibling, 4 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  8:28 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Changes for v7:
   - Rebase with u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae,
     and also make sure it's compatible with
     u-boot-usb-dc69e46302a36e60e2417bba8c6ea78761a37ebf.
   - Update TDI aliased functions, since there is another
     similar patch had been committed and acceptted.
   - ehci-hcd: ehci_get_portsc_register(): make sure port is always >= 0

Changes for v6:
   - usb_hub: Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY
     default value setup.
   - ehci-hcd: Simplify weak aliased function declaration
   - ehci-hcd: Drop redundant line feed

Changes for v5:
   - Split up EHCI changeset
   - usb_hub: replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.
   - ehci-faraday: fix the invalid multi-line comment style.
   - gadget-fotg210: coding style cleanup.
   - gadget-fotg210: drop postfix '__iomem' from struct fotg210_regs
   - gadget-fotg210: use permanent delay for hardware reset
   - gadget-fotg210: drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - gadget-fotg210: drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

Kuo-Jung Su (4):
  usb: hub: make minimum power-on delay configurable
  usb: ehci: add weak-aliased function for PORTSC
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 README                            |    3 +
 common/usb_hub.c                  |   15 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/host/Makefile         |    1 +
 drivers/usb/host/ehci-faraday.c   |  154 ++++++
 drivers/usb/host/ehci-hcd.c       |   28 +-
 include/usb/fotg210.h             |  364 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 10 files changed, 1576 insertions(+), 7 deletions(-)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v7 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-13  8:28                       ` [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
@ 2013-05-13  8:28                         ` Kuo-Jung Su
  2013-05-14  2:29                           ` [U-Boot] [PATCH v8 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 2/4] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
                                           ` (2 subsequent siblings)
  3 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  8:28 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch makes the minimum power-on delay for USB HUB
become configurable. The original design waits at least
100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
are known to require much longer delay interval.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae

Changes for v6:
   - Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY default value setup.

Changes for v5:
   - Split up from Faraday EHCI patch
   - Replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 README           |    3 +++
 common/usb_hub.c |    8 ++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/README b/README
index 0d37d56..c70a59b 100644
--- a/README
+++ b/README
@@ -1244,6 +1244,9 @@ The following options need to be configured:
 		CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
 		txfilltuning field in the EHCI controller on reset.

+		CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
+		interval for usb hub power-on delay.(minimum 100msec)
+
 - USB Device:
 		Define the below if you wish to use the USB console.
 		Once firmware is rebuilt from a serial console issue the
diff --git a/common/usb_hub.c b/common/usb_hub.c
index 0d79ec3..fc3a8c1 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -53,6 +53,10 @@
 #include <asm/4xx_pci.h>
 #endif

+#ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+#define CONFIG_USB_HUB_MIN_POWER_ON_DELAY	100
+#endif
+
 #define USB_BUFSIZ	512

 static struct usb_hub_device hub_dev[USB_MAX_HUB];
@@ -148,8 +152,8 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
 		debug("port %d returns %lX\n", i + 1, dev->status);
 	}

-	/* Wait at least 100 msec for power to become stable */
-	mdelay(max(pgood_delay, (unsigned)100));
+	/* Wait for power to become stable */
+	mdelay(max(pgood_delay, CONFIG_USB_HUB_MIN_POWER_ON_DELAY));
 }

 void usb_hub_reset(void)
--
1.7.9.5

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

* [U-Boot] [PATCH v7 2/4] usb: ehci: add weak-aliased function for PORTSC
  2013-05-13  8:28                       ` [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-13  8:28                         ` Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  8:28 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
not only leave RESERVED and CONFIGFLAG registers un-implemented
but also has their address spaces removed.

As an result, the PORTSC register of Faraday EHCI always
starts from 0x30 instead of 0x44 in standard EHCI.

So that we'll need a weak-aliased function for abstraction.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae
   - Drop TDI weak-aliased functions, since there is another similar
     patch had been committed and acceptted.
   - ehci_get_portsc_register(): make sure port is always >= 0

Changes for v6:
   - Simplify weak aliased function declaration
   - Drop redundant line feed

Changes for v5:
   - Split up from Faraday EHCI patch

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 drivers/usb/host/ehci-hcd.c |   23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index e0f3e4b..316de15 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -603,6 +603,23 @@ fail:
 	return -1;
 }

+__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/*
+	 * The u-boot would somehow set port=-1 at usb start-up,
+	 * so this quick fix is necessary.
+	 */
+	if (port < 0)
+		port = 0;
+
+	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%u) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
@@ -616,11 +633,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	int port = le16_to_cpu(req->index) & 0xff;
 	struct ehci_ctrl *ctrl = dev->controller;

-	if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		printf("The request port(%d) is not configured\n", port - 1);
+	status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1);
+	if (!status_reg)
 		return -1;
-	}
-	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
 	srclen = 0;

 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
--
1.7.9.5

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

* [U-Boot] [PATCH v7 3/4] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-13  8:28                       ` [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 2/4] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
@ 2013-05-13  8:28                         ` Kuo-Jung Su
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  8:28 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address space removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differ from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v7:
   - Nothing updates

Changes for v6:
   - Nothing updates

Changes for v5:
   - Break down EHCI changes as seperate changesets.
   - Fix the invalid multi-line comment style.

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 common/usb_hub.c                |    7 +-
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  154 +++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |    5 +
 include/usb/fotg210.h           |  364 +++++++++++++++++++++++++++++++++++++++
 include/usb/fusbh200.h          |   61 +++++++
 6 files changed, 591 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index fc3a8c1..774ba63 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -489,7 +489,11 @@ static int usb_hub_configure(struct usb_device *dev)
 			      i + 1, portstatus);
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_ENABLE);
-
+			/*
+			 * The following hack causes a ghost device problem
+			 * to Faraday EHCI
+			 */
+#ifndef CONFIG_USB_EHCI_FARADAY
 			/* EM interference sometimes causes bad shielded USB
 			 * devices to be shutdown by the hub, this hack enables
 			 * them again. Works at least with mouse driver */
@@ -501,6 +505,7 @@ static int usb_hub_configure(struct usb_device *dev)
 				      "re-enabling...\n", i + 1);
 				      usb_hub_port_connect_change(dev, i);
 			}
+#endif
 		}
 		if (portstatus & USB_PORT_STAT_SUSPEND) {
 			debug("port %d suspend change\n", i + 1);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..76b3b64
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,154 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+/*
+ * This ehci_set_usbmode() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+void ehci_set_usbmode(int index)
+{
+	/* nothing needs to be done */
+}
+
+/*
+ * This ehci_get_port_speed() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+{
+	int spd, ret = PORTSC_PSPD_HS;
+	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		ret = PORTSC_PSPD_FS;
+		break;
+	case 1:    /* low  speed */
+		ret = PORTSC_PSPD_LS;
+		break;
+	case 2:    /* high speed */
+		ret = PORTSC_PSPD_HS;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This ehci_get_portsc_register() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/*
+	 * The u-boot would somehow set port=-1 at usb start-up,
+	 * so this quick fix is necessary.
+	 */
+	if (port < 0)
+		port = 0;
+
+	/* Faraday EHCI has one and only one portsc register */
+	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%u) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)hcor + 0x20);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 316de15..be18a02 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -589,10 +589,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
 		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
 		      ehci_readl(&ctrl->hcor->or_portsc[0]),
 		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
 	}

 	free(qtd);
@@ -974,10 +976,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..2d2d243
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,364 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t miscr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[2];
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */
+};
+
+/* Miscellaneous Register */
+#define MISCR_SUSPEND  (1 << 6) /* Put transceiver in suspend mode */
+#define MISCR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define MISCR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define MISCR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* OTG Control Status Register */
+#define OTGCSR_SPD_HIGH     (2 << 22) /* Speed of the attached device (host) */
+#define OTGCSR_SPD_LOW      (1 << 22)
+#define OTGCSR_SPD_FULL     (0 << 22)
+#define OTGCSR_SPD_MASK     (3 << 22)
+#define OTGCSR_SPD_SHIFT    22
+#define OTGCSR_SPD(x)       (((x) >> 22) & 0x03)
+#define OTGCSR_DEV_A        (0 << 21) /* Acts as A-device */
+#define OTGCSR_DEV_B        (1 << 21) /* Acts as B-device */
+#define OTGCSR_ROLE_H       (0 << 20) /* Acts as Host */
+#define OTGCSR_ROLE_D       (1 << 20) /* Acts as Device */
+#define OTGCSR_A_VBUS_VLD   (1 << 19) /* A-device VBUS Valid */
+#define OTGCSR_A_SESS_VLD   (1 << 18) /* A-device Session Valid */
+#define OTGCSR_B_SESS_VLD   (1 << 17) /* B-device Session Valid */
+#define OTGCSR_B_SESS_END   (1 << 16) /* B-device Session End */
+#define OTGCSR_HFT_LONG     (1 << 11) /* HDISCON noise filter = 270 us*/
+#define OTGCSR_HFT          (0 << 11) /* HDISCON noise filter = 135 us*/
+#define OTGCSR_VFT_LONG     (1 << 10) /* VBUS noise filter = 472 us*/
+#define OTGCSR_VFT          (0 << 10) /* VBUS noise filter = 135 us*/
+#define OTGCSR_IDFT_LONG    (1 << 9)  /* ID noise filter = 4 ms*/
+#define OTGCSR_IDFT         (0 << 9)  /* ID noise filter = 3 ms*/
+#define OTGCSR_A_SRPR_VBUS  (0 << 8)  /* A-device: SRP responds to VBUS */
+#define OTGCSR_A_SRPR_DATA  (1 << 8)  /* A-device: SRP responds to DATA-LINE */
+#define OTGCSR_A_SRP_EN     (1 << 7)  /* A-device SRP detection enabled */
+#define OTGCSR_A_HNP        (1 << 6)  /* Set role=A-device with HNP enabled */
+#define OTGCSR_A_BUSDROP    (1 << 5)  /* A-device drop bus (power-down) */
+#define OTGCSR_A_BUSREQ     (1 << 4)  /* A-device request bus */
+#define OTGCSR_B_VBUS_DISC  (1 << 2)  /* B-device discharges VBUS */
+#define OTGCSR_B_HNP        (1 << 1)  /* B-device enable HNP */
+#define OTGCSR_B_BUSREQ     (1 << 0)  /* B-device request bus */
+
+/* OTG Interrupt Status Register */
+#define OTGISR_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGISR_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGISR_OVD          (1 << 10) /* over-current detected */
+#define OTGISR_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGISR_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGISR_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGISR_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGISR_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGISR_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* OTG Interrupt Enable Register */
+#define OTGIER_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGIER_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGIER_OVD          (1 << 10) /* over-current detected */
+#define OTGIER_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGIER_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGIER_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGIER_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGIER_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGIER_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* Global Interrupt Status Register (W1C) */
+#define ISR_HOST            (1 << 2)  /* USB Host interrupt */
+#define ISR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define ISR_DEV             (1 << 0)  /* USB Device interrupt */
+#define ISR_MASK            0x07
+
+/* Global Interrupt Mask Register */
+#define IMR_IRQLH           (1 << 3)  /* Interrupt triggered at level-high */
+#define IMR_IRQLL           (0 << 3)  /* Interrupt triggered@level-low */
+#define IMR_HOST            (1 << 2)  /* USB Host interrupt */
+#define IMR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define IMR_DEV             (1 << 0)  /* USB Device interrupt */
+#define IMR_MASK            0x0f
+
+/* Device Control Register */
+#define DEVCTRL_FS_FORCED   (1 << 9)  /* Forced to be Full-Speed Mode */
+#define DEVCTRL_HS          (1 << 6)  /* High Speed Mode */
+#define DEVCTRL_FS          (0 << 6)  /* Full Speed Mode */
+#define DEVCTRL_EN          (1 << 5)  /* Chip Enable */
+#define DEVCTRL_RESET       (1 << 4)  /* Chip Software Reset */
+#define DEVCTRL_SUSPEND     (1 << 3)  /* Enter Suspend Mode */
+#define DEVCTRL_GIRQ_EN     (1 << 2)  /* Global Interrupt Enabled */
+#define DEVCTRL_HALFSPD     (1 << 1)  /* Half speed mode for FPGA test */
+#define DEVCTRL_RWAKEUP     (1 << 0)  /* Enable remote wake-up */
+
+/* Device Address Register */
+#define DEVADDR_CONF        (1 << 7)  /* SET_CONFIGURATION has been executed */
+#define DEVADDR_ADDR(x)     ((x) & 0x7f)
+#define DEVADDR_ADDR_MASK   0x7f
+
+/* Device Test Register */
+#define DEVTEST_NOSOF       (1 << 6)  /* Do not generate SOF */
+#define DEVTEST_TST_MODE    (1 << 5)  /* Enter Test Mode */
+#define DEVTEST_TST_NOTS    (1 << 4)  /* Do not toggle sequence */
+#define DEVTEST_TST_NOCRC   (1 << 3)  /* Do not append CRC */
+#define DEVTEST_TST_CLREA   (1 << 2)  /* Clear External Side Address */
+#define DEVTEST_TST_CXLP    (1 << 1)  /* EP0 loopback test */
+#define DEVTEST_TST_CLRFF   (1 << 0)  /* Clear FIFO */
+
+/* SOF Frame Number Register */
+#define SOFFNR_UFN(x)       (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */
+#define SOFFNR_FNR(x)       ((x) & 0x7ff) /* SOF Frame Number */
+
+/* SOF Mask Timer Register */
+#define SOFMTR_TMR(x)       ((x) & 0xffff)
+
+/* PHY Test Mode Selector Register */
+#define PHYTMSR_TST_PKT     (1 << 4) /* Packet send test */
+#define PHYTMSR_TST_SE0NAK  (1 << 3) /* High-Speed quiescent state */
+#define PHYTMSR_TST_KSTA    (1 << 2) /* High-Speed K state */
+#define PHYTMSR_TST_JSTA    (1 << 1) /* High-Speed J state */
+#define PHYTMSR_UNPLUG      (1 << 0) /* Enable soft-detachment */
+
+/* CX FIFO Register */
+#define CXFIFO_BYTES(x)     (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */
+#define CXFIFO_FIFOE(x)     (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */
+#define CXFIFO_FIFOE_FIFO0  (1 << 8)
+#define CXFIFO_FIFOE_FIFO1  (1 << 9)
+#define CXFIFO_FIFOE_FIFO2  (1 << 10)
+#define CXFIFO_FIFOE_FIFO3  (1 << 11)
+#define CXFIFO_FIFOE_MASK   (0x0f << 8)
+#define CXFIFO_CXFIFOE      (1 << 5) /* CX FIFO empty */
+#define CXFIFO_CXFIFOF      (1 << 4) /* CX FIFO full */
+#define CXFIFO_CXFIFOCLR    (1 << 3) /* CX FIFO clear */
+#define CXFIFO_CXSTALL      (1 << 2) /* CX Stall */
+#define CXFIFO_TSTPKTFIN    (1 << 1) /* Test packet data transfer finished */
+#define CXFIFO_CXFIN        (1 << 0) /* CX data transfer finished */
+
+/* IDLE Counter Register */
+#define IDLE_MS(x)          ((x) & 0x07) /* PHY suspend delay = x ms */
+
+/* Group Interrupt Mask(Disable) Register */
+#define GIMR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GIMR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GIMR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+#define GIMR_MASK           0x07
+
+/* Group Interrupt Mask(Disable) Register 0 (CX) */
+#define GIMR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GIMR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GIMR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GIMR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GIMR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GIMR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+#define GIMR0_MASK          0x3f
+
+/* Group Interrupt Mask(Disable) Register 1 (FIFO) */
+#define GIMR1_FIFO_IN(x)    (1 << (((x) & 3) + 16))    /* FIFOx IN */
+#define GIMR1_FIFO_TX(x)    GIMR1_FIFO_IN(x)
+#define GIMR1_FIFO_OUT(x)   (1 << (((x) & 3) * 2))     /* FIFOx OUT */
+#define GIMR1_FIFO_SPK(x)   (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */
+#define GIMR1_FIFO_RX(x)    (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x))
+#define GIMR1_MASK          0xf00ff
+
+/* Group Interrupt Mask(Disable) Register 2 (Device) */
+#define GIMR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GIMR2_IDLE          (1 << 9)  /* Device idle */
+#define GIMR2_DMAERR        (1 << 8)  /* DMA error */
+#define GIMR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GIMR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GIMR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GIMR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GIMR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GIMR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GIMR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GIMR2_RESET         (1 << 0)  /* Reset Interrupt */
+#define GIMR2_MASK          0x7ff
+
+/* Group Interrupt Status Register */
+#define GISR_GRP2           (1 << 2) /* Interrupt group 2 */
+#define GISR_GRP1           (1 << 1) /* Interrupt group 1 */
+#define GISR_GRP0           (1 << 0) /* Interrupt group 0 */
+
+/* Group Interrupt Status Register 0 (CX) */
+#define GISR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GISR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GISR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GISR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GISR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GISR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Status Register 1 (FIFO) */
+#define GISR1_IN_FIFO(x)    (1 << (((x) & 0x03) + 16))    /* FIFOx IN */
+#define GISR1_OUT_FIFO(x)   (1 << (((x) & 0x03) * 2))     /* FIFOx OUT */
+#define GISR1_SPK_FIFO(x)   (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */
+#define GISR1_RX_FIFO(x)    (3 << (((x) & 0x03) * 2))     /* FIFOx OUT/SPK */
+
+/* Group Interrupt Status Register 2 (Device) */
+#define GISR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GISR2_IDLE          (1 << 9)  /* Device idle */
+#define GISR2_DMAERR        (1 << 8)  /* DMA error */
+#define GISR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GISR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GISR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GISR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GISR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GISR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GISR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GISR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Receive Zero-Length-Packet Register */
+#define RXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP rx interrupt */
+
+/* Transfer Zero-Length-Packet Register */
+#define TXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP tx interrupt */
+
+/* ISOC Error/Abort Status Register */
+#define ISOEASR_EP(x)       (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */
+
+/* IN Endpoint Register */
+#define IEP_SENDZLP         (1 << 15)     /* Send Zero-Length-Packet */
+#define IEP_TNRHB(x)        (((x) & 0x03) << 13) \
+	/* Transaction Number for High-Bandwidth EP(ISOC) */
+#define IEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define IEP_STALL           (1 << 11)     /* Stall */
+#define IEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* OUT Endpoint Register */
+#define OEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define OEP_STALL           (1 << 11)     /* Stall */
+#define OEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* Endpoint Map Register (EP1 ~ EP4) */
+#define EPMAP14_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 0)
+#define EPMAP14_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 4)
+#define EPMAP14_SET(ep, in, out) \
+	do { \
+		EPMAP14_SET_IN(ep, in); \
+		EPMAP14_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP14_DEFAULT     0x33221100 /* EP1->FIFO0, EP2->FIFO1... */
+
+/* Endpoint Map Register (EP5 ~ EP8) */
+#define EPMAP58_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 0)
+#define EPMAP58_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 4)
+#define EPMAP58_SET(ep, in, out) \
+	do { \
+		EPMAP58_SET_IN(ep, in); \
+		EPMAP58_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP58_DEFAULT     0x00000000 /* All EPx->FIFO0 */
+
+/* FIFO Map Register */
+#define FIFOMAP_BIDIR       (2 << 4)
+#define FIFOMAP_IN          (1 << 4)
+#define FIFOMAP_OUT         (0 << 4)
+#define FIFOMAP_DIR_MASK    0x30
+#define FIFOMAP_EP(x)       ((x) & 0x0f)
+#define FIFOMAP_EP_MASK     0x0f
+#define FIFOMAP_CFG_MASK    0x3f
+#define FIFOMAP_DEFAULT     0x04030201 /* FIFO0->EP1, FIFO1->EP2... */
+#define FIFOMAP(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Configuration Register */
+#define FIFOCFG_EN          (1 << 5)
+#define FIFOCFG_BLKSZ_1024  (1 << 4)
+#define FIFOCFG_BLKSZ_512   (0 << 4)
+#define FIFOCFG_3BLK        (2 << 2)
+#define FIFOCFG_2BLK        (1 << 2)
+#define FIFOCFG_1BLK        (0 << 2)
+#define FIFOCFG_NBLK_MASK   3
+#define FIFOCFG_NBLK_SHIFT  2
+#define FIFOCFG_INTR        (3 << 0)
+#define FIFOCFG_BULK        (2 << 0)
+#define FIFOCFG_ISOC        (1 << 0)
+#define FIFOCFG_RSVD        (0 << 0)  /* Reserved */
+#define FIFOCFG_TYPE_MASK   3
+#define FIFOCFG_TYPE_SHIFT  0
+#define FIFOCFG_CFG_MASK    0x3f
+#define FIFOCFG(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Control Status Register */
+#define FIFOCSR_RESET       (1 << 12) /* FIFO Reset */
+#define FIFOCSR_BYTES(x)    ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */
+
+/* DMA Target FIFO Register */
+#define DMAFIFO_CX          (1 << 4) /* DMA FIFO = CX FIFO */
+#define DMAFIFO_FIFO(x)     (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */
+
+/* DMA Control Register */
+#define DMACTRL_LEN(x)      (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */
+#define DMACTRL_LEN_SHIFT   8
+#define DMACTRL_CLRFF       (1 << 4) /* Clear FIFO upon DMA abort */
+#define DMACTRL_ABORT       (1 << 3) /* DMA abort */
+#define DMACTRL_IO2IO       (1 << 2) /* IO to IO */
+#define DMACTRL_FIFO2MEM    (0 << 1) /* FIFO to Memory */
+#define DMACTRL_MEM2FIFO    (1 << 1) /* Memory to FIFO */
+#define DMACTRL_START       (1 << 0) /* DMA start */
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..8a9c488
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,61 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+/* EOF & Async. Schedule Sleep Timer Register */
+#define EASSTR_RUNNING  (1 << 6) /* Put transceiver in running/resume mode */
+#define EASSTR_SUSPEND  (0 << 6) /* Put transceiver in suspend mode */
+#define EASSTR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define EASSTR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define EASSTR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* Bus Monitor Control Status Register */
+#define BMCSR_SPD_HIGH  (2 << 9) /* Speed of the attached device */
+#define BMCSR_SPD_LOW   (1 << 9)
+#define BMCSR_SPD_FULL  (0 << 9)
+#define BMCSR_SPD_MASK  (3 << 9)
+#define BMCSR_SPD_SHIFT 9
+#define BMCSR_SPD(x)    ((x >> 9) & 0x03)
+#define BMCSR_VBUS      (1 << 8) /* VBUS Valid */
+#define BMCSR_VBUS_OFF  (1 << 4) /* VBUS Off */
+#define BMCSR_VBUS_ON   (0 << 4) /* VBUS On */
+#define BMCSR_IRQLH     (1 << 3) /* IRQ triggered at level-high */
+#define BMCSR_IRQLL     (0 << 3) /* IRQ triggered@level-low */
+#define BMCSR_HALFSPD   (1 << 2) /* Half speed mode for FPGA test */
+#define BMCSR_HFT_LONG  (1 << 1) /* HDISCON noise filter = 270 us*/
+#define BMCSR_HFT       (0 << 1) /* HDISCON noise filter = 135 us*/
+#define BMCSR_VFT_LONG  (1 << 1) /* VBUS noise filter = 472 us*/
+#define BMCSR_VFT       (0 << 1) /* VBUS noise filter = 135 us*/
+
+/* Bus Monitor Interrupt Status Register */
+/* Bus Monitor Interrupt Enable Register */
+#define BMISR_DMAERR    (1 << 4) /* DMA error */
+#define BMISR_DMA       (1 << 3) /* DMA complete */
+#define BMISR_DEVRM     (1 << 2) /* device removed */
+#define BMISR_OVD       (1 << 1) /* over-current detected */
+#define BMISR_VBUSERR   (1 << 0) /* VBUS error */
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v7 4/4] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-13  8:28                       ` [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
                                           ` (2 preceding siblings ...)
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-05-13  8:28                         ` Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-13  8:28 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v7:
   - Nothing updates

Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup.
   - Drop postfix '__iomem' from struct fotg210_regs
   - Use permanent delay for hardware reset
   - Drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - Drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Remove dcache_enable() from usb_gadget_register_driver()

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 957 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..d003331
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,948 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs      *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id & 0x03) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) & 0x03);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], OEP_STALL);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t i;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(DEVCTRL_EN, &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(0, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable all interrupts */
+	writel(IMR_MASK, &regs->imr);
+	writel(GIMR_MASK, &regs->gimr);
+	writel(GIMR0_MASK, &regs->gimr0);
+	writel(GIMR1_MASK, &regs->gimr1);
+	writel(GIMR2_MASK, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(ISR_MASK, &regs->isr);
+	writel(0, &regs->gisr);
+	writel(0, &regs->gisr0);
+	writel(0, &regs->gisr1);
+	writel(0, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+	mdelay(10);
+	if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+	mdelay(10);
+	if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(EPMAP14_DEFAULT, &regs->epmap14);
+	writel(EPMAP58_DEFAULT, &regs->epmap58);
+	writel(FIFOMAP_DEFAULT, &regs->fifomap);
+	writel(0, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+		mdelay(10);
+		if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(IMR_IRQLH | IMR_HOST | IMR_OTG, &regs->imr);
+	writel(ISR_MASK, &regs->isr);
+	/* disable EP0 IN/OUT interrupt */
+	writel(GIMR0_CXOUT | GIMR0_CXIN, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(GIMR1_MASK, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN
+		| GIMR2_ZLPRX | GIMR2_ZLPTX, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_GIRQ_EN);
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	int fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->dma_ctrl) & DMACTRL_START)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((ulong)buf, (ulong)buf + len);
+	else
+		invalidate_dcache_range((ulong)buf, (ulong)buf + len);
+
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until cx/ep0 fifo empty */
+			fotg210_cxwait(chip, CXFIFO_CXFIFOE);
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+		} else {
+			/* Wait until epx fifo empty */
+			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+		}
+		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+
+		if (ep->id == 0) {
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+			do {
+				blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+			} while (blen < len);
+		} else {
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+			blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+		}
+		len  = (len < blen) ? len : blen;
+		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & GISR2_DMAFIN) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & GISR2_DMAERR) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(DMACTRL_ABORT | DMACTRL_CLRFF, &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & OTGCSR_DEV_B) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				/* SOF mask timer = 1100 ticks */
+				writel(SOFMTR_TMR(1100), &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				/* SOF mask timer = 10000 ticks */
+				writel(SOFMTR_TMR(10000), &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(DMAFIFO_CX, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->ep0_data);
+	tmp[1] = readl(&regs->ep0_data);
+	/* release data port */
+	writel(0, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(chip->addr | DEVADDR_CONF,
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue & DEVADDR_ADDR_MASK;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], IEP_STALL);
+				setbits_le32(&regs->oep[id - 1], OEP_STALL);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue)) {
+		setbits_le32(&regs->gimr1,
+			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+	}
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_IN));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+	clrbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return SOFFNR_FNR(readl(&regs->sof_fnr));
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name  = "ep0",
+			.ops   = &fotg210_ep_ops,
+		},
+		.desc      = &ep0_desc,
+		.chip      = &controller,
+		.maxpacket = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name  = "ep1",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name  = "ep2",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name  = "ep3",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name  = "ep4",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t id, st, isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & ISR_DEV) || !gisr)
+		return 0;
+
+	writel(ISR_DEV, &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & GISR_GRP0) {
+		st = readl(&regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & GISR0_CXERR)
+			printf("fotg210: cmd error\n");
+
+		if (st & GISR0_CXABORT)
+			printf("fotg210: cmd abort\n");
+
+		if (st & GISR0_CXSETUP)    /* setup */
+			fotg210_setup(chip);
+		else if (st & GISR0_CXEND) /* command finish */
+			setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & GISR_GRP1) {
+		st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & GISR1_RX_FIFO(id))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & GISR_GRP2) {
+		st = readl(&regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & GISR2_RESET)
+			printf("fotg210: reset by host\n");
+		else if (st & GISR2_SUSPEND)
+			printf("fotg210: suspend/removed\n");
+		else if (st & GISR2_RESUME)
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & GISR2_ISOCERR)
+			printf("fotg210: iso error\n");
+		if (st & GISR2_ISOCABT)
+			printf("fotg210: iso abort\n");
+		if (st & GISR2_DMAERR)
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-13  8:09                         ` Kuo-Jung Su
@ 2013-05-13 15:10                           ` Marek Vasut
  2013-05-14  1:26                             ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-13 15:10 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> 2013/5/13 Marek Vasut <marex@denx.de>:
> > Dear Kuo-Jung Su,
> > 
> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> 
> >> There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
> >> known to implement a non-standard TDI stuff.
> >> Futhermore, it not only leave reserved and CONFIGFLAG registers
> >> un-implemented but also has their address spaces removed.
> >> 
> >> And thus, we need weak-aliased functions to both TDI stuff
> >> and PORTSC registers for interface abstraction.
> >> 
> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> CC: Marek Vasut <marex@denx.de>
> >> ---
> >> 
> >> Changes for v6:
> >>    - Simplify weak aliased function declaration
> >>    - Drop redundant line feed
> >> 
> >> Changes for v5:
> >>    - Split up from Faraday EHCI patch
> >> 
> >> Changes for v2 - v4:
> >>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
> >>  
> >>  drivers/usb/host/ehci-hcd.c |   91
> >> 
> >> ++++++++++++++++++++++++++----------------- 1 file changed, 55
> >> insertions(+), 36 deletions(-)
> >> 
> >> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
> >> index c816878..ae3f2a4 100644
> >> --- a/drivers/usb/host/ehci-hcd.c
> >> +++ b/drivers/usb/host/ehci-hcd.c
> >> @@ -117,10 +117,44 @@ static struct descriptor {
> >> 
> >>  };
> >>  
> >>  #if defined(CONFIG_EHCI_IS_TDI)
> >> 
> >> -#define ehci_is_TDI()        (1)
> >> -#else
> >> -#define ehci_is_TDI()        (0)
> >> +# define ehci_is_TDI()       (1)
> > 
> > btw you can remove those braces around (1) and (0) below. But I have one
> > more question ...
> 
> Got it, thanks
> 
> > [...]
> > 
> >> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
> >> long pipe, void *buffer, uint32_t *status_reg;
> >> 
> >>       struct ehci_ctrl *ctrl = dev->controller;
> >> 
> >> -     if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
> >> { -             printf("The request port(%d) is not configured\n", -   
> >>                  le16_to_cpu(req->index) - 1);
> >> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
> >> +             le16_to_cpu(req->index) - 1);
> >> +     if (!status_reg)
> > 
> > What happens here if req->index is zero ?
> > 
> > Hint: the above code always does unsigned comparison ...
> > 
> > I think you should make the second argument of ehci_get_portsc_register()
> > unsigned short too (as is req->index in struct devrequest).
> 
> Sorry, but I'll prefer 'int' over 'unsigned short', since it looks to me
> that the u-boot would set 'req->index' to 0 at startup, which results in a
> 'port = -1' to be passed to ehci_get_portsc_register().
> 
> And I think '-1' is a better self-explain value, so I'd like to stick with
> 'int'

Sure, but then the comparison is signed, not unsigned. Besides, it's unnecessary 
change to the logic of the code. Or did I miss something ?

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-13 15:10                           ` Marek Vasut
@ 2013-05-14  1:26                             ` Kuo-Jung Su
  2013-05-14 13:47                               ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-14  1:26 UTC (permalink / raw)
  To: u-boot

2013/5/13 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/5/13 Marek Vasut <marex@denx.de>:
>> > Dear Kuo-Jung Su,
>> >
>> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >>
>> >> There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
>> >> known to implement a non-standard TDI stuff.
>> >> Futhermore, it not only leave reserved and CONFIGFLAG registers
>> >> un-implemented but also has their address spaces removed.
>> >>
>> >> And thus, we need weak-aliased functions to both TDI stuff
>> >> and PORTSC registers for interface abstraction.
>> >>
>> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >> CC: Marek Vasut <marex@denx.de>
>> >> ---
>> >>
>> >> Changes for v6:
>> >>    - Simplify weak aliased function declaration
>> >>    - Drop redundant line feed
>> >>
>> >> Changes for v5:
>> >>    - Split up from Faraday EHCI patch
>> >>
>> >> Changes for v2 - v4:
>> >>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
>> >>
>> >>  drivers/usb/host/ehci-hcd.c |   91
>> >>
>> >> ++++++++++++++++++++++++++----------------- 1 file changed, 55
>> >> insertions(+), 36 deletions(-)
>> >>
>> >> diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
>> >> index c816878..ae3f2a4 100644
>> >> --- a/drivers/usb/host/ehci-hcd.c
>> >> +++ b/drivers/usb/host/ehci-hcd.c
>> >> @@ -117,10 +117,44 @@ static struct descriptor {
>> >>
>> >>  };
>> >>
>> >>  #if defined(CONFIG_EHCI_IS_TDI)
>> >>
>> >> -#define ehci_is_TDI()        (1)
>> >> -#else
>> >> -#define ehci_is_TDI()        (0)
>> >> +# define ehci_is_TDI()       (1)
>> >
>> > btw you can remove those braces around (1) and (0) below. But I have one
>> > more question ...
>>
>> Got it, thanks
>>
>> > [...]
>> >
>> >> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev, unsigned
>> >> long pipe, void *buffer, uint32_t *status_reg;
>> >>
>> >>       struct ehci_ctrl *ctrl = dev->controller;
>> >>
>> >> -     if (le16_to_cpu(req->index) > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS)
>> >> { -             printf("The request port(%d) is not configured\n", -
>> >>                  le16_to_cpu(req->index) - 1);
>> >> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
>> >> +             le16_to_cpu(req->index) - 1);
>> >> +     if (!status_reg)
>> >
>> > What happens here if req->index is zero ?
>> >
>> > Hint: the above code always does unsigned comparison ...
>> >
>> > I think you should make the second argument of ehci_get_portsc_register()
>> > unsigned short too (as is req->index in struct devrequest).
>>
>> Sorry, but I'll prefer 'int' over 'unsigned short', since it looks to me
>> that the u-boot would set 'req->index' to 0 at startup, which results in a
>> 'port = -1' to be passed to ehci_get_portsc_register().
>>
>> And I think '-1' is a better self-explain value, so I'd like to stick with
>> 'int'
>
> Sure, but then the comparison is signed, not unsigned. Besides, it's unnecessary
> change to the logic of the code. Or did I miss something ?
>

1. There is a bug in ehci_submit_root() of usb ehci:

    int ehci_submit_root()
    {
         ......
         if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
            printf("The request port(%d) is not configured\n", port - 1);
            return -1;
         }
         status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
         ......
    }

    The 'port' is actually a '0' at start-up, so we actually accessed
a wrong register.
    But fortunately the wrong register actually points to CONFIGFLAG(0x40) with
    a safe value for the following codes.

2. One of Vivek Gautam's usb patches has altered the logic of usb host
    upon launching 'usb start', if we report a error upon (port - 1 < 0),
    the current u-boot usb would failed to scan ports. (At least it
failed at Faraday platforms.)
    However it looks to me that it's o.k to report a error upon (port
- 1 < 0) at old usb ehci stack.
    (i.e. 10 days ago, in master branch of u-boot)

And thus I add a quick check to PATCH v7.

__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
{
 /*
  * The u-boot would somehow set port=-1@usb start-up,
  * so this quick fix is necessary.
  */
 if (port < 0)
  port = 0;

 if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
  printf("The request port(%u) is not configured\n", port);
  return NULL;
 }

 return (uint32_t *)&hcor->or_portsc[port];
}

However I found that I've stupidly copied the logic

' if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) '

into ehci-faraday.c, so I'll post a v8 for this few minutes later....

> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v8 0/4] usb: add Faraday EHCI & Gadget support
  2013-05-13  8:28                         ` [U-Boot] [PATCH v7 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-14  2:29                           ` Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
                                               ` (3 more replies)
  0 siblings, 4 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-14  2:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Changes for v8:
   - ehci-faraday: ehci_get_portsc_register():
     Bug fixed, only port=0 is accepted.

Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae,
     and also make sure it's compatible to
     u-boot-usb-dc69e46302a36e60e2417bba8c6ea78761a37ebf.
   - Update TDI aliased functions, since there is another
     similar patch had been committed and acceptted.
   - ehci-hcd: ehci_get_portsc_register(): make sure port is always >= 0

Changes for v6:
   - usb_hub: Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY
     default value setup.
   - ehci-hcd: Simplify weak aliased function declaration
   - ehci-hcd: Drop redundant line feed

Changes for v5:
   - Split up EHCI changeset
   - usb_hub: replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.
   - ehci-faraday: fix the invalid multi-line comment style.
   - gadget-fotg210: coding style cleanup.
   - gadget-fotg210: drop postfix '__iomem' from struct fotg210_regs
   - gadget-fotg210: use permanent delay for hardware reset
   - gadget-fotg210: drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - gadget-fotg210: drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

Kuo-Jung Su (4):
  usb: hub: make minimum power-on delay configurable
  usb: ehci: add weak-aliased function for PORTSC
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 README                            |    3 +
 common/usb_hub.c                  |   15 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/host/Makefile         |    1 +
 drivers/usb/host/ehci-faraday.c   |  154 ++++++
 drivers/usb/host/ehci-hcd.c       |   28 +-
 include/usb/fotg210.h             |  364 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 10 files changed, 1576 insertions(+), 7 deletions(-)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v8 1/4] usb: hub: make minimum power-on delay configurable
  2013-05-14  2:29                           ` [U-Boot] [PATCH v8 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
@ 2013-05-14  2:29                             ` Kuo-Jung Su
  2013-05-15  7:29                               ` [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 2/4] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
                                               ` (2 subsequent siblings)
  3 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-14  2:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch makes the minimum power-on delay for USB HUB
become configurable. The original design waits at least
100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
are known to require much longer delay interval.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v8:
   - Nothing updates

Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae

Changes for v6:
   - Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY default value setup.

Changes for v5:
   - Split up from Faraday EHCI patch
   - Replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 README           |    3 +++
 common/usb_hub.c |    8 ++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/README b/README
index 0d37d56..c70a59b 100644
--- a/README
+++ b/README
@@ -1244,6 +1244,9 @@ The following options need to be configured:
 		CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
 		txfilltuning field in the EHCI controller on reset.

+		CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
+		interval for usb hub power-on delay.(minimum 100msec)
+
 - USB Device:
 		Define the below if you wish to use the USB console.
 		Once firmware is rebuilt from a serial console issue the
diff --git a/common/usb_hub.c b/common/usb_hub.c
index 0d79ec3..fc3a8c1 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -53,6 +53,10 @@
 #include <asm/4xx_pci.h>
 #endif

+#ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+#define CONFIG_USB_HUB_MIN_POWER_ON_DELAY	100
+#endif
+
 #define USB_BUFSIZ	512

 static struct usb_hub_device hub_dev[USB_MAX_HUB];
@@ -148,8 +152,8 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
 		debug("port %d returns %lX\n", i + 1, dev->status);
 	}

-	/* Wait at least 100 msec for power to become stable */
-	mdelay(max(pgood_delay, (unsigned)100));
+	/* Wait for power to become stable */
+	mdelay(max(pgood_delay, CONFIG_USB_HUB_MIN_POWER_ON_DELAY));
 }

 void usb_hub_reset(void)
--
1.7.9.5

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

* [U-Boot] [PATCH v8 2/4] usb: ehci: add weak-aliased function for PORTSC
  2013-05-14  2:29                           ` [U-Boot] [PATCH v8 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-14  2:29                             ` Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-14  2:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
not only leave RESERVED and CONFIGFLAG registers un-implemented
but also has their address spaces removed.

As an result, the PORTSC register of Faraday EHCI always
starts from 0x30 instead of 0x44 in standard EHCI.

So that we'll need a weak-aliased function for abstraction.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v8:
   - Nothing updates

Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae
   - Drop TDI weak-aliased functions, since there is another similar
     patch had been committed and acceptted.
   - ehci_get_portsc_register(): make sure port is always >= 0

Changes for v6:
   - Simplify weak aliased function declaration
   - Drop redundant line feed

Changes for v5:
   - Split up from Faraday EHCI patch

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 drivers/usb/host/ehci-hcd.c |   23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index e0f3e4b..316de15 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -603,6 +603,23 @@ fail:
 	return -1;
 }

+__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/*
+	 * The u-boot would somehow set port=-1 at usb start-up,
+	 * so this quick fix is necessary.
+	 */
+	if (port < 0)
+		port = 0;
+
+	if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		printf("The request port(%u) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
@@ -616,11 +633,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	int port = le16_to_cpu(req->index) & 0xff;
 	struct ehci_ctrl *ctrl = dev->controller;

-	if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		printf("The request port(%d) is not configured\n", port - 1);
+	status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1);
+	if (!status_reg)
 		return -1;
-	}
-	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
 	srclen = 0;

 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
--
1.7.9.5

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

* [U-Boot] [PATCH v8 3/4] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-14  2:29                           ` [U-Boot] [PATCH v8 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 2/4] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
@ 2013-05-14  2:29                             ` Kuo-Jung Su
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-14  2:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address space removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differ from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v8:
   - ehci-faraday: ehci_get_portsc_register():
     Bug fixed, only port=0 is accepted.

Changes for v7:
   - Nothing updates

Changes for v6:
   - Nothing updates

Changes for v5:
   - Break down EHCI changes as seperate changesets.
   - Fix the invalid multi-line comment style.

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 common/usb_hub.c                |    7 +-
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  154 +++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |    5 +
 include/usb/fotg210.h           |  364 +++++++++++++++++++++++++++++++++++++++
 include/usb/fusbh200.h          |   61 +++++++
 6 files changed, 591 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index fc3a8c1..774ba63 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -489,7 +489,11 @@ static int usb_hub_configure(struct usb_device *dev)
 			      i + 1, portstatus);
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_ENABLE);
-
+			/*
+			 * The following hack causes a ghost device problem
+			 * to Faraday EHCI
+			 */
+#ifndef CONFIG_USB_EHCI_FARADAY
 			/* EM interference sometimes causes bad shielded USB
 			 * devices to be shutdown by the hub, this hack enables
 			 * them again. Works at least with mouse driver */
@@ -501,6 +505,7 @@ static int usb_hub_configure(struct usb_device *dev)
 				      "re-enabling...\n", i + 1);
 				      usb_hub_port_connect_change(dev, i);
 			}
+#endif
 		}
 		if (portstatus & USB_PORT_STAT_SUSPEND) {
 			debug("port %d suspend change\n", i + 1);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..2cf8b15
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,154 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+/*
+ * This ehci_set_usbmode() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+void ehci_set_usbmode(int index)
+{
+	/* nothing needs to be done */
+}
+
+/*
+ * This ehci_get_port_speed() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+{
+	int spd, ret = PORTSC_PSPD_HS;
+	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		ret = PORTSC_PSPD_FS;
+		break;
+	case 1:    /* low  speed */
+		ret = PORTSC_PSPD_LS;
+		break;
+	case 2:    /* high speed */
+		ret = PORTSC_PSPD_HS;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This ehci_get_portsc_register() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/*
+	 * The u-boot would somehow set port=-1 at usb start-up,
+	 * so this quick fix is necessary.
+	 */
+	if (port < 0)
+		port = 0;
+
+	/* Faraday EHCI has one and only one portsc register */
+	if (port) {
+		printf("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)hcor + 0x20);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 316de15..be18a02 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -589,10 +589,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
 		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
 		      ehci_readl(&ctrl->hcor->or_portsc[0]),
 		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
 	}

 	free(qtd);
@@ -974,10 +976,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..2d2d243
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,364 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t miscr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[2];
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */
+};
+
+/* Miscellaneous Register */
+#define MISCR_SUSPEND  (1 << 6) /* Put transceiver in suspend mode */
+#define MISCR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define MISCR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define MISCR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* OTG Control Status Register */
+#define OTGCSR_SPD_HIGH     (2 << 22) /* Speed of the attached device (host) */
+#define OTGCSR_SPD_LOW      (1 << 22)
+#define OTGCSR_SPD_FULL     (0 << 22)
+#define OTGCSR_SPD_MASK     (3 << 22)
+#define OTGCSR_SPD_SHIFT    22
+#define OTGCSR_SPD(x)       (((x) >> 22) & 0x03)
+#define OTGCSR_DEV_A        (0 << 21) /* Acts as A-device */
+#define OTGCSR_DEV_B        (1 << 21) /* Acts as B-device */
+#define OTGCSR_ROLE_H       (0 << 20) /* Acts as Host */
+#define OTGCSR_ROLE_D       (1 << 20) /* Acts as Device */
+#define OTGCSR_A_VBUS_VLD   (1 << 19) /* A-device VBUS Valid */
+#define OTGCSR_A_SESS_VLD   (1 << 18) /* A-device Session Valid */
+#define OTGCSR_B_SESS_VLD   (1 << 17) /* B-device Session Valid */
+#define OTGCSR_B_SESS_END   (1 << 16) /* B-device Session End */
+#define OTGCSR_HFT_LONG     (1 << 11) /* HDISCON noise filter = 270 us*/
+#define OTGCSR_HFT          (0 << 11) /* HDISCON noise filter = 135 us*/
+#define OTGCSR_VFT_LONG     (1 << 10) /* VBUS noise filter = 472 us*/
+#define OTGCSR_VFT          (0 << 10) /* VBUS noise filter = 135 us*/
+#define OTGCSR_IDFT_LONG    (1 << 9)  /* ID noise filter = 4 ms*/
+#define OTGCSR_IDFT         (0 << 9)  /* ID noise filter = 3 ms*/
+#define OTGCSR_A_SRPR_VBUS  (0 << 8)  /* A-device: SRP responds to VBUS */
+#define OTGCSR_A_SRPR_DATA  (1 << 8)  /* A-device: SRP responds to DATA-LINE */
+#define OTGCSR_A_SRP_EN     (1 << 7)  /* A-device SRP detection enabled */
+#define OTGCSR_A_HNP        (1 << 6)  /* Set role=A-device with HNP enabled */
+#define OTGCSR_A_BUSDROP    (1 << 5)  /* A-device drop bus (power-down) */
+#define OTGCSR_A_BUSREQ     (1 << 4)  /* A-device request bus */
+#define OTGCSR_B_VBUS_DISC  (1 << 2)  /* B-device discharges VBUS */
+#define OTGCSR_B_HNP        (1 << 1)  /* B-device enable HNP */
+#define OTGCSR_B_BUSREQ     (1 << 0)  /* B-device request bus */
+
+/* OTG Interrupt Status Register */
+#define OTGISR_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGISR_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGISR_OVD          (1 << 10) /* over-current detected */
+#define OTGISR_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGISR_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGISR_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGISR_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGISR_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGISR_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* OTG Interrupt Enable Register */
+#define OTGIER_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGIER_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGIER_OVD          (1 << 10) /* over-current detected */
+#define OTGIER_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGIER_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGIER_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGIER_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGIER_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGIER_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* Global Interrupt Status Register (W1C) */
+#define ISR_HOST            (1 << 2)  /* USB Host interrupt */
+#define ISR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define ISR_DEV             (1 << 0)  /* USB Device interrupt */
+#define ISR_MASK            0x07
+
+/* Global Interrupt Mask Register */
+#define IMR_IRQLH           (1 << 3)  /* Interrupt triggered at level-high */
+#define IMR_IRQLL           (0 << 3)  /* Interrupt triggered@level-low */
+#define IMR_HOST            (1 << 2)  /* USB Host interrupt */
+#define IMR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define IMR_DEV             (1 << 0)  /* USB Device interrupt */
+#define IMR_MASK            0x0f
+
+/* Device Control Register */
+#define DEVCTRL_FS_FORCED   (1 << 9)  /* Forced to be Full-Speed Mode */
+#define DEVCTRL_HS          (1 << 6)  /* High Speed Mode */
+#define DEVCTRL_FS          (0 << 6)  /* Full Speed Mode */
+#define DEVCTRL_EN          (1 << 5)  /* Chip Enable */
+#define DEVCTRL_RESET       (1 << 4)  /* Chip Software Reset */
+#define DEVCTRL_SUSPEND     (1 << 3)  /* Enter Suspend Mode */
+#define DEVCTRL_GIRQ_EN     (1 << 2)  /* Global Interrupt Enabled */
+#define DEVCTRL_HALFSPD     (1 << 1)  /* Half speed mode for FPGA test */
+#define DEVCTRL_RWAKEUP     (1 << 0)  /* Enable remote wake-up */
+
+/* Device Address Register */
+#define DEVADDR_CONF        (1 << 7)  /* SET_CONFIGURATION has been executed */
+#define DEVADDR_ADDR(x)     ((x) & 0x7f)
+#define DEVADDR_ADDR_MASK   0x7f
+
+/* Device Test Register */
+#define DEVTEST_NOSOF       (1 << 6)  /* Do not generate SOF */
+#define DEVTEST_TST_MODE    (1 << 5)  /* Enter Test Mode */
+#define DEVTEST_TST_NOTS    (1 << 4)  /* Do not toggle sequence */
+#define DEVTEST_TST_NOCRC   (1 << 3)  /* Do not append CRC */
+#define DEVTEST_TST_CLREA   (1 << 2)  /* Clear External Side Address */
+#define DEVTEST_TST_CXLP    (1 << 1)  /* EP0 loopback test */
+#define DEVTEST_TST_CLRFF   (1 << 0)  /* Clear FIFO */
+
+/* SOF Frame Number Register */
+#define SOFFNR_UFN(x)       (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */
+#define SOFFNR_FNR(x)       ((x) & 0x7ff) /* SOF Frame Number */
+
+/* SOF Mask Timer Register */
+#define SOFMTR_TMR(x)       ((x) & 0xffff)
+
+/* PHY Test Mode Selector Register */
+#define PHYTMSR_TST_PKT     (1 << 4) /* Packet send test */
+#define PHYTMSR_TST_SE0NAK  (1 << 3) /* High-Speed quiescent state */
+#define PHYTMSR_TST_KSTA    (1 << 2) /* High-Speed K state */
+#define PHYTMSR_TST_JSTA    (1 << 1) /* High-Speed J state */
+#define PHYTMSR_UNPLUG      (1 << 0) /* Enable soft-detachment */
+
+/* CX FIFO Register */
+#define CXFIFO_BYTES(x)     (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */
+#define CXFIFO_FIFOE(x)     (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */
+#define CXFIFO_FIFOE_FIFO0  (1 << 8)
+#define CXFIFO_FIFOE_FIFO1  (1 << 9)
+#define CXFIFO_FIFOE_FIFO2  (1 << 10)
+#define CXFIFO_FIFOE_FIFO3  (1 << 11)
+#define CXFIFO_FIFOE_MASK   (0x0f << 8)
+#define CXFIFO_CXFIFOE      (1 << 5) /* CX FIFO empty */
+#define CXFIFO_CXFIFOF      (1 << 4) /* CX FIFO full */
+#define CXFIFO_CXFIFOCLR    (1 << 3) /* CX FIFO clear */
+#define CXFIFO_CXSTALL      (1 << 2) /* CX Stall */
+#define CXFIFO_TSTPKTFIN    (1 << 1) /* Test packet data transfer finished */
+#define CXFIFO_CXFIN        (1 << 0) /* CX data transfer finished */
+
+/* IDLE Counter Register */
+#define IDLE_MS(x)          ((x) & 0x07) /* PHY suspend delay = x ms */
+
+/* Group Interrupt Mask(Disable) Register */
+#define GIMR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GIMR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GIMR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+#define GIMR_MASK           0x07
+
+/* Group Interrupt Mask(Disable) Register 0 (CX) */
+#define GIMR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GIMR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GIMR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GIMR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GIMR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GIMR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+#define GIMR0_MASK          0x3f
+
+/* Group Interrupt Mask(Disable) Register 1 (FIFO) */
+#define GIMR1_FIFO_IN(x)    (1 << (((x) & 3) + 16))    /* FIFOx IN */
+#define GIMR1_FIFO_TX(x)    GIMR1_FIFO_IN(x)
+#define GIMR1_FIFO_OUT(x)   (1 << (((x) & 3) * 2))     /* FIFOx OUT */
+#define GIMR1_FIFO_SPK(x)   (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */
+#define GIMR1_FIFO_RX(x)    (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x))
+#define GIMR1_MASK          0xf00ff
+
+/* Group Interrupt Mask(Disable) Register 2 (Device) */
+#define GIMR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GIMR2_IDLE          (1 << 9)  /* Device idle */
+#define GIMR2_DMAERR        (1 << 8)  /* DMA error */
+#define GIMR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GIMR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GIMR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GIMR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GIMR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GIMR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GIMR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GIMR2_RESET         (1 << 0)  /* Reset Interrupt */
+#define GIMR2_MASK          0x7ff
+
+/* Group Interrupt Status Register */
+#define GISR_GRP2           (1 << 2) /* Interrupt group 2 */
+#define GISR_GRP1           (1 << 1) /* Interrupt group 1 */
+#define GISR_GRP0           (1 << 0) /* Interrupt group 0 */
+
+/* Group Interrupt Status Register 0 (CX) */
+#define GISR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GISR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GISR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GISR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GISR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GISR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Status Register 1 (FIFO) */
+#define GISR1_IN_FIFO(x)    (1 << (((x) & 0x03) + 16))    /* FIFOx IN */
+#define GISR1_OUT_FIFO(x)   (1 << (((x) & 0x03) * 2))     /* FIFOx OUT */
+#define GISR1_SPK_FIFO(x)   (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */
+#define GISR1_RX_FIFO(x)    (3 << (((x) & 0x03) * 2))     /* FIFOx OUT/SPK */
+
+/* Group Interrupt Status Register 2 (Device) */
+#define GISR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GISR2_IDLE          (1 << 9)  /* Device idle */
+#define GISR2_DMAERR        (1 << 8)  /* DMA error */
+#define GISR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GISR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GISR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GISR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GISR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GISR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GISR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GISR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Receive Zero-Length-Packet Register */
+#define RXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP rx interrupt */
+
+/* Transfer Zero-Length-Packet Register */
+#define TXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP tx interrupt */
+
+/* ISOC Error/Abort Status Register */
+#define ISOEASR_EP(x)       (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */
+
+/* IN Endpoint Register */
+#define IEP_SENDZLP         (1 << 15)     /* Send Zero-Length-Packet */
+#define IEP_TNRHB(x)        (((x) & 0x03) << 13) \
+	/* Transaction Number for High-Bandwidth EP(ISOC) */
+#define IEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define IEP_STALL           (1 << 11)     /* Stall */
+#define IEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* OUT Endpoint Register */
+#define OEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define OEP_STALL           (1 << 11)     /* Stall */
+#define OEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* Endpoint Map Register (EP1 ~ EP4) */
+#define EPMAP14_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 0)
+#define EPMAP14_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 4)
+#define EPMAP14_SET(ep, in, out) \
+	do { \
+		EPMAP14_SET_IN(ep, in); \
+		EPMAP14_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP14_DEFAULT     0x33221100 /* EP1->FIFO0, EP2->FIFO1... */
+
+/* Endpoint Map Register (EP5 ~ EP8) */
+#define EPMAP58_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 0)
+#define EPMAP58_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 4)
+#define EPMAP58_SET(ep, in, out) \
+	do { \
+		EPMAP58_SET_IN(ep, in); \
+		EPMAP58_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP58_DEFAULT     0x00000000 /* All EPx->FIFO0 */
+
+/* FIFO Map Register */
+#define FIFOMAP_BIDIR       (2 << 4)
+#define FIFOMAP_IN          (1 << 4)
+#define FIFOMAP_OUT         (0 << 4)
+#define FIFOMAP_DIR_MASK    0x30
+#define FIFOMAP_EP(x)       ((x) & 0x0f)
+#define FIFOMAP_EP_MASK     0x0f
+#define FIFOMAP_CFG_MASK    0x3f
+#define FIFOMAP_DEFAULT     0x04030201 /* FIFO0->EP1, FIFO1->EP2... */
+#define FIFOMAP(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Configuration Register */
+#define FIFOCFG_EN          (1 << 5)
+#define FIFOCFG_BLKSZ_1024  (1 << 4)
+#define FIFOCFG_BLKSZ_512   (0 << 4)
+#define FIFOCFG_3BLK        (2 << 2)
+#define FIFOCFG_2BLK        (1 << 2)
+#define FIFOCFG_1BLK        (0 << 2)
+#define FIFOCFG_NBLK_MASK   3
+#define FIFOCFG_NBLK_SHIFT  2
+#define FIFOCFG_INTR        (3 << 0)
+#define FIFOCFG_BULK        (2 << 0)
+#define FIFOCFG_ISOC        (1 << 0)
+#define FIFOCFG_RSVD        (0 << 0)  /* Reserved */
+#define FIFOCFG_TYPE_MASK   3
+#define FIFOCFG_TYPE_SHIFT  0
+#define FIFOCFG_CFG_MASK    0x3f
+#define FIFOCFG(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Control Status Register */
+#define FIFOCSR_RESET       (1 << 12) /* FIFO Reset */
+#define FIFOCSR_BYTES(x)    ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */
+
+/* DMA Target FIFO Register */
+#define DMAFIFO_CX          (1 << 4) /* DMA FIFO = CX FIFO */
+#define DMAFIFO_FIFO(x)     (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */
+
+/* DMA Control Register */
+#define DMACTRL_LEN(x)      (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */
+#define DMACTRL_LEN_SHIFT   8
+#define DMACTRL_CLRFF       (1 << 4) /* Clear FIFO upon DMA abort */
+#define DMACTRL_ABORT       (1 << 3) /* DMA abort */
+#define DMACTRL_IO2IO       (1 << 2) /* IO to IO */
+#define DMACTRL_FIFO2MEM    (0 << 1) /* FIFO to Memory */
+#define DMACTRL_MEM2FIFO    (1 << 1) /* Memory to FIFO */
+#define DMACTRL_START       (1 << 0) /* DMA start */
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..8a9c488
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,61 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+/* EOF & Async. Schedule Sleep Timer Register */
+#define EASSTR_RUNNING  (1 << 6) /* Put transceiver in running/resume mode */
+#define EASSTR_SUSPEND  (0 << 6) /* Put transceiver in suspend mode */
+#define EASSTR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define EASSTR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define EASSTR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* Bus Monitor Control Status Register */
+#define BMCSR_SPD_HIGH  (2 << 9) /* Speed of the attached device */
+#define BMCSR_SPD_LOW   (1 << 9)
+#define BMCSR_SPD_FULL  (0 << 9)
+#define BMCSR_SPD_MASK  (3 << 9)
+#define BMCSR_SPD_SHIFT 9
+#define BMCSR_SPD(x)    ((x >> 9) & 0x03)
+#define BMCSR_VBUS      (1 << 8) /* VBUS Valid */
+#define BMCSR_VBUS_OFF  (1 << 4) /* VBUS Off */
+#define BMCSR_VBUS_ON   (0 << 4) /* VBUS On */
+#define BMCSR_IRQLH     (1 << 3) /* IRQ triggered at level-high */
+#define BMCSR_IRQLL     (0 << 3) /* IRQ triggered@level-low */
+#define BMCSR_HALFSPD   (1 << 2) /* Half speed mode for FPGA test */
+#define BMCSR_HFT_LONG  (1 << 1) /* HDISCON noise filter = 270 us*/
+#define BMCSR_HFT       (0 << 1) /* HDISCON noise filter = 135 us*/
+#define BMCSR_VFT_LONG  (1 << 1) /* VBUS noise filter = 472 us*/
+#define BMCSR_VFT       (0 << 1) /* VBUS noise filter = 135 us*/
+
+/* Bus Monitor Interrupt Status Register */
+/* Bus Monitor Interrupt Enable Register */
+#define BMISR_DMAERR    (1 << 4) /* DMA error */
+#define BMISR_DMA       (1 << 3) /* DMA complete */
+#define BMISR_DEVRM     (1 << 2) /* device removed */
+#define BMISR_OVD       (1 << 1) /* over-current detected */
+#define BMISR_VBUSERR   (1 << 0) /* VBUS error */
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v8 4/4] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-14  2:29                           ` [U-Boot] [PATCH v8 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
                                               ` (2 preceding siblings ...)
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-05-14  2:29                             ` Kuo-Jung Su
  3 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-14  2:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v8:
   - Nothing updates

Changes for v7:
   - Nothing updates

Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup.
   - Drop postfix '__iomem' from struct fotg210_regs
   - Use permanent delay for hardware reset
   - Drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - Drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Remove dcache_enable() from usb_gadget_register_driver()

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 957 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..d003331
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,948 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs      *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id & 0x03) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) & 0x03);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], OEP_STALL);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t i;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(DEVCTRL_EN, &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(0, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable all interrupts */
+	writel(IMR_MASK, &regs->imr);
+	writel(GIMR_MASK, &regs->gimr);
+	writel(GIMR0_MASK, &regs->gimr0);
+	writel(GIMR1_MASK, &regs->gimr1);
+	writel(GIMR2_MASK, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(ISR_MASK, &regs->isr);
+	writel(0, &regs->gisr);
+	writel(0, &regs->gisr0);
+	writel(0, &regs->gisr1);
+	writel(0, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+	mdelay(10);
+	if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+	mdelay(10);
+	if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(EPMAP14_DEFAULT, &regs->epmap14);
+	writel(EPMAP58_DEFAULT, &regs->epmap58);
+	writel(FIFOMAP_DEFAULT, &regs->fifomap);
+	writel(0, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+		mdelay(10);
+		if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(IMR_IRQLH | IMR_HOST | IMR_OTG, &regs->imr);
+	writel(ISR_MASK, &regs->isr);
+	/* disable EP0 IN/OUT interrupt */
+	writel(GIMR0_CXOUT | GIMR0_CXIN, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(GIMR1_MASK, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN
+		| GIMR2_ZLPRX | GIMR2_ZLPTX, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_GIRQ_EN);
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	int fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->dma_ctrl) & DMACTRL_START)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((ulong)buf, (ulong)buf + len);
+	else
+		invalidate_dcache_range((ulong)buf, (ulong)buf + len);
+
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until cx/ep0 fifo empty */
+			fotg210_cxwait(chip, CXFIFO_CXFIFOE);
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+		} else {
+			/* Wait until epx fifo empty */
+			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+		}
+		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+
+		if (ep->id == 0) {
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+			do {
+				blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+			} while (blen < len);
+		} else {
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+			blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+		}
+		len  = (len < blen) ? len : blen;
+		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & GISR2_DMAFIN) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & GISR2_DMAERR) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(DMACTRL_ABORT | DMACTRL_CLRFF, &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & OTGCSR_DEV_B) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				/* SOF mask timer = 1100 ticks */
+				writel(SOFMTR_TMR(1100), &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				/* SOF mask timer = 10000 ticks */
+				writel(SOFMTR_TMR(10000), &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(DMAFIFO_CX, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->ep0_data);
+	tmp[1] = readl(&regs->ep0_data);
+	/* release data port */
+	writel(0, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(chip->addr | DEVADDR_CONF,
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue & DEVADDR_ADDR_MASK;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], IEP_STALL);
+				setbits_le32(&regs->oep[id - 1], OEP_STALL);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue)) {
+		setbits_le32(&regs->gimr1,
+			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+	}
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_IN));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+	clrbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return SOFFNR_FNR(readl(&regs->sof_fnr));
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name  = "ep0",
+			.ops   = &fotg210_ep_ops,
+		},
+		.desc      = &ep0_desc,
+		.chip      = &controller,
+		.maxpacket = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name  = "ep1",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name  = "ep2",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name  = "ep3",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name  = "ep4",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t id, st, isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & ISR_DEV) || !gisr)
+		return 0;
+
+	writel(ISR_DEV, &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & GISR_GRP0) {
+		st = readl(&regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & GISR0_CXERR)
+			printf("fotg210: cmd error\n");
+
+		if (st & GISR0_CXABORT)
+			printf("fotg210: cmd abort\n");
+
+		if (st & GISR0_CXSETUP)    /* setup */
+			fotg210_setup(chip);
+		else if (st & GISR0_CXEND) /* command finish */
+			setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & GISR_GRP1) {
+		st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & GISR1_RX_FIFO(id))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & GISR_GRP2) {
+		st = readl(&regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & GISR2_RESET)
+			printf("fotg210: reset by host\n");
+		else if (st & GISR2_SUSPEND)
+			printf("fotg210: suspend/removed\n");
+		else if (st & GISR2_RESUME)
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & GISR2_ISOCERR)
+			printf("fotg210: iso error\n");
+		if (st & GISR2_ISOCABT)
+			printf("fotg210: iso abort\n");
+		if (st & GISR2_DMAERR)
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-14  1:26                             ` Kuo-Jung Su
@ 2013-05-14 13:47                               ` Marek Vasut
  2013-05-15  1:03                                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-14 13:47 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> 2013/5/13 Marek Vasut <marex@denx.de>:
> > Dear Kuo-Jung Su,
> > 
> >> 2013/5/13 Marek Vasut <marex@denx.de>:
> >> > Dear Kuo-Jung Su,
> >> > 
> >> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> >> 
> >> >> There is at least one non-EHCI compliant controller (i.e. Faraday
> >> >> EHCI) known to implement a non-standard TDI stuff.
> >> >> Futhermore, it not only leave reserved and CONFIGFLAG registers
> >> >> un-implemented but also has their address spaces removed.
> >> >> 
> >> >> And thus, we need weak-aliased functions to both TDI stuff
> >> >> and PORTSC registers for interface abstraction.
> >> >> 
> >> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> >> CC: Marek Vasut <marex@denx.de>
> >> >> ---
> >> >> 
> >> >> Changes for v6:
> >> >>    - Simplify weak aliased function declaration
> >> >>    - Drop redundant line feed
> >> >> 
> >> >> Changes for v5:
> >> >>    - Split up from Faraday EHCI patch
> >> >> 
> >> >> Changes for v2 - v4:
> >> >>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
> >> >>  
> >> >>  drivers/usb/host/ehci-hcd.c |   91
> >> >> 
> >> >> ++++++++++++++++++++++++++----------------- 1 file changed, 55
> >> >> insertions(+), 36 deletions(-)
> >> >> 
> >> >> diff --git a/drivers/usb/host/ehci-hcd.c
> >> >> b/drivers/usb/host/ehci-hcd.c index c816878..ae3f2a4 100644
> >> >> --- a/drivers/usb/host/ehci-hcd.c
> >> >> +++ b/drivers/usb/host/ehci-hcd.c
> >> >> @@ -117,10 +117,44 @@ static struct descriptor {
> >> >> 
> >> >>  };
> >> >>  
> >> >>  #if defined(CONFIG_EHCI_IS_TDI)
> >> >> 
> >> >> -#define ehci_is_TDI()        (1)
> >> >> -#else
> >> >> -#define ehci_is_TDI()        (0)
> >> >> +# define ehci_is_TDI()       (1)
> >> > 
> >> > btw you can remove those braces around (1) and (0) below. But I have
> >> > one more question ...
> >> 
> >> Got it, thanks
> >> 
> >> > [...]
> >> > 
> >> >> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev,
> >> >> unsigned long pipe, void *buffer, uint32_t *status_reg;
> >> >> 
> >> >>       struct ehci_ctrl *ctrl = dev->controller;
> >> >> 
> >> >> -     if (le16_to_cpu(req->index) >
> >> >> CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { -             printf("The
> >> >> request port(%d) is not configured\n", -
> >> >> 
> >> >>                  le16_to_cpu(req->index) - 1);
> >> >> 
> >> >> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
> >> >> +             le16_to_cpu(req->index) - 1);
> >> >> +     if (!status_reg)
> >> > 
> >> > What happens here if req->index is zero ?
> >> > 
> >> > Hint: the above code always does unsigned comparison ...
> >> > 
> >> > I think you should make the second argument of
> >> > ehci_get_portsc_register() unsigned short too (as is req->index in
> >> > struct devrequest).
> >> 
> >> Sorry, but I'll prefer 'int' over 'unsigned short', since it looks to me
> >> that the u-boot would set 'req->index' to 0 at startup, which results in
> >> a 'port = -1' to be passed to ehci_get_portsc_register().
> >> 
> >> And I think '-1' is a better self-explain value, so I'd like to stick
> >> with 'int'
> > 
> > Sure, but then the comparison is signed, not unsigned. Besides, it's
> > unnecessary change to the logic of the code. Or did I miss something ?
> 
> 1. There is a bug in ehci_submit_root() of usb ehci:
> 
>     int ehci_submit_root()
>     {
>          ......
>          if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
>             printf("The request port(%d) is not configured\n", port - 1);
>             return -1;
>          }
>          status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
>          ......
>     }
> 
>     The 'port' is actually a '0' at start-up, so we actually accessed
> a wrong register.
>     But fortunately the wrong register actually points to CONFIGFLAG(0x40)
> with a safe value for the following codes.
> 
> 2. One of Vivek Gautam's usb patches has altered the logic of usb host
>     upon launching 'usb start', if we report a error upon (port - 1 < 0),
>     the current u-boot usb would failed to scan ports. (At least it
> failed at Faraday platforms.)
>     However it looks to me that it's o.k to report a error upon (port
> - 1 < 0)@old usb ehci stack.
>     (i.e. 10 days ago, in master branch of u-boot)
> 
> And thus I add a quick check to PATCH v7.
> 
> __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
> {
>  /*
>   * The u-boot would somehow set port=-1 at usb start-up,
>   * so this quick fix is necessary.
>   */
>  if (port < 0)
>   port = 0;

Maybe we should return fail, no ? Can you pinpoint where does the req->index 
(resp. port) get set to -1 ? And which commit introduced this breakage ?

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-14 13:47                               ` Marek Vasut
@ 2013-05-15  1:03                                 ` Kuo-Jung Su
  2013-05-15  2:42                                   ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  1:03 UTC (permalink / raw)
  To: u-boot

2013/5/14 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/5/13 Marek Vasut <marex@denx.de>:
>> > Dear Kuo-Jung Su,
>> >
>> >> 2013/5/13 Marek Vasut <marex@denx.de>:
>> >> > Dear Kuo-Jung Su,
>> >> >
>> >> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >> >>
>> >> >> There is at least one non-EHCI compliant controller (i.e. Faraday
>> >> >> EHCI) known to implement a non-standard TDI stuff.
>> >> >> Futhermore, it not only leave reserved and CONFIGFLAG registers
>> >> >> un-implemented but also has their address spaces removed.
>> >> >>
>> >> >> And thus, we need weak-aliased functions to both TDI stuff
>> >> >> and PORTSC registers for interface abstraction.
>> >> >>
>> >> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >> >> CC: Marek Vasut <marex@denx.de>
>> >> >> ---
>> >> >>
>> >> >> Changes for v6:
>> >> >>    - Simplify weak aliased function declaration
>> >> >>    - Drop redundant line feed
>> >> >>
>> >> >> Changes for v5:
>> >> >>    - Split up from Faraday EHCI patch
>> >> >>
>> >> >> Changes for v2 - v4:
>> >> >>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
>> >> >>
>> >> >>  drivers/usb/host/ehci-hcd.c |   91
>> >> >>
>> >> >> ++++++++++++++++++++++++++----------------- 1 file changed, 55
>> >> >> insertions(+), 36 deletions(-)
>> >> >>
>> >> >> diff --git a/drivers/usb/host/ehci-hcd.c
>> >> >> b/drivers/usb/host/ehci-hcd.c index c816878..ae3f2a4 100644
>> >> >> --- a/drivers/usb/host/ehci-hcd.c
>> >> >> +++ b/drivers/usb/host/ehci-hcd.c
>> >> >> @@ -117,10 +117,44 @@ static struct descriptor {
>> >> >>
>> >> >>  };
>> >> >>
>> >> >>  #if defined(CONFIG_EHCI_IS_TDI)
>> >> >>
>> >> >> -#define ehci_is_TDI()        (1)
>> >> >> -#else
>> >> >> -#define ehci_is_TDI()        (0)
>> >> >> +# define ehci_is_TDI()       (1)
>> >> >
>> >> > btw you can remove those braces around (1) and (0) below. But I have
>> >> > one more question ...
>> >>
>> >> Got it, thanks
>> >>
>> >> > [...]
>> >> >
>> >> >> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev,
>> >> >> unsigned long pipe, void *buffer, uint32_t *status_reg;
>> >> >>
>> >> >>       struct ehci_ctrl *ctrl = dev->controller;
>> >> >>
>> >> >> -     if (le16_to_cpu(req->index) >
>> >> >> CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { -             printf("The
>> >> >> request port(%d) is not configured\n", -
>> >> >>
>> >> >>                  le16_to_cpu(req->index) - 1);
>> >> >>
>> >> >> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
>> >> >> +             le16_to_cpu(req->index) - 1);
>> >> >> +     if (!status_reg)
>> >> >
>> >> > What happens here if req->index is zero ?
>> >> >
>> >> > Hint: the above code always does unsigned comparison ...
>> >> >
>> >> > I think you should make the second argument of
>> >> > ehci_get_portsc_register() unsigned short too (as is req->index in
>> >> > struct devrequest).
>> >>
>> >> Sorry, but I'll prefer 'int' over 'unsigned short', since it looks to me
>> >> that the u-boot would set 'req->index' to 0 at startup, which results in
>> >> a 'port = -1' to be passed to ehci_get_portsc_register().
>> >>
>> >> And I think '-1' is a better self-explain value, so I'd like to stick
>> >> with 'int'
>> >
>> > Sure, but then the comparison is signed, not unsigned. Besides, it's
>> > unnecessary change to the logic of the code. Or did I miss something ?
>>
>> 1. There is a bug in ehci_submit_root() of usb ehci:
>>
>>     int ehci_submit_root()
>>     {
>>          ......
>>          if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
>>             printf("The request port(%d) is not configured\n", port - 1);
>>             return -1;
>>          }
>>          status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
>>          ......
>>     }
>>
>>     The 'port' is actually a '0' at start-up, so we actually accessed
>> a wrong register.
>>     But fortunately the wrong register actually points to CONFIGFLAG(0x40)
>> with a safe value for the following codes.
>>
>> 2. One of Vivek Gautam's usb patches has altered the logic of usb host
>>     upon launching 'usb start', if we report a error upon (port - 1 < 0),
>>     the current u-boot usb would failed to scan ports. (At least it
>> failed at Faraday platforms.)
>>     However it looks to me that it's o.k to report a error upon (port
>> - 1 < 0)@old usb ehci stack.
>>     (i.e. 10 days ago, in master branch of u-boot)
>>
>> And thus I add a quick check to PATCH v7.
>>
>> __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
>> {
>>  /*
>>   * The u-boot would somehow set port=-1 at usb start-up,
>>   * so this quick fix is necessary.
>>   */
>>  if (port < 0)
>>   port = 0;
>
> Maybe we should return fail, no ?

No, it would make the 'usb start' to terminate immediately,
and results in a port scan failure to at least Faraday EHCI.

> Can you pinpoint where does the req->index
> (resp. port) get set to -1 ?

Later I'll try to find out where we have 'req->index' set as a '0' in
'usb start'.

> And which commit introduced this breakage ?

I believe it's there long ago, we just fortunately bypass the error at old day,
and now one of Vivek Gautam's USB patch make us face up to this issue.

>
> Best regards,
> Marek Vasut



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-15  1:03                                 ` Kuo-Jung Su
@ 2013-05-15  2:42                                   ` Kuo-Jung Su
  2013-05-15  3:29                                     ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  2:42 UTC (permalink / raw)
  To: u-boot

2013/5/15 Kuo-Jung Su <dantesu@gmail.com>:
> 2013/5/14 Marek Vasut <marex@denx.de>:
>> Dear Kuo-Jung Su,
>>
>>> 2013/5/13 Marek Vasut <marex@denx.de>:
>>> > Dear Kuo-Jung Su,
>>> >
>>> >> 2013/5/13 Marek Vasut <marex@denx.de>:
>>> >> > Dear Kuo-Jung Su,
>>> >> >
>>> >> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>> >> >>
>>> >> >> There is at least one non-EHCI compliant controller (i.e. Faraday
>>> >> >> EHCI) known to implement a non-standard TDI stuff.
>>> >> >> Futhermore, it not only leave reserved and CONFIGFLAG registers
>>> >> >> un-implemented but also has their address spaces removed.
>>> >> >>
>>> >> >> And thus, we need weak-aliased functions to both TDI stuff
>>> >> >> and PORTSC registers for interface abstraction.
>>> >> >>
>>> >> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>> >> >> CC: Marek Vasut <marex@denx.de>
>>> >> >> ---
>>> >> >>
>>> >> >> Changes for v6:
>>> >> >>    - Simplify weak aliased function declaration
>>> >> >>    - Drop redundant line feed
>>> >> >>
>>> >> >> Changes for v5:
>>> >> >>    - Split up from Faraday EHCI patch
>>> >> >>
>>> >> >> Changes for v2 - v4:
>>> >> >>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
>>> >> >>
>>> >> >>  drivers/usb/host/ehci-hcd.c |   91
>>> >> >>
>>> >> >> ++++++++++++++++++++++++++----------------- 1 file changed, 55
>>> >> >> insertions(+), 36 deletions(-)
>>> >> >>
>>> >> >> diff --git a/drivers/usb/host/ehci-hcd.c
>>> >> >> b/drivers/usb/host/ehci-hcd.c index c816878..ae3f2a4 100644
>>> >> >> --- a/drivers/usb/host/ehci-hcd.c
>>> >> >> +++ b/drivers/usb/host/ehci-hcd.c
>>> >> >> @@ -117,10 +117,44 @@ static struct descriptor {
>>> >> >>
>>> >> >>  };
>>> >> >>
>>> >> >>  #if defined(CONFIG_EHCI_IS_TDI)
>>> >> >>
>>> >> >> -#define ehci_is_TDI()        (1)
>>> >> >> -#else
>>> >> >> -#define ehci_is_TDI()        (0)
>>> >> >> +# define ehci_is_TDI()       (1)
>>> >> >
>>> >> > btw you can remove those braces around (1) and (0) below. But I have
>>> >> > one more question ...
>>> >>
>>> >> Got it, thanks
>>> >>
>>> >> > [...]
>>> >> >
>>> >> >> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev,
>>> >> >> unsigned long pipe, void *buffer, uint32_t *status_reg;
>>> >> >>
>>> >> >>       struct ehci_ctrl *ctrl = dev->controller;
>>> >> >>
>>> >> >> -     if (le16_to_cpu(req->index) >
>>> >> >> CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { -             printf("The
>>> >> >> request port(%d) is not configured\n", -
>>> >> >>
>>> >> >>                  le16_to_cpu(req->index) - 1);
>>> >> >>
>>> >> >> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
>>> >> >> +             le16_to_cpu(req->index) - 1);
>>> >> >> +     if (!status_reg)
>>> >> >
>>> >> > What happens here if req->index is zero ?
>>> >> >
>>> >> > Hint: the above code always does unsigned comparison ...
>>> >> >
>>> >> > I think you should make the second argument of
>>> >> > ehci_get_portsc_register() unsigned short too (as is req->index in
>>> >> > struct devrequest).
>>> >>
>>> >> Sorry, but I'll prefer 'int' over 'unsigned short', since it looks to me
>>> >> that the u-boot would set 'req->index' to 0 at startup, which results in
>>> >> a 'port = -1' to be passed to ehci_get_portsc_register().
>>> >>
>>> >> And I think '-1' is a better self-explain value, so I'd like to stick
>>> >> with 'int'
>>> >
>>> > Sure, but then the comparison is signed, not unsigned. Besides, it's
>>> > unnecessary change to the logic of the code. Or did I miss something ?
>>>
>>> 1. There is a bug in ehci_submit_root() of usb ehci:
>>>
>>>     int ehci_submit_root()
>>>     {
>>>          ......
>>>          if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
>>>             printf("The request port(%d) is not configured\n", port - 1);
>>>             return -1;
>>>          }
>>>          status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
>>>          ......
>>>     }
>>>
>>>     The 'port' is actually a '0' at start-up, so we actually accessed
>>> a wrong register.
>>>     But fortunately the wrong register actually points to CONFIGFLAG(0x40)
>>> with a safe value for the following codes.
>>>
>>> 2. One of Vivek Gautam's usb patches has altered the logic of usb host
>>>     upon launching 'usb start', if we report a error upon (port - 1 < 0),
>>>     the current u-boot usb would failed to scan ports. (At least it
>>> failed at Faraday platforms.)
>>>     However it looks to me that it's o.k to report a error upon (port
>>> - 1 < 0)@old usb ehci stack.
>>>     (i.e. 10 days ago, in master branch of u-boot)
>>>
>>> And thus I add a quick check to PATCH v7.
>>>
>>> __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
>>> {
>>>  /*
>>>   * The u-boot would somehow set port=-1 at usb start-up,
>>>   * so this quick fix is necessary.
>>>   */
>>>  if (port < 0)
>>>   port = 0;
>>
>> Maybe we should return fail, no ?
>
> No, it would make the 'usb start' to terminate immediately,
> and results in a port scan failure to at least Faraday EHCI.
>
>> Can you pinpoint where does the req->index
>> (resp. port) get set to -1 ?
>
> Later I'll try to find out where we have 'req->index' set as a '0' in
> 'usb start'.
>

It's from usb_new_device() --> usb_get_descriptor(), and thus
it's definitely correct to set index = 0 right here.
The only problem is 'We shall not always report an portsc error for
all request!'
Please refer to the patch attached at the tail of this mail.

>> And which commit introduced this breakage ?
>
> I believe it's there long ago, we just fortunately bypass the error at old day,
> and now one of Vivek Gautam's USB patch make us face up to this issue.
>

Shame on me....
It's nothing to do with Vivek Gautam's USB patch or the old USB ehci stack,
it's only mattered while reporting an portsc error. :P

>>
>> Best regards,
>> Marek Vasut
>
>

Here is the quick fix to this issue:


diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
index 2cf8b15..14f0894 100644
--- a/drivers/usb/host/ehci-faraday.c
+++ b/drivers/usb/host/ehci-faraday.c
@@ -136,16 +136,10 @@ int ehci_get_port_speed(struct ehci_hcor *hcor,
uint32_t reg)
  */
 uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
 {
- /*
- * The u-boot would somehow set port=-1 at usb start-up,
- * so this quick fix is necessary.
- */
- if (port < 0)
- port = 0;
-
  /* Faraday EHCI has one and only one portsc register */
  if (port) {
- printf("The request port(%d) is not configured\n", port);
+ /* ! Enable the print would lead to a timing issue ! */
+ debug("The request port(%d) is not configured\n", port);
  return NULL;
  }

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index be18a02..67d7d3f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -607,15 +607,9 @@ fail:

 __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
 {
- /*
- * The u-boot would somehow set port=-1@usb start-up,
- * so this quick fix is necessary.
- */
- if (port < 0)
- port = 0;
-
- if (port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
- printf("The request port(%u) is not configured\n", port);
+ if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+ /* ! Enable the print would lead to a timing issue ! */
+ debug("The request port(%u) is not configured\n", port);
  return NULL;
  }

@@ -636,8 +630,6 @@ ehci_submit_root(struct usb_device *dev, unsigned
long pipe, void *buffer,
  struct ehci_ctrl *ctrl = dev->controller;

  status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1);
- if (!status_reg)
- return -1;
  srclen = 0;

  debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -717,6 +709,8 @@ ehci_submit_root(struct usb_device *dev, unsigned
long pipe, void *buffer,
  srclen = 2;
  break;
  case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+ if (!status_reg)
+ return -1;
  memset(tmpbuf, 0, 4);
  reg = ehci_readl(status_reg);
  if (reg & EHCI_PS_CS)
@@ -761,6 +755,8 @@ ehci_submit_root(struct usb_device *dev, unsigned
long pipe, void *buffer,
  srclen = 4;
  break;
  case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+ if (!status_reg)
+ return -1;
  reg = ehci_readl(status_reg);
  reg &= ~EHCI_PS_CLEAR;
  switch (le16_to_cpu(req->value)) {
@@ -825,6 +821,8 @@ ehci_submit_root(struct usb_device *dev, unsigned
long pipe, void *buffer,
  (void) ehci_readl(&ctrl->hcor->or_usbcmd);
  break;
  case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+ if (!status_reg)
+ return -1;
  reg = ehci_readl(status_reg);
  switch (le16_to_cpu(req->value)) {
  case USB_PORT_FEAT_ENABLE:

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-15  2:42                                   ` Kuo-Jung Su
@ 2013-05-15  3:29                                     ` Marek Vasut
  2013-05-15  4:07                                       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-15  3:29 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> 2013/5/15 Kuo-Jung Su <dantesu@gmail.com>:
> > 2013/5/14 Marek Vasut <marex@denx.de>:
> >> Dear Kuo-Jung Su,
> >> 
> >>> 2013/5/13 Marek Vasut <marex@denx.de>:
> >>> > Dear Kuo-Jung Su,
> >>> > 
> >>> >> 2013/5/13 Marek Vasut <marex@denx.de>:
> >>> >> > Dear Kuo-Jung Su,
> >>> >> > 
> >>> >> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >>> >> >> 
> >>> >> >> There is at least one non-EHCI compliant controller (i.e. Faraday
> >>> >> >> EHCI) known to implement a non-standard TDI stuff.
> >>> >> >> Futhermore, it not only leave reserved and CONFIGFLAG registers
> >>> >> >> un-implemented but also has their address spaces removed.
> >>> >> >> 
> >>> >> >> And thus, we need weak-aliased functions to both TDI stuff
> >>> >> >> and PORTSC registers for interface abstraction.
> >>> >> >> 
> >>> >> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> >>> >> >> CC: Marek Vasut <marex@denx.de>
> >>> >> >> ---
> >>> >> >> 
> >>> >> >> Changes for v6:
> >>> >> >>    - Simplify weak aliased function declaration
> >>> >> >>    - Drop redundant line feed
> >>> >> >> 
> >>> >> >> Changes for v5:
> >>> >> >>    - Split up from Faraday EHCI patch
> >>> >> >> 
> >>> >> >> Changes for v2 - v4:
> >>> >> >>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
> >>> >> >>  
> >>> >> >>  drivers/usb/host/ehci-hcd.c |   91
> >>> >> >> 
> >>> >> >> ++++++++++++++++++++++++++----------------- 1 file changed, 55
> >>> >> >> insertions(+), 36 deletions(-)
> >>> >> >> 
> >>> >> >> diff --git a/drivers/usb/host/ehci-hcd.c
> >>> >> >> b/drivers/usb/host/ehci-hcd.c index c816878..ae3f2a4 100644
> >>> >> >> --- a/drivers/usb/host/ehci-hcd.c
> >>> >> >> +++ b/drivers/usb/host/ehci-hcd.c
> >>> >> >> @@ -117,10 +117,44 @@ static struct descriptor {
> >>> >> >> 
> >>> >> >>  };
> >>> >> >>  
> >>> >> >>  #if defined(CONFIG_EHCI_IS_TDI)
> >>> >> >> 
> >>> >> >> -#define ehci_is_TDI()        (1)
> >>> >> >> -#else
> >>> >> >> -#define ehci_is_TDI()        (0)
> >>> >> >> +# define ehci_is_TDI()       (1)
> >>> >> > 
> >>> >> > btw you can remove those braces around (1) and (0) below. But I
> >>> >> > have one more question ...
> >>> >> 
> >>> >> Got it, thanks
> >>> >> 
> >>> >> > [...]
> >>> >> > 
> >>> >> >> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev,
> >>> >> >> unsigned long pipe, void *buffer, uint32_t *status_reg;
> >>> >> >> 
> >>> >> >>       struct ehci_ctrl *ctrl = dev->controller;
> >>> >> >> 
> >>> >> >> -     if (le16_to_cpu(req->index) >
> >>> >> >> CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { -             printf("The
> >>> >> >> request port(%d) is not configured\n", -
> >>> >> >> 
> >>> >> >>                  le16_to_cpu(req->index) - 1);
> >>> >> >> 
> >>> >> >> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
> >>> >> >> +             le16_to_cpu(req->index) - 1);
> >>> >> >> +     if (!status_reg)
> >>> >> > 
> >>> >> > What happens here if req->index is zero ?
> >>> >> > 
> >>> >> > Hint: the above code always does unsigned comparison ...
> >>> >> > 
> >>> >> > I think you should make the second argument of
> >>> >> > ehci_get_portsc_register() unsigned short too (as is req->index in
> >>> >> > struct devrequest).
> >>> >> 
> >>> >> Sorry, but I'll prefer 'int' over 'unsigned short', since it looks
> >>> >> to me that the u-boot would set 'req->index' to 0 at startup, which
> >>> >> results in a 'port = -1' to be passed to
> >>> >> ehci_get_portsc_register().
> >>> >> 
> >>> >> And I think '-1' is a better self-explain value, so I'd like to
> >>> >> stick with 'int'
> >>> > 
> >>> > Sure, but then the comparison is signed, not unsigned. Besides, it's
> >>> > unnecessary change to the logic of the code. Or did I miss something
> >>> > ?
> >>> 
> >>> 1. There is a bug in ehci_submit_root() of usb ehci:
> >>>     int ehci_submit_root()
> >>>     {
> >>>     
> >>>          ......
> >>>          if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
> >>>          
> >>>             printf("The request port(%d) is not configured\n", port -
> >>>             1); return -1;
> >>>          
> >>>          }
> >>>          status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
> >>>          ......
> >>>     
> >>>     }
> >>>     
> >>>     The 'port' is actually a '0' at start-up, so we actually accessed
> >>> 
> >>> a wrong register.
> >>> 
> >>>     But fortunately the wrong register actually points to
> >>>     CONFIGFLAG(0x40)
> >>> 
> >>> with a safe value for the following codes.
> >>> 
> >>> 2. One of Vivek Gautam's usb patches has altered the logic of usb host
> >>> 
> >>>     upon launching 'usb start', if we report a error upon (port - 1 <
> >>>     0), the current u-boot usb would failed to scan ports. (At least
> >>>     it
> >>> 
> >>> failed at Faraday platforms.)
> >>> 
> >>>     However it looks to me that it's o.k to report a error upon (port
> >>> 
> >>> - 1 < 0)@old usb ehci stack.
> >>> 
> >>>     (i.e. 10 days ago, in master branch of u-boot)
> >>> 
> >>> And thus I add a quick check to PATCH v7.
> >>> 
> >>> __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int
> >>> port) {
> >>> 
> >>>  /*
> >>>  
> >>>   * The u-boot would somehow set port=-1 at usb start-up,
> >>>   * so this quick fix is necessary.
> >>>   */
> >>>  
> >>>  if (port < 0)
> >>>  
> >>>   port = 0;
> >> 
> >> Maybe we should return fail, no ?
> > 
> > No, it would make the 'usb start' to terminate immediately,
> > and results in a port scan failure to at least Faraday EHCI.
> > 
> >> Can you pinpoint where does the req->index
> >> (resp. port) get set to -1 ?
> > 
> > Later I'll try to find out where we have 'req->index' set as a '0' in
> > 'usb start'.
> 
> It's from usb_new_device() --> usb_get_descriptor(), and thus
> it's definitely correct to set index = 0 right here.
> The only problem is 'We shall not always report an portsc error for
> all request!'
> Please refer to the patch attached at the tail of this mail.
> 
> >> And which commit introduced this breakage ?
> > 
> > I believe it's there long ago, we just fortunately bypass the error at
> > old day, and now one of Vivek Gautam's USB patch make us face up to this
> > issue.
> 
> Shame on me....
> It's nothing to do with Vivek Gautam's USB patch or the old USB ehci stack,
> it's only mattered while reporting an portsc error. :P
> 
> >> Best regards,
> >> Marek Vasut

Ok, I think I almost see it there. Can you just make a patchset out of this 
stuff so I can digest it a little bit easier? Maybe stick the fixes first so I 
can pick them ASAP and the FHCI stuff after that.

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

* [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi
  2013-05-15  3:29                                     ` Marek Vasut
@ 2013-05-15  4:07                                       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  4:07 UTC (permalink / raw)
  To: u-boot

2013/5/15 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> 2013/5/15 Kuo-Jung Su <dantesu@gmail.com>:
>> > 2013/5/14 Marek Vasut <marex@denx.de>:
>> >> Dear Kuo-Jung Su,
>> >>
>> >>> 2013/5/13 Marek Vasut <marex@denx.de>:
>> >>> > Dear Kuo-Jung Su,
>> >>> >
>> >>> >> 2013/5/13 Marek Vasut <marex@denx.de>:
>> >>> >> > Dear Kuo-Jung Su,
>> >>> >> >
>> >>> >> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >>> >> >>
>> >>> >> >> There is at least one non-EHCI compliant controller (i.e. Faraday
>> >>> >> >> EHCI) known to implement a non-standard TDI stuff.
>> >>> >> >> Futhermore, it not only leave reserved and CONFIGFLAG registers
>> >>> >> >> un-implemented but also has their address spaces removed.
>> >>> >> >>
>> >>> >> >> And thus, we need weak-aliased functions to both TDI stuff
>> >>> >> >> and PORTSC registers for interface abstraction.
>> >>> >> >>
>> >>> >> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >>> >> >> CC: Marek Vasut <marex@denx.de>
>> >>> >> >> ---
>> >>> >> >>
>> >>> >> >> Changes for v6:
>> >>> >> >>    - Simplify weak aliased function declaration
>> >>> >> >>    - Drop redundant line feed
>> >>> >> >>
>> >>> >> >> Changes for v5:
>> >>> >> >>    - Split up from Faraday EHCI patch
>> >>> >> >>
>> >>> >> >> Changes for v2 - v4:
>> >>> >> >>    - See 'usb: ehci: add Faraday USB 2.0 EHCI support'
>> >>> >> >>
>> >>> >> >>  drivers/usb/host/ehci-hcd.c |   91
>> >>> >> >>
>> >>> >> >> ++++++++++++++++++++++++++----------------- 1 file changed, 55
>> >>> >> >> insertions(+), 36 deletions(-)
>> >>> >> >>
>> >>> >> >> diff --git a/drivers/usb/host/ehci-hcd.c
>> >>> >> >> b/drivers/usb/host/ehci-hcd.c index c816878..ae3f2a4 100644
>> >>> >> >> --- a/drivers/usb/host/ehci-hcd.c
>> >>> >> >> +++ b/drivers/usb/host/ehci-hcd.c
>> >>> >> >> @@ -117,10 +117,44 @@ static struct descriptor {
>> >>> >> >>
>> >>> >> >>  };
>> >>> >> >>
>> >>> >> >>  #if defined(CONFIG_EHCI_IS_TDI)
>> >>> >> >>
>> >>> >> >> -#define ehci_is_TDI()        (1)
>> >>> >> >> -#else
>> >>> >> >> -#define ehci_is_TDI()        (0)
>> >>> >> >> +# define ehci_is_TDI()       (1)
>> >>> >> >
>> >>> >> > btw you can remove those braces around (1) and (0) below. But I
>> >>> >> > have one more question ...
>> >>> >>
>> >>> >> Got it, thanks
>> >>> >>
>> >>> >> > [...]
>> >>> >> >
>> >>> >> >> @@ -609,13 +644,10 @@ ehci_submit_root(struct usb_device *dev,
>> >>> >> >> unsigned long pipe, void *buffer, uint32_t *status_reg;
>> >>> >> >>
>> >>> >> >>       struct ehci_ctrl *ctrl = dev->controller;
>> >>> >> >>
>> >>> >> >> -     if (le16_to_cpu(req->index) >
>> >>> >> >> CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) { -             printf("The
>> >>> >> >> request port(%d) is not configured\n", -
>> >>> >> >>
>> >>> >> >>                  le16_to_cpu(req->index) - 1);
>> >>> >> >>
>> >>> >> >> +     status_reg = ehci_get_portsc_register(ctrl->hcor,
>> >>> >> >> +             le16_to_cpu(req->index) - 1);
>> >>> >> >> +     if (!status_reg)
>> >>> >> >
>> >>> >> > What happens here if req->index is zero ?
>> >>> >> >
>> >>> >> > Hint: the above code always does unsigned comparison ...
>> >>> >> >
>> >>> >> > I think you should make the second argument of
>> >>> >> > ehci_get_portsc_register() unsigned short too (as is req->index in
>> >>> >> > struct devrequest).
>> >>> >>
>> >>> >> Sorry, but I'll prefer 'int' over 'unsigned short', since it looks
>> >>> >> to me that the u-boot would set 'req->index' to 0 at startup, which
>> >>> >> results in a 'port = -1' to be passed to
>> >>> >> ehci_get_portsc_register().
>> >>> >>
>> >>> >> And I think '-1' is a better self-explain value, so I'd like to
>> >>> >> stick with 'int'
>> >>> >
>> >>> > Sure, but then the comparison is signed, not unsigned. Besides, it's
>> >>> > unnecessary change to the logic of the code. Or did I miss something
>> >>> > ?
>> >>>
>> >>> 1. There is a bug in ehci_submit_root() of usb ehci:
>> >>>     int ehci_submit_root()
>> >>>     {
>> >>>
>> >>>          ......
>> >>>          if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
>> >>>
>> >>>             printf("The request port(%d) is not configured\n", port -
>> >>>             1); return -1;
>> >>>
>> >>>          }
>> >>>          status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
>> >>>          ......
>> >>>
>> >>>     }
>> >>>
>> >>>     The 'port' is actually a '0' at start-up, so we actually accessed
>> >>>
>> >>> a wrong register.
>> >>>
>> >>>     But fortunately the wrong register actually points to
>> >>>     CONFIGFLAG(0x40)
>> >>>
>> >>> with a safe value for the following codes.
>> >>>
>> >>> 2. One of Vivek Gautam's usb patches has altered the logic of usb host
>> >>>
>> >>>     upon launching 'usb start', if we report a error upon (port - 1 <
>> >>>     0), the current u-boot usb would failed to scan ports. (At least
>> >>>     it
>> >>>
>> >>> failed at Faraday platforms.)
>> >>>
>> >>>     However it looks to me that it's o.k to report a error upon (port
>> >>>
>> >>> - 1 < 0)@old usb ehci stack.
>> >>>
>> >>>     (i.e. 10 days ago, in master branch of u-boot)
>> >>>
>> >>> And thus I add a quick check to PATCH v7.
>> >>>
>> >>> __weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int
>> >>> port) {
>> >>>
>> >>>  /*
>> >>>
>> >>>   * The u-boot would somehow set port=-1 at usb start-up,
>> >>>   * so this quick fix is necessary.
>> >>>   */
>> >>>
>> >>>  if (port < 0)
>> >>>
>> >>>   port = 0;
>> >>
>> >> Maybe we should return fail, no ?
>> >
>> > No, it would make the 'usb start' to terminate immediately,
>> > and results in a port scan failure to at least Faraday EHCI.
>> >
>> >> Can you pinpoint where does the req->index
>> >> (resp. port) get set to -1 ?
>> >
>> > Later I'll try to find out where we have 'req->index' set as a '0' in
>> > 'usb start'.
>>
>> It's from usb_new_device() --> usb_get_descriptor(), and thus
>> it's definitely correct to set index = 0 right here.
>> The only problem is 'We shall not always report an portsc error for
>> all request!'
>> Please refer to the patch attached at the tail of this mail.
>>
>> >> And which commit introduced this breakage ?
>> >
>> > I believe it's there long ago, we just fortunately bypass the error at
>> > old day, and now one of Vivek Gautam's USB patch make us face up to this
>> > issue.
>>
>> Shame on me....
>> It's nothing to do with Vivek Gautam's USB patch or the old USB ehci stack,
>> it's only mattered while reporting an portsc error. :P
>>
>> >> Best regards,
>> >> Marek Vasut
>
> Ok, I think I almost see it there. Can you just make a patchset out of this
> stuff so I can digest it a little bit easier? Maybe stick the fixes first so I
> can pick them ASAP and the FHCI stuff after that.

Sure, I'll post a new patchset with this as 1st part.

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support
  2013-05-14  2:29                             ` [U-Boot] [PATCH v8 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-15  7:29                               ` Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 1/5] usb: ehci: prevent bad PORTSC register access Kuo-Jung Su
                                                   ` (4 more replies)
  0 siblings, 5 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  7:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differs from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Changes for v9:
   - ehci-hcd: prevent bad PORTSC register access
     in ehci_submit_root()
   - ehci-hcd: drop the quick fix to 'port=-1'
     from ehci_get_portsc_register().
   - ehci-faraday: drop the quick fix to 'port=-1'

Changes for v8:
   - ehci-faraday: ehci_get_portsc_register():
     Bug fixed, only port=0 is accepted.

Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae,
     and also make sure it's compatible to
     u-boot-usb-dc69e46302a36e60e2417bba8c6ea78761a37ebf.
   - Update TDI aliased functions, since there is another
     similar patch had been committed and acceptted.
   - ehci-hcd: ehci_get_portsc_register(): make sure port is always >= 0

Changes for v6:
   - usb_hub: Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY
     default value setup.
   - ehci-hcd: Simplify weak aliased function declaration
   - ehci-hcd: Drop redundant line feed

Changes for v5:
   - Split up EHCI changeset
   - usb_hub: replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.
   - ehci-faraday: fix the invalid multi-line comment style.
   - gadget-fotg210: coding style cleanup.
   - gadget-fotg210: drop postfix '__iomem' from struct fotg210_regs
   - gadget-fotg210: use permanent delay for hardware reset
   - gadget-fotg210: drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - gadget-fotg210: drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

Kuo-Jung Su (5):
  usb: ehci: prevent bad PORTSC register access
  usb: ehci: add weak-aliased function for PORTSC
  usb: hub: make minimum power-on delay configurable
  usb: ehci: add Faraday USB 2.0 EHCI support
  usb: gadget: add Faraday FOTG210 USB gadget support

 README                            |    3 +
 common/usb_hub.c                  |   15 +-
 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 drivers/usb/host/Makefile         |    1 +
 drivers/usb/host/ehci-faraday.c   |  148 ++++++
 drivers/usb/host/ehci-hcd.c       |   34 +-
 include/usb/fotg210.h             |  364 ++++++++++++++
 include/usb/fusbh200.h            |   61 +++
 10 files changed, 1575 insertions(+), 8 deletions(-)
 create mode 100644 drivers/usb/gadget/fotg210.c
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

--
1.7.9.5

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

* [U-Boot] [PATCH v9 1/5] usb: ehci: prevent bad PORTSC register access
  2013-05-15  7:29                               ` [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
@ 2013-05-15  7:29                                 ` Kuo-Jung Su
  2013-05-21 20:09                                   ` Marek Vasut
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 2/5] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
                                                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  7:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

1. The 'index' of ehci_submit_root() is not always > 0.

   e.g.
   While it gets invoked from usb_get_descriptor(),
   the 'index' is always a '0'. (See ch.9 of USB2.0)

2. The PORTSC register is not always required, and thus it
   should only report a port error when necessary.
   It would cause a port scan failure if the ehci_submit_root()
   always gets terminated by a port error.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v9:
   - 1st edition

 drivers/usb/host/ehci-hcd.c |   20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index e0f3e4b..6022049 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -616,11 +616,6 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	int port = le16_to_cpu(req->index) & 0xff;
 	struct ehci_ctrl *ctrl = dev->controller;

-	if (port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-		printf("The request port(%d) is not configured\n", port - 1);
-		return -1;
-	}
-	status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
 	srclen = 0;

 	debug("req=%u (%#x), type=%u (%#x), value=%u, index=%u\n",
@@ -631,6 +626,21 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	typeReq = req->request | req->requesttype << 8;

 	switch (typeReq) {
+	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
+	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
+		if (!port || port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+			printf("The request port(%d) is not configured\n", port - 1);
+			return -1;
+		}
+		status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
+		break;
+	default:
+		status_reg = NULL;
+		break;
+	}
+
+	switch (typeReq) {
 	case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
 		switch (le16_to_cpu(req->value) >> 8) {
 		case USB_DT_DEVICE:
--
1.7.9.5

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

* [U-Boot] [PATCH v9 2/5] usb: ehci: add weak-aliased function for PORTSC
  2013-05-15  7:29                               ` [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 1/5] usb: ehci: prevent bad PORTSC register access Kuo-Jung Su
@ 2013-05-15  7:29                                 ` Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 3/5] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
                                                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  7:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

There is at least one non-EHCI compliant controller (i.e. Faraday EHCI)
not only leave RESERVED and CONFIGFLAG registers un-implemented
but also has their address spaces removed.

As an result, the PORTSC register of Faraday EHCI always
starts from 0x30 instead of 0x44 in standard EHCI.

So that we'll need a weak-aliased function for abstraction.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v9:
   - Drop the quick fix to 'port=-1' from ehci_get_portsc_register().

Changes for v8:
   - Nothing updates

Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae
   - Drop TDI weak-aliased functions, since there is another similar
     patch had been committed and acceptted.
   - ehci_get_portsc_register(): make sure port is always >= 0

Changes for v6:
   - Simplify weak aliased function declaration
   - Drop redundant line feed

Changes for v5:
   - Split up from Faraday EHCI patch

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 drivers/usb/host/ehci-hcd.c |   17 +++++++++++++----
 1 file changed, 13 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 6022049..cfb2097 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -603,6 +603,17 @@ fail:
 	return -1;
 }

+__weak uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	if (port < 0 || port >= CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
+		/* Printing the message would cause a scan failure! */
+		debug("The request port(%u) is not configured\n", port);
+		return NULL;
+	}
+
+	return (uint32_t *)&hcor->or_portsc[port];
+}
+
 int
 ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 		 int length, struct devrequest *req)
@@ -629,11 +640,9 @@ ehci_submit_root(struct usb_device *dev, unsigned long pipe, void *buffer,
 	case USB_REQ_GET_STATUS | ((USB_RT_PORT | USB_DIR_IN) << 8):
 	case USB_REQ_SET_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
 	case USB_REQ_CLEAR_FEATURE | ((USB_DIR_OUT | USB_RT_PORT) << 8):
-		if (!port || port > CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS) {
-			printf("The request port(%d) is not configured\n", port - 1);
+		status_reg = ehci_get_portsc_register(ctrl->hcor, port - 1);
+		if (!status_reg)
 			return -1;
-		}
-		status_reg = (uint32_t *)&ctrl->hcor->or_portsc[port - 1];
 		break;
 	default:
 		status_reg = NULL;
--
1.7.9.5

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

* [U-Boot] [PATCH v9 3/5] usb: hub: make minimum power-on delay configurable
  2013-05-15  7:29                               ` [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 1/5] usb: ehci: prevent bad PORTSC register access Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 2/5] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
@ 2013-05-15  7:29                                 ` Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 4/5] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 5/5] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  4 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  7:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch makes the minimum power-on delay for USB HUB
become configurable. The original design waits at least
100 msec here, but some EHCI controlers(e.g. Faraday EHCI)
are known to require much longer delay interval.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v9:
   - Nothing updates

Changes for v8:
   - Nothing updates

Changes for v7:
   - Rebase to u-boot-bbd0f7e3ba66d288a2f146f1c7797801e04598ae

Changes for v6:
   - Simplify CONFIG_USB_HUB_MIN_POWER_ON_DELAY default value setup.

Changes for v5:
   - Split up from Faraday EHCI patch
   - Replace the Faraday EHCI ifdef for the long delay
     in usb_hub_configure() with the new configuration option:
     USB_HUB_MIN_POWER_ON_DELAY, which is used in usb_hub_power_on()
     to control the minimum usb hub power-on delay.

Changes for v2 - v4:
   - See 'usb: ehci: add Faraday USB 2.0 EHCI support'

 README           |    3 +++
 common/usb_hub.c |    8 ++++++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/README b/README
index defdedb..5bf4791 100644
--- a/README
+++ b/README
@@ -1245,6 +1245,9 @@ The following options need to be configured:
 		CONFIG_USB_EHCI_TXFIFO_THRESH enables setting of the
 		txfilltuning field in the EHCI controller on reset.

+		CONFIG_USB_HUB_MIN_POWER_ON_DELAY defines the minimum
+		interval for usb hub power-on delay.(minimum 100msec)
+
 - USB Device:
 		Define the below if you wish to use the USB console.
 		Once firmware is rebuilt from a serial console issue the
diff --git a/common/usb_hub.c b/common/usb_hub.c
index 0d79ec3..fc3a8c1 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -53,6 +53,10 @@
 #include <asm/4xx_pci.h>
 #endif

+#ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+#define CONFIG_USB_HUB_MIN_POWER_ON_DELAY	100
+#endif
+
 #define USB_BUFSIZ	512

 static struct usb_hub_device hub_dev[USB_MAX_HUB];
@@ -148,8 +152,8 @@ static void usb_hub_power_on(struct usb_hub_device *hub)
 		debug("port %d returns %lX\n", i + 1, dev->status);
 	}

-	/* Wait at least 100 msec for power to become stable */
-	mdelay(max(pgood_delay, (unsigned)100));
+	/* Wait for power to become stable */
+	mdelay(max(pgood_delay, CONFIG_USB_HUB_MIN_POWER_ON_DELAY));
 }

 void usb_hub_reset(void)
--
1.7.9.5

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

* [U-Boot] [PATCH v9 4/5] usb: ehci: add Faraday USB 2.0 EHCI support
  2013-05-15  7:29                               ` [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
                                                   ` (2 preceding siblings ...)
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 3/5] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
@ 2013-05-15  7:29                                 ` Kuo-Jung Su
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 5/5] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
  4 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  7:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This patch adds support to both Faraday FUSBH200 and FOTG210,
the differences between Faraday EHCI and standard EHCI are
listed bellow:

1. The PORTSC starts at 0x30 instead of 0x44.
2. The CONFIGFLAG(0x40) is not only un-implemented, and
   also has its address space removed.
3. Faraday EHCI is a TDI design, but it doesn't
   compatible with the general TDI implementation
   found at both U-Boot and Linux.
4. The ISOC descriptors differ from standard EHCI in
   several ways. But since U-boot doesn't support ISOC,
   we don't have to worry about that.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v9:
   - Drop the quick fix to 'port=-1' from ehci_get_portsc_register().

Changes for v8:
   - ehci-faraday: ehci_get_portsc_register():
     Bug fixed, only port=0 is accepted.

Changes for v7:
   - Nothing updates

Changes for v6:
   - Nothing updates

Changes for v5:
   - Break down EHCI changes as seperate changesets.
   - Fix the invalid multi-line comment style.

Changes for v4:
   - Use only macro constants and named bit/mask
   - Use weak-aliased functions for tdi implementation and
     also portsc registers to avoid poluting ehci.h with ifdefs

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 common/usb_hub.c                |    7 +-
 drivers/usb/host/Makefile       |    1 +
 drivers/usb/host/ehci-faraday.c |  148 ++++++++++++++++
 drivers/usb/host/ehci-hcd.c     |    5 +
 include/usb/fotg210.h           |  364 +++++++++++++++++++++++++++++++++++++++
 include/usb/fusbh200.h          |   61 +++++++
 6 files changed, 585 insertions(+), 1 deletion(-)
 create mode 100644 drivers/usb/host/ehci-faraday.c
 create mode 100644 include/usb/fotg210.h
 create mode 100644 include/usb/fusbh200.h

diff --git a/common/usb_hub.c b/common/usb_hub.c
index fc3a8c1..774ba63 100644
--- a/common/usb_hub.c
+++ b/common/usb_hub.c
@@ -489,7 +489,11 @@ static int usb_hub_configure(struct usb_device *dev)
 			      i + 1, portstatus);
 			usb_clear_port_feature(dev, i + 1,
 						USB_PORT_FEAT_C_ENABLE);
-
+			/*
+			 * The following hack causes a ghost device problem
+			 * to Faraday EHCI
+			 */
+#ifndef CONFIG_USB_EHCI_FARADAY
 			/* EM interference sometimes causes bad shielded USB
 			 * devices to be shutdown by the hub, this hack enables
 			 * them again. Works at least with mouse driver */
@@ -501,6 +505,7 @@ static int usb_hub_configure(struct usb_device *dev)
 				      "re-enabling...\n", i + 1);
 				      usb_hub_port_connect_change(dev, i);
 			}
+#endif
 		}
 		if (portstatus & USB_PORT_STAT_SUSPEND) {
 			debug("port %d suspend change\n", i + 1);
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 87a5970..98f2a10 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-mpc512x.o
 else
 COBJS-$(CONFIG_USB_EHCI_FSL) += ehci-fsl.o
 endif
+COBJS-$(CONFIG_USB_EHCI_FARADAY) += ehci-faraday.o
 COBJS-$(CONFIG_USB_EHCI_EXYNOS) += ehci-exynos.o
 COBJS-$(CONFIG_USB_EHCI_MXC) += ehci-mxc.o
 COBJS-$(CONFIG_USB_EHCI_MXS) += ehci-mxs.o
diff --git a/drivers/usb/host/ehci-faraday.c b/drivers/usb/host/ehci-faraday.c
new file mode 100644
index 0000000..86add36
--- /dev/null
+++ b/drivers/usb/host/ehci-faraday.c
@@ -0,0 +1,148 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <usb.h>
+#include <usb/fusbh200.h>
+#include <usb/fotg210.h>
+
+#include "ehci.h"
+
+#ifndef CONFIG_USB_EHCI_BASE_LIST
+#define CONFIG_USB_EHCI_BASE_LIST	{ CONFIG_USB_EHCI_BASE }
+#endif
+
+union ehci_faraday_regs {
+	struct fusbh200_regs usb;
+	struct fotg210_regs  otg;
+};
+
+static inline int ehci_is_fotg2xx(union ehci_faraday_regs *regs)
+{
+	return !readl(&regs->usb.easstr);
+}
+
+/*
+ * Create the appropriate control structures to manage
+ * a new EHCI host controller.
+ */
+int ehci_hcd_init(int index, struct ehci_hccr **ret_hccr,
+		struct ehci_hcor **ret_hcor)
+{
+	struct ehci_hccr *hccr;
+	struct ehci_hcor *hcor;
+	union ehci_faraday_regs *regs;
+	uint32_t base_list[] = CONFIG_USB_EHCI_BASE_LIST;
+
+	if (index < 0 || index >= ARRAY_SIZE(base_list))
+		return -1;
+	regs = (void __iomem *)base_list[index];
+	hccr = (struct ehci_hccr *)&regs->usb.hccr;
+	hcor = (struct ehci_hcor *)&regs->usb.hcor;
+
+	if (ehci_is_fotg2xx(regs)) {
+		/* A-device bus reset */
+		/* ... Power off A-device */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drop vbus and bus traffic */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* ... Power on A-device */
+		clrbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSDROP);
+		/* ... Drive vbus and bus traffic */
+		setbits_le32(&regs->otg.otgcsr, OTGCSR_A_BUSREQ);
+		mdelay(1);
+		/* Disable OTG & DEV interrupts, triggered at level-high */
+		writel(IMR_IRQLH | IMR_OTG | IMR_DEV, &regs->otg.imr);
+		/* Clear all interrupt status */
+		writel(ISR_HOST | ISR_OTG | ISR_DEV, &regs->otg.isr);
+	} else {
+		/* Interrupt=level-high */
+		setbits_le32(&regs->usb.bmcsr, BMCSR_IRQLH);
+		/* VBUS on */
+		clrbits_le32(&regs->usb.bmcsr, BMCSR_VBUS_OFF);
+		/* Disable all interrupts */
+		writel(0x00, &regs->usb.bmier);
+		writel(0x1f, &regs->usb.bmisr);
+	}
+
+	*ret_hccr = hccr;
+	*ret_hcor = hcor;
+
+	return 0;
+}
+
+/*
+ * Destroy the appropriate control structures corresponding
+ * the the EHCI host controller.
+ */
+int ehci_hcd_stop(int index)
+{
+	return 0;
+}
+
+/*
+ * This ehci_set_usbmode() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+void ehci_set_usbmode(int index)
+{
+	/* nothing needs to be done */
+}
+
+/*
+ * This ehci_get_port_speed() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+int ehci_get_port_speed(struct ehci_hcor *hcor, uint32_t reg)
+{
+	int spd, ret = PORTSC_PSPD_HS;
+	union ehci_faraday_regs *regs = (void __iomem *)((ulong)hcor - 0x10);
+
+	if (ehci_is_fotg2xx(regs))
+		spd = OTGCSR_SPD(readl(&regs->otg.otgcsr));
+	else
+		spd = BMCSR_SPD(readl(&regs->usb.bmcsr));
+
+	switch (spd) {
+	case 0:    /* full speed */
+		ret = PORTSC_PSPD_FS;
+		break;
+	case 1:    /* low  speed */
+		ret = PORTSC_PSPD_LS;
+		break;
+	case 2:    /* high speed */
+		ret = PORTSC_PSPD_HS;
+		break;
+	default:
+		printf("ehci-faraday: invalid device speed\n");
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * This ehci_get_portsc_register() overrides the weak function
+ * in "ehci-hcd.c".
+ */
+uint32_t *ehci_get_portsc_register(struct ehci_hcor *hcor, int port)
+{
+	/* Faraday EHCI has one and only one portsc register */
+	if (port) {
+		/* Printing the message would cause a scan failure! */
+		debug("The request port(%d) is not configured\n", port);
+		return NULL;
+	}
+
+	/* Faraday EHCI PORTSC register offset is 0x20 from hcor */
+	return (uint32_t *)((uint8_t *)hcor + 0x20);
+}
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index cfb2097..f6b4854 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -589,10 +589,12 @@ ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
 		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
 	} else {
 		dev->act_len = 0;
+#ifndef CONFIG_USB_EHCI_FARADAY
 		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
 		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
 		      ehci_readl(&ctrl->hcor->or_portsc[0]),
 		      ehci_readl(&ctrl->hcor->or_portsc[1]));
+#endif
 	}

 	free(qtd);
@@ -978,10 +980,13 @@ int usb_lowlevel_init(int index, void **controller)
 	cmd |= CMD_RUN;
 	ehci_writel(&ehcic[index].hcor->or_usbcmd, cmd);

+#ifndef CONFIG_USB_EHCI_FARADAY
 	/* take control over the ports */
 	cmd = ehci_readl(&ehcic[index].hcor->or_configflag);
 	cmd |= FLAG_CF;
 	ehci_writel(&ehcic[index].hcor->or_configflag, cmd);
+#endif
+
 	/* unblock posted write */
 	cmd = ehci_readl(&ehcic[index].hcor->or_usbcmd);
 	mdelay(5);
diff --git a/include/usb/fotg210.h b/include/usb/fotg210.h
new file mode 100644
index 0000000..2d2d243
--- /dev/null
+++ b/include/usb/fotg210.h
@@ -0,0 +1,364 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FOTG210_H
+#define _FOTG210_H
+
+struct fotg210_regs {
+	/* USB Host Controller */
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t rsvd1[3];
+	uint32_t miscr;	/* 0x40: Miscellaneous Register */
+	uint32_t rsvd2[15];
+	/* USB OTG Controller */
+	uint32_t otgcsr;/* 0x80: OTG Control Status Register */
+	uint32_t otgisr;/* 0x84: OTG Interrupt Status Register */
+	uint32_t otgier;/* 0x88: OTG Interrupt Enable Register */
+	uint32_t rsvd3[13];
+	uint32_t isr;	/* 0xC0: Global Interrupt Status Register */
+	uint32_t imr;	/* 0xC4: Global Interrupt Mask Register */
+	uint32_t rsvd4[14];
+	/* USB Device Controller */
+	uint32_t dev_ctrl;/* 0x100: Device Control Register */
+	uint32_t dev_addr;/* 0x104: Device Address Register */
+	uint32_t dev_test;/* 0x108: Device Test Register */
+	uint32_t sof_fnr; /* 0x10c: SOF Frame Number Register */
+	uint32_t sof_mtr; /* 0x110: SOF Mask Timer Register */
+	uint32_t phy_tmsr;/* 0x114: PHY Test Mode Selector Register */
+	uint32_t rsvd5[2];
+	uint32_t cxfifo;/* 0x120: CX FIFO Register */
+	uint32_t idle;	/* 0x124: IDLE Counter Register */
+	uint32_t rsvd6[2];
+	uint32_t gimr;	/* 0x130: Group Interrupt Mask Register */
+	uint32_t gimr0; /* 0x134: Group Interrupt Mask Register 0 */
+	uint32_t gimr1; /* 0x138: Group Interrupt Mask Register 1 */
+	uint32_t gimr2; /* 0x13c: Group Interrupt Mask Register 2 */
+	uint32_t gisr;	/* 0x140: Group Interrupt Status Register */
+	uint32_t gisr0; /* 0x144: Group Interrupt Status Register 0 */
+	uint32_t gisr1; /* 0x148: Group Interrupt Status Register 1 */
+	uint32_t gisr2; /* 0x14c: Group Interrupt Status Register 2 */
+	uint32_t rxzlp; /* 0x150: Receive Zero-Length-Packet Register */
+	uint32_t txzlp; /* 0x154: Transfer Zero-Length-Packet Register */
+	uint32_t isoeasr;/* 0x158: ISOC Error/Abort Status Register */
+	uint32_t rsvd7[1];
+	uint32_t iep[8]; /* 0x160 - 0x17f: IN Endpoint Register */
+	uint32_t oep[8]; /* 0x180 - 0x19f: OUT Endpoint Register */
+	uint32_t epmap14;/* 0x1a0: Endpoint Map Register (EP1 ~ 4) */
+	uint32_t epmap58;/* 0x1a4: Endpoint Map Register (EP5 ~ 8) */
+	uint32_t fifomap;/* 0x1a8: FIFO Map Register */
+	uint32_t fifocfg; /* 0x1ac: FIFO Configuration Register */
+	uint32_t fifocsr[4];/* 0x1b0 - 0x1bf: FIFO Control Status Register */
+	uint32_t dma_fifo; /* 0x1c0: DMA Target FIFO Register */
+	uint32_t rsvd8[1];
+	uint32_t dma_ctrl; /* 0x1c8: DMA Control Register */
+	uint32_t dma_addr; /* 0x1cc: DMA Address Register */
+	uint32_t ep0_data; /* 0x1d0: EP0 Setup Packet PIO Register */
+};
+
+/* Miscellaneous Register */
+#define MISCR_SUSPEND  (1 << 6) /* Put transceiver in suspend mode */
+#define MISCR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define MISCR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define MISCR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* OTG Control Status Register */
+#define OTGCSR_SPD_HIGH     (2 << 22) /* Speed of the attached device (host) */
+#define OTGCSR_SPD_LOW      (1 << 22)
+#define OTGCSR_SPD_FULL     (0 << 22)
+#define OTGCSR_SPD_MASK     (3 << 22)
+#define OTGCSR_SPD_SHIFT    22
+#define OTGCSR_SPD(x)       (((x) >> 22) & 0x03)
+#define OTGCSR_DEV_A        (0 << 21) /* Acts as A-device */
+#define OTGCSR_DEV_B        (1 << 21) /* Acts as B-device */
+#define OTGCSR_ROLE_H       (0 << 20) /* Acts as Host */
+#define OTGCSR_ROLE_D       (1 << 20) /* Acts as Device */
+#define OTGCSR_A_VBUS_VLD   (1 << 19) /* A-device VBUS Valid */
+#define OTGCSR_A_SESS_VLD   (1 << 18) /* A-device Session Valid */
+#define OTGCSR_B_SESS_VLD   (1 << 17) /* B-device Session Valid */
+#define OTGCSR_B_SESS_END   (1 << 16) /* B-device Session End */
+#define OTGCSR_HFT_LONG     (1 << 11) /* HDISCON noise filter = 270 us*/
+#define OTGCSR_HFT          (0 << 11) /* HDISCON noise filter = 135 us*/
+#define OTGCSR_VFT_LONG     (1 << 10) /* VBUS noise filter = 472 us*/
+#define OTGCSR_VFT          (0 << 10) /* VBUS noise filter = 135 us*/
+#define OTGCSR_IDFT_LONG    (1 << 9)  /* ID noise filter = 4 ms*/
+#define OTGCSR_IDFT         (0 << 9)  /* ID noise filter = 3 ms*/
+#define OTGCSR_A_SRPR_VBUS  (0 << 8)  /* A-device: SRP responds to VBUS */
+#define OTGCSR_A_SRPR_DATA  (1 << 8)  /* A-device: SRP responds to DATA-LINE */
+#define OTGCSR_A_SRP_EN     (1 << 7)  /* A-device SRP detection enabled */
+#define OTGCSR_A_HNP        (1 << 6)  /* Set role=A-device with HNP enabled */
+#define OTGCSR_A_BUSDROP    (1 << 5)  /* A-device drop bus (power-down) */
+#define OTGCSR_A_BUSREQ     (1 << 4)  /* A-device request bus */
+#define OTGCSR_B_VBUS_DISC  (1 << 2)  /* B-device discharges VBUS */
+#define OTGCSR_B_HNP        (1 << 1)  /* B-device enable HNP */
+#define OTGCSR_B_BUSREQ     (1 << 0)  /* B-device request bus */
+
+/* OTG Interrupt Status Register */
+#define OTGISR_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGISR_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGISR_OVD          (1 << 10) /* over-current detected */
+#define OTGISR_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGISR_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGISR_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGISR_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGISR_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGISR_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* OTG Interrupt Enable Register */
+#define OTGIER_APRM         (1 << 12) /* Mini-A plug removed */
+#define OTGIER_BPRM         (1 << 11) /* Mini-B plug removed */
+#define OTGIER_OVD          (1 << 10) /* over-current detected */
+#define OTGIER_IDCHG        (1 << 9)  /* ID(A/B) changed */
+#define OTGIER_RLCHG        (1 << 8)  /* Role(Host/Device) changed */
+#define OTGIER_BSESSEND     (1 << 6)  /* B-device Session End */
+#define OTGIER_AVBUSERR     (1 << 5)  /* A-device VBUS Error */
+#define OTGIER_ASRP         (1 << 4)  /* A-device SRP detected */
+#define OTGIER_BSRP         (1 << 0)  /* B-device SRP complete */
+
+/* Global Interrupt Status Register (W1C) */
+#define ISR_HOST            (1 << 2)  /* USB Host interrupt */
+#define ISR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define ISR_DEV             (1 << 0)  /* USB Device interrupt */
+#define ISR_MASK            0x07
+
+/* Global Interrupt Mask Register */
+#define IMR_IRQLH           (1 << 3)  /* Interrupt triggered at level-high */
+#define IMR_IRQLL           (0 << 3)  /* Interrupt triggered@level-low */
+#define IMR_HOST            (1 << 2)  /* USB Host interrupt */
+#define IMR_OTG             (1 << 1)  /* USB OTG interrupt */
+#define IMR_DEV             (1 << 0)  /* USB Device interrupt */
+#define IMR_MASK            0x0f
+
+/* Device Control Register */
+#define DEVCTRL_FS_FORCED   (1 << 9)  /* Forced to be Full-Speed Mode */
+#define DEVCTRL_HS          (1 << 6)  /* High Speed Mode */
+#define DEVCTRL_FS          (0 << 6)  /* Full Speed Mode */
+#define DEVCTRL_EN          (1 << 5)  /* Chip Enable */
+#define DEVCTRL_RESET       (1 << 4)  /* Chip Software Reset */
+#define DEVCTRL_SUSPEND     (1 << 3)  /* Enter Suspend Mode */
+#define DEVCTRL_GIRQ_EN     (1 << 2)  /* Global Interrupt Enabled */
+#define DEVCTRL_HALFSPD     (1 << 1)  /* Half speed mode for FPGA test */
+#define DEVCTRL_RWAKEUP     (1 << 0)  /* Enable remote wake-up */
+
+/* Device Address Register */
+#define DEVADDR_CONF        (1 << 7)  /* SET_CONFIGURATION has been executed */
+#define DEVADDR_ADDR(x)     ((x) & 0x7f)
+#define DEVADDR_ADDR_MASK   0x7f
+
+/* Device Test Register */
+#define DEVTEST_NOSOF       (1 << 6)  /* Do not generate SOF */
+#define DEVTEST_TST_MODE    (1 << 5)  /* Enter Test Mode */
+#define DEVTEST_TST_NOTS    (1 << 4)  /* Do not toggle sequence */
+#define DEVTEST_TST_NOCRC   (1 << 3)  /* Do not append CRC */
+#define DEVTEST_TST_CLREA   (1 << 2)  /* Clear External Side Address */
+#define DEVTEST_TST_CXLP    (1 << 1)  /* EP0 loopback test */
+#define DEVTEST_TST_CLRFF   (1 << 0)  /* Clear FIFO */
+
+/* SOF Frame Number Register */
+#define SOFFNR_UFN(x)       (((x) >> 11) & 0x7) /* SOF Micro-Frame Number */
+#define SOFFNR_FNR(x)       ((x) & 0x7ff) /* SOF Frame Number */
+
+/* SOF Mask Timer Register */
+#define SOFMTR_TMR(x)       ((x) & 0xffff)
+
+/* PHY Test Mode Selector Register */
+#define PHYTMSR_TST_PKT     (1 << 4) /* Packet send test */
+#define PHYTMSR_TST_SE0NAK  (1 << 3) /* High-Speed quiescent state */
+#define PHYTMSR_TST_KSTA    (1 << 2) /* High-Speed K state */
+#define PHYTMSR_TST_JSTA    (1 << 1) /* High-Speed J state */
+#define PHYTMSR_UNPLUG      (1 << 0) /* Enable soft-detachment */
+
+/* CX FIFO Register */
+#define CXFIFO_BYTES(x)     (((x) >> 24) & 0x7f) /* CX/EP0 FIFO byte count */
+#define CXFIFO_FIFOE(x)     (1 << (((x) & 0x03) + 8)) /* EPx FIFO empty */
+#define CXFIFO_FIFOE_FIFO0  (1 << 8)
+#define CXFIFO_FIFOE_FIFO1  (1 << 9)
+#define CXFIFO_FIFOE_FIFO2  (1 << 10)
+#define CXFIFO_FIFOE_FIFO3  (1 << 11)
+#define CXFIFO_FIFOE_MASK   (0x0f << 8)
+#define CXFIFO_CXFIFOE      (1 << 5) /* CX FIFO empty */
+#define CXFIFO_CXFIFOF      (1 << 4) /* CX FIFO full */
+#define CXFIFO_CXFIFOCLR    (1 << 3) /* CX FIFO clear */
+#define CXFIFO_CXSTALL      (1 << 2) /* CX Stall */
+#define CXFIFO_TSTPKTFIN    (1 << 1) /* Test packet data transfer finished */
+#define CXFIFO_CXFIN        (1 << 0) /* CX data transfer finished */
+
+/* IDLE Counter Register */
+#define IDLE_MS(x)          ((x) & 0x07) /* PHY suspend delay = x ms */
+
+/* Group Interrupt Mask(Disable) Register */
+#define GIMR_GRP2           (1 << 2) /* Disable interrupt group 2 */
+#define GIMR_GRP1           (1 << 1) /* Disable interrupt group 1 */
+#define GIMR_GRP0           (1 << 0) /* Disable interrupt group 0 */
+#define GIMR_MASK           0x07
+
+/* Group Interrupt Mask(Disable) Register 0 (CX) */
+#define GIMR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GIMR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GIMR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GIMR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GIMR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GIMR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+#define GIMR0_MASK          0x3f
+
+/* Group Interrupt Mask(Disable) Register 1 (FIFO) */
+#define GIMR1_FIFO_IN(x)    (1 << (((x) & 3) + 16))    /* FIFOx IN */
+#define GIMR1_FIFO_TX(x)    GIMR1_FIFO_IN(x)
+#define GIMR1_FIFO_OUT(x)   (1 << (((x) & 3) * 2))     /* FIFOx OUT */
+#define GIMR1_FIFO_SPK(x)   (1 << (((x) & 3) * 2 + 1)) /* FIFOx SHORT PACKET */
+#define GIMR1_FIFO_RX(x)    (GIMR1_FIFO_OUT(x) | GIMR1_FIFO_SPK(x))
+#define GIMR1_MASK          0xf00ff
+
+/* Group Interrupt Mask(Disable) Register 2 (Device) */
+#define GIMR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GIMR2_IDLE          (1 << 9)  /* Device idle */
+#define GIMR2_DMAERR        (1 << 8)  /* DMA error */
+#define GIMR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GIMR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GIMR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GIMR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GIMR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GIMR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GIMR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GIMR2_RESET         (1 << 0)  /* Reset Interrupt */
+#define GIMR2_MASK          0x7ff
+
+/* Group Interrupt Status Register */
+#define GISR_GRP2           (1 << 2) /* Interrupt group 2 */
+#define GISR_GRP1           (1 << 1) /* Interrupt group 1 */
+#define GISR_GRP0           (1 << 0) /* Interrupt group 0 */
+
+/* Group Interrupt Status Register 0 (CX) */
+#define GISR0_CXABORT       (1 << 5) /* CX command abort interrupt */
+#define GISR0_CXERR         (1 << 4) /* CX command error interrupt */
+#define GISR0_CXEND         (1 << 3) /* CX command end interrupt */
+#define GISR0_CXOUT         (1 << 2) /* EP0-OUT packet interrupt */
+#define GISR0_CXIN          (1 << 1) /* EP0-IN packet interrupt */
+#define GISR0_CXSETUP       (1 << 0) /* EP0-SETUP packet interrupt */
+
+/* Group Interrupt Status Register 1 (FIFO) */
+#define GISR1_IN_FIFO(x)    (1 << (((x) & 0x03) + 16))    /* FIFOx IN */
+#define GISR1_OUT_FIFO(x)   (1 << (((x) & 0x03) * 2))     /* FIFOx OUT */
+#define GISR1_SPK_FIFO(x)   (1 << (((x) & 0x03) * 2 + 1)) /* FIFOx SPK */
+#define GISR1_RX_FIFO(x)    (3 << (((x) & 0x03) * 2))     /* FIFOx OUT/SPK */
+
+/* Group Interrupt Status Register 2 (Device) */
+#define GISR2_WAKEUP        (1 << 10) /* Device waked up */
+#define GISR2_IDLE          (1 << 9)  /* Device idle */
+#define GISR2_DMAERR        (1 << 8)  /* DMA error */
+#define GISR2_DMAFIN        (1 << 7)  /* DMA finished */
+#define GISR2_ZLPRX         (1 << 6)  /* Zero-Length-Packet Rx Interrupt */
+#define GISR2_ZLPTX         (1 << 5)  /* Zero-Length-Packet Tx Interrupt */
+#define GISR2_ISOCABT       (1 << 4)  /* ISOC Abort Interrupt */
+#define GISR2_ISOCERR       (1 << 3)  /* ISOC Error Interrupt */
+#define GISR2_RESUME        (1 << 2)  /* Resume state change Interrupt */
+#define GISR2_SUSPEND       (1 << 1)  /* Suspend state change Interrupt */
+#define GISR2_RESET         (1 << 0)  /* Reset Interrupt */
+
+/* Receive Zero-Length-Packet Register */
+#define RXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP rx interrupt */
+
+/* Transfer Zero-Length-Packet Register */
+#define TXZLP_EP(x)         (1 << ((x) - 1)) /* EPx ZLP tx interrupt */
+
+/* ISOC Error/Abort Status Register */
+#define ISOEASR_EP(x)       (0x10001 << ((x) - 1)) /* EPx ISOC Error/Abort */
+
+/* IN Endpoint Register */
+#define IEP_SENDZLP         (1 << 15)     /* Send Zero-Length-Packet */
+#define IEP_TNRHB(x)        (((x) & 0x03) << 13) \
+	/* Transaction Number for High-Bandwidth EP(ISOC) */
+#define IEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define IEP_STALL           (1 << 11)     /* Stall */
+#define IEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* OUT Endpoint Register */
+#define OEP_RESET           (1 << 12)     /* Reset Toggle Sequence */
+#define OEP_STALL           (1 << 11)     /* Stall */
+#define OEP_MAXPS(x)        ((x) & 0x7ff) /* Max. packet size */
+
+/* Endpoint Map Register (EP1 ~ EP4) */
+#define EPMAP14_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 0)
+#define EPMAP14_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 1) << 3 + 4)
+#define EPMAP14_SET(ep, in, out) \
+	do { \
+		EPMAP14_SET_IN(ep, in); \
+		EPMAP14_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP14_DEFAULT     0x33221100 /* EP1->FIFO0, EP2->FIFO1... */
+
+/* Endpoint Map Register (EP5 ~ EP8) */
+#define EPMAP58_SET_IN(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 0)
+#define EPMAP58_SET_OUT(ep, fifo) \
+	((fifo) & 3) << (((ep) - 5) << 3 + 4)
+#define EPMAP58_SET(ep, in, out) \
+	do { \
+		EPMAP58_SET_IN(ep, in); \
+		EPMAP58_SET_OUT(ep, out); \
+	} while (0)
+
+#define EPMAP58_DEFAULT     0x00000000 /* All EPx->FIFO0 */
+
+/* FIFO Map Register */
+#define FIFOMAP_BIDIR       (2 << 4)
+#define FIFOMAP_IN          (1 << 4)
+#define FIFOMAP_OUT         (0 << 4)
+#define FIFOMAP_DIR_MASK    0x30
+#define FIFOMAP_EP(x)       ((x) & 0x0f)
+#define FIFOMAP_EP_MASK     0x0f
+#define FIFOMAP_CFG_MASK    0x3f
+#define FIFOMAP_DEFAULT     0x04030201 /* FIFO0->EP1, FIFO1->EP2... */
+#define FIFOMAP(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Configuration Register */
+#define FIFOCFG_EN          (1 << 5)
+#define FIFOCFG_BLKSZ_1024  (1 << 4)
+#define FIFOCFG_BLKSZ_512   (0 << 4)
+#define FIFOCFG_3BLK        (2 << 2)
+#define FIFOCFG_2BLK        (1 << 2)
+#define FIFOCFG_1BLK        (0 << 2)
+#define FIFOCFG_NBLK_MASK   3
+#define FIFOCFG_NBLK_SHIFT  2
+#define FIFOCFG_INTR        (3 << 0)
+#define FIFOCFG_BULK        (2 << 0)
+#define FIFOCFG_ISOC        (1 << 0)
+#define FIFOCFG_RSVD        (0 << 0)  /* Reserved */
+#define FIFOCFG_TYPE_MASK   3
+#define FIFOCFG_TYPE_SHIFT  0
+#define FIFOCFG_CFG_MASK    0x3f
+#define FIFOCFG(fifo, cfg)  (((cfg) & 0x3f) << (((fifo) & 3) << 3))
+
+/* FIFO Control Status Register */
+#define FIFOCSR_RESET       (1 << 12) /* FIFO Reset */
+#define FIFOCSR_BYTES(x)    ((x) & 0x7ff) /* Length(bytes) for OUT-EP/FIFO */
+
+/* DMA Target FIFO Register */
+#define DMAFIFO_CX          (1 << 4) /* DMA FIFO = CX FIFO */
+#define DMAFIFO_FIFO(x)     (1 << ((x) & 0x3)) /* DMA FIFO = FIFOx */
+
+/* DMA Control Register */
+#define DMACTRL_LEN(x)      (((x) & 0x1ffff) << 8) /* DMA length (Bytes) */
+#define DMACTRL_LEN_SHIFT   8
+#define DMACTRL_CLRFF       (1 << 4) /* Clear FIFO upon DMA abort */
+#define DMACTRL_ABORT       (1 << 3) /* DMA abort */
+#define DMACTRL_IO2IO       (1 << 2) /* IO to IO */
+#define DMACTRL_FIFO2MEM    (0 << 1) /* FIFO to Memory */
+#define DMACTRL_MEM2FIFO    (1 << 1) /* Memory to FIFO */
+#define DMACTRL_START       (1 << 0) /* DMA start */
+
+#endif
diff --git a/include/usb/fusbh200.h b/include/usb/fusbh200.h
new file mode 100644
index 0000000..8a9c488
--- /dev/null
+++ b/include/usb/fusbh200.h
@@ -0,0 +1,61 @@
+/*
+ * Faraday USB 2.0 EHCI Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef _FUSBH200_H
+#define _FUSBH200_H
+
+struct fusbh200_regs {
+	struct {
+		uint32_t data[4];
+	} hccr;			/* 0x00 - 0x0f: hccr */
+	struct {
+		uint32_t data[9];
+	} hcor;			/* 0x10 - 0x33: hcor */
+	uint32_t easstr;/* 0x34: EOF&Async. Sched. Sleep Timer Register */
+	uint32_t rsvd[2];
+	uint32_t bmcsr;	/* 0x40: Bus Monitor Control Status Register */
+	uint32_t bmisr;	/* 0x44: Bus Monitor Interrupt Status Register */
+	uint32_t bmier; /* 0x48: Bus Monitor Interrupt Enable Register */
+};
+
+/* EOF & Async. Schedule Sleep Timer Register */
+#define EASSTR_RUNNING  (1 << 6) /* Put transceiver in running/resume mode */
+#define EASSTR_SUSPEND  (0 << 6) /* Put transceiver in suspend mode */
+#define EASSTR_EOF2(x)  (((x) & 0x3) << 4) /* EOF 2 Timing */
+#define EASSTR_EOF1(x)  (((x) & 0x3) << 2) /* EOF 1 Timing */
+#define EASSTR_ASST(x)  (((x) & 0x3) << 0) /* Async. Sched. Sleep Timer */
+
+/* Bus Monitor Control Status Register */
+#define BMCSR_SPD_HIGH  (2 << 9) /* Speed of the attached device */
+#define BMCSR_SPD_LOW   (1 << 9)
+#define BMCSR_SPD_FULL  (0 << 9)
+#define BMCSR_SPD_MASK  (3 << 9)
+#define BMCSR_SPD_SHIFT 9
+#define BMCSR_SPD(x)    ((x >> 9) & 0x03)
+#define BMCSR_VBUS      (1 << 8) /* VBUS Valid */
+#define BMCSR_VBUS_OFF  (1 << 4) /* VBUS Off */
+#define BMCSR_VBUS_ON   (0 << 4) /* VBUS On */
+#define BMCSR_IRQLH     (1 << 3) /* IRQ triggered at level-high */
+#define BMCSR_IRQLL     (0 << 3) /* IRQ triggered@level-low */
+#define BMCSR_HALFSPD   (1 << 2) /* Half speed mode for FPGA test */
+#define BMCSR_HFT_LONG  (1 << 1) /* HDISCON noise filter = 270 us*/
+#define BMCSR_HFT       (0 << 1) /* HDISCON noise filter = 135 us*/
+#define BMCSR_VFT_LONG  (1 << 1) /* VBUS noise filter = 472 us*/
+#define BMCSR_VFT       (0 << 1) /* VBUS noise filter = 135 us*/
+
+/* Bus Monitor Interrupt Status Register */
+/* Bus Monitor Interrupt Enable Register */
+#define BMISR_DMAERR    (1 << 4) /* DMA error */
+#define BMISR_DMA       (1 << 3) /* DMA complete */
+#define BMISR_DEVRM     (1 << 2) /* device removed */
+#define BMISR_OVD       (1 << 1) /* over-current detected */
+#define BMISR_VBUSERR   (1 << 0) /* VBUS error */
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v9 5/5] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-15  7:29                               ` [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
                                                   ` (3 preceding siblings ...)
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 4/5] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
@ 2013-05-15  7:29                                 ` Kuo-Jung Su
  2013-05-19 18:37                                   ` Marek Vasut
  4 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-15  7:29 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FOTG210 is an OTG chip which could operate
as either an EHCI Host or a USB Device at a time.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Marek Vasut <marex@denx.de>
---
Changes for v9:
   - Nothing updates

Changes for v8:
   - Nothing updates

Changes for v7:
   - Nothing updates

Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup.
   - Drop postfix '__iomem' from struct fotg210_regs
   - Use permanent delay for hardware reset
   - Drop '#ifndef CONFIG_SYS_DCACHE_OFF'
   - Drop magic numbers

Changes for v4:
   - Use only macro constants and named bit/mask
   - Remove dcache_enable() from usb_gadget_register_driver()

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.

 drivers/usb/gadget/Makefile       |    1 +
 drivers/usb/gadget/fotg210.c      |  948 +++++++++++++++++++++++++++++++++++++
 drivers/usb/gadget/gadget_chips.h |    8 +
 3 files changed, 957 insertions(+)
 create mode 100644 drivers/usb/gadget/fotg210.c

diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index e545b6b..432cf17 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -35,6 +35,7 @@ endif
 # new USB gadget layer dependencies
 ifdef CONFIG_USB_GADGET
 COBJS-$(CONFIG_USB_GADGET_S3C_UDC_OTG) += s3c_udc_otg.o
+COBJS-$(CONFIG_USB_GADGET_FOTG210) += fotg210.o
 COBJS-$(CONFIG_USBDOWNLOAD_GADGET) += g_dnl.o
 COBJS-$(CONFIG_DFU_FUNCTION) += f_dfu.o
 endif
diff --git a/drivers/usb/gadget/fotg210.c b/drivers/usb/gadget/fotg210.c
new file mode 100644
index 0000000..d003331
--- /dev/null
+++ b/drivers/usb/gadget/fotg210.c
@@ -0,0 +1,948 @@
+/*
+ * Faraday USB 2.0 OTG Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <config.h>
+#include <net.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <linux/types.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <usb/fotg210.h>
+
+#define CFG_NUM_ENDPOINTS		4
+#define CFG_EP0_MAX_PACKET_SIZE	64
+#define CFG_EPX_MAX_PACKET_SIZE	512
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+
+struct fotg210_chip;
+
+struct fotg210_ep {
+	struct usb_ep ep;
+
+	uint maxpacket;
+	uint id;
+	uint stopped;
+
+	struct list_head                      queue;
+	struct fotg210_chip                  *chip;
+	const struct usb_endpoint_descriptor *desc;
+};
+
+struct fotg210_request {
+	struct usb_request req;
+	struct list_head   queue;
+	struct fotg210_ep *ep;
+};
+
+struct fotg210_chip {
+	struct usb_gadget         gadget;
+	struct usb_gadget_driver *driver;
+	struct fotg210_regs      *regs;
+	uint8_t                   irq;
+	uint16_t                  addr;
+	int                       pullup;
+	enum usb_device_state     state;
+	struct fotg210_ep         ep[1 + CFG_NUM_ENDPOINTS];
+};
+
+static struct usb_endpoint_descriptor ep0_desc = {
+	.bLength = sizeof(struct usb_endpoint_descriptor),
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = USB_DIR_IN,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+};
+
+static inline int fifo_to_ep(struct fotg210_chip *chip, int id, int in)
+{
+	return (id < 0) ? 0 : ((id & 0x03) + 1);
+}
+
+static inline int ep_to_fifo(struct fotg210_chip *chip, int id)
+{
+	return (id <= 0) ? -1 : ((id - 1) & 0x03);
+}
+
+static inline int ep_reset(struct fotg210_chip *chip, uint8_t ep_addr)
+{
+	int ep = ep_addr & USB_ENDPOINT_NUMBER_MASK;
+	struct fotg210_regs *regs = chip->regs;
+
+	if (ep_addr & USB_DIR_IN) {
+		/* reset endpoint */
+		setbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->iep[ep - 1], IEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->iep[ep - 1], IEP_STALL);
+	} else {
+		/* reset endpoint */
+		setbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		mdelay(1);
+		clrbits_le32(&regs->oep[ep - 1], OEP_RESET);
+		/* clear endpoint stall */
+		clrbits_le32(&regs->oep[ep - 1], OEP_STALL);
+	}
+
+	return 0;
+}
+
+static int fotg210_reset(struct fotg210_chip *chip)
+{
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t i;
+
+	chip->state = USB_STATE_POWERED;
+
+	/* chip enable */
+	writel(DEVCTRL_EN, &regs->dev_ctrl);
+
+	/* device address reset */
+	chip->addr = 0;
+	writel(0, &regs->dev_addr);
+
+	/* set idle counter to 7ms */
+	writel(7, &regs->idle);
+
+	/* disable all interrupts */
+	writel(IMR_MASK, &regs->imr);
+	writel(GIMR_MASK, &regs->gimr);
+	writel(GIMR0_MASK, &regs->gimr0);
+	writel(GIMR1_MASK, &regs->gimr1);
+	writel(GIMR2_MASK, &regs->gimr2);
+
+	/* clear interrupts */
+	writel(ISR_MASK, &regs->isr);
+	writel(0, &regs->gisr);
+	writel(0, &regs->gisr0);
+	writel(0, &regs->gisr1);
+	writel(0, &regs->gisr2);
+
+	/* chip reset */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_RESET);
+	mdelay(10);
+	if (readl(&regs->dev_ctrl) & DEVCTRL_RESET) {
+		printf("fotg210: chip reset failed\n");
+		return -1;
+	}
+
+	/* CX FIFO reset */
+	setbits_le32(&regs->cxfifo, CXFIFO_CXFIFOCLR);
+	mdelay(10);
+	if (readl(&regs->cxfifo) & CXFIFO_CXFIFOCLR) {
+		printf("fotg210: ep0 fifo reset failed\n");
+		return -1;
+	}
+
+	/* create static ep-fifo map (EP1 <-> FIFO0, EP2 <-> FIFO1 ...) */
+	writel(EPMAP14_DEFAULT, &regs->epmap14);
+	writel(EPMAP58_DEFAULT, &regs->epmap58);
+	writel(FIFOMAP_DEFAULT, &regs->fifomap);
+	writel(0, &regs->fifocfg);
+	for (i = 0; i < 8; ++i) {
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->iep[i]);
+		writel(CFG_EPX_MAX_PACKET_SIZE, &regs->oep[i]);
+	}
+
+	/* FIFO reset */
+	for (i = 0; i < 4; ++i) {
+		writel(FIFOCSR_RESET, &regs->fifocsr[i]);
+		mdelay(10);
+		if (readl(&regs->fifocsr[i]) & FIFOCSR_RESET) {
+			printf("fotg210: fifo%d reset failed\n", i);
+			return -1;
+		}
+	}
+
+	/* enable only device interrupt and triggered at level-high */
+	writel(IMR_IRQLH | IMR_HOST | IMR_OTG, &regs->imr);
+	writel(ISR_MASK, &regs->isr);
+	/* disable EP0 IN/OUT interrupt */
+	writel(GIMR0_CXOUT | GIMR0_CXIN, &regs->gimr0);
+	/* disable EPX IN+SPK+OUT interrupts */
+	writel(GIMR1_MASK, &regs->gimr1);
+	/* disable wakeup+idle+dma+zlp interrupts */
+	writel(GIMR2_WAKEUP | GIMR2_IDLE | GIMR2_DMAERR | GIMR2_DMAFIN
+		| GIMR2_ZLPRX | GIMR2_ZLPTX, &regs->gimr2);
+	/* enable all group interrupt */
+	writel(0, &regs->gimr);
+
+	/* suspend delay = 3 ms */
+	writel(3, &regs->idle);
+
+	/* turn-on device interrupts */
+	setbits_le32(&regs->dev_ctrl, DEVCTRL_GIRQ_EN);
+
+	return 0;
+}
+
+static inline int fotg210_cxwait(struct fotg210_chip *chip, uint32_t mask)
+{
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if ((readl(&regs->cxfifo) & mask) != mask)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("fotg210: cx/ep0 timeout\n");
+
+	return ret;
+}
+
+static int fotg210_dma(struct fotg210_ep *ep, struct fotg210_request *req)
+{
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint8_t *buf  = req->req.buf + req->req.actual;
+	uint32_t len  = req->req.length - req->req.actual;
+	int fifo = ep_to_fifo(chip, ep->id);
+	int ret = -EBUSY;
+
+	/* 1. init dma buffer */
+	if (len > ep->maxpacket)
+		len = ep->maxpacket;
+
+	/* 2. wait for dma ready (hardware) */
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->dma_ctrl) & DMACTRL_START)) {
+			ret = 0;
+			break;
+		}
+	}
+	if (ret) {
+		printf("fotg210: dma busy\n");
+		req->req.status = ret;
+		return ret;
+	}
+
+	/* 3. DMA target setup */
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		flush_dcache_range((ulong)buf, (ulong)buf + len);
+	else
+		invalidate_dcache_range((ulong)buf, (ulong)buf + len);
+
+	writel(virt_to_phys(buf), &regs->dma_addr);
+
+	if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+		if (ep->id == 0) {
+			/* Wait until cx/ep0 fifo empty */
+			fotg210_cxwait(chip, CXFIFO_CXFIFOE);
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+		} else {
+			/* Wait until epx fifo empty */
+			fotg210_cxwait(chip, CXFIFO_FIFOE(fifo));
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+		}
+		writel(DMACTRL_LEN(len) | DMACTRL_MEM2FIFO, &regs->dma_ctrl);
+	} else {
+		uint32_t blen;
+
+		if (ep->id == 0) {
+			writel(DMAFIFO_CX, &regs->dma_fifo);
+			do {
+				blen = CXFIFO_BYTES(readl(&regs->cxfifo));
+			} while (blen < len);
+		} else {
+			writel(DMAFIFO_FIFO(fifo), &regs->dma_fifo);
+			blen = FIFOCSR_BYTES(readl(&regs->fifocsr[fifo]));
+		}
+		len  = (len < blen) ? len : blen;
+		writel(DMACTRL_LEN(len) | DMACTRL_FIFO2MEM, &regs->dma_ctrl);
+	}
+
+	/* 4. DMA start */
+	setbits_le32(&regs->dma_ctrl, DMACTRL_START);
+
+	/* 5. DMA wait */
+	ret = -EBUSY;
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		tmp = readl(&regs->gisr2);
+		/* DMA complete */
+		if (tmp & GISR2_DMAFIN) {
+			ret = 0;
+			break;
+		}
+		/* DMA error */
+		if (tmp & GISR2_DMAERR) {
+			printf("fotg210: dma error\n");
+			break;
+		}
+		/* resume, suspend, reset */
+		if (tmp & (GISR2_RESUME | GISR2_SUSPEND | GISR2_RESET)) {
+			printf("fotg210: dma reset by host\n");
+			break;
+		}
+	}
+
+	/* 7. DMA target reset */
+	if (ret)
+		writel(DMACTRL_ABORT | DMACTRL_CLRFF, &regs->dma_ctrl);
+
+	writel(0, &regs->gisr2);
+	writel(0, &regs->dma_fifo);
+
+	req->req.status = ret;
+	if (!ret)
+		req->req.actual += len;
+	else
+		printf("fotg210: ep%d dma error(code=%d)\n", ep->id, ret);
+
+	return len;
+}
+
+/*
+ * result of setup packet
+ */
+#define CX_IDLE		0
+#define CX_FINISH	1
+#define CX_STALL	2
+
+static void fotg210_setup(struct fotg210_chip *chip)
+{
+	int id, ret = CX_IDLE;
+	uint32_t tmp[2];
+	struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)tmp;
+	struct fotg210_regs *regs = chip->regs;
+
+	/*
+	 * If this is the first Cx 8 byte command,
+	 * we can now query USB mode (high/full speed; USB 2.0/USB 1.0)
+	 */
+	if (chip->state == USB_STATE_POWERED) {
+		chip->state = USB_STATE_DEFAULT;
+		if (readl(&regs->otgcsr) & OTGCSR_DEV_B) {
+			/* Mini-B */
+			if (readl(&regs->dev_ctrl) & DEVCTRL_HS) {
+				puts("fotg210: HS\n");
+				chip->gadget.speed = USB_SPEED_HIGH;
+				/* SOF mask timer = 1100 ticks */
+				writel(SOFMTR_TMR(1100), &regs->sof_mtr);
+			} else {
+				puts("fotg210: FS\n");
+				chip->gadget.speed = USB_SPEED_FULL;
+				/* SOF mask timer = 10000 ticks */
+				writel(SOFMTR_TMR(10000), &regs->sof_mtr);
+			}
+		} else {
+			printf("fotg210: mini-A?\n");
+		}
+	}
+
+	/* switch data port to ep0 */
+	writel(DMAFIFO_CX, &regs->dma_fifo);
+	/* fetch 8 bytes setup packet */
+	tmp[0] = readl(&regs->ep0_data);
+	tmp[1] = readl(&regs->ep0_data);
+	/* release data port */
+	writel(0, &regs->dma_fifo);
+
+	if (req->bRequestType & USB_DIR_IN)
+		ep0_desc.bEndpointAddress = USB_DIR_IN;
+	else
+		ep0_desc.bEndpointAddress = USB_DIR_OUT;
+
+	ret = CX_IDLE;
+
+	if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (req->bRequest) {
+		case USB_REQ_SET_CONFIGURATION:
+			debug("fotg210: set_cfg(%d)\n", req->wValue & 0x00FF);
+			if (!(req->wValue & 0x00FF)) {
+				chip->state = USB_STATE_ADDRESS;
+				writel(chip->addr, &regs->dev_addr);
+			} else {
+				chip->state = USB_STATE_CONFIGURED;
+				writel(chip->addr | DEVADDR_CONF,
+					&regs->dev_addr);
+			}
+			ret = CX_IDLE;
+			break;
+
+		case USB_REQ_SET_ADDRESS:
+			debug("fotg210: set_addr(0x%04X)\n", req->wValue);
+			chip->state = USB_STATE_ADDRESS;
+			chip->addr  = req->wValue & DEVADDR_ADDR_MASK;
+			ret = CX_FINISH;
+			writel(chip->addr, &regs->dev_addr);
+			break;
+
+		case USB_REQ_CLEAR_FEATURE:
+			debug("fotg210: clr_feature(%d, %d)\n",
+				req->bRequestType & 0x03, req->wValue);
+			switch (req->wValue) {
+			case 0:    /* [Endpoint] halt */
+				ep_reset(chip, req->wIndex);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* [Device] remote wake-up */
+			case 2:    /* [Device] test mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_SET_FEATURE:
+			debug("fotg210: set_feature(%d, %d)\n",
+				req->wValue, req->wIndex & 0xf);
+			switch (req->wValue) {
+			case 0:    /* Endpoint Halt */
+				id = req->wIndex & 0xf;
+				setbits_le32(&regs->iep[id - 1], IEP_STALL);
+				setbits_le32(&regs->oep[id - 1], OEP_STALL);
+				ret = CX_FINISH;
+				break;
+			case 1:    /* Remote Wakeup */
+			case 2:    /* Test Mode */
+			default:
+				ret = CX_STALL;
+				break;
+			}
+			break;
+
+		case USB_REQ_GET_STATUS:
+			debug("fotg210: get_status\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SET_DESCRIPTOR:
+			debug("fotg210: set_descriptor\n");
+			ret = CX_STALL;
+			break;
+
+		case USB_REQ_SYNCH_FRAME:
+			debug("fotg210: sync frame\n");
+			ret = CX_STALL;
+			break;
+		}
+	} /* if ((req->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) */
+
+	if (ret == CX_IDLE && chip->driver->setup) {
+		if (chip->driver->setup(&chip->gadget, req) < 0)
+			ret = CX_STALL;
+		else
+			ret = CX_FINISH;
+	}
+
+	switch (ret) {
+	case CX_FINISH:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+		break;
+
+	case CX_STALL:
+		setbits_le32(&regs->cxfifo, CXFIFO_CXSTALL | CXFIFO_CXFIN);
+		printf("fotg210: cx_stall!\n");
+		break;
+
+	case CX_IDLE:
+		debug("fotg210: cx_idle?\n");
+	default:
+		break;
+	}
+}
+
+/*
+ * fifo - FIFO id
+ * zlp  - zero length packet
+ */
+static void fotg210_recv(struct fotg210_chip *chip, int ep_id)
+{
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_ep *ep = chip->ep + ep_id;
+	struct fotg210_request *req;
+	int len;
+
+	if (ep->stopped || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		printf("fotg210: ep%d recv, invalid!\n", ep->id);
+		return;
+	}
+
+	if (list_empty(&ep->queue)) {
+		printf("fotg210: ep%d recv, drop!\n", ep->id);
+		return;
+	}
+
+	req = list_first_entry(&ep->queue, struct fotg210_request, queue);
+	len = fotg210_dma(ep, req);
+	if (len < ep->ep.maxpacket || req->req.length <= req->req.actual) {
+		list_del_init(&req->queue);
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	if (ep->id > 0 && list_empty(&ep->queue)) {
+		setbits_le32(&regs->gimr1,
+			GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+	}
+}
+
+/*
+ * USB Gadget Layer
+ */
+static int fotg210_ep_enable(
+	struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+	int in = (desc->bEndpointAddress & USB_DIR_IN) ? 1 : 0;
+
+	if (!_ep || !desc
+		|| desc->bDescriptorType != USB_DT_ENDPOINT
+		|| le16_to_cpu(desc->wMaxPacketSize) == 0) {
+		printf("fotg210: bad ep or descriptor\n");
+		return -EINVAL;
+	}
+
+	ep->desc = desc;
+	ep->stopped = 0;
+
+	if (in)
+		setbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_IN));
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		return -EINVAL;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_ISOC));
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_BULK));
+		break;
+
+	case USB_ENDPOINT_XFER_INT:
+		setbits_le32(&regs->fifocfg,
+			FIFOCFG(id, FIFOCFG_EN | FIFOCFG_INTR));
+		break;
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_disable(struct usb_ep *_ep)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int id = ep_to_fifo(chip, ep->id);
+
+	ep->desc = NULL;
+	ep->stopped = 1;
+
+	clrbits_le32(&regs->fifocfg, FIFOCFG(id, FIFOCFG_CFG_MASK));
+	clrbits_le32(&regs->fifomap, FIFOMAP(id, FIFOMAP_DIR_MASK));
+
+	return 0;
+}
+
+static struct usb_request *fotg210_ep_alloc_request(
+	struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct fotg210_request *req = malloc(sizeof(*req));
+
+	if (req) {
+		memset(req, 0, sizeof(*req));
+		INIT_LIST_HEAD(&req->queue);
+	}
+	return &req->req;
+}
+
+static void fotg210_ep_free_request(
+	struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	free(req);
+}
+
+static int fotg210_ep_queue(
+	struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	struct fotg210_request *req;
+
+	req = container_of(_req, struct fotg210_request, req);
+	if (!_req || !_req->complete || !_req->buf
+		|| !list_empty(&req->queue)) {
+		printf("fotg210: invalid request to ep%d\n", ep->id);
+		return -EINVAL;
+	}
+
+	if (!chip || chip->state == USB_STATE_SUSPENDED) {
+		printf("fotg210: request while chip suspended\n");
+		return -EINVAL;
+	}
+
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (req->req.length == 0) {
+		req->req.status = 0;
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+		return 0;
+	}
+
+	if (ep->id == 0) {
+		do {
+			int len = fotg210_dma(ep, req);
+			if (len < ep->ep.maxpacket)
+				break;
+			if (ep->desc->bEndpointAddress & USB_DIR_IN)
+				udelay(100);
+		} while (req->req.length > req->req.actual);
+	} else {
+		if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+			do {
+				int len = fotg210_dma(ep, req);
+				if (len < ep->ep.maxpacket)
+					break;
+			} while (req->req.length > req->req.actual);
+		} else {
+			list_add_tail(&req->queue, &ep->queue);
+			clrbits_le32(&regs->gimr1,
+				GIMR1_FIFO_RX(ep_to_fifo(chip, ep->id)));
+		}
+	}
+
+	if (ep->id == 0 || (ep->desc->bEndpointAddress & USB_DIR_IN)) {
+		if (req->req.complete)
+			req->req.complete(&ep->ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_request *req;
+
+	/* make sure it's actually queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req)
+		return -EINVAL;
+
+	/* remove the request */
+	list_del_init(&req->queue);
+
+	/* update status & invoke complete callback */
+	if (req->req.status == -EINPROGRESS) {
+		req->req.status = -ECONNRESET;
+		if (req->req.complete)
+			req->req.complete(_ep, &req->req);
+	}
+
+	return 0;
+}
+
+static int fotg210_ep_halt(struct usb_ep *_ep, int halt)
+{
+	struct fotg210_ep *ep = container_of(_ep, struct fotg210_ep, ep);
+	struct fotg210_chip *chip = ep->chip;
+	struct fotg210_regs *regs = chip->regs;
+	int ret = -1;
+
+	debug("fotg210: ep%d halt=%d\n", ep->id, halt);
+
+	/* Endpoint STALL */
+	if (ep->id > 0 && ep->id <= CFG_NUM_ENDPOINTS) {
+		if (halt) {
+			/* wait until all ep fifo empty */
+			fotg210_cxwait(chip, 0xf00);
+			/* stall */
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				setbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				setbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		} else {
+			if (ep->desc->bEndpointAddress & USB_DIR_IN) {
+				clrbits_le32(&regs->iep[ep->id - 1],
+					IEP_STALL);
+			} else {
+				clrbits_le32(&regs->oep[ep->id - 1],
+					OEP_STALL);
+			}
+		}
+		ret = 0;
+	}
+
+	return ret;
+}
+
+/*
+ * activate/deactivate link with host.
+ */
+static void pullup(struct fotg210_chip *chip, int is_on)
+{
+	struct fotg210_regs *regs = chip->regs;
+
+	if (is_on) {
+		if (!chip->pullup) {
+			chip->state = USB_STATE_POWERED;
+			chip->pullup = 1;
+			/* enable the chip */
+			setbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+			/* clear unplug bit (BIT0) */
+			clrbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		}
+	} else {
+		chip->state = USB_STATE_NOTATTACHED;
+		chip->pullup = 0;
+		chip->addr = 0;
+		writel(chip->addr, &regs->dev_addr);
+		/* set unplug bit (BIT0) */
+		setbits_le32(&regs->phy_tmsr, PHYTMSR_UNPLUG);
+		/* disable the chip */
+		clrbits_le32(&regs->dev_ctrl, DEVCTRL_EN);
+	}
+}
+
+static int fotg210_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct fotg210_chip *chip;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+
+	debug("fotg210: pullup=%d\n", is_on);
+
+	pullup(chip, is_on);
+
+	return 0;
+}
+
+static int fotg210_get_frame(struct usb_gadget *_gadget)
+{
+	struct fotg210_chip *chip;
+	struct fotg210_regs *regs;
+
+	chip = container_of(_gadget, struct fotg210_chip, gadget);
+	regs = chip->regs;
+
+	return SOFFNR_FNR(readl(&regs->sof_fnr));
+}
+
+static struct usb_gadget_ops fotg210_gadget_ops = {
+	.get_frame = fotg210_get_frame,
+	.pullup = fotg210_pullup,
+};
+
+static struct usb_ep_ops fotg210_ep_ops = {
+	.enable         = fotg210_ep_enable,
+	.disable        = fotg210_ep_disable,
+	.queue          = fotg210_ep_queue,
+	.dequeue        = fotg210_ep_dequeue,
+	.set_halt       = fotg210_ep_halt,
+	.alloc_request  = fotg210_ep_alloc_request,
+	.free_request   = fotg210_ep_free_request,
+};
+
+static struct fotg210_chip controller = {
+	.regs = (void __iomem *)CONFIG_FOTG210_BASE,
+	.gadget = {
+		.name = "fotg210_udc",
+		.ops = &fotg210_gadget_ops,
+		.ep0 = &controller.ep[0].ep,
+		.speed = USB_SPEED_UNKNOWN,
+		.is_dualspeed = 1,
+		.is_otg = 0,
+		.is_a_peripheral = 0,
+		.b_hnp_enable = 0,
+		.a_hnp_support = 0,
+		.a_alt_hnp_support = 0,
+	},
+	.ep[0] = {
+		.id = 0,
+		.ep = {
+			.name  = "ep0",
+			.ops   = &fotg210_ep_ops,
+		},
+		.desc      = &ep0_desc,
+		.chip      = &controller,
+		.maxpacket = CFG_EP0_MAX_PACKET_SIZE,
+	},
+	.ep[1] = {
+		.id = 1,
+		.ep = {
+			.name  = "ep1",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[2] = {
+		.id = 2,
+		.ep = {
+			.name  = "ep2",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[3] = {
+		.id = 3,
+		.ep = {
+			.name  = "ep3",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+	.ep[4] = {
+		.id = 4,
+		.ep = {
+			.name  = "ep4",
+			.ops   = &fotg210_ep_ops,
+		},
+		.chip      = &controller,
+		.maxpacket = CFG_EPX_MAX_PACKET_SIZE,
+	},
+};
+
+int usb_gadget_handle_interrupts(void)
+{
+	struct fotg210_chip *chip = &controller;
+	struct fotg210_regs *regs = chip->regs;
+	uint32_t id, st, isr, gisr;
+
+	isr  = readl(&regs->isr) & (~readl(&regs->imr));
+	gisr = readl(&regs->gisr) & (~readl(&regs->gimr));
+	if (!(isr & ISR_DEV) || !gisr)
+		return 0;
+
+	writel(ISR_DEV, &regs->isr);
+
+	/* CX interrupts */
+	if (gisr & GISR_GRP0) {
+		st = readl(&regs->gisr0);
+		writel(0, &regs->gisr0);
+
+		if (st & GISR0_CXERR)
+			printf("fotg210: cmd error\n");
+
+		if (st & GISR0_CXABORT)
+			printf("fotg210: cmd abort\n");
+
+		if (st & GISR0_CXSETUP)    /* setup */
+			fotg210_setup(chip);
+		else if (st & GISR0_CXEND) /* command finish */
+			setbits_le32(&regs->cxfifo, CXFIFO_CXFIN);
+	}
+
+	/* FIFO interrupts */
+	if (gisr & GISR_GRP1) {
+		st = readl(&regs->gisr1);
+		for (id = 0; id < 4; ++id) {
+			if (st & GISR1_RX_FIFO(id))
+				fotg210_recv(chip, fifo_to_ep(chip, id, 0));
+		}
+	}
+
+	/* Device Status Interrupts */
+	if (gisr & GISR_GRP2) {
+		st = readl(&regs->gisr2);
+		writel(0, &regs->gisr2);
+
+		if (st & GISR2_RESET)
+			printf("fotg210: reset by host\n");
+		else if (st & GISR2_SUSPEND)
+			printf("fotg210: suspend/removed\n");
+		else if (st & GISR2_RESUME)
+			printf("fotg210: resume\n");
+
+		/* Errors */
+		if (st & GISR2_ISOCERR)
+			printf("fotg210: iso error\n");
+		if (st & GISR2_ISOCABT)
+			printf("fotg210: iso abort\n");
+		if (st & GISR2_DMAERR)
+			printf("fotg210: dma error\n");
+	}
+
+	return 0;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	int i, ret = 0;
+	struct fotg210_chip *chip = &controller;
+
+	if (!driver    || !driver->bind || !driver->setup) {
+		puts("fotg210: bad parameter.\n");
+		return -EINVAL;
+	}
+
+	INIT_LIST_HEAD(&chip->gadget.ep_list);
+	for (i = 0; i < CFG_NUM_ENDPOINTS + 1; ++i) {
+		struct fotg210_ep *ep = chip->ep + i;
+
+		ep->ep.maxpacket = ep->maxpacket;
+		INIT_LIST_HEAD(&ep->queue);
+
+		if (ep->id == 0) {
+			ep->stopped = 0;
+		} else {
+			ep->stopped = 1;
+			list_add_tail(&ep->ep.ep_list, &chip->gadget.ep_list);
+		}
+	}
+
+	if (fotg210_reset(chip)) {
+		puts("fotg210: reset failed.\n");
+		return -EINVAL;
+	}
+
+	ret = driver->bind(&chip->gadget);
+	if (ret) {
+		debug("fotg210: driver->bind() returned %d\n", ret);
+		return ret;
+	}
+	chip->driver = driver;
+
+	return ret;
+}
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct fotg210_chip *chip = &controller;
+
+	driver->unbind(&chip->gadget);
+	chip->driver = NULL;
+
+	pullup(chip, 0);
+
+	return 0;
+}
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index e570142..f038747 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -150,6 +150,12 @@
 #define gadget_is_mv(g)        0
 #endif

+#ifdef CONFIG_USB_GADGET_FOTG210
+#define gadget_is_fotg210(g)        (!strcmp("fotg210_udc", (g)->name))
+#else
+#define gadget_is_fotg210(g)        0
+#endif
+
 /*
  * CONFIG_USB_GADGET_SX2
  * CONFIG_USB_GADGET_AU1X00
@@ -215,5 +221,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x20;
 	else if (gadget_is_mv(gadget))
 		return 0x21;
+	else if (gadget_is_fotg210(gadget))
+		return 0x22;
 	return -ENOENT;
 }
--
1.7.9.5

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

* [U-Boot] [PATCH v9 5/5] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 5/5] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
@ 2013-05-19 18:37                                   ` Marek Vasut
  2013-05-20  0:56                                     ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2013-05-19 18:37 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> The Faraday FOTG210 is an OTG chip which could operate
> as either an EHCI Host or a USB Device at a time.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Marek Vasut <marex@denx.de>

I'll test those on monday on EHCI system.

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v9 5/5] usb: gadget: add Faraday FOTG210 USB gadget support
  2013-05-19 18:37                                   ` Marek Vasut
@ 2013-05-20  0:56                                     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-05-20  0:56 UTC (permalink / raw)
  To: u-boot

2013/5/20 Marek Vasut <marex@denx.de>:
> Dear Kuo-Jung Su,
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> The Faraday FOTG210 is an OTG chip which could operate
>> as either an EHCI Host or a USB Device at a time.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Marek Vasut <marex@denx.de>
>
> I'll test those on monday on EHCI system.
>
> Best regards,
> Marek Vasut

Got it, thanks!

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v9 1/5] usb: ehci: prevent bad PORTSC register access
  2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 1/5] usb: ehci: prevent bad PORTSC register access Kuo-Jung Su
@ 2013-05-21 20:09                                   ` Marek Vasut
  0 siblings, 0 replies; 311+ messages in thread
From: Marek Vasut @ 2013-05-21 20:09 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,


Works fine, thanks!

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
@ 2013-06-10 17:59               ` Albert ARIBAUD
  2013-06-11  3:09                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-10 17:59 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
> index 5bbb0a0..5a13af5 100644
> --- a/arch/arm/include/asm/dma-mapping.h
> +++ b/arch/arm/include/asm/dma-mapping.h
> @@ -3,6 +3,9 @@
>   * Stelian Pop <stelian@popies.net>
>   * Lead Tech Design <www.leadtechdesign.com>
>   *
> + * (C) Copyright 2010
> + * Dante Su <dantesu@faraday-tech.com>

Fix Copyright notices (dates) throughout the patch (and series as
needed).

>   * See file CREDITS for list of people who contributed to this
>   * project.
>   *
> @@ -24,22 +27,76 @@
>  #ifndef __ASM_ARM_DMA_MAPPING_H
>  #define __ASM_ARM_DMA_MAPPING_H
> 
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +#include <asm/u-boot.h>
> +#include <asm/global_data.h>
> +#include <asm/io.h>
> +#include <malloc.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> +
>  enum dma_data_direction {
>  	DMA_BIDIRECTIONAL	= 0,
>  	DMA_TO_DEVICE		= 1,
>  	DMA_FROM_DEVICE		= 2,
>  };
> 
> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
>  {
> -	*handle = (unsigned long)malloc(len);
> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> +	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
> +
> +	if (va && gd->arch.cpu_mmu) {
> +		invalidate_dcache_range((ulong)va, (ulong)va + len);
> +		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
> +		if (!map)
> +			free(va);
> +		va = map;
> +	}
> +
> +	if (handle)
> +		*handle = virt_to_phys(va);
> +
> +	return va;
> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> +	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>  	return (void *)*handle;

This is not identical to what the code was before the patch. Why the
difference?

> 1.7.9.5

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v4 2/7] arm: add Faraday common utilities
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 2/7] arm: add Faraday common utilities Kuo-Jung Su
@ 2013-06-10 18:05               ` Albert ARIBAUD
  2013-06-11  3:02                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-10 18:05 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Tue,  7 May 2013 14:25:08 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:


> diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
> index 440b041..a103922 100644
> --- a/arch/arm/include/asm/mach-types.h
> +++ b/arch/arm/include/asm/mach-types.h

Do not assign to mach-types. If mach-type was assigned in the ARM
machine base, then request for an update of mach-types, or define
your specific machine type in your board's config header file.

> 1.7.9.5

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v4 6/7] arm: add Faraday firmware image utility
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 6/7] arm: add Faraday firmware image utility Kuo-Jung Su
@ 2013-06-10 18:38               ` Albert ARIBAUD
  2013-06-11  3:00                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-10 18:38 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Tue,  7 May 2013 14:25:12 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> ---
> Changes for v4:
>    - Coding Style cleanup.
>    - Break up from [arm: add Faraday A36x SoC platform support]
> 
> Changes for v3:
>    - Coding Style cleanup.
>    - Always insert a blank line between declarations and code.
> 
> Changes for v2:
>    - Coding Style cleanup.
> 
>  arch/arm/cpu/faraday/Makefile     |    2 +-
>  arch/arm/cpu/faraday/cmd_bootfa.c |  132 +++++++++++++++++++++++++++++++++++++
>  arch/arm/cpu/faraday/fwimage.h    |   38 +++++++++++
>  arch/arm/cpu/faraday/fwimage2.h   |   70 ++++++++++++++++++++
>  arch/arm/cpu/u-boot.lds           |   11 ++++
>  5 files changed, 252 insertions(+), 1 deletion(-)
>  create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
>  create mode 100644 arch/arm/cpu/faraday/fwimage.h
>  create mode 100644 arch/arm/cpu/faraday/fwimage2.h

What is the rationale behind a specific boot command? What prevents
using the existing tools and formats?

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v4 7/7] arm: add Faraday A36x SoC platform support
  2013-05-07  6:25             ` [U-Boot] [PATCH v4 7/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-06-10 18:39               ` Albert ARIBAUD
  2013-06-11  3:01                 ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-10 18:39 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Tue,  7 May 2013 14:25:13 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

>  arch/arm/cpu/faraday/a360/Makefile        |   49 +++++
>  arch/arm/cpu/faraday/a369/Makefile        |   50 +++++
>  arch/arm/cpu/faraday/a369/cmd_fa606.c     |   77 ++++++++
>  arch/arm/include/asm/arch-a360/hardware.h |   73 +++++++
>  arch/arm/include/asm/arch-a360/pmu.h      |   39 ++++
>  arch/arm/include/asm/arch-a360/scu.h      |   27 +++
>  arch/arm/include/asm/arch-a369/ahbc.h     |   23 +++
>  arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++++
>  arch/arm/include/asm/arch-a369/scu.h      |  213 ++++++++++++++++++++
>  board/faraday/a360evb/Makefile            |   49 +++++
>  board/faraday/a360evb/board.c             |   73 +++++++
>  board/faraday/a360evb/clk.c               |   57 ++++++
>  board/faraday/a360evb/config.mk           |   33 ++++
>  board/faraday/a360evb/lowlevel_init.S     |   33 ++++
>  board/faraday/a369evb/Makefile            |   49 +++++
>  board/faraday/a369evb/board.c             |  184 +++++++++++++++++
>  board/faraday/a369evb/clk.c               |   80 ++++++++
>  board/faraday/a369evb/config.mk           |   33 ++++
>  board/faraday/a369evb/lowlevel_init.S     |  136 +++++++++++++
>  boards.cfg                                |    3 +
>  include/configs/a360.h                    |   63 ++++++
>  include/configs/a369-common.h             |   74 +++++++
>  include/configs/a369.h                    |   33 ++++
>  include/configs/a369_fa606te.h            |   29 +++
>  include/configs/faraday-common.h          |  304 +++++++++++++++++++++++++++++
>  include/faraday/ftsmc020.h                |    1 +
>  26 files changed, 1873 insertions(+)

Please add entries in MAINTAINERS file.

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v4 6/7] arm: add Faraday firmware image utility
  2013-06-10 18:38               ` Albert ARIBAUD
@ 2013-06-11  3:00                 ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-11  3:00 UTC (permalink / raw)
  To: u-boot

2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Tue,  7 May 2013 14:25:12 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Albert Aribaud <albert.u.boot@aribaud.net>
>> ---
>> Changes for v4:
>>    - Coding Style cleanup.
>>    - Break up from [arm: add Faraday A36x SoC platform support]
>>
>> Changes for v3:
>>    - Coding Style cleanup.
>>    - Always insert a blank line between declarations and code.
>>
>> Changes for v2:
>>    - Coding Style cleanup.
>>
>>  arch/arm/cpu/faraday/Makefile     |    2 +-
>>  arch/arm/cpu/faraday/cmd_bootfa.c |  132 +++++++++++++++++++++++++++++++++++++
>>  arch/arm/cpu/faraday/fwimage.h    |   38 +++++++++++
>>  arch/arm/cpu/faraday/fwimage2.h   |   70 ++++++++++++++++++++
>>  arch/arm/cpu/u-boot.lds           |   11 ++++
>>  5 files changed, 252 insertions(+), 1 deletion(-)
>>  create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
>>  create mode 100644 arch/arm/cpu/faraday/fwimage.h
>>  create mode 100644 arch/arm/cpu/faraday/fwimage2.h
>
> What is the rationale behind a specific boot command?

Got it, thanks.
I'll add the rationale at next patch.

> What prevents
> using the existing tools and formats?
>

The private firmware image format is designed for better backward compatibility
to the hard-wired ROM code for Faraday A36x SoC.

I'll try to revise the design and see if it's possible to adapt it to
existing u-boot tools and formats.

> Amicalement,
> --
> Albert.



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 7/7] arm: add Faraday A36x SoC platform support
  2013-06-10 18:39               ` Albert ARIBAUD
@ 2013-06-11  3:01                 ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-11  3:01 UTC (permalink / raw)
  To: u-boot

2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Tue,  7 May 2013 14:25:13 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>>  arch/arm/cpu/faraday/a360/Makefile        |   49 +++++
>>  arch/arm/cpu/faraday/a369/Makefile        |   50 +++++
>>  arch/arm/cpu/faraday/a369/cmd_fa606.c     |   77 ++++++++
>>  arch/arm/include/asm/arch-a360/hardware.h |   73 +++++++
>>  arch/arm/include/asm/arch-a360/pmu.h      |   39 ++++
>>  arch/arm/include/asm/arch-a360/scu.h      |   27 +++
>>  arch/arm/include/asm/arch-a369/ahbc.h     |   23 +++
>>  arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++++
>>  arch/arm/include/asm/arch-a369/scu.h      |  213 ++++++++++++++++++++
>>  board/faraday/a360evb/Makefile            |   49 +++++
>>  board/faraday/a360evb/board.c             |   73 +++++++
>>  board/faraday/a360evb/clk.c               |   57 ++++++
>>  board/faraday/a360evb/config.mk           |   33 ++++
>>  board/faraday/a360evb/lowlevel_init.S     |   33 ++++
>>  board/faraday/a369evb/Makefile            |   49 +++++
>>  board/faraday/a369evb/board.c             |  184 +++++++++++++++++
>>  board/faraday/a369evb/clk.c               |   80 ++++++++
>>  board/faraday/a369evb/config.mk           |   33 ++++
>>  board/faraday/a369evb/lowlevel_init.S     |  136 +++++++++++++
>>  boards.cfg                                |    3 +
>>  include/configs/a360.h                    |   63 ++++++
>>  include/configs/a369-common.h             |   74 +++++++
>>  include/configs/a369.h                    |   33 ++++
>>  include/configs/a369_fa606te.h            |   29 +++
>>  include/configs/faraday-common.h          |  304 +++++++++++++++++++++++++++++
>>  include/faraday/ftsmc020.h                |    1 +
>>  26 files changed, 1873 insertions(+)
>
> Please add entries in MAINTAINERS file.
>

Got it, thanks

> Amicalement,
> --
> Albert.



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 2/7] arm: add Faraday common utilities
  2013-06-10 18:05               ` Albert ARIBAUD
@ 2013-06-11  3:02                 ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-11  3:02 UTC (permalink / raw)
  To: u-boot

2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Tue,  7 May 2013 14:25:08 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>
>> diff --git a/arch/arm/include/asm/mach-types.h b/arch/arm/include/asm/mach-types.h
>> index 440b041..a103922 100644
>> --- a/arch/arm/include/asm/mach-types.h
>> +++ b/arch/arm/include/asm/mach-types.h
>
> Do not assign to mach-types. If mach-type was assigned in the ARM
> machine base, then request for an update of mach-types, or define
> your specific machine type in your board's config header file.
>

Got it, thanks


--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores
  2013-06-10 17:59               ` Albert ARIBAUD
@ 2013-06-11  3:09                 ` Kuo-Jung Su
  2013-06-11 15:28                   ` Albert ARIBAUD
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-11  3:09 UTC (permalink / raw)
  To: u-boot

2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
>> index 5bbb0a0..5a13af5 100644
>> --- a/arch/arm/include/asm/dma-mapping.h
>> +++ b/arch/arm/include/asm/dma-mapping.h
>> @@ -3,6 +3,9 @@
>>   * Stelian Pop <stelian@popies.net>
>>   * Lead Tech Design <www.leadtechdesign.com>
>>   *
>> + * (C) Copyright 2010
>> + * Dante Su <dantesu@faraday-tech.com>
>
> Fix Copyright notices (dates) throughout the patch (and series as
> needed).
>

Got it, thanks.

>>   * See file CREDITS for list of people who contributed to this
>>   * project.
>>   *
>> @@ -24,22 +27,76 @@
>>  #ifndef __ASM_ARM_DMA_MAPPING_H
>>  #define __ASM_ARM_DMA_MAPPING_H
>>
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +#include <asm/u-boot.h>
>> +#include <asm/global_data.h>
>> +#include <asm/io.h>
>> +#include <malloc.h>
>> +
>> +DECLARE_GLOBAL_DATA_PTR;
>> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> +
>>  enum dma_data_direction {
>>       DMA_BIDIRECTIONAL       = 0,
>>       DMA_TO_DEVICE           = 1,
>>       DMA_FROM_DEVICE         = 2,
>>  };
>>
>> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
>>  {
>> -     *handle = (unsigned long)malloc(len);
>> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> +     void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
>> +
>> +     if (va && gd->arch.cpu_mmu) {
>> +             invalidate_dcache_range((ulong)va, (ulong)va + len);
>> +             map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
>> +             if (!map)
>> +                     free(va);
>> +             va = map;
>> +     }
>> +
>> +     if (handle)
>> +             *handle = virt_to_phys(va);
>> +
>> +     return va;
>> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> +     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>>       return (void *)*handle;
>
> This is not identical to what the code was before the patch. Why the
> difference?
>

Yes, it's not identical to what the code was.

It was:
    *handle = (unsigned long)malloc(len);
But I think it should be
    *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);

Because even though the MMU/D-cache is off, some DMA engines still
requires strict address alignment.

For example, the Faraday FTMAC110 & FTGMAC100 ether-net controllers
expect the descriptors are always aligned to 16-bytes boundary.

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores
  2013-06-11  3:09                 ` Kuo-Jung Su
@ 2013-06-11 15:28                   ` Albert ARIBAUD
  2013-06-14  5:44                     ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-11 15:28 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Tue, 11 Jun 2013 11:09:57 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> 2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> > Hi Kuo-Jung,
> >
> > On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
> > wrote:
> >
> >> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
> >> index 5bbb0a0..5a13af5 100644
> >> --- a/arch/arm/include/asm/dma-mapping.h
> >> +++ b/arch/arm/include/asm/dma-mapping.h
> >> @@ -3,6 +3,9 @@
> >>   * Stelian Pop <stelian@popies.net>
> >>   * Lead Tech Design <www.leadtechdesign.com>
> >>   *
> >> + * (C) Copyright 2010
> >> + * Dante Su <dantesu@faraday-tech.com>
> >
> > Fix Copyright notices (dates) throughout the patch (and series as
> > needed).
> >
> 
> Got it, thanks.
> 
> >>   * See file CREDITS for list of people who contributed to this
> >>   * project.
> >>   *
> >> @@ -24,22 +27,76 @@
> >>  #ifndef __ASM_ARM_DMA_MAPPING_H
> >>  #define __ASM_ARM_DMA_MAPPING_H
> >>
> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> >> +#include <asm/u-boot.h>
> >> +#include <asm/global_data.h>
> >> +#include <asm/io.h>
> >> +#include <malloc.h>
> >> +
> >> +DECLARE_GLOBAL_DATA_PTR;
> >> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> >> +
> >>  enum dma_data_direction {
> >>       DMA_BIDIRECTIONAL       = 0,
> >>       DMA_TO_DEVICE           = 1,
> >>       DMA_FROM_DEVICE         = 2,
> >>  };
> >>
> >> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
> >> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
> >>  {
> >> -     *handle = (unsigned long)malloc(len);
> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
> >> +     void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
> >> +
> >> +     if (va && gd->arch.cpu_mmu) {
> >> +             invalidate_dcache_range((ulong)va, (ulong)va + len);
> >> +             map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
> >> +             if (!map)
> >> +                     free(va);
> >> +             va = map;
> >> +     }
> >> +
> >> +     if (handle)
> >> +             *handle = virt_to_phys(va);
> >> +
> >> +     return va;
> >> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
> >> +     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
> >>       return (void *)*handle;
> >
> > This is not identical to what the code was before the patch. Why the
> > difference?
> >
> 
> Yes, it's not identical to what the code was.
> 
> It was:
>     *handle = (unsigned long)malloc(len);
> But I think it should be
>     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
> 
> Because even though the MMU/D-cache is off, some DMA engines still
> requires strict address alignment.
> 
> For example, the Faraday FTMAC110 & FTGMAC100 ether-net controllers
> expect the descriptors are always aligned to 16-bytes boundary.

Unless there exists an actual case where the current form causes an
issue, please leave it unchanged. And if it is needed, then please make
it a separate patch.

> Best wishes,
> Kuo-Jung Su

Amicalement,
-- 
Albert.

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

* [U-Boot] [U-Boot, v4] spi: add Faraday FTSPI010 SPI controller support
  2013-05-07  6:34           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
@ 2013-06-12 18:56             ` Jagan Teki
  2013-06-14  6:00               ` Kuo-Jung Su
  2013-11-22  7:44             ` [U-Boot] [PATCH v5] spi: ftssp010_spi: add Faraday " Kuo-Jung Su
  2013-11-28  2:46             ` [U-Boot] [PATCH v6] " Kuo-Jung Su
  2 siblings, 1 reply; 311+ messages in thread
From: Jagan Teki @ 2013-06-12 18:56 UTC (permalink / raw)
  To: u-boot

Hi,

Few comments, please get back your inputs.

Use commit header as "spi: ftssp010_spi: "

On 07-05-2013 12:04, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> The Faraday FTSSP010 is a multi-function controller
> which supports I2S/SPI/SSP/AC97/SPDIF. However This
> patch implements only the SPI mode.
>
> NOTE:
> The DMA and CS/Clock control logic has been altered
> since hardware revision 1.19.0. So this patch
> would first detects the revision id of the underlying
> chip, and then switch to the corresponding software
> control routines.
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Tom Rini <trini@ti.com>
>
> ---
> Changes for v4:
>     - Coding Style cleanup.
>     - Make it a separate patch, rather then a part of
>       Faraday A36x patch series
>     - Use macro constants for timeout control
>
> Changes for v3:
>     - Coding Style cleanup.
>     - Drop macros for wirtel()/readl(), call them directly.
>     - Always insert a blank line between declarations and code.
>     - Replace all the infinite wait loop with a timeout.
>     - Add '__iomem' to all the declaration of HW register pointers.
>
> Changes for v2:
>     - Coding Style cleanup.
>     - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>     - Use structure based hardware registers to replace the macro constants.
>     - Replace BIT() with BIT_MASK().
>
>   drivers/spi/Makefile        |    1 +
>   drivers/spi/ftssp010_spi.c  |  385 +++++++++++++++++++++++++++++++++++++++++++
>   drivers/spi/ftssp010_spi.h  |   86 ++++++++++
>   include/faraday/ftgpio010.h |   25 +++
>   4 files changed, 497 insertions(+)
>   create mode 100644 drivers/spi/ftssp010_spi.c
>   create mode 100644 drivers/spi/ftssp010_spi.h
>   create mode 100644 include/faraday/ftgpio010.h
>
> --
> 1.7.9.5
>
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index d08609e..947d60e 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
>   COBJS-$(CONFIG_CF_SPI) += cf_spi.o
>   COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
>   COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
> +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o

Place into in alphabetic order, to make sure some kind of coding style.

>   COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
>   COBJS-$(CONFIG_ICH_SPI) +=  ich.o
>   COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
> diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
> new file mode 100644
> index 0000000..d401ecc
> --- /dev/null
> +++ b/drivers/spi/ftssp010_spi.c
> @@ -0,0 +1,385 @@
> +/*
> + * Faraday Multi-function Controller - SPI Mode
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later version.
> + * See the file COPYING in the root directory of the source tree for details.
> + */
Little bit uneasy with the above license note, any reason for this GPL 
w.r.t your company style. refer license note on drivers/spi/exynos_spi.c

> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <spi.h>
> +#include <malloc.h>
> +#include <faraday/ftgpio010.h>
Does this include file is an arch' specific, means struct ftgpio010_regs
is used by some other drivers on ur board?

> +#include "ftssp010_spi.h"
Please don't use extra include file, use the same structure's in driver 
it self, IMHO.

> +
> +#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
> +#define CFG_CS_TIMEOUT  (CONFIG_SYS_HZ >> 2) /* 250 ms */
> +

----- TAG+
> +struct ftssp010_chip {
> +	void __iomem *regs;
> +	uint32_t fifo;
> +	uint32_t rev;
> +	uint32_t div;
> +	uint32_t mode;
> +
> +	struct {
> +		void __iomem *regs;
> +		uint32_t      pin;
> +	} gpio;
> +};
> +
> +static struct ftssp010_chip chip_list[] = {
> +#ifdef CONFIG_FTSSP010_BASE
> +	{
> +		.regs = (void __iomem *)CONFIG_FTSSP010_BASE,
> +# ifdef CONFIG_FTSSP010_GPIO_BASE
> +		.gpio = {
> +			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE,
> +			CONFIG_FTSSP010_GPIO_PIN
> +		},
> +# endif
> +	},
> +#endif /* #ifdef CONFIG_FTSSP010_BASE */
> +#ifdef CONFIG_FTSSP010_BASE1
> +	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE1, },
> +# ifdef CONFIG_FTSSP010_GPIO_BASE1
> +		.gpio = {
> +			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE1,
> +			CONFIG_FTSSP010_GPIO_PIN1
> +		},
> +# endif
> +#endif
> +#ifdef CONFIG_FTSSP010_BASE2
> +	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE2, },
> +# ifdef CONFIG_FTSSP010_GPIO_BASE2
> +		.gpio = {
> +			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE2,
> +			CONFIG_FTSSP010_GPIO_PIN2
> +		},
> +# endif
> +#endif
> +#ifdef CONFIG_FTSSP010_BASE3
> +	{ .regs = (void __iomem *)CONFIG_FTSSP010_BASE3, },
> +# ifdef CONFIG_FTSSP010_GPIO_BASE3
> +		.gpio = {
> +			(void __iomem *)CONFIG_FTSSP010_GPIO_BASE3,
> +			CONFIG_FTSSP010_GPIO_PIN3
> +		},
> +# endif
> +#endif
> +};
---- TAG-

TAG+ ... TAG- this type of assignment is old way.
please use the structure macro assignment instead of void __iomem *

ex:
#define CONFIG_MY_REG_BASE	0xF1000000

struct my_reg {
	u32 r1;
	u32 r2;
	u32 r3;
	u32 r4;
}

#define my_reg_base ((struct my_reg *) CONFIG_MY_REG_BASE)

then use readl(&my_reg_base->r3);

see the example usage on
http://patchwork.ozlabs.org/patch/246468/
https://github.com/Xilinx/u-boot-xlnx/blob/master/drivers/spi/zynq_qspips.c

> +
> +static inline int ftssp010_wait_tx(struct ftssp010_chip *chip)
> +{
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +	int ret = -1;
> +	ulong ts;
> +
> +	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
> +		if (!(readl(&regs->sr) & SR_TFNF))
> +			continue;
> +		ret = 0;
> +		break;
> +	}
> +
> +	if (ret)
> +		printf("ftssp010: tx timeout\n");
> +
> +	return ret;
> +}
> +
> +static inline int ftssp010_wait_rx(struct ftssp010_chip *chip)
> +{
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +	int ret = -1;
> +	ulong ts;
> +
> +	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
> +		if (!SR_RFVE(readl(&regs->sr)))
> +			continue;
> +		ret = 0;
> +		break;
> +	}
> +
> +	if (ret)
> +		printf("ftssp010: rx timeout\n");
> +
> +	return ret;
> +}
> +
> +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
> +	const void *tx_buf, void *rx_buf, int len, uint flags)
> +{
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +	const uint8_t *txb = tx_buf;
> +	uint8_t       *rxb = rx_buf;
> +
> +	while (len > 0) {
> +		int i, depth = min(chip->fifo >> 2, len);
> +		uint32_t xmsk = 0;
> +
> +		if (tx_buf) {
> +			for (i = 0; i < depth; ++i) {
> +				ftssp010_wait_tx(chip);
> +				writel(*txb++, &regs->dr);
> +			}
> +			xmsk |= CR2_TXEN | CR2_TXDOE;
> +			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
> +				setbits_le32(&regs->cr[2], xmsk);
> +		}
> +		if (rx_buf) {
> +			xmsk |= CR2_RXEN;
> +			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
> +				setbits_le32(&regs->cr[2], xmsk);
> +			for (i = 0; i < depth; ++i) {
> +				ftssp010_wait_rx(chip);
> +				*rxb++ = (uint8_t)readl(&regs->dr);
> +			}
> +		}
> +
> +		len -= depth;
> +	}
> +
> +	return 0;
> +}
> +
> +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
> +	const void *tx_buf, void *rx_buf, int len, uint flags)
> +{
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +	const uint8_t *txb = tx_buf;
> +	uint8_t       *rxb = rx_buf;
> +
> +	while (len > 0) {
> +		int i, depth = min(chip->fifo >> 2, len);
> +		uint32_t tmp;
> +
> +		for (i = 0; i < depth; ++i) {
> +			ftssp010_wait_tx(chip);
> +			writel(txb ? (*txb++) : 0, &regs->dr);
> +		}
> +		for (i = 0; i < depth; ++i) {
> +			ftssp010_wait_rx(chip);
> +			tmp = readl(&regs->dr);
> +			if (rxb)
> +				*rxb++ = (uint8_t)tmp;
> +		}
> +
> +		len -= depth;
> +	}
> +
> +	return 0;
> +}
> +
> +/*
> + * Determine if a SPI chipselect is valid.
> + * This function is provided by the board if the low-level SPI driver
> + * needs it to determine if a given chipselect is actually valid.
> + *
> + * Returns: 1 if bus:cs identifies a valid chip on this board, 0
> + * otherwise.
> + */
> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
> +{
> +	int ret = 0;
> +	struct ftssp010_chip *chip;
> +	struct ftssp010_regs __iomem *regs;
> +	uint32_t txfifo, rxfifo;
> +
> +	if (bus >= ARRAY_SIZE(chip_list))
> +		return ret;
> +
> +	chip = chip_list + bus;
> +	regs = chip->regs;
> +	chip->rev = readl(&regs->revr);
> +	txfifo = FEAR_TXFIFO(readl(&regs->fear));
> +	rxfifo = FEAR_RXFIFO(readl(&regs->fear));
> +	chip->fifo = min(txfifo, rxfifo);
> +
> +	debug("ftssp010: rev=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
> +
> +	if (chip->rev >= 0x00011900) {
> +		if (cs < 4)
> +			ret = 1;
> +	} else if (!cs) {
> +		struct ftgpio010_regs *gpio = chip->gpio.regs;
> +		uint32_t mask = BIT_MASK(chip->gpio.pin);
> +
> +		if (gpio) {
> +			/* setup gpio pin as an output pin */
> +			setbits_le32(&gpio->dir, mask);
> +			ret = 1;
> +		}
> +	}
> +
> +	return ret;
> +}
> +
> +/*
> + * Activate a SPI chipselect.
> + * This function is provided by the board code when using a driver
> + * that can't control its chipselects automatically (e.g.
> + * common/soft_spi.c). When called, it should activate the chip select
> + * to the device identified by "slave".
> + */
> +void spi_cs_activate(struct spi_slave *slave)
> +{
> +	struct ftssp010_chip *chip = chip_list + slave->bus;
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +
> +	/* cs pull low */
> +	if (chip->rev >= 0x00011900) {
> +		writel((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
> +			| CR2_RXFCLR, &regs->cr[2]);
> +	} else {
> +		struct ftgpio010_regs *gpio = chip->gpio.regs;
> +		uint32_t mask = BIT_MASK(chip->gpio.pin);
> +
> +		if (gpio)
> +			setbits_le32(&gpio->clr, mask);
> +	}
> +	udelay_masked(1);
> +}
> +
> +/*
> + * Deactivate a SPI chipselect.
> + * This function is provided by the board code when using a driver
> + * that can't control its chipselects automatically (e.g.
> + * common/soft_spi.c). When called, it should deactivate the chip
> + * select to the device identified by "slave".
> + */
> +void spi_cs_deactivate(struct spi_slave *slave)
> +{
> +	struct ftssp010_chip *chip = chip_list + slave->bus;
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +	ulong ts;
> +
> +	/* wait until device idle */
> +	for (ts = get_timer(0); get_timer(ts) < CFG_CS_TIMEOUT; ) {
> +		if (readl(&regs->sr) & SR_BUSY)
> +			continue;
> +		break;
> +	}
> +	if (readl(&regs->sr) & SR_BUSY)
> +		printf("ftspi010: busy timeout at cs deactivate\n");
> +
> +	/* cs pull high */
> +	if (chip->rev >= 0x00011900) {
> +		writel((slave->cs << 10) | CR2_FS, &regs->cr[2]);
> +	} else {
> +		struct ftgpio010_regs *gpio = chip->gpio.regs;
> +		uint32_t mask = BIT_MASK(chip->gpio.pin);
> +
> +		if (gpio)
> +			setbits_le32(&gpio->set, mask);
> +	}
> +	udelay_masked(1);
> +}
> +
> +void spi_init(void)
> +{
> +}
> +
> +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
> +{
> +	uint32_t clk, div;
> +	struct spi_slave *ss;
> +	struct ftssp010_chip *chip;
> +
> +	if (!spi_cs_is_valid(bus, cs))
> +		return NULL;
> +
> +	if (mode != SPI_MODE_0) {
> +		printf("ftssp010: MODE%d is not supported\n", mode);
> +		return NULL;
> +	}
> +

----- TAG+
> +	ss = malloc(sizeof(struct spi_slave));
> +	if (!ss)
> +		return NULL;
> +
> +	ss->bus = bus;
> +	ss->cs  = cs;
----- TAG-
Pleas use spi_alloc_slave() instead of malloc()
see the sample code on "drivers/spi/exynos_spi.c"

> +
> +#ifdef CONFIG_FTSSP010_SCLK
> +	clk = CONFIG_FTSSP010_SCLK;
> +#else
> +	clk = clk_get_rate("SSP");
> +#endif
> +	if (max_hz > 0) {
> +		for (div = 0; div < 0xFFFF; ++div) {
> +			if ((clk / (2 * (div + 1))) <= max_hz)
> +				break;
> +		}
> +	} else {
> +		div = 7;
> +	}
> +
> +	chip = chip_list + bus;
> +	chip->div  = div;
> +	chip->mode = mode;
> +
> +	debug("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
> +
> +	return ss;
> +}
> +
> +void spi_free_slave(struct spi_slave *slave)
> +{
> +	free(slave);
> +}
> +
> +int spi_claim_bus(struct spi_slave *slave)
> +{
> +	struct ftssp010_chip *chip = chip_list + slave->bus;
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +
> +	writel(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
> +
> +	if (chip->rev >= 0x00011900) {
> +		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
> +			&regs->cr[0]);
> +		writel(CR2_TXFCLR | CR2_RXFCLR,
> +			&regs->cr[2]);
> +	} else {
> +		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
> +			&regs->cr[0]);
> +		writel(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
> +			&regs->cr[2]);
> +	}
> +
> +	spi_cs_deactivate(slave);
> +
> +	return 0;
> +}
> +
> +void spi_release_bus(struct spi_slave *slave)
> +{
> +	struct ftssp010_chip *chip = chip_list + slave->bus;
> +	struct ftssp010_regs __iomem *regs = chip->regs;
> +
> +	writel(0, &regs->cr[2]);
> +}
> +
> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
> +			 const void *dout, void *din, unsigned long flags)
> +{
> +	struct ftssp010_chip *chip = chip_list + slave->bus;
> +	uint32_t len = bitlen >> 3;
> +
> +	if (flags & SPI_XFER_BEGIN)
> +		spi_cs_activate(slave);
> +
> +	if (chip->rev >= 0x00011900)
> +		ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags);
> +	else
> +		ftssp010_spi_work_transfer(chip, dout, din, len, flags);
> +
> +	if (flags & SPI_XFER_END)
> +		spi_cs_deactivate(slave);
> +
> +	return 0;
> +}

---- TAG+
> diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
> new file mode 100644
> index 0000000..5258edc
> --- /dev/null
> +++ b/drivers/spi/ftssp010_spi.h
> @@ -0,0 +1,86 @@
> +/*
> + * Faraday Multi-function Controller - SPI Mode
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later version.
> + * See the file COPYING in the root directory of the source tree for details.
> + */
> +
> +#ifndef _FTSSP010_H
> +#define _FTSSP010_H
> +
> +/* FTSSP010 HW Registers */
> +struct ftssp010_regs {
> +	uint32_t cr[3];/* control register */
> +	uint32_t sr;   /* status register */
> +	uint32_t icr;  /* interrupt control register */
> +	uint32_t isr;  /* interrupt status register */
> +	uint32_t dr;   /* data register */
> +	uint32_t rsvd[17];
> +	uint32_t revr; /* revision register */
> +	uint32_t fear; /* feature register */
> +};
> +
> +/* Control Register 0  */
> +#define CR0_FFMT_MASK       (7 << 12)
> +#define CR0_FFMT_SSP        (0 << 12)
> +#define CR0_FFMT_SPI        (1 << 12)
> +#define CR0_FFMT_MICROWIRE  (2 << 12)
> +#define CR0_FFMT_I2S        (3 << 12)
> +#define CR0_FFMT_AC97       (4 << 12)
> +#define CR0_FLASH           (1 << 11)
> +#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
> +#define CR0_LBM             (1 << 7)  /* Loopback mode */
> +#define CR0_LSB             (1 << 6)  /* LSB first */
> +#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
> +#define CR0_FSJUSTIFY       (1 << 4)
> +#define CR0_OPM_SLAVE       (0 << 2)
> +#define CR0_OPM_MASTER      (3 << 2)
> +#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
> +#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
> +#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
> +#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
> +#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
> +#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
> +
> +/* Control Register 1 */
> +
> +#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
> +#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
> +#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
> +
> +/* Control Register 2 */
> +#define CR2_FSOS(x)         (((x) & 0x03) << 10)	/* FS/CS Select */
> +#define CR2_FS              (1 << 9)	/* FS/CS Signal Level */
> +#define CR2_TXEN            (1 << 8)	/* Tx Enable */
> +#define CR2_RXEN            (1 << 7)	/* Rx Enable */
> +#define CR2_SSPRST          (1 << 6)	/* SSP reset */
> +#define CR2_TXFCLR          (1 << 3)	/* TX FIFO Clear */
> +#define CR2_RXFCLR          (1 << 2)	/* RX FIFO Clear */
> +#define CR2_TXDOE           (1 << 1)	/* TX Data Output Enable */
> +#define CR2_SSPEN           (1 << 0)	/* SSP Enable */
> +
> +/*
> + * Status Register
> + */
> +#define SR_RFF       (1 << 0) /* receive FIFO full */
> +#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
> +#define SR_BUSY      (1 << 2) /* bus is busy */
> +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid entries */
> +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */
> +
> +/*
> + * Feature Register
> + */
> +#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
> +#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
> +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
> +#define FEAR_AC97        (1 << 24)
> +#define FEAR_I2S         (1 << 25)
> +#define FEAR_SPI_MWR     (1 << 26)
> +#define FEAR_SSP         (1 << 27)
> +#define FEAR_SPDIF       (1 << 28)
> +
> +#endif /* EOF */
---- TAG-

Please use the same defination on driver code itself.

Thanks,
Jagan.

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

* [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores
  2013-06-11 15:28                   ` Albert ARIBAUD
@ 2013-06-14  5:44                     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-14  5:44 UTC (permalink / raw)
  To: u-boot

2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Tue, 11 Jun 2013 11:09:57 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> 2013/6/11 Albert ARIBAUD <albert.u.boot@aribaud.net>:
>> > Hi Kuo-Jung,
>> >
>> > On Tue,  7 May 2013 14:25:07 +0800, Kuo-Jung Su <dantesu@gmail.com>
>> > wrote:
>> >
>> >> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
>> >> index 5bbb0a0..5a13af5 100644
>> >> --- a/arch/arm/include/asm/dma-mapping.h
>> >> +++ b/arch/arm/include/asm/dma-mapping.h
>> >> @@ -3,6 +3,9 @@
>> >>   * Stelian Pop <stelian@popies.net>
>> >>   * Lead Tech Design <www.leadtechdesign.com>
>> >>   *
>> >> + * (C) Copyright 2010
>> >> + * Dante Su <dantesu@faraday-tech.com>
>> >
>> > Fix Copyright notices (dates) throughout the patch (and series as
>> > needed).
>> >
>>
>> Got it, thanks.
>>
>> >>   * See file CREDITS for list of people who contributed to this
>> >>   * project.
>> >>   *
>> >> @@ -24,22 +27,76 @@
>> >>  #ifndef __ASM_ARM_DMA_MAPPING_H
>> >>  #define __ASM_ARM_DMA_MAPPING_H
>> >>
>> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> >> +#include <asm/u-boot.h>
>> >> +#include <asm/global_data.h>
>> >> +#include <asm/io.h>
>> >> +#include <malloc.h>
>> >> +
>> >> +DECLARE_GLOBAL_DATA_PTR;
>> >> +#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> >> +
>> >>  enum dma_data_direction {
>> >>       DMA_BIDIRECTIONAL       = 0,
>> >>       DMA_TO_DEVICE           = 1,
>> >>       DMA_FROM_DEVICE         = 2,
>> >>  };
>> >>
>> >> -static void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> >> +static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
>> >>  {
>> >> -     *handle = (unsigned long)malloc(len);
>> >> +#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
>> >> +     void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
>> >> +
>> >> +     if (va && gd->arch.cpu_mmu) {
>> >> +             invalidate_dcache_range((ulong)va, (ulong)va + len);
>> >> +             map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
>> >> +             if (!map)
>> >> +                     free(va);
>> >> +             va = map;
>> >> +     }
>> >> +
>> >> +     if (handle)
>> >> +             *handle = virt_to_phys(va);
>> >> +
>> >> +     return va;
>> >> +#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
>> >> +     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>> >>       return (void *)*handle;
>> >
>> > This is not identical to what the code was before the patch. Why the
>> > difference?
>> >
>>
>> Yes, it's not identical to what the code was.
>>
>> It was:
>>     *handle = (unsigned long)malloc(len);
>> But I think it should be
>>     *handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>>
>> Because even though the MMU/D-cache is off, some DMA engines still
>> requires strict address alignment.
>>
>> For example, the Faraday FTMAC110 & FTGMAC100 ether-net controllers
>> expect the descriptors are always aligned to 16-bytes boundary.
>
> Unless there exists an actual case where the current form causes an
> issue, please leave it unchanged. And if it is needed, then please make
> it a separate patch.
>

Got it, thanks.
I'll make it a separate patch.


--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [U-Boot, v4] spi: add Faraday FTSPI010 SPI controller support
  2013-06-12 18:56             ` [U-Boot] [U-Boot, " Jagan Teki
@ 2013-06-14  6:00               ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-14  6:00 UTC (permalink / raw)
  To: u-boot

2013/6/13 Jagan Teki <jagannadh.teki@gmail.com>:
> Hi,
>
> Few comments, please get back your inputs.
>
> Use commit header as "spi: ftssp010_spi: "
>

Got it, thanks

>
> On 07-05-2013 12:04, Kuo-Jung Su wrote:
>>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> The Faraday FTSSP010 is a multi-function controller
>> which supports I2S/SPI/SSP/AC97/SPDIF. However This
>> patch implements only the SPI mode.
>>
>> NOTE:
>> The DMA and CS/Clock control logic has been altered
>> since hardware revision 1.19.0. So this patch
>> would first detects the revision id of the underlying
>> chip, and then switch to the corresponding software
>> control routines.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Tom Rini <trini@ti.com>
>>
>> ---
>> Changes for v4:
>>     - Coding Style cleanup.
>>     - Make it a separate patch, rather then a part of
>>       Faraday A36x patch series
>>     - Use macro constants for timeout control
>>
>> Changes for v3:
>>     - Coding Style cleanup.
>>     - Drop macros for wirtel()/readl(), call them directly.
>>     - Always insert a blank line between declarations and code.
>>     - Replace all the infinite wait loop with a timeout.
>>     - Add '__iomem' to all the declaration of HW register pointers.
>>
>> Changes for v2:
>>     - Coding Style cleanup.
>>     - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
>>     - Use structure based hardware registers to replace the macro
>> constants.
>>     - Replace BIT() with BIT_MASK().
>>
>>   drivers/spi/Makefile        |    1 +
>>   drivers/spi/ftssp010_spi.c  |  385
>> +++++++++++++++++++++++++++++++++++++++++++
>>   drivers/spi/ftssp010_spi.h  |   86 ++++++++++
>>   include/faraday/ftgpio010.h |   25 +++
>>   4 files changed, 497 insertions(+)
>>   create mode 100644 drivers/spi/ftssp010_spi.c
>>   create mode 100644 drivers/spi/ftssp010_spi.h
>>   create mode 100644 include/faraday/ftgpio010.h
>>
>> --
>> 1.7.9.5
>>
>>
>> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
>> index d08609e..947d60e 100644
>> --- a/drivers/spi/Makefile
>> +++ b/drivers/spi/Makefile
>> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
>>   COBJS-$(CONFIG_CF_SPI) += cf_spi.o
>>   COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
>>   COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
>> +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
>
>
> Place into in alphabetic order, to make sure some kind of coding style.
>
>

Got it, thanks

>>   COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
>>   COBJS-$(CONFIG_ICH_SPI) +=  ich.o
>>   COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
>> diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
>> new file mode 100644
>> index 0000000..d401ecc
>> --- /dev/null
>> +++ b/drivers/spi/ftssp010_spi.c
>> @@ -0,0 +1,385 @@
>> +/*
>> + * Faraday Multi-function Controller - SPI Mode
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for
>> details.
>> + */
>
> Little bit uneasy with the above license note, any reason for this GPL w.r.t
> your company style. refer license note on drivers/spi/exynos_spi.c
>

Got it, thanks

>
>> +
>> +#include <common.h>
>> +#include <asm/io.h>
>> +#include <spi.h>
>> +#include <malloc.h>
>> +#include <faraday/ftgpio010.h>
>
> Does this include file is an arch' specific, means struct ftgpio010_regs
> is used by some other drivers on ur board?
>

No, it's not.
I'll merge it into the ftssp010_spi.c.

>> +#include "ftssp010_spi.h"
>
> Please don't use extra include file, use the same structure's in driver it
> self, IMHO.
>

Got it, thanks

>
>> +
>> +#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
>> +#define CFG_CS_TIMEOUT  (CONFIG_SYS_HZ >> 2) /* 250 ms */
>> +
>
>
> ----- TAG+
>
>> +struct ftssp010_chip {
>> +       void __iomem *regs;
>> +       uint32_t fifo;
>> +       uint32_t rev;
>> +       uint32_t div;
>> +       uint32_t mode;
>> +
>> +       struct {
>> +               void __iomem *regs;
>> +               uint32_t      pin;
>> +       } gpio;
>> +};
>> +
>> +static struct ftssp010_chip chip_list[] = {
>> +#ifdef CONFIG_FTSSP010_BASE
>> +       {
>> +               .regs = (void __iomem *)CONFIG_FTSSP010_BASE,
>> +# ifdef CONFIG_FTSSP010_GPIO_BASE
>> +               .gpio = {
>> +                       (void __iomem *)CONFIG_FTSSP010_GPIO_BASE,
>> +                       CONFIG_FTSSP010_GPIO_PIN
>> +               },
>> +# endif
>> +       },
>> +#endif /* #ifdef CONFIG_FTSSP010_BASE */
>> +#ifdef CONFIG_FTSSP010_BASE1
>> +       { .regs = (void __iomem *)CONFIG_FTSSP010_BASE1, },
>> +# ifdef CONFIG_FTSSP010_GPIO_BASE1
>> +               .gpio = {
>> +                       (void __iomem *)CONFIG_FTSSP010_GPIO_BASE1,
>> +                       CONFIG_FTSSP010_GPIO_PIN1
>> +               },
>> +# endif
>> +#endif
>> +#ifdef CONFIG_FTSSP010_BASE2
>> +       { .regs = (void __iomem *)CONFIG_FTSSP010_BASE2, },
>> +# ifdef CONFIG_FTSSP010_GPIO_BASE2
>> +               .gpio = {
>> +                       (void __iomem *)CONFIG_FTSSP010_GPIO_BASE2,
>> +                       CONFIG_FTSSP010_GPIO_PIN2
>> +               },
>> +# endif
>> +#endif
>> +#ifdef CONFIG_FTSSP010_BASE3
>> +       { .regs = (void __iomem *)CONFIG_FTSSP010_BASE3, },
>> +# ifdef CONFIG_FTSSP010_GPIO_BASE3
>> +               .gpio = {
>> +                       (void __iomem *)CONFIG_FTSSP010_GPIO_BASE3,
>> +                       CONFIG_FTSSP010_GPIO_PIN3
>> +               },
>> +# endif
>> +#endif
>> +};
>
> ---- TAG-
>
> TAG+ ... TAG- this type of assignment is old way.
> please use the structure macro assignment instead of void __iomem *
>
> ex:
> #define CONFIG_MY_REG_BASE      0xF1000000
>
> struct my_reg {
>         u32 r1;
>         u32 r2;
>         u32 r3;
>         u32 r4;
> }
>
> #define my_reg_base ((struct my_reg *) CONFIG_MY_REG_BASE)
>
> then use readl(&my_reg_base->r3);
>
> see the example usage on
> http://patchwork.ozlabs.org/patch/246468/
> https://github.com/Xilinx/u-boot-xlnx/blob/master/drivers/spi/zynq_qspips.c
>
>

Got it, thanks

>> +
>> +static inline int ftssp010_wait_tx(struct ftssp010_chip *chip)
>> +{
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +       int ret = -1;
>> +       ulong ts;
>> +
>> +       for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
>> +               if (!(readl(&regs->sr) & SR_TFNF))
>> +                       continue;
>> +               ret = 0;
>> +               break;
>> +       }
>> +
>> +       if (ret)
>> +               printf("ftssp010: tx timeout\n");
>> +
>> +       return ret;
>> +}
>> +
>> +static inline int ftssp010_wait_rx(struct ftssp010_chip *chip)
>> +{
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +       int ret = -1;
>> +       ulong ts;
>> +
>> +       for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
>> +               if (!SR_RFVE(readl(&regs->sr)))
>> +                       continue;
>> +               ret = 0;
>> +               break;
>> +       }
>> +
>> +       if (ret)
>> +               printf("ftssp010: rx timeout\n");
>> +
>> +       return ret;
>> +}
>> +
>> +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
>> +       const void *tx_buf, void *rx_buf, int len, uint flags)
>> +{
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +       const uint8_t *txb = tx_buf;
>> +       uint8_t       *rxb = rx_buf;
>> +
>> +       while (len > 0) {
>> +               int i, depth = min(chip->fifo >> 2, len);
>> +               uint32_t xmsk = 0;
>> +
>> +               if (tx_buf) {
>> +                       for (i = 0; i < depth; ++i) {
>> +                               ftssp010_wait_tx(chip);
>> +                               writel(*txb++, &regs->dr);
>> +                       }
>> +                       xmsk |= CR2_TXEN | CR2_TXDOE;
>> +                       if ((readl(&regs->cr[2]) & xmsk) != xmsk)
>> +                               setbits_le32(&regs->cr[2], xmsk);
>> +               }
>> +               if (rx_buf) {
>> +                       xmsk |= CR2_RXEN;
>> +                       if ((readl(&regs->cr[2]) & xmsk) != xmsk)
>> +                               setbits_le32(&regs->cr[2], xmsk);
>> +                       for (i = 0; i < depth; ++i) {
>> +                               ftssp010_wait_rx(chip);
>> +                               *rxb++ = (uint8_t)readl(&regs->dr);
>> +                       }
>> +               }
>> +
>> +               len -= depth;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
>> +       const void *tx_buf, void *rx_buf, int len, uint flags)
>> +{
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +       const uint8_t *txb = tx_buf;
>> +       uint8_t       *rxb = rx_buf;
>> +
>> +       while (len > 0) {
>> +               int i, depth = min(chip->fifo >> 2, len);
>> +               uint32_t tmp;
>> +
>> +               for (i = 0; i < depth; ++i) {
>> +                       ftssp010_wait_tx(chip);
>> +                       writel(txb ? (*txb++) : 0, &regs->dr);
>> +               }
>> +               for (i = 0; i < depth; ++i) {
>> +                       ftssp010_wait_rx(chip);
>> +                       tmp = readl(&regs->dr);
>> +                       if (rxb)
>> +                               *rxb++ = (uint8_t)tmp;
>> +               }
>> +
>> +               len -= depth;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +/*
>> + * Determine if a SPI chipselect is valid.
>> + * This function is provided by the board if the low-level SPI driver
>> + * needs it to determine if a given chipselect is actually valid.
>> + *
>> + * Returns: 1 if bus:cs identifies a valid chip on this board, 0
>> + * otherwise.
>> + */
>> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
>> +{
>> +       int ret = 0;
>> +       struct ftssp010_chip *chip;
>> +       struct ftssp010_regs __iomem *regs;
>> +       uint32_t txfifo, rxfifo;
>> +
>> +       if (bus >= ARRAY_SIZE(chip_list))
>> +               return ret;
>> +
>> +       chip = chip_list + bus;
>> +       regs = chip->regs;
>> +       chip->rev = readl(&regs->revr);
>> +       txfifo = FEAR_TXFIFO(readl(&regs->fear));
>> +       rxfifo = FEAR_RXFIFO(readl(&regs->fear));
>> +       chip->fifo = min(txfifo, rxfifo);
>> +
>> +       debug("ftssp010: rev=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
>> +
>> +       if (chip->rev >= 0x00011900) {
>> +               if (cs < 4)
>> +                       ret = 1;
>> +       } else if (!cs) {
>> +               struct ftgpio010_regs *gpio = chip->gpio.regs;
>> +               uint32_t mask = BIT_MASK(chip->gpio.pin);
>> +
>> +               if (gpio) {
>> +                       /* setup gpio pin as an output pin */
>> +                       setbits_le32(&gpio->dir, mask);
>> +                       ret = 1;
>> +               }
>> +       }
>> +
>> +       return ret;
>> +}
>> +
>> +/*
>> + * Activate a SPI chipselect.
>> + * This function is provided by the board code when using a driver
>> + * that can't control its chipselects automatically (e.g.
>> + * common/soft_spi.c). When called, it should activate the chip select
>> + * to the device identified by "slave".
>> + */
>> +void spi_cs_activate(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +
>> +       /* cs pull low */
>> +       if (chip->rev >= 0x00011900) {
>> +               writel((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
>> +                       | CR2_RXFCLR, &regs->cr[2]);
>> +       } else {
>> +               struct ftgpio010_regs *gpio = chip->gpio.regs;
>> +               uint32_t mask = BIT_MASK(chip->gpio.pin);
>> +
>> +               if (gpio)
>> +                       setbits_le32(&gpio->clr, mask);
>> +       }
>> +       udelay_masked(1);
>> +}
>> +
>> +/*
>> + * Deactivate a SPI chipselect.
>> + * This function is provided by the board code when using a driver
>> + * that can't control its chipselects automatically (e.g.
>> + * common/soft_spi.c). When called, it should deactivate the chip
>> + * select to the device identified by "slave".
>> + */
>> +void spi_cs_deactivate(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +       ulong ts;
>> +
>> +       /* wait until device idle */
>> +       for (ts = get_timer(0); get_timer(ts) < CFG_CS_TIMEOUT; ) {
>> +               if (readl(&regs->sr) & SR_BUSY)
>> +                       continue;
>> +               break;
>> +       }
>> +       if (readl(&regs->sr) & SR_BUSY)
>> +               printf("ftspi010: busy timeout at cs deactivate\n");
>> +
>> +       /* cs pull high */
>> +       if (chip->rev >= 0x00011900) {
>> +               writel((slave->cs << 10) | CR2_FS, &regs->cr[2]);
>> +       } else {
>> +               struct ftgpio010_regs *gpio = chip->gpio.regs;
>> +               uint32_t mask = BIT_MASK(chip->gpio.pin);
>> +
>> +               if (gpio)
>> +                       setbits_le32(&gpio->set, mask);
>> +       }
>> +       udelay_masked(1);
>> +}
>> +
>> +void spi_init(void)
>> +{
>> +}
>> +
>> +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint
>> mode)
>> +{
>> +       uint32_t clk, div;
>> +       struct spi_slave *ss;
>> +       struct ftssp010_chip *chip;
>> +
>> +       if (!spi_cs_is_valid(bus, cs))
>> +               return NULL;
>> +
>> +       if (mode != SPI_MODE_0) {
>> +               printf("ftssp010: MODE%d is not supported\n", mode);
>> +               return NULL;
>> +       }
>> +
>
>
> ----- TAG+
>
>> +       ss = malloc(sizeof(struct spi_slave));
>> +       if (!ss)
>> +               return NULL;
>> +
>> +       ss->bus = bus;
>> +       ss->cs  = cs;
>
> ----- TAG-
> Pleas use spi_alloc_slave() instead of malloc()
> see the sample code on "drivers/spi/exynos_spi.c"
>
>

Got it, thanks

>> +
>> +#ifdef CONFIG_FTSSP010_SCLK
>> +       clk = CONFIG_FTSSP010_SCLK;
>> +#else
>> +       clk = clk_get_rate("SSP");
>> +#endif
>> +       if (max_hz > 0) {
>> +               for (div = 0; div < 0xFFFF; ++div) {
>> +                       if ((clk / (2 * (div + 1))) <= max_hz)
>> +                               break;
>> +               }
>> +       } else {
>> +               div = 7;
>> +       }
>> +
>> +       chip = chip_list + bus;
>> +       chip->div  = div;
>> +       chip->mode = mode;
>> +
>> +       debug("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
>> +
>> +       return ss;
>> +}
>> +
>> +void spi_free_slave(struct spi_slave *slave)
>> +{
>> +       free(slave);
>> +}
>> +
>> +int spi_claim_bus(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +
>> +       writel(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
>> +
>> +       if (chip->rev >= 0x00011900) {
>> +               writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO |
>> CR0_FLASH,
>> +                       &regs->cr[0]);
>> +               writel(CR2_TXFCLR | CR2_RXFCLR,
>> +                       &regs->cr[2]);
>> +       } else {
>> +               writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
>> +                       &regs->cr[0]);
>> +               writel(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
>> +                       &regs->cr[2]);
>> +       }
>> +
>> +       spi_cs_deactivate(slave);
>> +
>> +       return 0;
>> +}
>> +
>> +void spi_release_bus(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs __iomem *regs = chip->regs;
>> +
>> +       writel(0, &regs->cr[2]);
>> +}
>> +
>> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>> +                        const void *dout, void *din, unsigned long flags)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       uint32_t len = bitlen >> 3;
>> +
>> +       if (flags & SPI_XFER_BEGIN)
>> +               spi_cs_activate(slave);
>> +
>> +       if (chip->rev >= 0x00011900)
>> +               ftssp010_spi_work_transfer_v1_19(chip, dout, din, len,
>> flags);
>> +       else
>> +               ftssp010_spi_work_transfer(chip, dout, din, len, flags);
>> +
>> +       if (flags & SPI_XFER_END)
>> +               spi_cs_deactivate(slave);
>> +
>> +       return 0;
>> +}
>
>
> ---- TAG+
>
>> diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
>> new file mode 100644
>> index 0000000..5258edc
>> --- /dev/null
>> +++ b/drivers/spi/ftssp010_spi.h
>> @@ -0,0 +1,86 @@
>> +/*
>> + * Faraday Multi-function Controller - SPI Mode
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for
>> details.
>> + */
>> +
>> +#ifndef _FTSSP010_H
>> +#define _FTSSP010_H
>> +
>> +/* FTSSP010 HW Registers */
>> +struct ftssp010_regs {
>> +       uint32_t cr[3];/* control register */
>> +       uint32_t sr;   /* status register */
>> +       uint32_t icr;  /* interrupt control register */
>> +       uint32_t isr;  /* interrupt status register */
>> +       uint32_t dr;   /* data register */
>> +       uint32_t rsvd[17];
>> +       uint32_t revr; /* revision register */
>> +       uint32_t fear; /* feature register */
>> +};
>> +
>> +/* Control Register 0  */
>> +#define CR0_FFMT_MASK       (7 << 12)
>> +#define CR0_FFMT_SSP        (0 << 12)
>> +#define CR0_FFMT_SPI        (1 << 12)
>> +#define CR0_FFMT_MICROWIRE  (2 << 12)
>> +#define CR0_FFMT_I2S        (3 << 12)
>> +#define CR0_FFMT_AC97       (4 << 12)
>> +#define CR0_FLASH           (1 << 11)
>> +#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
>> +#define CR0_LBM             (1 << 7)  /* Loopback mode */
>> +#define CR0_LSB             (1 << 6)  /* LSB first */
>> +#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
>> +#define CR0_FSJUSTIFY       (1 << 4)
>> +#define CR0_OPM_SLAVE       (0 << 2)
>> +#define CR0_OPM_MASTER      (3 << 2)
>> +#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
>> +#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
>> +#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
>> +#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
>> +#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
>> +#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
>> +
>> +/* Control Register 1 */
>> +
>> +#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
>> +#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
>> +#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
>> +
>> +/* Control Register 2 */
>> +#define CR2_FSOS(x)         (((x) & 0x03) << 10)       /* FS/CS Select */
>> +#define CR2_FS              (1 << 9)   /* FS/CS Signal Level */
>> +#define CR2_TXEN            (1 << 8)   /* Tx Enable */
>> +#define CR2_RXEN            (1 << 7)   /* Rx Enable */
>> +#define CR2_SSPRST          (1 << 6)   /* SSP reset */
>> +#define CR2_TXFCLR          (1 << 3)   /* TX FIFO Clear */
>> +#define CR2_RXFCLR          (1 << 2)   /* RX FIFO Clear */
>> +#define CR2_TXDOE           (1 << 1)   /* TX Data Output Enable */
>> +#define CR2_SSPEN           (1 << 0)   /* SSP Enable */
>> +
>> +/*
>> + * Status Register
>> + */
>> +#define SR_RFF       (1 << 0) /* receive FIFO full */
>> +#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
>> +#define SR_BUSY      (1 << 2) /* bus is busy */
>> +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid
>> entries */
>> +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid
>> entries */
>> +
>> +/*
>> + * Feature Register
>> + */
>> +#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
>> +#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
>> +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
>> +#define FEAR_AC97        (1 << 24)
>> +#define FEAR_I2S         (1 << 25)
>> +#define FEAR_SPI_MWR     (1 << 26)
>> +#define FEAR_SSP         (1 << 27)
>> +#define FEAR_SPDIF       (1 << 28)
>> +
>> +#endif /* EOF */
>
> ---- TAG-
>
> Please use the same defination on driver code itself.
>

Got it, thanks



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v5 00/14] arm: add Faraday A36x SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (10 preceding siblings ...)
  2013-03-29  7:06 ` [U-Boot] [PATCH 11/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-06-17 12:06 ` Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 01/14] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
                     ` (13 more replies)
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                   ` (6 subsequent siblings)
  18 siblings, 14 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

   https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.4.0 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2013.04/u-boot

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (14):
  arm: dma_alloc_coherent: malloc() -> memalign()
  net: ftgmac100: add MMU/D-cache support
  net: add Faraday FTMAC110 10/100Mbps ethernet support
  video: add Faraday FTLCDC200 LCD controller support
  nand: add Faraday FTNANDC021 NAND controller support
  cfi_flash: use buffer length in unmap_physmem()
  arm: add MMU/D-Cache support for Faraday cores
  arm: add Faraday processor core support
  arm: add Faraday FTINTC020 interrupt controller support
  arm: add Faraday FTTMR010 timer support
  arm: add Faraday FTPWMTMR010 timer support
  arm: add Faraday firmware image support
  mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  arm: add Faraday A360/A369 SoC platform support

 MAINTAINERS                                   |    5 +
 README                                        |    6 +
 arch/arm/cpu/faraday/Makefile                 |   58 +++
 arch/arm/cpu/faraday/a360/Makefile            |   49 ++
 arch/arm/cpu/faraday/a369/Makefile            |   50 ++
 arch/arm/cpu/faraday/a369/cmd_fa606.c         |   86 ++++
 arch/arm/cpu/faraday/cmd_bootfa.c             |  143 ++++++
 arch/arm/cpu/faraday/config.mk                |   33 ++
 arch/arm/cpu/faraday/cpu.c                    |  346 ++++++++++++++
 arch/arm/cpu/faraday/ftintc020.c              |  156 +++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c            |  128 +++++
 arch/arm/cpu/faraday/fttmr010.c               |  136 ++++++
 arch/arm/cpu/faraday/fwimage.h                |   47 ++
 arch/arm/cpu/faraday/fwimage2.h               |   67 +++
 arch/arm/cpu/faraday/start.S                  |  431 +++++++++++++++++
 arch/arm/cpu/u-boot.lds                       |   11 +
 arch/arm/include/asm/arch-a360/hardware.h     |   84 ++++
 arch/arm/include/asm/arch-a360/pmu.h          |   54 +++
 arch/arm/include/asm/arch-a360/scu.h          |   48 ++
 arch/arm/include/asm/arch-a369/ahbc.h         |   34 ++
 arch/arm/include/asm/arch-a369/hardware.h     |   99 ++++
 arch/arm/include/asm/arch-a369/scu.h          |  224 +++++++++
 arch/arm/include/asm/arch-faraday/clock.h     |   41 ++
 arch/arm/include/asm/arch-faraday/interrupt.h |   29 ++
 arch/arm/include/asm/dma-mapping.h            |   61 ++-
 arch/arm/include/asm/global_data.h            |    4 +
 arch/arm/include/asm/io.h                     |  160 ++++++-
 arch/arm/include/asm/system.h                 |    7 +-
 arch/arm/lib/cache-cp15.c                     |   12 +
 board/faraday/a360evb/Makefile                |   49 ++
 board/faraday/a360evb/board.c                 |   72 +++
 board/faraday/a360evb/clock.c                 |   72 +++
 board/faraday/a360evb/config.mk               |   33 ++
 board/faraday/a360evb/lowlevel_init.S         |   33 ++
 board/faraday/a369evb/Makefile                |   49 ++
 board/faraday/a369evb/board.c                 |  176 +++++++
 board/faraday/a369evb/clock.c                 |   80 ++++
 board/faraday/a369evb/config.mk               |   33 ++
 board/faraday/a369evb/lowlevel_init.S         |  136 ++++++
 boards.cfg                                    |    3 +
 drivers/mmc/ftsdc010_mci.c                    |    2 +-
 drivers/mtd/cfi_flash.c                       |    2 +-
 drivers/mtd/nand/Makefile                     |    1 +
 drivers/mtd/nand/ftnandc021.c                 |  622 +++++++++++++++++++++++++
 drivers/net/Makefile                          |    1 +
 drivers/net/ftgmac100.c                       |   70 ++-
 drivers/net/ftmac110.c                        |  484 +++++++++++++++++++
 drivers/net/ftmac110.h                        |  188 ++++++++
 drivers/video/Makefile                        |    1 +
 drivers/video/ftlcdc200.c                     |  148 ++++++
 drivers/video/ftlcdc200_panel.c               |  221 +++++++++
 include/common.h                              |    5 +
 include/configs/a360.h                        |   60 +++
 include/configs/a369-common.h                 |   72 +++
 include/configs/a369.h                        |   34 ++
 include/configs/a369_fa606te.h                |   31 ++
 include/configs/faraday-common.h              |  243 ++++++++++
 include/faraday/ftintc020.h                   |   37 ++
 include/faraday/ftlcdc200.h                   |  179 +++++++
 include/faraday/ftnandc021.h                  |  153 ++++++
 include/faraday/ftpwmtmr010.h                 |   41 ++
 include/faraday/ftsmc020.h                    |    1 +
 include/faraday/fttmr010.h                    |   17 +
 include/lcd.h                                 |   33 ++
 include/netdev.h                              |    1 +
 65 files changed, 5956 insertions(+), 36 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftintc020.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 arch/arm/include/asm/arch-faraday/clock.h
 create mode 100644 arch/arm/include/asm/arch-faraday/interrupt.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/faraday/ftintc020.h
 create mode 100644 include/faraday/ftlcdc200.h
 create mode 100644 include/faraday/ftnandc021.h
 create mode 100644 include/faraday/ftpwmtmr010.h

--
1.7.9.5

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

* [U-Boot] [PATCH v5 01/14] arm: dma_alloc_coherent: malloc() -> memalign()
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 02/14] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
                     ` (12 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Even though the MMU/D-cache is off, some DMA engines still
expect strict address alignment.

For example, the incoming Faraday FTMAC110 & FTGMAC100 ethernet
controllers expect the tx/rx descriptors should always be aligned
to 16-bytes boundary.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Initial commit, which is separated from
     "arm: add MMU/D-Cache support for Faraday cores"

 arch/arm/include/asm/dma-mapping.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..a11178f 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -32,7 +32,7 @@ enum dma_data_direction {

 static void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	*handle = (unsigned long)malloc(len);
+	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
 }

--
1.7.9.5

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

* [U-Boot] [PATCH v5 02/14] net: ftgmac100: add MMU/D-cache support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 01/14] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-23  7:16     ` Albert ARIBAUD
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
                     ` (11 subsequent siblings)
  13 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

1. Dynamically allocate the tx/rx descriptors
   through dma_alloc_coherent(), instead of
   allocating at compile/link time.

2. Do not block on ftgmac100_send(), the packet
   has been copied to a safe buffer. Although it's
   a little bit slower, but the tx performance is
   never critical.

3. No matter if MMU/D-cache is on or off, this patch
   always depends on previous patch:

   arm: dma_alloc_coherent: malloc() -> memalign().

   Because the FTGMAC100 expects the tx/rx descriptors
   are always be aligned to 16-bytes boundary.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
CC: Joe Hershberger <joe.hershberger@gmail.com>
CC: Tom Rini <trini@ti.com>
---
Changes for v5:
   - Chain it back to Faraday A360/A369 patch series, because this
     strongly depends on patch to dma_alloc_coherent() at the
     Faraday A360/A369 patch series.

Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series

Changes for v3:
   - Coding Style cleanup

Changes for v2:
   - Coding Style cleanup
   - Cleanup (Drop cosmetic patch)

 drivers/net/ftgmac100.c |   70 +++++++++++++++++++++++++++++++++--------------
 1 file changed, 49 insertions(+), 21 deletions(-)

diff --git a/drivers/net/ftgmac100.c b/drivers/net/ftgmac100.c
index 69ba57d..2dbb328 100644
--- a/drivers/net/ftgmac100.c
+++ b/drivers/net/ftgmac100.c
@@ -27,11 +27,13 @@
 #include <malloc.h>
 #include <net.h>
 #include <asm/io.h>
+#include <asm/dma-mapping.h>
 #include <linux/mii.h>

 #include "ftgmac100.h"

 #define ETH_ZLEN	60
+#define CFG_XBUF_SIZE	1536

 /* RBSR - hw default init value is also 0x640 */
 #define RBSR_DEFAULT_VALUE	0x640
@@ -40,8 +42,10 @@
 #define PKTBUFSTX	4	/* must be power of 2 */

 struct ftgmac100_data {
-	struct ftgmac100_txdes txdes[PKTBUFSTX];
-	struct ftgmac100_rxdes rxdes[PKTBUFSRX];
+	ulong txdes_dma;
+	struct ftgmac100_txdes *txdes;
+	ulong rxdes_dma;
+	struct ftgmac100_rxdes *rxdes;
 	int tx_index;
 	int rx_index;
 	int phy_addr;
@@ -375,13 +379,34 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)
 {
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
-	struct ftgmac100_txdes *txdes = priv->txdes;
-	struct ftgmac100_rxdes *rxdes = priv->rxdes;
+	struct ftgmac100_txdes *txdes;
+	struct ftgmac100_rxdes *rxdes;
 	unsigned int maccr;
+	void *buf;
 	int i;

 	debug("%s()\n", __func__);

+	if (!priv->txdes) {
+		txdes = dma_alloc_coherent(
+			sizeof(*txdes) * PKTBUFSTX, &priv->txdes_dma);
+		if (!txdes)
+			panic("ftgmac100: out of memory\n");
+		memset(txdes, 0, sizeof(*txdes) * PKTBUFSTX);
+		priv->txdes = txdes;
+	}
+	txdes = priv->txdes;
+
+	if (!priv->rxdes) {
+		rxdes = dma_alloc_coherent(
+			sizeof(*rxdes) * PKTBUFSRX, &priv->rxdes_dma);
+		if (!rxdes)
+			panic("ftgmac100: out of memory\n");
+		memset(rxdes, 0, sizeof(*rxdes) * PKTBUFSRX);
+		priv->rxdes = rxdes;
+	}
+	rxdes = priv->rxdes;
+
 	/* set the ethernet address */
 	ftgmac100_set_mac_from_env(dev);

@@ -397,21 +422,31 @@ static int ftgmac100_init(struct eth_device *dev, bd_t *bd)

 	for (i = 0; i < PKTBUFSTX; i++) {
 		/* TXBUF_BADR */
-		txdes[i].txdes3 = 0;
+		if (!txdes[i].txdes2) {
+			buf = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+			if (!buf)
+				panic("ftgmac100: out of memory\n");
+			txdes[i].txdes3 = virt_to_phys(buf);
+			txdes[i].txdes2 = (uint)buf;
+		}
 		txdes[i].txdes1 = 0;
 	}

 	for (i = 0; i < PKTBUFSRX; i++) {
 		/* RXBUF_BADR */
-		rxdes[i].rxdes3 = (unsigned int)NetRxPackets[i];
+		if (!rxdes[i].rxdes2) {
+			buf = NetRxPackets[i];
+			rxdes[i].rxdes3 = virt_to_phys(buf);
+			rxdes[i].rxdes2 = (uint)buf;
+		}
 		rxdes[i].rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
 	}

 	/* transmit ring */
-	writel((unsigned int)txdes, &ftgmac100->txr_badr);
+	writel(priv->txdes_dma, &ftgmac100->txr_badr);

 	/* receive ring */
-	writel((unsigned int)rxdes, &ftgmac100->rxr_badr);
+	writel(priv->rxdes_dma, &ftgmac100->rxr_badr);

 	/* poll receive descriptor automatically */
 	writel(FTGMAC100_APTC_RXPOLL_CNT(1), &ftgmac100->aptc);
@@ -466,8 +501,11 @@ static int ftgmac100_recv(struct eth_device *dev)
 	debug("%s(): RX buffer %d, %x received\n",
 	       __func__, priv->rx_index, rxlen);

+	/* invalidate d-cache */
+	dma_map_single((void *)curr_des->rxdes2, rxlen, DMA_FROM_DEVICE);
+
 	/* pass the packet up to the protocol layers. */
-	NetReceive((void *)curr_des->rxdes3, rxlen);
+	NetReceive((void *)curr_des->rxdes2, rxlen);

 	/* release buffer to DMA */
 	curr_des->rxdes0 &= ~FTGMAC100_RXDES0_RXPKT_RDY;
@@ -485,7 +523,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	struct ftgmac100 *ftgmac100 = (struct ftgmac100 *)dev->iobase;
 	struct ftgmac100_data *priv = dev->priv;
 	struct ftgmac100_txdes *curr_des = &priv->txdes[priv->tx_index];
-	int start;

 	if (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
 		debug("%s(): no TX descriptor available\n", __func__);
@@ -496,8 +533,8 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)

 	length = (length < ETH_ZLEN) ? ETH_ZLEN : length;

-	/* initiate a transmit sequence */
-	curr_des->txdes3 = (unsigned int)packet;	/* TXBUF_BADR */
+	memcpy((void *)curr_des->txdes2, (void *)packet, length);
+	dma_map_single((void *)curr_des->txdes2, length, DMA_TO_DEVICE);

 	/* only one descriptor on TXBUF */
 	curr_des->txdes0 &= FTGMAC100_TXDES0_EDOTR;
@@ -509,15 +546,6 @@ static int ftgmac100_send(struct eth_device *dev, void *packet, int length)
 	/* start transmit */
 	writel(1, &ftgmac100->txpd);

-	/* wait for transfer to succeed */
-	start = get_timer(0);
-	while (curr_des->txdes0 & FTGMAC100_TXDES0_TXDMA_OWN) {
-		if (get_timer(0) >= 5) {
-			debug("%s(): timed out\n", __func__);
-			return -1;
-		}
-	}
-
 	debug("%s(): packet sent\n", __func__);

 	priv->tx_index = (priv->tx_index + 1) % PKTBUFSTX;
--
1.7.9.5

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

* [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 01/14] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 02/14] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-23  7:18     ` Albert ARIBAUD
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 04/14] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
                     ` (10 subsequent siblings)
  13 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTMAC110 10/100Mbps supports half-word data transfer for Linux.
However it has a weird DMA alignment issue:

(1) Tx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: O.K

(2) Rx DMA Buffer Address:
    1 bytes aligned: Invalid
    2 bytes aligned: O.K
    4 bytes aligned: Invalid!!!

NOTE:
No matter if MMU/D-cache is on or off, this patch
always depends on previous patch:

arm: dma_alloc_coherent: malloc() -> memalign().

Because the FTMAC110 expects the tx/rx descriptors
are always be aligned to 16-bytes boundary.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
CC: Joe Hershberger <joe.hershberger@gmail.com>
CC: Tom Rini <trini@ti.com>
---
Changes for v5:
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - Chain it back to Faraday A360/A369 patch series, because this
     strongly depends on patch to dma_alloc_coherent() at the
     Faraday A360/A369 patch series.

Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Use macro constants for timeout control
   - Use only named constants for bit mask/shift and values
   - Drop the magic number from mdio read/write.

Changes for v3:
   - Coding Style cleanup.
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Make a correction to multi-line comment style
   - Use random MAC address while having trouble
     to get one from environment variables.
   - Add comments to timing control registers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - ftmac110: Remove debug codes.

 drivers/net/Makefile   |    1 +
 drivers/net/ftmac110.c |  484 ++++++++++++++++++++++++++++++++++++++++++++++++
 drivers/net/ftmac110.h |  188 +++++++++++++++++++
 include/netdev.h       |    1 +
 4 files changed, 674 insertions(+)
 create mode 100644 drivers/net/ftmac110.c
 create mode 100644 drivers/net/ftmac110.h

diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 786a656..0e23817 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -46,6 +46,7 @@ COBJS-$(CONFIG_ETHOC) += ethoc.o
 COBJS-$(CONFIG_FEC_MXC) += fec_mxc.o
 COBJS-$(CONFIG_FSLDMAFEC) += fsl_mcdmafec.o mcfmii.o
 COBJS-$(CONFIG_FTGMAC100) += ftgmac100.o
+COBJS-$(CONFIG_FTMAC110) += ftmac110.o
 COBJS-$(CONFIG_FTMAC100) += ftmac100.o
 COBJS-$(CONFIG_GRETH) += greth.o
 COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-ip_sw.o
diff --git a/drivers/net/ftmac110.c b/drivers/net/ftmac110.c
new file mode 100644
index 0000000..1afd95a
--- /dev/null
+++ b/drivers/net/ftmac110.c
@@ -0,0 +1,484 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <net.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/dma-mapping.h>
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+#include <miiphy.h>
+#endif
+
+#include "ftmac110.h"
+
+#define CFG_RXDES_NUM   8
+#define CFG_TXDES_NUM   2
+#define CFG_XBUF_SIZE   1536
+
+#define CFG_MDIORD_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_MDIOWR_TIMEOUT  (CONFIG_SYS_HZ >> 1) /* 500 ms */
+#define CFG_LINKUP_TIMEOUT  (CONFIG_SYS_HZ << 2) /* 4 sec */
+
+/*
+ * FTMAC110 DMA design issue
+ *
+ * Its DMA engine has a weird restriction that its Rx DMA engine
+ * accepts only 16-bits aligned address, 32-bits aligned is not
+ * acceptable. However this restriction does not apply to Tx DMA.
+ *
+ * Conclusion:
+ * (1) Tx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: O.K (-> u-boot ZeroCopy is possible)
+ * (2) Rx DMA Buffer Address:
+ *     1 bytes aligned: Invalid
+ *     2 bytes aligned: O.K
+ *     4 bytes aligned: Invalid
+ */
+
+struct ftmac110_chip {
+	void __iomem *regs;
+	uint32_t imr;
+	uint32_t maccr;
+	uint32_t lnkup;
+	uint32_t phy_addr;
+
+	struct ftmac110_rxd *rxd;
+	ulong                rxd_dma;
+	uint32_t             rxd_idx;
+
+	struct ftmac110_txd *txd;
+	ulong                txd_dma;
+	uint32_t             txd_idx;
+};
+
+static int ftmac110_reset(struct eth_device *dev);
+
+static uint16_t mdio_read(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+	uint16_t ret = 0xffff;
+
+	tmp = PHYCR_READ
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT);
+
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_MDIORD_TIMEOUT; ) {
+		tmp = readl(&regs->phycr);
+		if (tmp & PHYCR_READ)
+			continue;
+		break;
+	}
+
+	if (tmp & PHYCR_READ)
+		printf("ftmac110: mdio read timeout\n");
+	else
+		ret = (uint16_t)(tmp & 0xffff);
+
+	return ret;
+}
+
+static void mdio_write(struct eth_device *dev,
+	uint8_t phyaddr, uint8_t phyreg, uint16_t phydata)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+	uint32_t tmp, ts;
+
+	tmp = PHYCR_WRITE
+		| (phyaddr << PHYCR_ADDR_SHIFT)
+		| (phyreg  << PHYCR_REG_SHIFT);
+
+	writel(phydata, &regs->phydr);
+	writel(tmp, &regs->phycr);
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_MDIOWR_TIMEOUT; ) {
+		if (readl(&regs->phycr) & PHYCR_WRITE)
+			continue;
+		break;
+	}
+
+	if (readl(&regs->phycr) & PHYCR_WRITE)
+		printf("ftmac110: mdio write timeout\n");
+}
+
+static uint32_t ftmac110_phyqry(struct eth_device *dev)
+{
+	ulong ts;
+	uint32_t maccr;
+	uint16_t pa, tmp, bmsr, bmcr;
+	struct ftmac110_chip *chip = dev->priv;
+
+	/* Default = 100Mbps Full */
+	maccr = MACCR_100M | MACCR_FD;
+
+	/* 1. find the phy device  */
+	for (pa = 0; pa < 32; ++pa) {
+		tmp = mdio_read(dev, pa, MII_PHYSID1);
+		if (tmp == 0xFFFF || tmp == 0x0000)
+			continue;
+		chip->phy_addr = pa;
+		break;
+	}
+	if (pa >= 32) {
+		puts("ftmac110: phy device not found!\n");
+		goto exit;
+	}
+
+	/* 2. wait until link-up & auto-negotiation complete */
+	chip->lnkup = 0;
+	bmcr = mdio_read(dev, chip->phy_addr, MII_BMCR);
+	ts = get_timer(0);
+	do {
+		bmsr = mdio_read(dev, chip->phy_addr, MII_BMSR);
+		chip->lnkup = (bmsr & BMSR_LSTATUS) ? 1 : 0;
+		if (!chip->lnkup)
+			continue;
+		if (!(bmcr & BMCR_ANENABLE) || (bmsr & BMSR_ANEGCOMPLETE))
+			break;
+	} while (get_timer(ts) < CFG_LINKUP_TIMEOUT);
+	if (!chip->lnkup) {
+		puts("ftmac110: link down\n");
+		goto exit;
+	}
+	if (!(bmcr & BMCR_ANENABLE))
+		puts("ftmac110: auto negotiation disabled\n");
+	else if (!(bmsr & BMSR_ANEGCOMPLETE))
+		puts("ftmac110: auto negotiation timeout\n");
+
+	/* 3. derive MACCR */
+	if ((bmcr & BMCR_ANENABLE) && (bmsr & BMSR_ANEGCOMPLETE)) {
+		tmp  = mdio_read(dev, chip->phy_addr, MII_ADVERTISE);
+		tmp &= mdio_read(dev, chip->phy_addr, MII_LPA);
+		if (tmp & LPA_100FULL)      /* 100Mbps full-duplex */
+			maccr = MACCR_100M | MACCR_FD;
+		else if (tmp & LPA_100HALF) /* 100Mbps half-duplex */
+			maccr = MACCR_100M;
+		else if (tmp & LPA_10FULL)  /* 10Mbps full-duplex */
+			maccr = MACCR_FD;
+		else if (tmp & LPA_10HALF)  /* 10Mbps half-duplex */
+			maccr = 0;
+	} else {
+		if (bmcr & BMCR_SPEED100)
+			maccr = MACCR_100M;
+		else
+			maccr = 0;
+		if (bmcr & BMCR_FULLDPLX)
+			maccr |= MACCR_FD;
+	}
+
+exit:
+	printf("ftmac110: %d Mbps, %s\n",
+		   (maccr & MACCR_100M) ? 100 : 10,
+		   (maccr & MACCR_FD) ? "Full" : "half");
+	return maccr;
+}
+
+static int ftmac110_reset(struct eth_device *dev)
+{
+	uint8_t *a;
+	uint32_t i, maccr;
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+
+	/* 1. MAC reset */
+	writel(MACCR_RESET, &regs->maccr);
+	for (i = get_timer(0); get_timer(i) < 1000; ) {
+		if (readl(&regs->maccr) & MACCR_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->maccr) & MACCR_RESET) {
+		printf("ftmac110: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* 1-1. Init tx ring */
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		/* owned by SW */
+		chip->txd[i].ct[0] = 0;
+	}
+	chip->txd_idx = 0;
+
+	/* 1-2. Init rx ring */
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		/* owned by HW */
+		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+	}
+	chip->rxd_idx = 0;
+
+	/* 2. PHY status query */
+	maccr = ftmac110_phyqry(dev);
+
+	/* 3. Fix up the MACCR value */
+	chip->maccr = maccr | MACCR_CRCAPD | MACCR_RXALL | MACCR_RXRUNT
+		| MACCR_RXEN | MACCR_TXEN | MACCR_RXDMAEN | MACCR_TXDMAEN;
+
+	/* 4. MAC address setup */
+	a = dev->enetaddr;
+	writel(a[1] | (a[0] << 8), &regs->mac[0]);
+	writel(a[5] | (a[4] << 8) | (a[3] << 16)
+		| (a[2] << 24), &regs->mac[1]);
+
+	/* 5. MAC registers setup */
+	writel(chip->rxd_dma, &regs->rxba);
+	writel(chip->txd_dma, &regs->txba);
+	/* interrupt at each tx/rx */
+	writel(ITC_DEFAULT, &regs->itc);
+	/* no tx pool, rx poll = 1 normal cycle */
+	writel(APTC_DEFAULT, &regs->aptc);
+	/* rx threshold = [6/8 fifo, 2/8 fifo] */
+	writel(DBLAC_DEFAULT, &regs->dblac);
+	/* disable & clear all interrupt status */
+	chip->imr = 0;
+	writel(ISR_ALL, &regs->isr);
+	writel(chip->imr, &regs->imr);
+	/* enable mac */
+	writel(chip->maccr, &regs->maccr);
+
+	return 0;
+}
+
+static int ftmac110_probe(struct eth_device *dev, bd_t *bis)
+{
+	debug("ftmac110: probe\n");
+
+	if (ftmac110_reset(dev))
+		return -1;
+
+	return 0;
+}
+
+static void ftmac110_halt(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+
+	writel(0, &regs->imr);
+	writel(0, &regs->maccr);
+
+	debug("ftmac110: halt\n");
+}
+
+static int ftmac110_send(struct eth_device *dev, void *pkt, int len)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_regs *regs = chip->regs;
+	struct ftmac110_txd *des;
+
+	if (!chip->lnkup)
+		return 0;
+
+	if (len <= 0 || len > CFG_XBUF_SIZE) {
+		printf("ftmac110: bad tx pkt len(%d)\n", len);
+		return 0;
+	}
+
+	len = max(60, len);
+
+	des = &chip->txd[chip->txd_idx];
+	if (le32_to_cpu(des->ct[0]) & FTMAC110_TXCT0_OWNER) {
+		/* kick-off Tx DMA */
+		writel(0xffffffff, &regs->txpd);
+		printf("ftmac110: out of txd\n");
+		return 0;
+	}
+
+	memcpy(des->vbuf, (void *)pkt, len);
+	dma_map_single(des->vbuf, len, DMA_TO_DEVICE);
+
+	/* update len, fts and lts */
+	des->ct[1] &= cpu_to_le32(FTMAC110_TXCT1_END);
+	des->ct[1] |= cpu_to_le32(FTMAC110_TXCT1_LEN(len)
+		| FTMAC110_TXCT1_FTS | FTMAC110_TXCT1_LTS);
+
+	/* set owner bit and clear others */
+	des->ct[0] = cpu_to_le32(FTMAC110_TXCT0_OWNER);
+
+	/* kick-off Tx DMA */
+	writel(0xffffffff, &regs->txpd);
+
+	chip->txd_idx = (chip->txd_idx + 1) % CFG_TXDES_NUM;
+
+	return len;
+}
+
+static int ftmac110_recv(struct eth_device *dev)
+{
+	struct ftmac110_chip *chip = dev->priv;
+	struct ftmac110_rxd *des;
+	uint32_t ct0, len, rlen = 0;
+	uint8_t *buf;
+
+	if (!chip->lnkup)
+		return 0;
+
+	do {
+		des = &chip->rxd[chip->rxd_idx];
+		ct0 = le32_to_cpu(des->ct[0]);
+		if (ct0 & FTMAC110_RXCT0_OWNER)
+			break;
+
+		len = FTMAC110_RXCT0_LEN(ct0);
+		buf = des->vbuf;
+
+		if (ct0 & FTMAC110_RXCT0_ERRMASK) {
+			printf("ftmac110: rx error\n");
+		} else {
+			dma_map_single(buf, len, DMA_FROM_DEVICE);
+			NetReceive(buf, len);
+			rlen += len;
+		}
+
+		/* owned by hardware */
+		des->ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+
+		chip->rxd_idx = (chip->rxd_idx + 1) % CFG_RXDES_NUM;
+	} while (0);
+
+	return rlen;
+}
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+
+static int ftmac110_mdio_read(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t *value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		*value = mdio_read(dev, addr, reg);
+	}
+
+	return ret;
+}
+
+static int ftmac110_mdio_write(
+	const char *devname, uint8_t addr, uint8_t reg, uint16_t value)
+{
+	int ret = 0;
+	struct eth_device *dev;
+
+	dev = eth_get_dev_by_name(devname);
+	if (dev == NULL) {
+		printf("%s: no such device\n", devname);
+		ret = -1;
+	} else {
+		mdio_write(dev, addr, reg, value);
+	}
+
+	return ret;
+}
+
+#endif    /* #if defined(CONFIG_MII) || defined(CONFIG_CMD_MII) */
+
+int ftmac110_initialize(bd_t *bis)
+{
+	int i, card_nr = 0;
+	struct eth_device *dev;
+	struct ftmac110_chip *chip;
+
+	dev = malloc(sizeof(*dev) + sizeof(*chip));
+	if (dev == NULL) {
+		panic("ftmac110: out of memory 1\n");
+		return -1;
+	}
+	chip = (struct ftmac110_chip *)(dev + 1);
+	memset(dev, 0, sizeof(*dev) + sizeof(*chip));
+
+	sprintf(dev->name, "FTMAC110#%d", card_nr);
+
+	dev->iobase = CONFIG_FTMAC110_BASE;
+	chip->regs = (void __iomem *)dev->iobase;
+	dev->priv = chip;
+	dev->init = ftmac110_probe;
+	dev->halt = ftmac110_halt;
+	dev->send = ftmac110_send;
+	dev->recv = ftmac110_recv;
+
+	if (!eth_getenv_enetaddr_by_index("eth", card_nr, dev->enetaddr))
+		eth_random_enetaddr(dev->enetaddr);
+
+	/* allocate tx descriptors (it must be 16 bytes aligned) */
+	chip->txd = dma_alloc_coherent(
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM, &chip->txd_dma);
+	if (!chip->txd)
+		panic("ftmac110: out of memory 3\n");
+	memset(chip->txd, 0,
+		sizeof(struct ftmac110_txd) * CFG_TXDES_NUM);
+	for (i = 0; i < CFG_TXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE);
+		if (!va)
+			panic("ftmac110: out of memory 4\n");
+		chip->txd[i].vbuf  = va;
+		chip->txd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->txd[i].ct[1] = 0;
+		chip->txd[i].ct[0] = 0; /* owned by SW */
+	}
+	chip->txd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_TXCT1_END);
+	chip->txd_idx = 0;
+
+	/* allocate rx descriptors (it must be 16 bytes aligned) */
+	chip->rxd = dma_alloc_coherent(
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM, &chip->rxd_dma);
+	if (!chip->rxd)
+		panic("ftmac110: out of memory 4\n");
+	memset((void *)chip->rxd, 0,
+		sizeof(struct ftmac110_rxd) * CFG_RXDES_NUM);
+	for (i = 0; i < CFG_RXDES_NUM; ++i) {
+		void *va = memalign(ARCH_DMA_MINALIGN, CFG_XBUF_SIZE + 2);
+		if (!va)
+			panic("ftmac110: out of memory 5\n");
+		/* it needs to be exactly 2 bytes aligned */
+		va = ((uint8_t *)va + 2);
+		chip->rxd[i].vbuf  = va;
+		chip->rxd[i].buf   = cpu_to_le32(virt_to_phys(va));
+		chip->rxd[i].ct[1] = cpu_to_le32(CFG_XBUF_SIZE);
+		chip->rxd[i].ct[0] = cpu_to_le32(FTMAC110_RXCT0_OWNER);
+	}
+	chip->rxd[i - 1].ct[1] |= cpu_to_le32(FTMAC110_RXCT1_END);
+	chip->rxd_idx = 0;
+
+	eth_register(dev);
+
+#if defined(CONFIG_MII) || defined(CONFIG_CMD_MII)
+	miiphy_register(dev->name, ftmac110_mdio_read, ftmac110_mdio_write);
+#endif
+
+	card_nr++;
+
+	return card_nr;
+}
diff --git a/drivers/net/ftmac110.h b/drivers/net/ftmac110.h
new file mode 100644
index 0000000..4bb8b76
--- /dev/null
+++ b/drivers/net/ftmac110.h
@@ -0,0 +1,188 @@
+/*
+ * Faraday 10/100Mbps Ethernet Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _FTMAC110_H
+#define _FTMAC110_H
+
+struct ftmac110_regs {
+	uint32_t isr;    /* 0x00: Interrups Status Register */
+	uint32_t imr;    /* 0x04: Interrupt Mask Register */
+	uint32_t mac[2]; /* 0x08: MAC Address */
+	uint32_t mht[2]; /* 0x10: Multicast Hash Table Register */
+	uint32_t txpd;   /* 0x18: Tx Poll Demand Register */
+	uint32_t rxpd;   /* 0x1c: Rx Poll Demand Register */
+	uint32_t txba;   /* 0x20: Tx Ring Base Address Register */
+	uint32_t rxba;   /* 0x24: Rx Ring Base Address Register */
+	uint32_t itc;    /* 0x28: Interrupt Timer Control Register */
+	uint32_t aptc;   /* 0x2C: Automatic Polling Timer Control Register */
+	uint32_t dblac;  /* 0x30: DMA Burst Length&Arbitration Control */
+	uint32_t revr;   /* 0x34: Revision Register */
+	uint32_t fear;   /* 0x38: Feature Register */
+	uint32_t rsvd[19];
+	uint32_t maccr;  /* 0x88: MAC Control Register */
+	uint32_t macsr;  /* 0x8C: MAC Status Register */
+	uint32_t phycr;  /* 0x90: PHY Control Register */
+	uint32_t phydr;  /* 0x94: PHY Data Register */
+	uint32_t fcr;    /* 0x98: Flow Control Register */
+	uint32_t bpr;    /* 0x9C: Back Pressure Register */
+};
+
+/*
+ * Interrupt status/mask register(ISR/IMR) bits
+ */
+#define ISR_ALL          0x3ff
+#define ISR_PHYSTCHG     (1 << 9) /* phy status change */
+#define ISR_AHBERR       (1 << 8) /* bus error */
+#define ISR_RXLOST       (1 << 7) /* rx lost */
+#define ISR_RXFIFO       (1 << 6) /* rx to fifo */
+#define ISR_TXLOST       (1 << 5) /* tx lost */
+#define ISR_TXOK         (1 << 4) /* tx to ethernet */
+#define ISR_NOTXBUF      (1 << 3) /* out of tx buffer */
+#define ISR_TXFIFO       (1 << 2) /* tx to fifo */
+#define ISR_NORXBUF      (1 << 1) /* out of rx buffer */
+#define ISR_RXOK         (1 << 0) /* rx to buffer */
+
+/*
+ * MACCR control bits
+ */
+#define MACCR_100M       (1 << 18) /* 100Mbps mode */
+#define MACCR_RXBCST     (1 << 17) /* rx broadcast packet */
+#define MACCR_RXMCST     (1 << 16) /* rx multicast packet */
+#define MACCR_FD         (1 << 15) /* full duplex */
+#define MACCR_CRCAPD     (1 << 14) /* tx crc append */
+#define MACCR_RXALL      (1 << 12) /* rx all packets */
+#define MACCR_RXFTL      (1 << 11) /* rx packet even it's > 1518 byte */
+#define MACCR_RXRUNT     (1 << 10) /* rx packet even it's < 64 byte */
+#define MACCR_RXMCSTHT   (1 << 9)  /* rx multicast hash table */
+#define MACCR_RXEN       (1 << 8)  /* rx enable */
+#define MACCR_RXINHDTX   (1 << 6)  /* rx in half duplex tx */
+#define MACCR_TXEN       (1 << 5)  /* tx enable */
+#define MACCR_CRCDIS     (1 << 4)  /* tx packet even it's crc error */
+#define MACCR_LOOPBACK   (1 << 3)  /* loop-back */
+#define MACCR_RESET      (1 << 2)  /* reset */
+#define MACCR_RXDMAEN    (1 << 1)  /* rx dma enable */
+#define MACCR_TXDMAEN    (1 << 0)  /* tx dma enable */
+
+/*
+ * PHYCR control bits
+ */
+#define PHYCR_READ       (1 << 26)
+#define PHYCR_WRITE      (1 << 27)
+#define PHYCR_REG_SHIFT  21
+#define PHYCR_ADDR_SHIFT 16
+
+/*
+ * ITC control bits
+ */
+
+/* Tx Cycle Length */
+#define ITC_TX_CYCLONG   (1 << 15) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_TX_CYCNORM   (0 << 15) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_TX_THR(n)    (((n) & 0x7) << 12)
+/* Tx Interrupt Timeout = n * Tx Cycle */
+#define ITC_TX_ITMO(n)   (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define ITC_RX_CYCLONG   (1 << 7)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define ITC_RX_CYCNORM   (0 << 7)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Threshold: Aggregate n interrupts as 1 interrupt */
+#define ITC_RX_THR(n)    (((n) & 0x7) << 4)
+/* Rx Interrupt Timeout = n * Rx Cycle */
+#define ITC_RX_ITMO(n)   (((n) & 0xf) << 0)
+
+#define ITC_DEFAULT \
+	(ITC_TX_THR(1) | ITC_TX_ITMO(0) | ITC_RX_THR(1) | ITC_RX_ITMO(0))
+
+/*
+ * APTC contrl bits
+ */
+
+/* Tx Cycle Length */
+#define APTC_TX_CYCLONG  (1 << 12) /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_TX_CYCNORM  (0 << 12) /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Tx Poll Timeout = n * Tx Cycle, 0=No auto polling */
+#define APTC_TX_PTMO(n)  (((n) & 0xf) << 8)
+/* Rx Cycle Length */
+#define APTC_RX_CYCLONG  (1 << 4)  /* 100Mbps=81.92us; 10Mbps=819.2us */
+#define APTC_RX_CYCNORM  (0 << 4)  /* 100Mbps=5.12us;  10Mbps=51.2us */
+/* Rx Poll Timeout = n * Rx Cycle, 0=No auto polling */
+#define APTC_RX_PTMO(n)  (((n) & 0xf) << 0)
+
+#define APTC_DEFAULT     (APTC_TX_PTMO(0) | APTC_RX_PTMO(1))
+
+/*
+ * DBLAC contrl bits
+ */
+#define DBLAC_BURST_MAX_ANY  (0 << 14) /* un-limited */
+#define DBLAC_BURST_MAX_32X4 (2 << 14) /* max = 32 x 4 bytes */
+#define DBLAC_BURST_MAX_64X4 (3 << 14) /* max = 64 x 4 bytes */
+#define DBLAC_RXTHR_EN       (1 << 9)  /* enable rx threshold arbitration */
+#define DBLAC_RXTHR_HIGH(n)  (((n) & 0x7) << 6) /* upper bound = n/8 fifo */
+#define DBLAC_RXTHR_LOW(n)   (((n) & 0x7) << 3) /* lower bound = n/8 fifo */
+#define DBLAC_BURST_CAP16    (1 << 2)  /* support burst 16 */
+#define DBLAC_BURST_CAP8     (1 << 1)  /* support burst 8 */
+#define DBLAC_BURST_CAP4     (1 << 0)  /* support burst 4 */
+
+#define DBLAC_DEFAULT \
+	(DBLAC_RXTHR_EN | DBLAC_RXTHR_HIGH(6) | DBLAC_RXTHR_LOW(2))
+
+/*
+ * descriptor structure
+ */
+struct ftmac110_rxd {
+	uint32_t ct[2];
+	uint32_t buf;
+	void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_RXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_RXCT0_FRS         BIT_MASK(29) /* first pkt desc */
+#define FTMAC110_RXCT0_LRS         BIT_MASK(28) /* last pkt desc */
+#define FTMAC110_RXCT0_ODDNB       BIT_MASK(22) /* odd nibble */
+#define FTMAC110_RXCT0_RUNT        BIT_MASK(21) /* runt pkt */
+#define FTMAC110_RXCT0_FTL         BIT_MASK(20) /* frame too long */
+#define FTMAC110_RXCT0_CRC         BIT_MASK(19) /* pkt crc error */
+#define FTMAC110_RXCT0_ERR         BIT_MASK(18) /* bus error */
+#define FTMAC110_RXCT0_ERRMASK     (0x1f << 18) /* all errors */
+#define FTMAC110_RXCT0_BCST        BIT_MASK(17) /* Bcst pkt */
+#define FTMAC110_RXCT0_MCST        BIT_MASK(16) /* Mcst pkt */
+#define FTMAC110_RXCT0_LEN(x)      ((x) & 0x7ff)
+
+#define FTMAC110_RXCT1_END         BIT_MASK(31)
+#define FTMAC110_RXCT1_BUFSZ(x)    ((x) & 0x7ff)
+
+struct ftmac110_txd {
+	uint32_t ct[2];
+	uint32_t buf;
+	void    *vbuf; /* reserved */
+};
+
+#define FTMAC110_TXCT0_OWNER       BIT_MASK(31) /* owner: 1=HW, 0=SW */
+#define FTMAC110_TXCT0_COL         0x00000003   /* collision */
+
+#define FTMAC110_TXCT1_END         BIT_MASK(31) /* end of ring */
+#define FTMAC110_TXCT1_TXIC        BIT_MASK(30) /* tx done interrupt */
+#define FTMAC110_TXCT1_TX2FIC      BIT_MASK(29) /* tx fifo interrupt */
+#define FTMAC110_TXCT1_FTS         BIT_MASK(28) /* first pkt desc */
+#define FTMAC110_TXCT1_LTS         BIT_MASK(27) /* last pkt desc */
+#define FTMAC110_TXCT1_LEN(x)      ((x) & 0x7ff)
+
+#endif  /* FTMAC110_H */
diff --git a/include/netdev.h b/include/netdev.h
index df454b5..c8d3b62 100644
--- a/include/netdev.h
+++ b/include/netdev.h
@@ -67,6 +67,7 @@ int fecmxc_initialize(bd_t *bis);
 int fecmxc_initialize_multi(bd_t *bis, int dev_id, int phy_id, uint32_t addr);
 int ftgmac100_initialize(bd_t *bits);
 int ftmac100_initialize(bd_t *bits);
+int ftmac110_initialize(bd_t *bits);
 int greth_initialize(bd_t *bis);
 void gt6426x_eth_initialize(bd_t *bis);
 int inca_switch_initialize(bd_t *bis);
--
1.7.9.5

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

* [U-Boot] [PATCH v5 04/14] video: add Faraday FTLCDC200 LCD controller support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
                     ` (9 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTLCDC200 Color LCD controller performs translation of
pixel-coded data into the required formats and timings to
drive a variety of single/dual mono and color LCDs.

Depending on the LCD type and mode, the unpacked data can represent:
   1. an actual true display gray or color value
   2. an address to a 256 x 16 bit wide palette RAM gray or color value.

The FTLCDC200 generates 4 individual interrupts for:
   1. DMA FIFO underflow
   2. base address update
   3. vertical status
   4. bus error.

There is also a single combined interrupt that is raised when any of
the individual interrupts become active.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Anatolij Gustschin <agust@denx.de>
---
Changes for v5:
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - Chain it back to Faraday A360/A369 patch series, because
     Faraday A369 depends on the header file of this patch
     for I2C work-around.(Enable I2C clock to prevent I2C bus hangs)

Changes for v4:
   - Nothing updates

Changes for v3:
   - Nothing updates

Changes for v2:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series

 drivers/video/Makefile          |    1 +
 drivers/video/ftlcdc200.c       |  148 ++++++++++++++++++++++++++
 drivers/video/ftlcdc200_panel.c |  221 +++++++++++++++++++++++++++++++++++++++
 include/faraday/ftlcdc200.h     |  179 +++++++++++++++++++++++++++++++
 include/lcd.h                   |   33 ++++++
 5 files changed, 582 insertions(+)
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/faraday/ftlcdc200.h

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 68ff34b..92ab9d1 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
 				exynos_mipi_dsi_lowlevel.o
 COBJS-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o
 COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
+COBJS-$(CONFIG_FTLCDC200) += ftlcdc200.o ftlcdc200_panel.o
 COBJS-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o
 COBJS-$(CONFIG_PXA_LCD) += pxa_lcd.o
 COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o
diff --git a/drivers/video/ftlcdc200.c b/drivers/video/ftlcdc200.c
new file mode 100644
index 0000000..331a35f
--- /dev/null
+++ b/drivers/video/ftlcdc200.c
@@ -0,0 +1,148 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+#ifndef CONFIG_FTLCDC200_FREQ
+#define CONFIG_FTLCDC200_FREQ	clock_get_rate(AHB_CLK)
+#endif
+
+static struct ftlcdc200_regs *regs = (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+static void ftlcdc2xx_fixup(struct vidinfo *panel)
+{
+	u_long ht, vt;
+	u_long div, clk;
+	long fps = 60;
+	long upper = 32767;
+	long lower = -32767;
+
+	if (panel->vl_fps)
+		return;
+
+	/* If it's serial mode */
+	if (panel->vl_serial & SPPR_SERIAL)
+		clk = CONFIG_FTLCDC200_FREQ / 3;
+	else
+		clk = CONFIG_FTLCDC200_FREQ;
+
+	/* Derive clock divisor */
+	ht = panel->vl_col + panel->vl_hbp + panel->vl_hfp + panel->vl_hsw;
+	vt = panel->vl_row + panel->vl_vbp + panel->vl_vfp + panel->vl_vsw;
+	for (div = 1; div <= 0x7f; ++div) {
+		long tmp = (clk / div / ht / vt);
+		if (fps > tmp) {
+			lower = tmp;
+			break;
+		}
+		upper = tmp;
+	}
+	if ((upper - fps) > (fps - lower))
+		div += 1;
+	div = (div > 1) ? (div - 1) : div;
+
+	/* Update hardware register cache */
+	panel->vl_polarity = (panel->vl_polarity & (~0x7f00))
+		| ((div - 1) << 8);
+
+	/* Derive real frame rate */
+	panel->vl_fps = (u_long)(clk / div / ht / vt);
+
+	debug("ftlcdc200: %s\n", panel->vl_name);
+	debug("ftlcdc200: fps=%u (%u < FPS < %u)\n",
+		   (unsigned int)panel->vl_fps,
+		   (unsigned int)lower,
+		   (unsigned int)upper);
+	debug("ftlcdc200: div=%u (ahb=%u MHz)\n",
+		   (unsigned int)div,
+		   (unsigned int)CONFIG_FTLCDC200_FREQ / 1000000);
+}
+
+/* setcolreg used in 8bpp/16bpp */
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+/* initcolregs used in monochrome */
+void lcd_initcolregs(void)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+	uint32_t i, v;
+
+	/*
+	 * initialize the contrast lookup table and the Red, Green, Blue
+	 * gamma lookup table, fill the straight line x-y=0 to the contrast
+	 * and gamma lookup table
+	 */
+	for (i = 0; i < 64; i++) {
+		v = 0x03020100 + 0x04040404 * i;
+		writel(v, &regs->gamma_r[i]);
+		writel(v, &regs->gamma_g[i]);
+		writel(v, &regs->gamma_b[i]);
+	}
+
+	writel(virt_to_phys(lcdbase), &regs->fb0);
+
+	debug("ftlcdc200: fb_base=0x%08X at 0x%08X\n",
+		(uint32_t)lcdbase, readl(&regs->fb0));
+}
+
+void lcd_enable(void)
+{
+	struct vidinfo *panel = &panel_info;
+
+	/* 1. derive the clock parameters at runtime */
+	ftlcdc2xx_fixup(panel);
+	/* 2. disable lcd */
+	writel(0, &regs->fer);
+	/* 3. setup panel parameters */
+	writel(panel->vl_pixel, &regs->ppr);
+	writel(HTCR_PL(panel->vl_col) | HTCR_HSYNC(panel->vl_hsw)
+		| HTCR_HBP(panel->vl_hbp) | HTCR_HFP(panel->vl_hfp),
+		&regs->htcr);
+	writel(VTCR0_LF(panel->vl_row) | VTCR0_VSYNC(panel->vl_vsw)
+		| VTCR0_VFP(panel->vl_vfp), &regs->vtcr[0]);
+	writel(VTCR1_VBP(panel->vl_vbp), &regs->vtcr[1]);
+	writel(panel->vl_polarity, &regs->pcr);
+	writel(panel->vl_serial, &regs->sppr);
+	writel(panel->vl_ccir656, &regs->ccir);
+	/* 4. default 4 cycles delay for all framebuffer */
+	writel(0x04040404, &regs->fifo);
+	/* 5. disable & clean interrupts */
+	writel(0x00, &regs->ier);
+	writel(0x0f, &regs->iscr);
+	/* 6. enable lcd */
+	writel(panel->vl_enable, &regs->fer);
+}
+
+ulong calc_fbsize(void)
+{
+	return ((panel_info.vl_col * panel_info.vl_row *
+			 NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
+}
diff --git a/drivers/video/ftlcdc200_panel.c b/drivers/video/ftlcdc200_panel.c
new file mode 100644
index 0000000..43b38c7
--- /dev/null
+++ b/drivers/video/ftlcdc200_panel.c
@@ -0,0 +1,221 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+struct vidinfo panel_info = {
+#if defined(CONFIG_FTLCDC200_320X240P_SHARP)
+	.vl_name  = "SHARP-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x10,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x10,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0f,
+	.vl_vbp   = 0x07,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBLP,
+	.vl_polarity = POL_DIV(23) | POL_IHS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240P_AUO)
+	.vl_name  = "AUO-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PWROFF,
+	.vl_polarity = POL_DIV(21) | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240S_AUO)
+	.vl_name  = "AUO-320x240s",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(1),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_640X480P_PV)
+	.vl_name  = "PV-640x480p",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x63,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2D,
+	.vl_vsw   = 0x44,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(6) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480S_TPO)
+	.vl_name  = "TPO-800x480s",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x01,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(1) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(0),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_TPO)
+	.vl_name  = "TPO-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x04,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0xD4,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x0A,
+	.vl_vbp   = 0x22,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_CPT)
+	/* Chunghwa Picture Tubes - CLAA048LA0BCT */
+	.vl_name  = "CPT-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x32,
+	.vl_hbp   = 0x31,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0E,
+	.vl_vbp   = 0x05,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X600_VGA)
+	.vl_name  = "D-SUB: VGA-800x600",
+	.vl_col   = 800,
+	.vl_row   = 600,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(3) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_1024X768_VGA)
+	.vl_name  = "D-SUB: VGA-1024x768",
+	.vl_col   = 1024,
+	.vl_row   = 768,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(2) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_720X480_NTSC)
+	.vl_name  = "A/V: NTSC-720x480",
+	.vl_col   = 720,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x06,
+	.vl_hfp   = 0x7D,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x0F,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1A,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 3,
+#elif defined(CONFIG_FTLCDC200_640X480_NTSC)
+	.vl_name  = "A/V: NTSC-640x480",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x02,
+	.vl_hfp   = 0xD1,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x10,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x19,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 1,
+#else
+#error "Please specific target LCD panel."
+#endif
+};
diff --git a/include/faraday/ftlcdc200.h b/include/faraday/ftlcdc200.h
new file mode 100644
index 0000000..35f19b7
--- /dev/null
+++ b/include/faraday/ftlcdc200.h
@@ -0,0 +1,179 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTLCDC200_H
+#define __FTLCDC200_H
+
+/* FTLCDC200 Registers */
+struct ftlcdc200_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t fer;  /* 0x000: Function Enable Register */
+	uint32_t ppr;  /* 0x004: Panel Pixel Register */
+	uint32_t ier;  /* 0x008: Interrupt Enable Register */
+	uint32_t iscr; /* 0x00C: Interrupt Status Clear Register */
+	uint32_t isr;  /* 0x010: Interrupt Status Register */
+	uint32_t rsvd0[1];
+	uint32_t fb0;  /* 0x018: Framebuffer Base Register 0 */
+	uint32_t rsvd1[2];
+	uint32_t fb1;  /* 0x024: Framebuffer Base Register 1 */
+	uint32_t rsvd2[2];
+	uint32_t fb2;  /* 0x030: Framebuffer Base Register 2 */
+	uint32_t rsvd3[2];
+	uint32_t fb3;  /* 0x03C: Framebuffer Base Register 3 */
+	uint32_t rsvd4[2];
+	uint32_t patg; /* 0x048: Pattern Generator */
+	uint32_t fifo; /* 0x04C: FIFO Threshold */
+	uint32_t gpio; /* 0x050: GPIO */
+	uint32_t rsvd5[43];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t htcr;    /* Horizontal Timing Control Register */
+	uint32_t vtcr[2]; /* Vertical Timing Control Register */
+	uint32_t pcr;     /* Polarity Control Register */
+	uint32_t rsvd6[60];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t sppr;    /* Serial Panel Pixel Register */
+	uint32_t ccir;    /* CCIR565 Register */
+	uint32_t rsvd7[62];
+
+	/* 0x300 ~ 0x3ff */
+	uint32_t pipr;    /* Picture-In-Picture Register */
+	uint32_t pip1pos; /* Sub-picture 1 position */
+	uint32_t pip1dim; /* Sub-picture 1 dimension */
+	uint32_t pip2pos; /* Sub-picture 2 position */
+	uint32_t pip2dim; /* Sub-picture 2 dimension */
+	uint32_t rsvd8[59];
+
+	/* 0x400 ~ 0x5ff */
+	uint32_t cmnt[4]; /* Color Management */
+	uint32_t rsvd9[124];
+
+	/* 0x600 ~ 0x6ff */
+	uint32_t gamma_r[64]; /* RED - Gamma Correct */
+
+	/* 0x700 ~ 0x7ff */
+	uint32_t gamma_g[64]; /* GREEN - Gamma Correct */
+
+	/* 0x800 ~ 0x8ff */
+	uint32_t gamma_b[64]; /* BLUE - Gamma Correct */
+
+	/* 0x900 ~ 0x9ff */
+	uint32_t rsvd10[64];
+
+	/* 0xa00 ~ 0xbff */
+	uint32_t palette[128];  /* Palette Write Port */
+
+	/* 0xc00 ~ 0xcff */
+	uint32_t cstn_cr;       /* CSTN Control Register */
+	uint32_t cstn_pr;       /* CSTN Parameter Register */
+	uint32_t rsvd11[62];
+
+	/* 0xd00 ~ 0xdff */
+	uint32_t cstn_bmap[16]; /* CSTN bitmap write port */
+	uint32_t rsvd12[48];
+};
+
+/* LCD Function Enable Register */
+#define FER_EN          (1 << 0)    /* chip enabled */
+#define FER_ON          (1 << 1)    /* screen on */
+#define FER_YUV420      (3 << 2)
+#define FER_YUV422      (2 << 2)
+#define FER_YUV         (1 << 3)    /* 1:YUV, 0:RGB */
+
+/* LCD Panel Pixel Register */
+#define PPR_BPP_1       (0 << 0)
+#define PPR_BPP_2       (1 << 0)
+#define PPR_BPP_4       (2 << 0)
+#define PPR_BPP_8       (3 << 0)
+#define PPR_BPP_16      (4 << 0)
+#define PPR_BPP_24      (5 << 0)
+#define PPR_BPP_MASK    (7 << 0)
+#define PPR_PWROFF      (1 << 3)
+#define PPR_BGR         (1 << 4)
+#define PPR_ENDIAN_LBLP (0 << 5)
+#define PPR_ENDIAN_BBBP (1 << 5)
+#define PPR_ENDIAN_LBBP (2 << 5)
+#define PPR_ENDIAN_MASK (3 << 5)
+#define PPR_RGB1        (PPR_BPP_1)
+#define PPR_RGB2        (PPR_BPP_2)
+#define PPR_RGB4        (PPR_BPP_4)
+#define PPR_RGB8        (PPR_BPP_8)
+#define PPR_RGB12       (PPR_BPP_16 | (2 << 7))
+#define PPR_RGB16_555   (PPR_BPP_16 | (1 << 7))
+#define PPR_RGB16_565   (PPR_BPP_16 | (0 << 7))
+#define PPR_RGB24       (PPR_BPP_24)
+#define PPR_RGB32       (PPR_BPP_24)
+#define PPR_RGB_MASK    (PPR_BPP_MASK | (3 << 7))
+#define PPR_VCOMP_VSYNC (0 << 9)
+#define PPR_VCOMP_VBP   (1 << 9)
+#define PPR_VCOMP_VAIMG (2 << 9)
+#define PPR_VCOMP_VFP   (3 << 9)
+#define PPR_VCOMP_MASK  (3 << 9)
+#define	PPR_PANEL_6BIT  (0 << 11)
+#define	PPR_PANEL_8BIT  (1 << 11)
+#define	PPR_DITHER565   (0 << 12)
+#define	PPR_DITHER555   (1 << 12)
+#define	PPR_DITHER444   (2 << 12)
+#define	PPR_HCLK_RESET  (1 << 14)
+#define	PPR_LCCLK_RESET (1 << 15)
+
+/* LCD Interrupt Enable Register */
+#define IER_FIFOUR      (1 << 0)
+#define IER_NEXTFB      (1 << 1)
+#define IER_VCOMP       (1 << 2)
+#define IER_BUSERR      (1 << 3)
+
+/* LCD Interrupt Status Register */
+#define ISR_FIFOUR      (1 << 0)
+#define ISR_NEXTFB      (1 << 1)
+#define ISR_VCOMP       (1 << 2)
+#define ISR_BUSERR      (1 << 3)
+
+/* LCD Horizontal Timing Control Register */
+#define HTCR_HBP(x)     ((((x) - 1) & 0xff) << 24)
+#define HTCR_HFP(x)     ((((x) - 1) & 0xff) << 16)
+#define HTCR_HSYNC(x)   ((((x) - 1) & 0xff) << 8)
+#define HTCR_PL(x)      (((x >> 4) - 1) & 0xff)
+
+/* LCD Vertical Timing Control Register 0 */
+#define VTCR0_VFP(x)    (((x) & 0xff) << 24)
+#define VTCR0_VSYNC(x)  ((((x) - 1) & 0x3f) << 16)
+#define VTCR0_LF(x)     (((x) - 1) & 0xfff)
+
+/* LCD Vertical Timing Control Register 1 */
+#define VTCR1_VBP(x)    ((x) & 0xff)
+
+/* LCD Polarity Control Register */
+#define PCR_IVS         (1 << 0)
+#define PCR_IHS         (1 << 1)
+#define PCR_ICK         (1 << 2)
+#define PCR_IDE         (1 << 3)
+#define PCR_IPWR        (1 << 4)
+#define PCR_DIV(x)      ((((x) - 1) & 0x7f) << 8)
+
+/* LCD Serial Panel Pixel Register */
+#define SPPR_SERIAL     (1 << 0)
+#define SPPR_DELTA      (1 << 1)
+#define SPPR_CS(x)      ((x) << 2)
+#define SPPR_CS_RGB     (0 << 2)
+#define SPPR_CS_BRG     (1 << 2)
+#define SPPR_CS_GBR     (2 << 2)
+#define SPPR_LSR        (1 << 4)
+#define SPPR_AUO052     (1 << 5)
+
+/* LCD CCIR656 Register */
+#define CCIR_PAL        (0 << 0)
+#define CCIR_NTSC       (1 << 0)
+#define CCIR_P640       (0 << 1)
+#define CCIR_P720       (1 << 1)
+#define CCIR_PHASE(x)   ((x) << 2)
+
+#endif /* __FTLCDC200_H */
diff --git a/include/lcd.h b/include/lcd.h
index 30225ed..14fa4fd 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -253,6 +253,39 @@ typedef struct vidinfo {

 void init_panel_info(vidinfo_t *vid);

+#elif defined(CONFIG_FTLCDC200)
+
+typedef struct vidinfo {
+	ushort	vl_col;		/* Number of columns (i.e. 800) */
+	ushort	vl_row;		/* Number of rows (i.e. 600) */
+
+	u_char	vl_bpix;	/* Bits per pixel, 0 = 1, 1 = 2 ... 4 = 16 */
+
+	/* Timing Parameters */
+	u_char	vl_fps;		/* Frame per second */
+
+	u_char	vl_hsw;
+	u_char	vl_hbp;
+	u_char	vl_hfp;
+
+	u_char	vl_vsw;
+	u_char	vl_vbp;
+	u_char	vl_vfp;
+
+	/* Pre-defined FTLCDC200 register values */
+	u_long	vl_enable;	/* LCDEnable */
+	u_long	vl_pixel;	/* PanelPixel */
+	u_long	vl_polarity;/* Polarity */
+	u_long	vl_serial;	/* SerialPanelPixel */
+	u_long	vl_ccir656;	/* CCIR656 */
+
+	/* Panel name */
+	char	*vl_name;
+
+	ushort	*cmap;		/* Pointer to the colormap */
+	void	*priv;		/* Pointer to driver-specific data */
+} vidinfo_t;
+
 #else

 typedef struct vidinfo {
--
1.7.9.5

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

* [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND controller support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 04/14] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-18  0:08     ` Scott Wood
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 06/14] cfi_flash: use buffer length in unmap_physmem() Kuo-Jung Su
                     ` (8 subsequent siblings)
  13 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is a integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v5 (Part of A360/A369 patch series):
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - For there is a strong dependancy between this and A360/A369 patch
     series, it had been chained back to A360/A369 patch series.
   - The latest nand_base requires the ecc.strength to be set properlly,
     so this patch adds ecc.strength setting accroding to ECC algorithm.

Changes for v5 (Standalone):
   - Update README for the description of CONFIG_SYS_FTNANDC021_TIMING.
   - Drop redundant white space. (i.e. if (mtd->writesize >= ' '4096))

Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Drop the faraday/nand.h to remove dependency to
     Faraday A36x patch series.
   - CONFIG_SYS_NAND_TIMING -> CONFIG_SYS_FTNANDC021_TIMING
   - Remove non-ECC code.
   - Implement private hwecc read/write_page functions
     to get rid of .eccpos & .eccbytes.
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Re-write this driver with ECC enabled and correct column address
     handling for OOB read/write,
   - Fix issuses addressed by Scott.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 README                        |    6 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  622 +++++++++++++++++++++++++++++++++++++++++
 include/faraday/ftnandc021.h  |  153 ++++++++++
 4 files changed, 782 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 include/faraday/ftnandc021.h

diff --git a/README b/README
index ac1ec44..3dbb7cc 100644
--- a/README
+++ b/README
@@ -3930,6 +3930,12 @@ Low Level (hardware related) configuration options:
 		- drivers/mtd/nand/ndfc.c
 		- drivers/mtd/nand/mxc_nand.c

+- CONFIG_SYS_FTNANDC021_TIMING
+		This option specifies an array of customized timing parameters
+		for Faraday FTNANDC021 NAND flash controller.
+		e.g.
+		#define CONFIG_SYS_FTNANDC021_TIMING { 0x02240264, 0x42054209 }
+
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
 		a default value will be used.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index 8821704..f2c8b1a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -64,6 +64,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..b189909
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,622 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <nand.h>
+#include <malloc.h>
+
+#include <faraday/ftnandc021.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+#define CFG_RST_TIMEOUT CONFIG_SYS_HZ /* 1 sec reset timeout */
+#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
+
+struct ftnandc021_chip {
+	void __iomem *regs;
+	int alen;
+	int pgsz;
+	int bksz;
+
+	int col;    /* current column address */
+	int page;   /* current row address/page index */
+	int cmd;    /* current NAND command code */
+	int cmd_hc; /* current FTNANDC021 command code */
+};
+
+static struct nand_ecclayout ftnandc021_ecclayout[] = {
+	{ /* page size = 512 (oob size = 16) */
+		.oobfree = {
+			{ 9, 3 },
+		}
+	},
+	{ /* page size = 2048 (oob size = 64) */
+		.oobfree = {
+			{ 9, 3 },
+		},
+	},
+	{ /* page size = 4096 (oob size = 128) */
+		.oobfree = {
+			{ 9, 7 },
+		},
+	},
+};
+
+static inline int ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t st = readl(&regs->idr[1]);
+
+	if (st & NAND_STATUS_FAIL)
+		return -EIO;
+
+	if (!(st & NAND_STATUS_READY))
+		return -EBUSY;
+
+	if (!(st & NAND_STATUS_WP))
+		return -EIO;
+
+	return 0;
+}
+
+static inline int ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	char rc = 'c';
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			rc = 'e';
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	switch (rc) {
+	case 'e':
+		printf("ftnandc021: ecc timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	case 'c':
+		printf("ftnandc021: cmd timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	default:
+		break;
+	}
+
+	return rc ? -ETIMEDOUT : 0;
+}
+
+static int ftnandc021_read_page(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	/*
+	 * OOB has been read at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it here.
+	 */
+	chip->read_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static void ftnandc021_write_page(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	/*
+	 * OOB has been written at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it here.
+	 */
+	chip->write_buf(mtd, buf, mtd->writesize);
+}
+
+static int ftnandc021_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	printf("ftnandc021: read_page_raw is not supported\n");
+	return -EIO;
+}
+
+static void ftnandc021_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	printf("ftnandc021: write_page_raw is not supported\n");
+}
+
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 0;
+
+	priv->cmd_hc = cmd;
+
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : (We have queued data at the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+	case FTNANDC021_CMD_WRPG:
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+static int ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t ts, bk, pg, ac, mask;
+#ifdef CONFIG_SYS_FTNANDC021_TIMING
+	uint32_t timing[] = CONFIG_SYS_FTNANDC021_TIMING;
+
+	writel(timing[0], &regs->atr[0]);
+	writel(timing[1], &regs->atr[1]);
+#endif
+
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	mask = SRR_CHIP_RESET | SRR_ECC_EN;
+	writel(mask, &regs->srr);
+	for (ts = get_timer(0); get_timer(ts) < CFG_RST_TIMEOUT; ) {
+		if (readl(&regs->srr) & SRR_CHIP_RESET)
+			continue;
+		break;
+	}
+	if (readl(&regs->srr) & SRR_CHIP_RESET) {
+		printf("ftnandc021: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* sanity check on page size */
+	if (priv->pgsz != 512 && priv->pgsz != 2048 && priv->pgsz != 4096) {
+		printf("ftnandc021: invalid page size=%d\n", priv->pgsz);
+		return -EINVAL;
+	}
+
+	bk = ffs(priv->bksz / priv->pgsz) - 5;
+	pg = (priv->pgsz < 2048) ? 0 : (ffs(priv->pgsz) - 11);
+	ac = priv->alen - 3;
+
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* IO mode = PIO */
+	writel(0, &regs->bcr);
+
+	/* ECC mode */
+	chip->ecc.layout         = ftnandc021_ecclayout + pg;
+	chip->ecc.size           = priv->pgsz;
+	chip->ecc.steps          = 1;
+	chip->ecc.read_page      = ftnandc021_read_page;
+	chip->ecc.write_page     = ftnandc021_write_page;
+	chip->ecc.read_page_raw  = ftnandc021_read_page_raw;
+	chip->ecc.write_page_raw = ftnandc021_write_page_raw;
+	chip->ecc.mode           = NAND_ECC_HW;
+	if (CFGR_ECC_TYPE(readl(&regs->cfgr)) == CFGR_ECC_BCH)
+		chip->ecc.strength = 8;
+	else
+		chip->ecc.strength = 4;
+
+	/* reset the attached flash */
+	if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+		return -ENXIO;
+
+	return 0;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv))
+		ret = 0;
+	else if (!(readl(&regs->sr) & SR_READY))
+		ret = 0;
+
+	return ret;
+}
+
+static int ftnandc021_pio_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = -ETIMEDOUT;
+	uint32_t ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
+		if (!(readl(&regs->ior) & IOR_READY))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftnandc021: pio timeout\n");
+
+	return ret;
+}
+
+static void ftnandc021_read_oob(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	memset(buf, 0xff, len);
+
+	/* bad block */
+	buf[chip->badblockpos] = readl(&regs->bbird) & 0xff;
+
+	/* data */
+	tmp = readl(&regs->crcrd);
+	buf[8] = (tmp >> 0) & 0xff;
+	buf[9] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[12] = (tmp >> 16) & 0xff;
+		buf[13] = (tmp >> 24) & 0xff;
+	}
+
+	tmp = readl(&regs->lsnrd);
+	buf[10] = (tmp >> 0) & 0xff;
+	buf[11] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[14] = (tmp >> 16) & 0xff;
+		buf[15] = (tmp >> 24) & 0xff;
+	}
+}
+
+static void ftnandc021_write_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	/* bad block */
+	tmp = buf[chip->badblockpos];
+	writel(tmp, &regs->bbiwr);
+
+	/* mark it as 'not blank' */
+	tmp = 'W' | (buf[9] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	writel(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	writel(tmp, &regs->lsnwr);
+}
+
+static uint8_t ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+		if (priv->col < 8) {
+			uint32_t idx = priv->col >> 2;
+			uint32_t pos = priv->col & 0x3;
+			uint32_t tmp = readl(&regs->idr[idx]);
+
+			ret = (uint8_t)(tmp >> (pos << 3));
+			priv->col += 1;
+		}
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint8_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: unknown cmd=0x%x in read_byte\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t ret = 0xffff;
+	uint8_t *buf = (uint8_t *)&ret;
+
+	/* LSB format */
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return ret;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void ftnandc021_read_buf(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	int off;
+
+	if (priv->col >= mtd->writesize)
+		return;
+
+	if (priv->cmd == NAND_CMD_READOOB)
+		BUG();	/* should never happen */
+
+	/* skip if it's a blank page */
+	if (chip->oob_poi[8] != 'W') {
+		memset(buf, 0xff, len);
+		return;
+	}
+
+	off = 0;
+	while (off < len && priv->col < mtd->writesize) {
+		ftnandc021_pio_wait(priv);
+		*(uint32_t *)(buf + off) = readl(&regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void ftnandc021_write_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	int off;
+
+	/*
+	 * FTNANDC021 HW design issues:
+	 *
+	 * 1. OOB data must be set before issuing write command,
+	 *    so it's too late to do it right here
+	 * 2. Only after command issued, the data register
+	 *    could accept data.
+	 */
+	if (priv->col >= mtd->writesize)
+		return;
+
+	for (off = 0; off < len && priv->col < mtd->writesize; ) {
+		ftnandc021_pio_wait(priv);
+		writel(*(uint32_t *)(buf + off), &regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int ftnandc021_verify_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	int ret = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021: out of memory\n");
+		return -ENOMEM;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			ret = -EINVAL;
+	}
+
+	free(tmp);
+	return ret;
+}
+
+static void ftnandc021_cmdfunc(struct mtd_info *mtd,
+	unsigned cmd, int col, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+
+	priv->cmd = cmd;
+	priv->col = col;
+	priv->page = page;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		priv->col = 0;
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID))
+			printf("ftnandc021: RDID failed.\n");
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		priv->col = mtd->writesize;
+		/* fall-through */
+	case NAND_CMD_READ0:	/* 0x00 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* fetch oob to check if it's a blank page */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+			break;
+		}
+		ftnandc021_read_oob(mtd, chip->oob_poi, mtd->oobsize);
+		/* skip if we don't need page data */
+		if (priv->col >= mtd->writesize)
+			break;
+		/* skip if it's a blank page */
+		if (chip->oob_poi[8] != 'W') {
+			debug("ftnandc021: skip page %d\n", page);
+			break;
+		}
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG))
+			printf("ftnandc021: RDPG failed.\n");
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK))
+			printf("ftnandc021: ERBLK failed\n");
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDST))
+			printf("ftnandc021: RDST failed\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* OOB data must be set before issuing command */
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->oobsize);
+		priv->cmd_hc = (priv->col >= mtd->writesize)
+			? FTNANDC021_CMD_WROOB : FTNANDC021_CMD_WRPG;
+		if (ftnandc021_command(priv, priv->cmd_hc))
+			printf("ftnandc021: CMD_HC=%d failed\n", priv->cmd_hc);
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		/* nothing needs to be done */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+			printf("ftnandc021: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021: unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void ftnandc021_hwcontrol(struct mtd_info *mtd,
+	int cmd, unsigned int ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen)
+{
+	struct ftnandc021_chip *priv;
+
+	priv = calloc(1, sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regs = (void __iomem *)iobase;
+	priv->pgsz = 1 << chip->page_shift;
+	priv->bksz = 1 << chip->phys_erase_shift;
+	priv->alen = alen;
+
+	chip->priv = priv;
+
+	debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n",
+		   priv->pgsz, priv->bksz, priv->alen);
+
+	/* hardware reset */
+	if (ftnandc021_reset(chip))
+		return -EINVAL;
+
+	/* hwcontrol always must be implemented */
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	return 0;
+}
diff --git a/include/faraday/ftnandc021.h b/include/faraday/ftnandc021.h
new file mode 100644
index 0000000..64af806
--- /dev/null
+++ b/include/faraday/ftnandc021.h
@@ -0,0 +1,153 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTNANDC021_H
+#define __FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+	/* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4];/* ECC Parity Register */
+	uint32_t ecc_sr;   /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+	/* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsn;	 /* LSN Initialize */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+	/* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+	/* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* ECC Status Register */
+#define ECC_SR_CERR      (1 << 3)  /* correction error */
+#define ECC_SR_ERR       (1 << 2)  /* ecc error */
+#define ECC_SR_DEC       (1 << 1)  /* ecc decode finished */
+#define ECC_SR_ENC       (1 << 0)  /* ecc encode finished */
+
+/* Status Register */
+#define SR_BLANK         (1 << 7)  /* blanking check failed */
+#define SR_ECC           (1 << 6)  /* ecc timeout */
+#define SR_STS           (1 << 4)  /* status error */
+#define SR_CRC           (1 << 3)  /* crc error */
+#define SR_CMD           (1 << 2)  /* command finished */
+#define SR_READY         (1 << 1)  /* chip ready/busy */
+#define SR_ENA           (1 << 0)  /* chip enabled */
+
+/* Access Control Register */
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        (1 << 7)  /* command start */
+
+/* Flow Control Register */
+#define FCR_SWCRC        (1 << 8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       (1 << 7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        (1 << 4)  /* 16 bit data bus */
+#define FCR_WPROT        (1 << 3)  /* write protected */
+#define FCR_NOSC         (1 << 2)  /* bypass status check error */
+#define FCR_MICRON       (1 << 1)  /* Micron 2-plane command */
+#define FCR_NOBC         (1 << 0)  /* skip blanking check error */
+
+/* Interrupt Enable Register */
+#define IER_ENA          (1 << 7)  /* interrupt enabled */
+#define IER_ECC          (1 << 3)  /* ecc error timeout */
+#define IER_STS          (1 << 2)  /* status error */
+#define IER_CRC          (1 << 1)  /* crc error */
+#define IER_CMD          (1 << 0)  /* command finished */
+
+/* BMC PIO Status Register */
+#define IOR_READY        (1 << 0)  /* PIO ready */
+
+/* MLC Software Reset Register */
+#define SRR_ECC_EN       (1 << 8)  /* ECC enabled */
+#define SRR_NANDC_RESET  (1 << 2)  /* NANDC reset */
+#define SRR_BMC_RESET    (1 << 1)  /* BMC reset */
+#define SRR_ECC_RESET    (1 << 0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+/* Memory Configuration Register */
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* Configuration Register */
+#define CFGR_ECC_TYPE(x) (((x) >> 16) & 0xf)
+#define CFGR_ECC_RS      4
+#define CFGR_ECC_BCH     8
+#define CFGR_IOBITS(x)   (((x) >> 8) & 0xff) /* Max. data width */
+#define CFGR_MAXFLS(x)   ((x) & 0xf) /* Max. flash chips */
+
+/* FTNANDC021 built-in command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02   /* reset flash */
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen);
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v5 06/14] cfi_flash: use buffer length in unmap_physmem()
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 07/14] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
                     ` (7 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

While the flash_detect_legacy() of drivers/mtd/cfi_flash.c
feed unmap_physmem() with MAP_NOCACHE as 2nd parameter,
the do_spi_flash_read_write() of common/cmd_sf.c
feed unmap_physmem() with the length of the mapped buffer
as 2nd parameter.

It's apparently a bug, and I personally think the 2nd parameter
should be the length of the mapped buffer.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Stefan Roese <sr@denx.de>
---
Changes for v5:
   - Initial commit, which is separated from
     "arm: add MMU/D-Cache support for Faraday cores"

 drivers/mtd/cfi_flash.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 25f8752..0d7a5ac 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1820,7 +1820,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)
 					break;
 				else
 					unmap_physmem((void *)info->start[0],
-						      MAP_NOCACHE);
+						      info->portwidth);
 			}
 		}

--
1.7.9.5

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

* [U-Boot] [PATCH v5 07/14] arm: add MMU/D-Cache support for Faraday cores
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (5 preceding siblings ...)
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 06/14] cfi_flash: use buffer length in unmap_physmem() Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 08/14] arm: add Faraday processor core support Kuo-Jung Su
                     ` (6 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This updates the map_physmem()/unmap_physmem(), and use
them to implement dma_alloc_coherent() & dma_free_coherent().

It uses 1MB section for each mapping, and thus wastes lots of
address space, however this should still be good enough for
tiny systems (i.e. u-boot).

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Add void dram_bank_mmu_setup() into 'arch/arm/cpu/faraday/cpu.c'
     to override the weak function in "cache-cp15.c".
   - Use small page (4KB) to map relocated exception table to 0x0000

Changes for v4:
   - Coding Style cleanup.

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - Drop static non-cached region, now we use map_physmem()/unmap_physmem()
     for dynamic mappings.

Changes for v2:
   - Coding Style cleanup.
   - cache-cp15: Enable write buffer in write-through mode.

 arch/arm/include/asm/dma-mapping.h |   59 ++++++++++++-
 arch/arm/include/asm/global_data.h |    4 +
 arch/arm/include/asm/io.h          |  160 ++++++++++++++++++++++++++++++++++--
 arch/arm/include/asm/system.h      |    7 +-
 arch/arm/lib/cache-cp15.c          |   12 +++
 5 files changed, 230 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index a11178f..5a13af5 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -3,6 +3,9 @@
  * Stelian Pop <stelian@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
  *
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -24,22 +27,76 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };

-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (va && gd->arch.cpu_mmu) {
+		invalidate_dcache_range((ulong)va, (ulong)va + len);
+		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
+		if (!map)
+			free(va);
+		va = map;
+	}
+
+	if (handle)
+		*handle = virt_to_phys(va);
+
+	return va;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+}
+
+static inline void dma_free_coherent(void *vaddr, ulong len)
+{
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *tmp = (void *)virt_to_phys(vaddr);
+	unmap_physmem(vaddr, len);
+	vaddr = tmp;
+#endif
+	free(vaddr);
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (unsigned long)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 7611d0a..fc78c6a 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -42,6 +42,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..37c737e 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/io.h
  *
  *  Copyright (C) 1996-2000 Russell King
+ *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -28,9 +29,36 @@
 #if 0	/* XXX###XXX */
 #include <asm/arch/hardware.h>
 #endif	/* XXX###XXX */
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/system.h>
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#ifndef CONFIG_MMAP_START
+#define CONFIG_MMAP_START   0xd0000000
+#endif
+
+#ifndef CONFIG_MMAP_END
+#define CONFIG_MMAP_END     0xfff00000
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
+/* arch/$(ARCH)/lib/cache.c */
+void invalidate_icache_all(void);
+void flush_dcache_all(void);
+void flush_dcache_range(ulong start, ulong stop);

 static inline void sync(void)
 {
+#ifndef CONFIG_SYS_DCACHE_OFF
+	flush_dcache_all();
+#endif
+#ifndef CONFIG_SYS_ICACHE_OFF
+	invalidate_icache_all();
+#endif
 }

 /*
@@ -39,27 +67,143 @@ static inline void sync(void)
  * properties specified by "flags".
  */
 #define MAP_NOCACHE	(0)
-#define MAP_WRCOMBINE	(0)
-#define MAP_WRBACK	(0)
-#define MAP_WRTHROUGH	(0)
+#define MAP_WRCOMBINE	(1)
+#define MAP_WRBACK	(2)
+#define MAP_WRTHROUGH	(3)
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+static inline void map_flush(ulong start, ulong end)
+{
+	flush_dcache_range(start, end);
+
+	/* invalidate D-TLB */
+	start &= 0xfff00000;
+	end = (end + 0x000fffff) & 0xfff00000;
+	__asm__ __volatile__ (
+		"mov r3, %0\n"
+		"1:\n"
+		"mcr p15, 0, r3, c8, c6, 1\n"
+		"add r3, r3, #4096\n"
+		"cmp r3, %1\n"
+		"blo 1b\n"
+		: /* output */
+		: "r"(start), "r"(end) /* input */
+		: "r3" /* clobber list */
+	);
+}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */

 static inline void *
-map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+map_physmem(phys_addr_t paddr, ulong len, ulong flags)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 vaddr, nattr, oattr, addr, size, end;
+
+	/* 1. check if we have to create a mapping for it */
+	vaddr = paddr;
+	addr  = page_table[vaddr >> 20] & 0xfff00000;
+	oattr = page_table[vaddr >> 20] & 0x1f;
+	switch (flags) {
+	case MAP_WRCOMBINE:
+		nattr = DCACHE_WRITECOMBINE;
+		break;
+	case MAP_WRTHROUGH:
+		nattr = DCACHE_WRITETHROUGH;
+		break;
+	case MAP_WRBACK:
+		nattr = DCACHE_WRITEBACK;
+		break;
+	default:
+		nattr = DCACHE_OFF;
+		break;
+	}
+	if ((nattr == oattr) && (vaddr == addr))
+		return (void *)paddr;
+
+	/* 2. find a contiguous region for it */
+	end = (paddr + len + 0x000fffff) & 0xfff00000;
+	len = end - (paddr & 0xfff00000);
+	size = 0;
+	addr = CONFIG_MMAP_START;
+	vaddr = addr;
+	while (addr < CONFIG_MMAP_END) {
+		/* if va == pa, then it's free to use */
+		if (addr == (page_table[addr >> 20] & 0xfff00000)) {
+			size += SZ_1M;
+		} else {
+			size = 0;
+			vaddr = addr + SZ_1M;
+		}
+		if (size >= len)
+			break;
+		addr += SZ_1M;
+	}
+	if (size < len)
+		return NULL;
+
+	/* 3. create the map */
+	map_flush(vaddr, vaddr + size);
+	addr = vaddr;
+	vaddr += paddr & 0x000fffff;
+	paddr &= 0xfff00000;
+	while (size) {
+		page_table[addr >> 20] = paddr | (3 << 10) | nattr;
+		size -= SZ_1M;
+		addr += SZ_1M;
+		paddr += SZ_1M;
+	}
+	return (void *)vaddr;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (void *)paddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
  * Take down a mapping set up by map_physmem().
  */
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
+static inline void unmap_physmem(void *vaddr, ulong len)
 {
-
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 addr, end;
+
+	/* 1. skip on NULL pointer */
+	if (!vaddr)
+		return;
+
+	/* 2. check if it's the right address map */
+	addr = (u32)vaddr;
+	if ((page_table[addr >> 20] & 0xfff00000) == addr)
+		return;
+
+	/* 3. reset the map */
+	end = (addr + len + 0x000fffff) & 0xfff00000;
+	addr &= 0xfff00000;
+	map_flush(addr, end);
+	while (addr < end) {
+		page_table[addr >> 20] = addr | (3 << 10) | DCACHE_OFF;
+		addr += SZ_1M;
+	}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

-static inline phys_addr_t virt_to_phys(void * vaddr)
+static inline phys_addr_t virt_to_phys(void *vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	phys_addr_t phys = (phys_addr_t)vaddr;
+
+	if (!gd->arch.cpu_mmu || !vaddr)
+		return phys;
+
+	phys = page_table[(u32)vaddr >> 20] & 0xfff00000;
+	phys += (u32)vaddr & 0x000fffff;
+
+	return phys;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	return (phys_addr_t)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 760345f..050b707 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -97,9 +97,10 @@ static inline void set_dacr(unsigned int val)

 /* options available for data cache on each page */
 enum dcache_option {
-	DCACHE_OFF = 0x12,
-	DCACHE_WRITETHROUGH = 0x1a,
-	DCACHE_WRITEBACK = 0x1e,
+	DCACHE_OFF = 0x12,          /* non-cached + non-buffered */
+	DCACHE_WRITECOMBINE = 0x16, /* non-cached + buffered */
+	DCACHE_WRITETHROUGH = 0x1a, /* cached + non-buffered */
+	DCACHE_WRITEBACK = 0x1e,    /* cached + buffered */
 };

 /* Size of an MMU section */
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 4abe1cf..97436f6 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -1,6 +1,8 @@
 /*
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -126,6 +128,10 @@ static inline void mmu_setup(void)

 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#ifdef CONFIG_FARADAY
+	reg |= CR_W;	/* enable write buffer */
+	reg |= CR_Z;	/* enable branch prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -140,9 +146,15 @@ static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;

+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
+
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | cache_bit);
--
1.7.9.5

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

* [U-Boot] [PATCH v5 08/14] arm: add Faraday processor core support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (6 preceding siblings ...)
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 07/14] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 09/14] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
                     ` (5 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds i/d-cache control, mmu setup & bootstrap code
for Faraday cores.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Initial commit which is separated from
     "arm: add Faraday common utilities"

 arch/arm/cpu/faraday/Makefile  |   55 +++++
 arch/arm/cpu/faraday/config.mk |   33 +++
 arch/arm/cpu/faraday/cpu.c     |  346 ++++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/start.S   |  431 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 865 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..ecb240a
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,55 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+src-y  := cpu.o
+
+START	= start.o
+COBJS	= $(src-y)
+
+ifdef	CONFIG_SPL_BUILD
+ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE
+START	:=
+endif
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f03030a
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
+
+PLATFORM_CPPFLAGS += -march=armv4
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..570b8b2
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,346 @@
+/*
+ * arch/arm/cpu/faraday/cpu.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+
+	disable_interrupts();
+
+	/* turn off D-cache */
+	dcache_disable();
+
+	/* flush I-cache */
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n" /* invalidate i-cache all */
+		:      /* output */
+		:      /* input */
+		: "r0" /* clobber list */
+	);
+
+	return 0;
+}
+
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#else
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c14,0\n" /* clean & invalidate d-cache all */
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n" /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n" /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c6,0\n" /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r0"/* clobber list */
+	);
+}
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c5,0\n" /* invalidate i-cache all */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
+
+void enable_caches(void)
+{
+	icache_enable();
+
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		puts("MMU:   on\n");
+		dcache_enable();
+	} else
+#endif
+		puts("MMU:   off\n");
+}
+
+#define CPUID_VID(x)        (((x) >> 24) & 0xff)
+#define CPUID_ISA(x)        (((x) >> 16) & 0xff)
+#define CPUID_PID(x)        (((x) >>  4) & 0x0fff)
+#define CPUID_REV(x)        ((x) & 0x0f) /* revision */
+#define CPUID_NOREV(x)      (((x) >>  4) & 0x0fffffff)
+
+/* Vendor ID */
+#define CPUID_VID_ARM       0x41
+#define CPUID_VID_FARADAY   0x66
+
+/* Instruction Set Architecture */
+#define CPUID_ISA_ARMV4     0x01
+#define CPUID_ISA_ARMV5TE   0x05
+#define CPUID_ISA_ARMV5TEJ  0x06
+
+/* Faraday ARMv4 cores */
+#define CPUID_FA526         0x6601526
+#define CPUID_FA626         0x6601626
+
+/* Faraday ARMv5TE cores */
+#define CPUID_FA606TE       0x6605606
+#define CPUID_FA616TE       0x6605616
+#define CPUID_FA626TE       0x6605626
+#define CPUID_FA726TE       0x6605726
+
+#ifdef CONFIG_ARCH_CPU_INIT
+
+int arch_cpu_init(void)
+{
+	unsigned int id, ctr;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		"mrc p15, 0, %1, c0, c0, 1\n"
+		: "=r"(id), "=r"(ctr) /* output */
+		: /* input */
+	);
+
+	gd->arch.cpu_id = id;
+
+	/* MMU/D-Cache */
+	switch (CPUID_NOREV(gd->arch.cpu_id)) {
+	case CPUID_FA606TE: /* FA606TE (no-mmu) */
+		/* Disable MMU/D-Cache */
+		gd->arch.cpu_mmu = 0;
+		break;
+	default:
+		/* Enable MMU/D-Cache */
+		gd->arch.cpu_mmu = 1;
+		break;
+	}
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+	uint vid = CPUID_VID(gd->arch.cpu_id);
+	uint pid = CPUID_PID(gd->arch.cpu_id);
+
+	/* build cpu_name */
+	switch (vid) {
+	case CPUID_VID_FARADAY:	/* Faraday */
+		switch (CPUID_ISA(gd->arch.cpu_id)) {
+		case CPUID_ISA_ARMV5TE:
+			sprintf(cpu_name, "FA%xTE", pid);
+			break;
+		default:
+			sprintf(cpu_name, "FA%x", pid);
+			break;
+		}
+		break;
+	case CPUID_VID_ARM:	/* ARM */
+		if ((pid & 0xff0) == 0xc00)
+			sprintf(cpu_name, "Cortex-A%u", (pid & 0x00f));
+		else if (pid >= 0xa00)
+			sprintf(cpu_name, "ARM%x", 0x1000 + (pid - 0xa00));
+		else
+			sprintf(cpu_name, "ARM%x", pid);
+		break;
+	default:
+		sprintf(cpu_name, "Unknown");
+		break;
+	}
+
+	/* print cpu_info */
+	printf("CPU:   %s %u MHz\n",
+		cpu_name, (unsigned int)(clock_get_rate(CPU_CLK) / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clock_get_rate(AHB_CLK) / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clock_get_rate(APB_CLK) / 1000000));
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+
+#undef  CACHE_SETUP
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+#define CACHE_SETUP DCACHE_WRITETHROUGH
+#else
+#define CACHE_SETUP DCACHE_WRITEBACK
+#endif
+
+#ifdef CONFIG_USE_IRQ
+static u32 page_table[256] __aligned(1024);
+#endif
+
+/*
+ * This dram_bank_mmu_setup() overrides the weak function
+ * in "cache-cp15.c".
+ */
+void dram_bank_mmu_setup(int bank)
+{
+	u32 pa, *sect_table = (u32 *)gd->arch.tlb_addr;
+	bd_t *bd = gd->bd;
+	int	i;
+
+	for (i = bd->bi_dram[bank].start >> 20;
+	     i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
+	     i++) {
+		pa = i << 20;
+		sect_table[i] = pa | (3 << 10) | CACHE_SETUP;
+	}
+
+#ifdef CONFIG_USE_IRQ
+	/* only setup exception table when bank == 0 */
+	if (bank)
+		return;
+
+	/* make sure the exception table is mapped to 0x00000000 */
+	sect_table[0] = (u32)page_table | 0x11; /* coarse page */
+	page_table[0] = gd->relocaddr | 0xff2; /* small page (4KB) */
+
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n" /* invalidate TLB */
+		"mcr p15, 0, r0, c7, c5, 0\n" /* invalidate I Cache */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+#endif /* CONFIG_USE_IRQ */
+}
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt __iomem *regs =
+		(struct ftwdt010_wdt __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with System Reset Function */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+	/* Kick it to make sure it's in running state */
+	writel(FTWDT010_WDRESTART_MAGIC, &regs->wdrestart);
+#endif
+}
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..916b4a2
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,431 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * Relocate U-Boot to RAM
+	 * It's copied from the old u-boot release.
+	 */
+#ifndef CONFIG_SPL_BUILD
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq rr_exit
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+rr_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo rr_loop
+
+	/* Adjust the pc to use the correct text address */
+	adr r0, _start
+	ldr r1, _TEXT_BASE
+	sub r2, pc, r0
+	add r2, r2, #4
+	add pc, r1, r2
+
+rr_exit:
+#endif  /* !CONFIG_SPL_BUILD */
+
+	bl	_main
+
+/*---------------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
--
1.7.9.5

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

* [U-Boot] [PATCH v5 09/14] arm: add Faraday FTINTC020 interrupt controller support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (7 preceding siblings ...)
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 08/14] arm: add Faraday processor core support Kuo-Jung Su
@ 2013-06-17 12:06   ` Kuo-Jung Su
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 10/14] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
                     ` (4 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:06 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Coding Style cleanup.
   - Now the irq is always enabled inside irq_install_handler().

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile    |    1 +
 arch/arm/cpu/faraday/ftintc020.c |  156 ++++++++++++++++++++++++++++++++++++++
 include/common.h                 |    3 +
 include/faraday/ftintc020.h      |   37 +++++++++
 4 files changed, 197 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftintc020.c
 create mode 100644 include/faraday/ftintc020.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index ecb240a..35926c2 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
 LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o
+src-$(CONFIG_FTINTC020)   += ftintc020.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/ftintc020.c b/arch/arm/cpu/faraday/ftintc020.c
new file mode 100644
index 0000000..542f616
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftintc020.c
@@ -0,0 +1,156 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftintc020.h>
+
+static struct ftintc020_regs *regs = (void __iomem *)CONFIG_FTINTC020_BASE;
+
+static struct {
+	void  *data;
+	void (*func)(void *data);
+} irq_hndl[64];
+
+static inline void irq_acknowledge(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		writel(mask, &regs->irq32.scr);
+	else
+		writel(mask, &regs->irq64.scr);
+}
+
+void irq_enable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		setbits_le32(&regs->irq32.ena, mask);
+	else
+		setbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_disable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		clrbits_le32(&regs->irq32.ena, mask);
+	else
+		clrbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_set_trigger(int irq, int edge, int low)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (edge) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tmr, mask);
+		else
+			setbits_le32(&regs->irq64.tmr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tmr, mask);
+		else
+			clrbits_le32(&regs->irq64.tmr, mask);
+	}
+
+	if (low) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tlr, mask);
+		else
+			setbits_le32(&regs->irq64.tlr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tlr, mask);
+		else
+			clrbits_le32(&regs->irq64.tlr, mask);
+	}
+}
+
+void do_irq(struct pt_regs *pt_regs)
+{
+	int irq;
+	uint32_t stat;
+
+	irq  = 32;
+	stat = readl(&regs->irq64.sr);     /* IRQ 32 ~ 63 */
+	if (!stat) {
+		irq  = 0;
+		stat = readl(&regs->irq32.sr); /* IRQ  0 ~ 31 */
+	}
+	irq += ffs(stat) - 1;
+
+	if (irq < 0) {
+		printf("interrupts: no irq!?\n");
+		return;
+	}
+
+	if (irq_hndl[irq].func)
+		irq_hndl[irq].func(irq_hndl[irq].data);
+	else
+		printf("Unhandled IRQ = %d\n", irq);
+
+	irq_acknowledge(irq);
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *hndl, void *data)
+{
+	if (irq >= 0 && irq < 64) {
+		irq_hndl[irq].func = hndl;
+		irq_hndl[irq].data = data;
+		irq_enable(irq);
+	}
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq >= 0 && irq < 64) {
+		irq_hndl[irq].func = NULL;
+		irq_hndl[irq].data = NULL;
+		irq_disable(irq);
+	}
+}
+
+int arch_interrupt_init(void)
+{
+	int i;
+
+	for (i = 0; i < 64; ++i)
+		irq_free_handler(i);
+
+	/* hardware reset */
+	writel(0x00000000, &regs->irq32.ena);
+	writel(0xffffffff, &regs->irq32.scr);
+	writel(0x00000000, &regs->irq32.tmr);
+	writel(0x00000000, &regs->irq32.tlr);
+
+	writel(0x00000000, &regs->irq64.ena);
+	writel(0xffffffff, &regs->irq64.scr);
+	writel(0x00000000, &regs->irq64.tmr);
+	writel(0x00000000, &regs->irq64.tlr);
+
+	return 0;
+}
diff --git a/include/common.h b/include/common.h
index 126891d..812e9b6 100644
--- a/include/common.h
+++ b/include/common.h
@@ -110,6 +110,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_FARADAY
+#include <asm/arch-faraday/interrupt.h>
+#endif

 #include <part.h>
 #include <flash.h>
diff --git a/include/faraday/ftintc020.h b/include/faraday/ftintc020.h
new file mode 100644
index 0000000..e23d1e7
--- /dev/null
+++ b/include/faraday/ftintc020.h
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTINTC020_H
+#define ARCH_ARM_CPU_FARADAY_FTINTC020_H
+
+struct ftintc020_pic_regs {
+	uint32_t src; /* source register */
+	uint32_t ena; /* enable register */
+	uint32_t scr; /* status clear register */
+	uint32_t tmr; /* trigger mode register */
+	uint32_t tlr; /* trigger level register */
+	uint32_t sr;  /* status register */
+	uint32_t rsvd[2];
+};
+
+struct ftintc020_regs {
+	/* IRQ/FIQ:  0 ~ 31 */
+	struct ftintc020_pic_regs irq32; /* 0x00 - 0x1C: IRQ 0 ~ 31 */
+	struct ftintc020_pic_regs fiq32; /* 0x20 - 0x3C: FIQ 0 ~ 31 */
+	uint32_t rsvd1[4];               /* 0x40 - 0x4C: Reserved */
+	uint32_t revision;               /* 0x50: Revision Register */
+	uint32_t feature;                /* 0x54: Feature Register */
+	uint32_t rsvd2[2];               /* 0x58 - 0x5C: Reserved */
+	/* IRQ/FIQ: 32 ~ 63 */
+	struct ftintc020_pic_regs irq64; /* 0x60 - 0x7C: IRQ 32 ~ 63 */
+	struct ftintc020_pic_regs fiq64; /* 0x80 - 0x9C: FIQ 32 ~ 63 */
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v5 10/14] arm: add Faraday FTTMR010 timer support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (8 preceding siblings ...)
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 09/14] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
@ 2013-06-17 12:07   ` Kuo-Jung Su
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 11/14] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
                     ` (3 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Drop IRQ dependant implementation
   - Use gd->arch.timer_rate_hz for timer clock source
   - Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    1 +
 arch/arm/cpu/faraday/fttmr010.c |  136 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 +++++
 3 files changed, 154 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 35926c2..658d9ed 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -27,6 +27,7 @@ LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
+src-$(CONFIG_FTTMR010)    += fttmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..9d6f7ac
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,136 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 72abcb3..ef10f31 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -57,6 +57,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -70,4 +80,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v5 11/14] arm: add Faraday FTPWMTMR010 timer support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (9 preceding siblings ...)
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 10/14] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
@ 2013-06-17 12:07   ` Kuo-Jung Su
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 12/14] arm: add Faraday specific boot command Kuo-Jung Su
                     ` (2 subsequent siblings)
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Drop IRQ dependant implementation
   - Use gd->arch.timer_rate_hz for timer clock source
   - Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    1 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  128 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 ++++++++++++
 3 files changed, 170 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 658d9ed..6b96e32 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -28,6 +28,7 @@ LIB	= $(obj)lib$(CPU).o
 src-y  := cpu.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
+src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..8f8185e
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,128 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+#ifdef CONFIG_A369_FA606TE_PLATFORM
+#define TIMER_ID    4
+#else
+#define TIMER_ID    0
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftpwmtmr010_regs *regs = (void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..9455577
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v5 12/14] arm: add Faraday specific boot command
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (10 preceding siblings ...)
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 11/14] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
@ 2013-06-17 12:07   ` Kuo-Jung Su
  2013-06-23  7:22     ` Albert ARIBAUD
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 13/14] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 14/14] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
  13 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

At the time of writting, none of Faraday NAND & SPI controllers
supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
to implement a 1st level bootstrap code stored in the embedded ROM
inside the SoC.

After power-on, the ROM code (1st level bootstrap code) would load
the 2nd bootstrap code into SRAM without any SDRAM initialization.

The 2nd bootstrap code would then initialize SDRAM and load the
generic firmware (u-boot/linux) into SDRAM, and finally make
a long-jump to the firmware.

Which means the SPL design of U-boot would never fit to A360/A369,
since it's usually not possible to alter a embedded ROM code.
And because both the 1st & 2nd level bootstrap code use the private
Faraday Firmware Image Format, it would be better to drop U-boot
image support to simplify the design.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Rename from 'arm: add Faraday firmware image utility'
     into 'arm: add Faraday specific boot command'
   - Add missing CRC check to the command 'bootfa'.
   - Add rationale to the command 'bootfa'.

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.

Changes for v2:
   - Coding Style cleanup.

 arch/arm/cpu/faraday/Makefile     |    2 +-
 arch/arm/cpu/faraday/cmd_bootfa.c |  276 +++++++++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/fwimage.h    |   47 +++++++
 arch/arm/cpu/faraday/fwimage2.h   |   67 +++++++++
 arch/arm/cpu/u-boot.lds           |   11 ++
 5 files changed, 402 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 6b96e32..ef6a72e 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk

 LIB	= $(obj)lib$(CPU).o

-src-y  := cpu.o
+src-y  := cpu.o cmd_bootfa.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
 src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..cdc47a3
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,276 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * This command is used to boot faraday firmware from MMC/USB/SPI/NAND/NOR
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * At the time of writting, none of Faraday NAND & SPI controllers
+ * supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
+ * to implement a 1st level bootstrap code stored in the embedded ROM
+ * inside the SoC.
+ *
+ * After power-on, the ROM code (1st level bootstrap code) would load
+ * the 2nd bootstrap code into SRAM without any SDRAM initialization.
+ *
+ * The 2nd bootstrap code would then initialize SDRAM and load the
+ * generic firmware (u-boot/linux) into SDRAM, and finally make
+ * a long-jump to the firmware.
+ *
+ * Which means the SPL design of U-boot would never fit to A360/A369,
+ * since it's usually not possible to alter a embedded ROM code.
+ * And because both the 1st & 2nd level bootstrap code use the private
+ * Faraday Firmware Image Format, it would be better to drop U-boot
+ * image support to simplify the design.
+ *
+ * The Faraday Firmware Image Format uses a 1 KB (1024 Bytes) header:
+ *
+ * +----------------+ 0x0000
+ * | MAGIC          | Magic number
+ * +----------------+ 0x0004
+ * | HDR LENGTH     | The size of this header
+ * +----------------+ 0x0008
+ * |                |
+ * | SYS PARAMETERS | A set of (addr, data) for 32-bit register write,
+ * |                | which is for SDRAM initialization and timing control.
+ * +----------------+ 0x0108
+ * |                |
+ * | PART TABLE     | A partition table with max. 10 entries.
+ * |                |
+ * +----------------+ 0x03D8
+ * | HDR CHECKSUM   | Header Checksum (CRC32)
+ * +----------------+ 0x03DC
+ * | HDR REVISION   | Header Revision ID
+ * +----------------+ 0x03E0
+ * | HDR TIMESTAMP  | Header Creation Timestamp
+ * +----------------+ 0x03E4
+ * | RESERVED       |
+ * +----------------+ 0x0400
+ *
+ * The entry of partitoin table is:
+ *
+ * +----------------+ 0x0000
+ * | NAME           | The name of the partition
+ * +----------------+ 0x0020
+ * | OFFSET         | The offset address of the flash memory.
+ * +----------------+ 0x0024
+ * | LENGTH         | The data length of the partition.
+ * +----------------+ 0x0028
+ * | Load Address   | The address in SDRAM to store the firmware.
+ * +----------------+ 0x002C
+ * | Quick CRC      | An optional CRC32 agains 256KB of TOP & BUTTOM.
+ * +----------------+ 0x0030
+ * | FLAGS          | The flags/attribute of the partition
+ * +----------------+ 0x0034
+ * | RESERVED       |
+ * +----------------+ 0x0040
+ * | MAGIC=0x1000   | It's always a 0x1000.
+ * +----------------+ 0x0044
+ * | MAGIC=0x0001   | It's always a 0x0001.
+ * +----------------+ 0x0048
+ *
+ * The usage of the command 'bootfa' is:
+ *
+ * bootfa <interface> <fw_name>
+ * - boot from 'interface' with the firmware named as <fw_name>
+ *   where 'interface' could be any one of <usb | mmc | nand | sf>
+ *
+ * ex: bootfa usb linux
+ *
+ * The rationale is:
+ *
+ * 1. If 'interface' is either 'usb' or 'mmc/sd', then jumps to 2-a;
+ *    else jumps to 2-b.
+ * 2-a. Translate 'fw_name' to 'filename' from the built-in rules
+ *      (i.e. 'linux' -> 'zimage'), jumps to 3-a.
+ * 2-b. Use 'nand' or 'sf' or 'cp' to load image header into SDRAM,
+ *      and the looking for the 'fw_name' in the partition table.
+ *      If part->name equals 'fw_name', then jumps to 3-b;
+ *      else report an error and exit.
+ * 3-a. Use 'fatload' to load the firmware into SDRAM by filename,
+ *      and then jumps to 4.
+ * 3-b. Use 'nand' or 'sf' or 'cp' to load the firmware into SDRAM
+ *      by .offset & .length of the corresponding partition info,
+ *      and then jumps to 4.
+ * 4. Use 'go' to shift control to the loaded firmware.
+ */
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static int hdr_invalid(struct fwimage2 *img)
+{
+	uint32_t cksum_old, cksum_new;
+
+	if (le32_to_cpu(img->revision) != FWIMAGE2_REVISION)
+		return 0;
+
+	cksum_old = le32_to_cpu(img->hcrc);
+	img->hcrc = 0;
+	cksum_new = crc32_no_comp(0xFFFFFFFF, img, sizeof(struct fwimage2));
+	img->hcrc = cpu_to_le32(cksum_old);
+
+	return (cksum_new != cksum_old);
+}
+
+static int part_invalid(struct fwpart *part, uint8_t *buf)
+{
+	uint32_t len = le32_to_cpu(part->length);
+	uint32_t cksum = 0xFFFFFFFF;
+
+	if (len <= SZ_512K) {
+		cksum = crc32_no_comp(cksum, buf, len);
+	} else {
+		cksum = crc32_no_comp(cksum, buf, SZ_256K);
+		cksum = crc32_no_comp(cksum, buf + len - SZ_256K, SZ_256K);
+	}
+
+	return (cksum != le32_to_cpu(part->qcrc));
+}
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *ppart = hdr->part;
+	static struct fwpart part_local;
+
+	if (hdr_invalid(hdr)) {
+		printf("part_lookup: bad header\n");
+		return NULL;
+	}
+
+	for (i = 0; ppart[i].length > 0 && i < 10; ++i) {
+		if (!strcmp(name, ppart[i].name)) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				ppart[i].name, ppart[i].offset, ppart[i].length);
+
+			memcpy(&part_local, &ppart[i], sizeof(struct fwpart));
+			return &part_local;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part = NULL;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400",
+			CONFIG_SYS_FLASH_BASE,
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x",
+			CONFIG_SYS_FLASH_BASE + part->offset,
+			CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400",
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	if (part && part_invalid(part, (void *)CONFIG_SYS_LOAD_ADDR)) {
+		printf("bad partition!\n");
+		return 1;
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..c6a3e80
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t count;
+	uint32_t version; /* ycmo100525: for firmware image version */
+	uint32_t addr[31];
+	uint32_t data[31];
+};
+
+struct fwfile {
+	char name[64];
+	uint32_t size;
+};
+
+struct fwimage {
+	uint32_t magic; /* Image Header Magic */
+	uint32_t length;/* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam param;
+
+	struct fwfile  file[1];
+};
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H */
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..52e0b94
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage2.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+
+#include "fwimage.h"
+
+struct fwpart {
+	char name[32];
+
+	uint32_t offset;
+	uint32_t length;
+
+	uint32_t load;
+	uint32_t qcrc; /* Quick checksum againsts 256KB of TOP & BOTTOM */
+
+	uint32_t flags;
+#define FWIMAGE2_PART_FILESYSTEM    0x80000000 /* Is a filesystem ? */
+
+	uint32_t rsvd[3];
+	uint32_t magic1000; /* It's always 0x1000 */
+	uint32_t magic0001; /* It's always 0x0001 */
+}; /* size = 72 bytes */
+
+struct fwimage2 {
+	uint32_t magic; /* Image Header Magic */
+#define FWIMAGE2_MAGIC  0x00484946 /* "FIH\0" */
+
+	uint32_t hlen;  /* Image Header Length */
+
+	/* 256 bytes, 32-bit memory write */
+	struct {
+		uint32_t addr;
+		uint32_t data;
+	} mw32[32];
+
+	/* 720 bytes, partition table */
+	struct fwpart part[10];
+
+	uint32_t hcrc;     /* Image Header Checksum (CRC32) */
+	uint32_t revision; /* Image Format Revision ID */
+#define FWIMAGE2_REVISION   0x00000202 /* v2.2 */
+
+	uint32_t time;     /* Image Creation Timestamp */
+	uint32_t rsvd[7];
+}; /* size = 1024 bytes */
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H */
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index d9bbee3..ac59fec 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -23,6 +23,8 @@
  * MA 02111-1307 USA
  */

+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -35,6 +37,15 @@ SECTIONS
 	{
 		__image_copy_start = .;
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}

--
1.7.9.5

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

* [U-Boot] [PATCH v5 13/14] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (11 preceding siblings ...)
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 12/14] arm: add Faraday specific boot command Kuo-Jung Su
@ 2013-06-17 12:07   ` Kuo-Jung Su
  2013-06-17 18:32     ` Andy Fleming
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 14/14] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
  13 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This updates ftsdc010_mci.c for latest Faraday clock APIs.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Andy Fleming <afleming@gmail.com>
---
Changes for v5:
   - Initial commit

 drivers/mmc/ftsdc010_mci.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
index 562b14a..0a0a19b 100644
--- a/drivers/mmc/ftsdc010_mci.c
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -363,7 +363,7 @@ int ftsdc010_mmc_init(int devid)
 #ifdef CONFIG_SYS_CLK_FREQ
 	chip->sclk = CONFIG_SYS_CLK_FREQ;
 #else
-	chip->sclk = clk_get_rate("SDC");
+	chip->sclk = clock_get_rate(MMC_CLK);
 #endif

 	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
--
1.7.9.5

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

* [U-Boot] [PATCH v5 14/14] arm: add Faraday A360/A369 SoC platform support
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
                     ` (12 preceding siblings ...)
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 13/14] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
@ 2013-06-17 12:07   ` Kuo-Jung Su
  13 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-17 12:07 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds board support for the Faraday A360/A369 SoC platforms.

Working functions:
- MMU/D-cache
- SD Host controller
- USB EHCI controller
- USB Gadget controller
- Network
- NAND

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Define Faraday machine type in board's config header file
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise clock management system

Changes for v4:
   - Coding Style cleanup.
   - Break-down the interrupt, timers and common utilties.

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 MAINTAINERS                                   |    5 +
 arch/arm/cpu/faraday/a360/Makefile            |   49 +++++
 arch/arm/cpu/faraday/a369/Makefile            |   50 +++++
 arch/arm/cpu/faraday/a369/cmd_fa606.c         |   86 +++++++++
 arch/arm/include/asm/arch-a360/hardware.h     |   84 +++++++++
 arch/arm/include/asm/arch-a360/pmu.h          |   54 ++++++
 arch/arm/include/asm/arch-a360/scu.h          |   48 +++++
 arch/arm/include/asm/arch-a369/ahbc.h         |   34 ++++
 arch/arm/include/asm/arch-a369/hardware.h     |   99 ++++++++++
 arch/arm/include/asm/arch-a369/scu.h          |  224 +++++++++++++++++++++++
 arch/arm/include/asm/arch-faraday/clock.h     |   41 +++++
 arch/arm/include/asm/arch-faraday/interrupt.h |   29 +++
 board/faraday/a360evb/Makefile                |   49 +++++
 board/faraday/a360evb/board.c                 |   72 ++++++++
 board/faraday/a360evb/clock.c                 |   72 ++++++++
 board/faraday/a360evb/config.mk               |   33 ++++
 board/faraday/a360evb/lowlevel_init.S         |   33 ++++
 board/faraday/a369evb/Makefile                |   49 +++++
 board/faraday/a369evb/board.c                 |  176 ++++++++++++++++++
 board/faraday/a369evb/clock.c                 |   80 ++++++++
 board/faraday/a369evb/config.mk               |   33 ++++
 board/faraday/a369evb/lowlevel_init.S         |  136 ++++++++++++++
 boards.cfg                                    |    3 +
 include/common.h                              |    2 +
 include/configs/a360.h                        |   60 ++++++
 include/configs/a369-common.h                 |   72 ++++++++
 include/configs/a369.h                        |   34 ++++
 include/configs/a369_fa606te.h                |   31 ++++
 include/configs/faraday-common.h              |  243 +++++++++++++++++++++++++
 include/faraday/ftsmc020.h                    |    1 +
 30 files changed, 1982 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 arch/arm/include/asm/arch-faraday/clock.h
 create mode 100644 arch/arm/include/asm/arch-faraday/interrupt.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 14075af..65f00aa 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -643,6 +643,11 @@ Po-Yu Chuang <ratbert@faraday-tech.com>

 	a320evb		FA526 (ARM920T-like) (a320 SoC)

+Kuo-Jung Su <dantesu@faraday-tech.com>
+
+	a360evb		FA626TE (Faraday ARMv5TE) (a360 SoC)
+	a369evb		FA626TE & FA606TE (Faraday ARMv5TE) (a369 SoC)
+
 Eric Cooper <ecc@cmu.edu>

 	dockstar	ARM926EJS (Kirkwood SoC)
diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..7113f66
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..4dddd36
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+obj-$(CONFIG_CMD_FA606) += cmd_fa606.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/cmd_fa606.c b/arch/arm/cpu/faraday/a369/cmd_fa606.c
new file mode 100644
index 0000000..aa9fa6c
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/cmd_fa606.c
@@ -0,0 +1,86 @@
+/*
+ * arch/arm/cpu/faraday/a369/cmd_fa606.c
+ *
+ * This command would start the A369 slave cpu:FA606TE,
+ * and also immediately halt the master cpu:FA626TE.
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/ahbc.h>
+
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a369ahbc_regs *ahbc = (void __iomem *)CONFIG_AHBC2_BASE;
+
+static int do_fa606(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int addr = CONFIG_SYS_LOAD_ADDR;
+
+	if (argc >= 2)
+		addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("FA606TE Image at 0x%08X\n", addr);
+	printf("FA626TE is going to halt...\n");
+
+	cleanup_before_linux();
+
+	/* 1. FA606TE address offset = 0 */
+	printf("FA606 address shift disable.\n");
+	writel(0x00000000, &ahbc->cpusao);
+
+	/* 2. Generate a long-jump to 0x00000000 */
+	writel(0xEA00000A, 0x00); /* b   0x30 */
+	writel(addr,       0x20);
+	writel(0xE3A00020, 0x30); /* mov r0, #32 ; 0x20 */
+	writel(0xE590F000, 0x34); /* ldr pc, [r0] */
+
+	/* 3. Pinmux = ICE + LCD */
+	writel(GPMUX_DEFAULT, &scu->gpmux);
+	writel(SCCFG0_DEFAULT, &scu->sccfg[0]);
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+	writel(MFPMUX0_TS(1) | MFPMUX0_ISP(2) | MFPMUX0_SATA(1)
+		| MFPMUX0_EXTAHB(1), &scu->mfpmux[0]);
+	writel(MFPMUX1_SSP0(1), &scu->mfpmux[1]);
+	udelay(5000);
+
+	/* 4. FA606TE clock enable & reset */
+	writel(0x00000000, &scu->hclkgr);
+	udelay(5000);
+	writel(GPMUX_DEFAULT | GPMUX_CPUS_START, &scu->gpmux);
+
+	/* 5. FA626TE is going to halt... */
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15,0,r0,c7,c0,4\n"
+		:
+		:
+		: "r0" /* clobber list */
+	);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	fa606, 2, 0, do_fa606,
+	"launch firmware with A369's built-in fa606te\n",
+	"fa606 [address] - mov pc of fa606te to the specified address.\n"
+);
diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..770964f
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/include/asm/arch-a360/hardware.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC020_BASE		0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+#define CONFIG_FTSSP010_GPIO_BASE	0x98700000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+#define CONFIG_FOTG210_BASE         0x90B00000
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/pmu.h b/arch/arm/include/asm/arch-a360/pmu.h
new file mode 100644
index 0000000..47bc8a4
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/pmu.h
@@ -0,0 +1,54 @@
+/*
+ * arch/arm/include/asm/arch-a360/pmu.h
+ *
+* (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_PMU_H
+#define __ASM_ARCH_PMU_H
+
+struct a360pmu_regs {
+	uint32_t idr;      /* ID register */
+	uint32_t rsvd0;
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pmr;      /* Power mode register */
+
+	uint32_t pmcr;     /* Power manager control register */
+	uint32_t peer;     /* Power manager edge detect enable register */
+	uint32_t pesr;     /* Power manager edge detect status register */
+	uint32_t rsvd1;
+
+	uint32_t pmsr;     /* Power manager status register */
+	uint32_t pgsr;     /* Power manager GPIO sleep state register */
+	uint32_t rsvd2;
+	uint32_t mcr;      /* Misc. control register */
+
+	uint32_t pdcr;     /* PLL/DLL control register */
+	uint32_t rsvd3[7];
+
+	uint32_t pspr[16]; /* Power manager scratch pad register */
+
+	uint32_t rsvd4[3];
+	uint32_t jssr;     /* Jumper setting status register */
+};
+
+#define PMR_FCS     (1 << 2) /* Activate freq. change sequence */
+#define PMR_TURBO   (1 << 1) /* Activate CPU turbo mode (2 x AHB) */
+#define PMR_SLEEP   (1 << 0) /* Activate system sleep mode */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/scu.h b/arch/arm/include/asm/arch-a360/scu.h
new file mode 100644
index 0000000..c02c5aa
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/scu.h
@@ -0,0 +1,48 @@
+/*
+ * arch/arm/include/asm/arch-a360/scu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a360scu_regs {
+	uint32_t idr;      /* 0x00: ID Register */
+	uint32_t gcr;      /* 0x04: General Control Register */
+	uint32_t ccr;      /* 0x08: Clock Configuration Register */
+	uint32_t hcer;     /* 0x0C: AHB Clock Enable Register */
+	uint32_t pcer;     /* 0x10: APB Clock Enable Register */
+	uint32_t csr;      /* 0x14: Configuration Strap Register */
+	uint32_t iomcr[4]; /* IO Mux Control Register */
+	uint32_t iopcr[2]; /* IO Parameter Control Register */
+	uint32_t cescr;    /* CPU Edge Sync Control Register */
+	uint32_t expcr[3]; /* PCI-Express Control Register */
+};
+
+#define CSR_PLL_PRESCALE    (1 << 9)
+#define CSR_PCIE_MODE1      (1 << 8)
+#define CSR_PCIE_MODE0      (1 << 7)
+#define CSR_DBG_SW          (1 << 6)
+#define CSR_DBG_EN          (1 << 5)
+#define CSR_NAND_LP         (1 << 4)         /* NAND: Large Page */
+#define CSR_NAND_AL(x)      (((x) >> 2) & 3) /* NAND: Address Length */
+#define CSR_NAND_16X        (1 << 1)         /* NAND: 16-bits */
+#define CSR_SPIBOOT         (1 << 0)         /* Boot from SPI(1)/NAND(0) */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/ahbc.h b/arch/arm/include/asm/arch-a369/ahbc.h
new file mode 100644
index 0000000..5a77825
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/ahbc.h
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/include/asm/arch-a369/ahbc.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_AHBC_H
+#define __ASM_ARCH_AHBC_H
+
+struct a369ahbc_regs {
+	uint32_t slave[32];/* Slave Device Configurations */
+	uint32_t priority; /* Priority */
+	uint32_t idle_cnt; /* IDLE Counter */
+	uint32_t control;  /* Control Register */
+	uint32_t revision; /* Revision ID */
+	uint32_t cpusao;   /* CPUS (FA606TE) Address Offset */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..e71fc10
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,99 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDR_BASE             0x93100000
+#define CONFIG_AHB_BASE             0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/scu.h b/arch/arm/include/asm/arch-a369/scu.h
new file mode 100644
index 0000000..ca6f44f
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/scu.h
@@ -0,0 +1,224 @@
+/*
+ * arch/arm/include/asm/arch-a369/scu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a369scu_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)   (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x) ((((x) >> 3) & 0x3) > 2 ? 2 : (((x) >> 3) & 0x3))
+#define HWCFG_DLL_OFF     (1 << 2)
+#define HWCFG_PLL_OFF     (1 << 1)
+#define HWCFG_OSCHCNT_OFF (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 0x3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 0x3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 0x3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif
diff --git a/arch/arm/include/asm/arch-faraday/clock.h b/arch/arm/include/asm/arch-faraday/clock.h
new file mode 100644
index 0000000..74db551
--- /dev/null
+++ b/arch/arm/include/asm/arch-faraday/clock.h
@@ -0,0 +1,41 @@
+/*
+ * asm/arch-faraday/clock.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ASM_ARCH_FARADAY_CLOCK_H
+#define _ASM_ARCH_FARADAY_CLOCK_H
+
+/* Clock identifiers */
+enum clk_id {
+	SYS_CLK,
+	AHB_CLK,
+	APB_CLK,
+	CPU_CLK,
+	I2C_CLK,
+	MMC_CLK,
+	SDC_CLK,
+	SPI_CLK,
+	SSP_CLK,
+};
+
+void  clock_init(void);
+ulong clock_get_rate(enum clk_id id);
+
+#endif	/* _ASM_ARCH_FARADAY_CLOCK_H */
diff --git a/arch/arm/include/asm/arch-faraday/interrupt.h b/arch/arm/include/asm/arch-faraday/interrupt.h
new file mode 100644
index 0000000..8a38946
--- /dev/null
+++ b/arch/arm/include/asm/arch-faraday/interrupt.h
@@ -0,0 +1,29 @@
+/*
+ * asm/arch-faraday/interrupt.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ASM_ARCH_FARADAY_INTERRUPT_H
+#define _ASM_ARCH_FARADAY_INTERRUPT_H
+
+void irq_set_trigger(int irq, int edge, int low);
+void irq_enable(int irq);
+void irq_disable(int irq);
+
+#endif	/* _ASM_ARCH_FARADAY_INTERRUPT_H */
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..75a5668
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clock.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..f241bb3
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,72 @@
+/*
+ * board/faraday/a360evb/board.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <asm/arch/scu.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a360scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+/*
+ * pinmux
+ */
+static void pinmux_init(void)
+{
+	writel(0x00555500, &scu->iomcr[3]);
+	setbits_le32(&scu->iomcr[0], 0x800002AA);
+	setbits_le32(&scu->iomcr[1], 0x82AAAAAA);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_early_init_f(void)
+{
+	pinmux_init();
+	clock_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	return ftmac110_initialize(bd);
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a360evb/clock.c b/board/faraday/a360evb/clock.c
new file mode 100644
index 0000000..a52ff09
--- /dev/null
+++ b/board/faraday/a360evb/clock.c
@@ -0,0 +1,72 @@
+/*
+ * board/faraday/a360evb/clock.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/pmu.h>
+#include <asm/arch-faraday/clock.h>
+
+static struct a360scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a360pmu_regs *pmu = (void __iomem *)CONFIG_PMU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 40000000; /* 40 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return clk_get_rate_sys() * ((readl(&pmu->pdcr) >> 3) & 0x3f) / 8;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	uint32_t s = readl(&scu->csr);
+	uint32_t p = readl(&pmu->pmr);
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (s & CSR_PLL_PRESCALE) ? 2 : 4;
+
+	return (p & PMR_TURBO) ? (clk * mul) : clk;
+}
+
+ulong clock_get_rate(enum clk_id id)
+{
+	switch (id) {
+	case SYS_CLK:
+		return clk_get_rate_sys();
+	case AHB_CLK:
+		return clk_get_rate_ahb();
+	case APB_CLK:
+		return clk_get_rate_apb();
+	case CPU_CLK:
+		return clk_get_rate_cpu();
+	case I2C_CLK:
+		return clk_get_rate_apb();
+	case MMC_CLK:
+	case SDC_CLK:
+		return clk_get_rate_ahb();
+	case SPI_CLK:
+	case SSP_CLK:
+		return clk_get_rate_apb();
+	default:
+		return 0;
+	}
+}
+
+void clock_init(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate_apb();
+}
diff --git a/board/faraday/a360evb/config.mk b/board/faraday/a360evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a360evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..0d6c43f
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,33 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..75a5668
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clock.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..260cac3
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,176 @@
+/*
+ * board/faraday/a369evb/board.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/scu.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftlcdc200.h>
+#include <faraday/ftsdc010.h>
+#include <faraday/ftnandc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct ftlcdc200_regs *lcd = (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+/* System Control Uint (pinmux) */
+static void scu_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&scu->hclkgr);
+		setbits_le32(&scu->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_SUPP_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &scu->hclkgr);
+		writel(GPMUX_DEFAULT, &scu->gpmux);
+		clrbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &scu->mfpmux[0]);
+#endif
+	}
+
+	/* Clock Setup: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+
+	/* Enable LCD for I2C/TVEncode work-around */
+	/* ... Clock DIV=32 */
+	writel(PCR_DIV(32), &lcd->pcr);
+	/* ... Enable LCD */
+	writel(FER_EN | FER_ON, &lcd->fer);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	/* 1. NOR flash */
+	/* Bank 0: base=0x00000000, size=64MB, 16bits */
+	writel(FTSMC020_BANK_ENABLE | FTSMC020_BANK_BASE(0)
+		| FTSMC020_BANK_SIZE_64M | FTSMC020_BANK_MBW_16,
+		&smc->bank[0].cr);
+	/* Bank 0: worst timing */
+	writel(FTSMC020_TPR_WORST, &smc->bank[0].tpr);
+
+	/* 2. Unused Area */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	scu_init();
+	smc_init();
+	clock_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_SYS_NAND_SELF_INIT
+void board_nand_init(void)
+{
+	int alen, devnum = 0;
+	struct mtd_info *mtd = &nand_info[devnum];
+	struct nand_chip *chip;
+	uint32_t iobase = CONFIG_SYS_NAND_BASE;
+	uint32_t ehwcfg = readl(&scu->ehwcfg);
+
+	chip = calloc(1, sizeof(*chip));
+	if (!chip)
+		return;
+	mtd->priv = chip;
+
+	/* page size */
+	switch (EHWCFG_NAND_PS(ehwcfg)) {
+	case 0:
+		chip->page_shift = 9;	/* 512 */
+		break;
+	case 1:
+		chip->page_shift = 11;	/* 2048 */
+		break;
+	default:
+		chip->page_shift = 12;	/* 4096 */
+		break;
+	}
+
+	/* block size */
+	chip->phys_erase_shift = chip->page_shift + 4
+		+ EHWCFG_NAND_BK(ehwcfg);
+
+	/* address length/cycle */
+	alen = 3 + EHWCFG_NAND_AC(ehwcfg);
+
+	if (ftnandc021_init(chip, iobase, alen))
+		goto bni_err;
+
+	if (nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS))
+		goto bni_err;
+
+	nand_register(devnum);
+
+	return;
+
+bni_err:
+	free(chip);
+}
+#endif /* #ifdef CONFIG_SYS_NAND_SELF_INIT */
diff --git a/board/faraday/a369evb/clock.c b/board/faraday/a369evb/clock.c
new file mode 100644
index 0000000..843a41f
--- /dev/null
+++ b/board/faraday/a369evb/clock.c
@@ -0,0 +1,80 @@
+/*
+ * board/faraday/a369evb/clock.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch-faraday/clock.h>
+
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 33000000; /* 33 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return (clk_get_rate_sys() * PLLCR_NS(readl(&scu->pllcr))) >> 3;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+#ifndef CONFIG_A369_FA606TE_PLATFORM
+	/* If it's an internal CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after
+	 * kicking off slave cpu, so we could check the
+	 * GPMUX_CPUS_START to determine if it's a master.
+	 */
+	if (!(readl(&scu->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&scu->hwcfg));
+#endif
+
+	return clk;
+}
+
+ulong clock_get_rate(enum clk_id id)
+{
+	switch (id) {
+	case SYS_CLK:
+		return clk_get_rate_sys();
+	case AHB_CLK:
+		return clk_get_rate_ahb();
+	case APB_CLK:
+		return clk_get_rate_apb();
+	case CPU_CLK:
+		return clk_get_rate_cpu();
+	case I2C_CLK:
+		return clk_get_rate_apb();
+	case MMC_CLK:
+	case SDC_CLK:
+		return clk_get_rate_ahb();
+	case SPI_CLK:
+	case SSP_CLK:
+		return clk_get_rate_apb();
+	default:
+		return 0;
+	}
+}
+
+void clock_init(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate_apb();
+}
diff --git a/board/faraday/a369evb/config.mk b/board/faraday/a369evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a369evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..0e02636
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,136 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+	.macro	_v3_mw32
+
+	ldr r0, =0x1008
+	ldr r3, =0x1108
+_v3_mw32_loop:
+	cmp   r0, r3
+	movhs r1, #0
+	ldrlo r1, [r0, #0]
+	ldrlo r2, [r0, #4]
+	teq   r1, #0
+	strne r2, [r1, #0]
+	addne r0, #8
+	bne   _v3_mw32_loop
+
+	.endm	/* _v3_mw32 */
+
+	.macro	_sdram_enable
+
+	/* Clear SDRAM CKE, GPIO Hold, READ Hold */
+	ldr r0, =CONFIG_SCU_BASE
+	mov r1, #7
+	str r1, [r0, #0x14]
+
+	/* Wait until sdram ready */
+	ldr r0, =CONFIG_DDR_BASE
+_sdram_wait:
+	ldr r1, [r0, #0x04]
+	teq r1, #0x100
+	bne _sdram_wait
+
+	.endm	/* _sdram_enable */
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	/* Check image header */
+	ldr   r1, =0x1000
+	ldr   r0, [r1, #0]
+	ldr   r1, =0x00484946	/* "FIH\0" */
+	ldr   r2, =0x33333639	/* "3369" */
+	teq   r0, r1
+	teqne r0, r2
+	bne _exit
+	_v3_mw32
+	_sdram_enable
+
+#if 1
+	/* Create a shadow copy onto SDRAM (limited to 512K) */
+	mov	r0, #0               /* r0 <- start of source */
+	ldr	r1, =CONFIG_AHB_BASE
+	ldr r2, [r1,#0x18]
+	bic r1, r2, #0x000f0000  /* r1 <- SDRAM base */
+	mov	r2, #0x80000         /* r2 <- source end address (512KB) */
+
+_copy_loop:
+	ldmia	r0!, {r3-r10} /* copy from source address [r0] */
+	stmia	r1!, {r3-r10} /* copy to   target address [r1] */
+	cmp	r0, r2            /* until source end addreee [r2] */
+	ble	_copy_loop
+#else
+	/* Adjust lr(r14) to the remapped address */
+	ldr r0, =CONFIG_AHB_BASE
+	ldr r1, [r0,#0x18]    /* r1 = AHB slave 6 */
+	bic r1, r1, #0xff000000
+	bic r1, r1, #0x00f00000
+	lsr r1, r1, #16
+	add r1, r1, #20
+	mov r2, #1
+	lsl r2, r2, r1
+	add lr, lr, r2
+#endif
+
+	/* AHB remap */
+	mov r0, #0
+	ldr r1, =CONFIG_AHB_BASE
+	ldr r2, =CONFIG_DDR_BASE
+	/* magic (r5) = REG32(0x00) XOR 0xFFFFFFFF */
+	ldr r5, [r0, #0]
+	ldr r3, =0xffffffff
+	eor r5, r5, r3
+	/* r3 = REG32(CONFIG_IOBASE_DDR + 0x10) & 0x00FFFFFF */
+	ldr r3, [r2, #0x10]
+	bic r3, #0xff000000
+	/* r4 = 0x00100f01 */
+	ldr r4, =0x00100f01
+
+	/*
+	 * invalidate i-cache all to make sure the codes bellow
+	 * to be fetched into a single 32-bytes cache line
+	 */
+	mcr p15, 0, r0, c7, c5, 0
+
+	.align 5
+
+	str r3, [r2, #0x10] /* REG32(CONFIG_IOBASE_DDR + 0x10) &= 0x00FFFFFF */
+	str r4, [r1, #0x88] /* REG32(CONFIG_IOBASE_AHB + 0x88)  = 0x00100F01 */
+
+_remap_wait:
+	str r5, [r0, #0]
+	ldr r1, [r0, #0]
+	teq r1, r5
+	bne _remap_wait		/* while(magic != REG32(addr)) */
+
+_exit:
+	mov	pc, lr
diff --git a/boards.cfg b/boards.cfg
index e2a8d42..16610e2 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -73,6 +73,9 @@ mini2440                     arm         arm920t     mini2440            friendl
 VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
 smdk2410                     arm         arm920t     -                   samsung        s3c24x0
 omap1510inn                  arm         arm925t     -                   ti
+a360                         arm         faraday     a360evb             faraday        a360
+a369                         arm         faraday     a369evb             faraday        a369
+a369_fa606te                 arm         faraday     a369evb             faraday        a369
 integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap:CM926EJ_S
 integratorcp_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorcp:CM924EJ_S
 aspenite                     arm         arm926ejs   -                   Marvell        armada100
diff --git a/include/common.h b/include/common.h
index 812e9b6..dc48a84 100644
--- a/include/common.h
+++ b/include/common.h
@@ -111,6 +111,8 @@ typedef volatile unsigned char	vu_char;
 #include <asm/arch/hardware.h>
 #endif
 #ifdef CONFIG_FARADAY
+#include <asm/arch/hardware.h>
+#include <asm/arch-faraday/clock.h>
 #include <asm/arch-faraday/interrupt.h>
 #endif

diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..1614ff4
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,60 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/*
+ * Memory Configuration
+ */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_256M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_PIN    26
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369-common.h b/include/configs/a369-common.h
new file mode 100644
index 0000000..85aa685
--- /dev/null
+++ b/include/configs/a369-common.h
@@ -0,0 +1,72 @@
+#ifndef __CONFIG_A369_COMMON_H
+#define __CONFIG_A369_COMMON_H
+
+#include <asm/hardware.h>
+
+/* A369 Platform Common Configuration */
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_512M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* Interrupt controler */
+#ifndef CONFIG_FTINTC020_BASE
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+#endif
+
+/* NAND Flash */
+#define CONFIG_SYS_MAX_NAND_DEVICE      1 /* Max. num. of devices */
+#define CONFIG_SYS_FTNANDC021_TIMING    { 0x02240264, 0x42054209 }
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_BASE   0x92600000 /* GPIO 1 */
+#define CONFIG_FTSSP010_GPIO_PIN    27
+
+/* NOR Flash */
+/*
+#define PHYS_FLASH_SIZE             SZ_64M
+#define CONFIG_SYS_FLASH_BASE       0x20000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH  FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS  1
+#define CONFIG_SYS_MAX_FLASH_SECT   1024
+*/
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_IN_NAND
+#define CONFIG_ENV_OFFSET           0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND    0x07FE0000
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..da7856e
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,34 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_PLATFORM
+
+/* Support USB-EHCI */
+#define CONFIG_SUPP_EHCI_FARADAY
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Support runtime switching to built-in slave core: FA606TE */
+#define CONFIG_CMD_FA606
+
+/* Autoboot */
+#define CONFIG_BOOTDELAY            3
+#define CONFIG_BOOTCOMMAND          "bootfa nand linux"
+
+/* A369 common configuration */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/a369_fa606te.h b/include/configs/a369_fa606te.h
new file mode 100644
index 0000000..c549edb
--- /dev/null
+++ b/include/configs/a369_fa606te.h
@@ -0,0 +1,31 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_FA606TE_PLATFORM
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Disable I-CACHE */
+#define CONFIG_SYS_ICACHE_OFF
+
+/* Set interrupt controler to FTINCT020:1 */
+#undef  CONFIG_FTINTC020_BASE
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE1
+
+/* A369 common configuration */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..64e8a71
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,243 @@
+/*
+ * include/configs/faraday-common.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+#include <asm/mach-types.h>
+
+#ifndef MACH_TYPE_FARADAY
+#define MACH_TYPE_FARADAY           758
+#endif
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+#define CONFIG_BOARD_EARLY_INIT_F   1
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_8M
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+/*
+ * CPU
+ */
+#define CONFIG_FARADAY
+#define CONFIG_ARCH_CPU_INIT
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_SYS_CACHELINE_SIZE	32
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+/*
+ * Interrupt
+ */
+#if defined(CONFIG_USE_IRQ) && defined(CONFIG_FTI2C010_BASE)
+# define CONFIG_FTINTC020
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_SYS_HZ               1000
+
+#ifdef CONFIG_FTTMR010_BASE
+# define CONFIG_FTTMR010
+#endif /* CONFIG_FTTMR010_BASE */
+
+#ifdef CONFIG_FTPWMTMR010_BASE
+# define CONFIG_FTPWMTMR010
+#endif /* CONFIG_FTPWMTMR010_BASE */
+
+/*
+ * Serial Info
+ */
+#ifdef CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# ifndef CONFIG_SYS_NS16550_CLK
+#  define CONFIG_SYS_NS16550_CLK     18432000
+# endif
+# define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE -4
+# define CONFIG_CONS_INDEX           1
+# define CONFIG_BAUDRATE             38400
+# undef  CONFIG_HWFLOW
+# undef  CONFIG_MODEM_SUPPORT
+#endif /* #ifdef CONFIG_FTUART010_BASE */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTMAC110_BASE
+# define CONFIG_FTMAC110
+#endif
+#ifdef CONFIG_FTGMAC100_BASE
+# define CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA    /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR    32 /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT 20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif
+
+/*
+ * NOR Flash
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* print 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * NAND Flash
+ */
+#ifdef CONFIG_FTNANDC021_BASE
+# define CONFIG_SYS_NAND_SELF_INIT
+# define CONFIG_NAND_FTNANDC021
+# define CONFIG_SYS_NAND_BASE           CONFIG_FTNANDC021_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+#endif
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010_BASE
+# define CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* The hardware core supports SDIO */
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if defined(CONFIG_SUPP_EHCI_FARADAY) && (CONFIG_USB_MAX_CONTROLLER_COUNT > 0)
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#if defined(CONFIG_SUPP_USB_RNDIS) && defined(CONFIG_FOTG210_BASE)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+#endif
+
+/*
+ * LCD
+ */
+#if defined(CONFIG_SUPP_VGA_CONSOLE) && defined(CONFIG_FTLCDC200_BASE)
+# define CONFIG_FTLCDC200
+# define CONFIG_FTLCDC200_800X480S_TPO
+# define LCD_BPP                    4 /* 16-bit per pixel */
+# define CONFIG_LCD
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+#ifndef CONFIG_SYS_LOAD_ADDR        /* Default load address */
+# define CONFIG_SYS_LOAD_ADDR       (CONFIG_SYS_SDRAM_BASE + SZ_1M)
+#endif
+/* Console Baud-Rate Table */
+#define CONFIG_SYS_BAUDRATE_TABLE   { 115200, 57600, 38400, 19200, 9600 }
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 59c6f8e..aa02717 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -82,5 +82,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_WORST	0x0f1ff3ff /* worst but safe */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v5 13/14] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 13/14] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
@ 2013-06-17 18:32     ` Andy Fleming
  2013-06-18  0:48       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Andy Fleming @ 2013-06-17 18:32 UTC (permalink / raw)
  To: u-boot

On Mon, Jun 17, 2013 at 7:07 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> This updates ftsdc010_mci.c for latest Faraday clock APIs.
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> CC: Andy Fleming <afleming@gmail.com>
>


Acked-by: Andy Fleming <afleming@freescale.com>

Since this is part of a series, it should go in with the rest of them,
rather than through the mmc tree.

Andy

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

* [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND controller support
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
@ 2013-06-18  0:08     ` Scott Wood
  2013-06-18  0:51       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-06-18  0:08 UTC (permalink / raw)
  To: u-boot

On 06/17/2013 07:06:55 AM, Kuo-Jung Su wrote:
> diff --git a/README b/README
> index ac1ec44..3dbb7cc 100644
> --- a/README
> +++ b/README
> @@ -3930,6 +3930,12 @@ Low Level (hardware related) configuration  
> options:
>  		- drivers/mtd/nand/ndfc.c
>  		- drivers/mtd/nand/mxc_nand.c
> 
> +- CONFIG_SYS_FTNANDC021_TIMING
> +		This option specifies an array of customized timing  
> parameters
> +		for Faraday FTNANDC021 NAND flash controller.
> +		e.g.
> +		#define CONFIG_SYS_FTNANDC021_TIMING { 0x02240264,  
> 0x42054209 }

But what does 0x02240264 mean?  What does 0x42054209 mean?  I wasn't  
looking for an example, but rather the name of the register you're  
going to use each array element to initialize.

> +	off = 0;
> +	while (off < len && priv->col < mtd->writesize) {
> +		ftnandc021_pio_wait(priv);
> +		*(uint32_t *)(buf + off) = readl(&regs->dr);

This looks like illegal type-punning.  Use memcpy.

Likewise elsewhere.

-Scott

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

* [U-Boot] [PATCH v5 13/14] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  2013-06-17 18:32     ` Andy Fleming
@ 2013-06-18  0:48       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-18  0:48 UTC (permalink / raw)
  To: u-boot

2013/6/18 Andy Fleming <afleming@gmail.com>:
>
>
>
> On Mon, Jun 17, 2013 at 7:07 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> This updates ftsdc010_mci.c for latest Faraday clock APIs.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Albert Aribaud <albert.u.boot@aribaud.net>
>> CC: Andy Fleming <afleming@gmail.com>
>
>
>
> Acked-by: Andy Fleming <afleming@freescale.com>
>
> Since this is part of a series, it should go in with the rest of them,
> rather than through the mmc tree.
>

Got it, thanks



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND controller support
  2013-06-18  0:08     ` Scott Wood
@ 2013-06-18  0:51       ` Kuo-Jung Su
  2013-06-18  0:56         ` Scott Wood
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-18  0:51 UTC (permalink / raw)
  To: u-boot

2013/6/18 Scott Wood <scottwood@freescale.com>:
> On 06/17/2013 07:06:55 AM, Kuo-Jung Su wrote:
>>
>> diff --git a/README b/README
>> index ac1ec44..3dbb7cc 100644
>> --- a/README
>> +++ b/README
>> @@ -3930,6 +3930,12 @@ Low Level (hardware related) configuration options:
>>                 - drivers/mtd/nand/ndfc.c
>>                 - drivers/mtd/nand/mxc_nand.c
>>
>> +- CONFIG_SYS_FTNANDC021_TIMING
>> +               This option specifies an array of customized timing
>> parameters
>> +               for Faraday FTNANDC021 NAND flash controller.
>> +               e.g.
>> +               #define CONFIG_SYS_FTNANDC021_TIMING { 0x02240264,
>> 0x42054209 }
>
>
> But what does 0x02240264 mean?  What does 0x42054209 mean?  I wasn't looking
> for an example, but rather the name of the register you're going to use each
> array element to initialize.
>

Got it, thanks

>> +       off = 0;
>> +       while (off < len && priv->col < mtd->writesize) {
>> +               ftnandc021_pio_wait(priv);
>> +               *(uint32_t *)(buf + off) = readl(&regs->dr);
>
>
> This looks like illegal type-punning.  Use memcpy.
>
> Likewise elsewhere.

How about put_unaligned() / get_unaligned() ?
It looks more simpler and safer to me.

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND controller support
  2013-06-18  0:51       ` Kuo-Jung Su
@ 2013-06-18  0:56         ` Scott Wood
  0 siblings, 0 replies; 311+ messages in thread
From: Scott Wood @ 2013-06-18  0:56 UTC (permalink / raw)
  To: u-boot

On 06/17/2013 07:51:44 PM, Kuo-Jung Su wrote:
> 2013/6/18 Scott Wood <scottwood@freescale.com>:
> > On 06/17/2013 07:06:55 AM, Kuo-Jung Su wrote:
> >> +       off = 0;
> >> +       while (off < len && priv->col < mtd->writesize) {
> >> +               ftnandc021_pio_wait(priv);
> >> +               *(uint32_t *)(buf + off) = readl(&regs->dr);
> >
> >
> > This looks like illegal type-punning.  Use memcpy.
> >
> > Likewise elsewhere.
> 
> How about put_unaligned() / get_unaligned() ?
> It looks more simpler and safer to me.

That's fine too.

-Scott

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

* [U-Boot] [PATCH v5 02/14] net: ftgmac100: add MMU/D-cache support
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 02/14] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
@ 2013-06-23  7:16     ` Albert ARIBAUD
  2013-06-24  1:31       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-23  7:16 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Mon, 17 Jun 2013 20:06:52 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> 3. No matter if MMU/D-cache is on or off, this patch
>    always depends on previous patch:
> 
>    arm: dma_alloc_coherent: malloc() -> memalign().
> 
>    Because the FTGMAC100 expects the tx/rx descriptors
>    are always be aligned to 16-bytes boundary.

Nitpick: as a general rule, the commit message does not need to mention
that a patch in a series depends on a previous one; this is implied by
the series itself.

In fact, it should even /refrain/ from doing so because even though the
series is usually applied atomically, it is not impossible that a an
unrelated 'hot' bugfix patch slip in the middle of it, so "previous
patch", which makes sense at submission time, might not make sense any
more later.

Personally I like the commit message to only provide a short explanation
of the whys and hows of the patch itself, and put any additional info
after the commit message separator "---" below or, if using patman, in
the cover letter.

> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
> CC: Joe Hershberger <joe.hershberger@gmail.com>
> CC: Tom Rini <trini@ti.com>
> ---
> Changes for v5:

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-06-17 12:06   ` [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
@ 2013-06-23  7:18     ` Albert ARIBAUD
  2013-06-23 11:09       ` Tom Rini
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-23  7:18 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Mon, 17 Jun 2013 20:06:53 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> NOTE:
> No matter if MMU/D-cache is on or off, this patch
> always depends on previous patch:
> 
> arm: dma_alloc_coherent: malloc() -> memalign().
> 
> Because the FTMAC110 expects the tx/rx descriptors
> are always be aligned to 16-bytes boundary.

Ditto patch 01/14.

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v5 12/14] arm: add Faraday specific boot command
  2013-06-17 12:07   ` [U-Boot] [PATCH v5 12/14] arm: add Faraday specific boot command Kuo-Jung Su
@ 2013-06-23  7:22     ` Albert ARIBAUD
  2013-06-24  1:30       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-23  7:22 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Mon, 17 Jun 2013 20:07:02 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> At the time of writting, none of Faraday NAND & SPI controllers
> supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
> to implement a 1st level bootstrap code stored in the embedded ROM
> inside the SoC.
> 
> After power-on, the ROM code (1st level bootstrap code) would load
> the 2nd bootstrap code into SRAM without any SDRAM initialization.
> 
> The 2nd bootstrap code would then initialize SDRAM and load the
> generic firmware (u-boot/linux) into SDRAM, and finally make
> a long-jump to the firmware.
> 
> Which means the SPL design of U-boot would never fit to A360/A369,
> since it's usually not possible to alter a embedded ROM code.
> And because both the 1st & 2nd level bootstrap code use the private
> Faraday Firmware Image Format, it would be better to drop U-boot
> image support to simplify the design.

Please reword the last sentence: you're not suggesting "to drop 
U-boot support" from U-Boot, right? You're only suggesting adding the
Faraday image format.

Also, maybe the long explanation should go in the cover letter and a
single shorter paragraph should be given as commit message here.

> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> ---

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-06-23  7:18     ` Albert ARIBAUD
@ 2013-06-23 11:09       ` Tom Rini
  2013-06-23 13:18         ` Albert ARIBAUD
  0 siblings, 1 reply; 311+ messages in thread
From: Tom Rini @ 2013-06-23 11:09 UTC (permalink / raw)
  To: u-boot

On Sun, Jun 23, 2013 at 09:18:11AM +0200, Albert ARIBAUD wrote:
> Hi Kuo-Jung,
> 
> On Mon, 17 Jun 2013 20:06:53 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
> 
> > NOTE:
> > No matter if MMU/D-cache is on or off, this patch
> > always depends on previous patch:
> > 
> > arm: dma_alloc_coherent: malloc() -> memalign().
> > 
> > Because the FTMAC110 expects the tx/rx descriptors
> > are always be aligned to 16-bytes boundary.
> 
> Ditto patch 01/14.

Hasn't hit the list yet :)

-- 
Tom
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <http://lists.denx.de/pipermail/u-boot/attachments/20130623/24638562/attachment.pgp>

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

* [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-06-23 11:09       ` Tom Rini
@ 2013-06-23 13:18         ` Albert ARIBAUD
  2013-06-23 15:17           ` Tom Rini
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-06-23 13:18 UTC (permalink / raw)
  To: u-boot

Hi Tom,

On Sun, 23 Jun 2013 07:09:49 -0400, Tom Rini <trini@ti.com> wrote:

> On Sun, Jun 23, 2013 at 09:18:11AM +0200, Albert ARIBAUD wrote:
> > Hi Kuo-Jung,
> > 
> > On Mon, 17 Jun 2013 20:06:53 +0800, Kuo-Jung Su <dantesu@gmail.com>
> > wrote:
> > 
> > > NOTE:
> > > No matter if MMU/D-cache is on or off, this patch
> > > always depends on previous patch:
> > > 
> > > arm: dma_alloc_coherent: malloc() -> memalign().
> > > 
> > > Because the FTMAC110 expects the tx/rx descriptors
> > > are always be aligned to 16-bytes boundary.
> > 
> > Ditto patch 01/14.

Actually I meant 02/14, as 01/14 is the patch upon which 02 and 03
depend.
 
> Hasn't hit the list yet :)

Hmm... Gmane has the full series, and so has patchwork.

Or did I miss a joke/pun/other(please specify)?

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-06-23 13:18         ` Albert ARIBAUD
@ 2013-06-23 15:17           ` Tom Rini
  0 siblings, 0 replies; 311+ messages in thread
From: Tom Rini @ 2013-06-23 15:17 UTC (permalink / raw)
  To: u-boot

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 06/23/2013 09:18 AM, Albert ARIBAUD wrote:
> Hi Tom,
> 
> On Sun, 23 Jun 2013 07:09:49 -0400, Tom Rini <trini@ti.com> wrote:
> 
>> On Sun, Jun 23, 2013 at 09:18:11AM +0200, Albert ARIBAUD wrote:
>>> Hi Kuo-Jung,
>>> 
>>> On Mon, 17 Jun 2013 20:06:53 +0800, Kuo-Jung Su 
>>> <dantesu@gmail.com> wrote:
>>> 
>>>> NOTE: No matter if MMU/D-cache is on or off, this patch 
>>>> always depends on previous patch:
>>>> 
>>>> arm: dma_alloc_coherent: malloc() -> memalign().
>>>> 
>>>> Because the FTMAC110 expects the tx/rx descriptors are
>>>> always be aligned to 16-bytes boundary.
>>> 
>>> Ditto patch 01/14.
> 
> Actually I meant 02/14, as 01/14 is the patch upon which 02 and 03
>  depend.
> 
>> Hasn't hit the list yet :)
> 
> Hmm... Gmane has the full series, and so has patchwork.
> 
> Or did I miss a joke/pun/other(please specify)?

No, I just assumed you had a comment in 1/14, hadn't looked at the
whole thing yet.

- -- 
Tom
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://www.enigmail.net/

iQIcBAEBAgAGBQJRxxGDAAoJENk4IS6UOR1WhFIP/2VWO75krgx9OPR0j5uf7NXl
HmcGzctPU1eyxQs5Ss7YgaZueo3dZ76+2zboJ/Y/PfjXjKyWvh2i7BsILElhr1CJ
ufhtS35/Gfi4jvxokMf2w5KTcahXq6SGgo4C8sUc85NfIscnMnWROaFFVe8LiInq
DchFQiqEN1yTJr/nyTnjV/BjHg9L2piXRmTrdxtDjQIYI2Fi7WLIRYTbfqeWwLZ4
AvWwCIh7mDzHM1QQ/+pVsNjJvDZS0Ae1NsM9JS7QRjPlBHVECt/AWqxMnSYsZFfa
A7FyZyBzVtfp3QHYP2jQnS6ZcE4ErYd4aorrnvN4TMmaWzl0jcD3HeCf40SWGAVm
HFzvANj530C3XyPSHHVyCjAGc9ijNO6K9vVZCJpsYceyM3OLMArwIWnuYwFQfqSN
kmhbfOfbSOQhNaiECaZOkSlZEymq1//F25hr1uF0T8nQfXMZMh64NcOyXTysBhX3
WpCpujp/eAywpZaK40Odu2bBiVsSsBtdxkhQACcyIp1bnJslioE3GXEWmwBShP5A
O1a09a3MZG+chAZgiLK4a12JqqapMO2so6Dq7CEw7See/Xkg0WkeTt7NtwTFPlvK
R5x6gfr5EkE0uBWLAr8yJ4HtmUJY4BnlRqXxTYA2Za6d6x5vgIFgkDjQccnPD0JA
8pOaSTargAx7Y1PwZvPG
=X+XJ
-----END PGP SIGNATURE-----

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

* [U-Boot] [PATCH v5 12/14] arm: add Faraday specific boot command
  2013-06-23  7:22     ` Albert ARIBAUD
@ 2013-06-24  1:30       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-24  1:30 UTC (permalink / raw)
  To: u-boot

2013/6/23 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Mon, 17 Jun 2013 20:07:02 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> At the time of writting, none of Faraday NAND & SPI controllers
>> supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
>> to implement a 1st level bootstrap code stored in the embedded ROM
>> inside the SoC.
>>
>> After power-on, the ROM code (1st level bootstrap code) would load
>> the 2nd bootstrap code into SRAM without any SDRAM initialization.
>>
>> The 2nd bootstrap code would then initialize SDRAM and load the
>> generic firmware (u-boot/linux) into SDRAM, and finally make
>> a long-jump to the firmware.
>>
>> Which means the SPL design of U-boot would never fit to A360/A369,
>> since it's usually not possible to alter a embedded ROM code.
>> And because both the 1st & 2nd level bootstrap code use the private
>> Faraday Firmware Image Format, it would be better to drop U-boot
>> image support to simplify the design.
>
> Please reword the last sentence: you're not suggesting "to drop
> U-boot support" from U-Boot, right? You're only suggesting adding the
> Faraday image format.
>

1. Got it, I'll reword the last sentence.
2. Yes, what I meant is "Drop u-boot image support in Faraday image utility"
However I forget that's a tool which is not actually related to U-boot. :P

> Also, maybe the long explanation should go in the cover letter and a
> single shorter paragraph should be given as commit message here.
>

Got it, thanks.


--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v5 02/14] net: ftgmac100: add MMU/D-cache support
  2013-06-23  7:16     ` Albert ARIBAUD
@ 2013-06-24  1:31       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-06-24  1:31 UTC (permalink / raw)
  To: u-boot

2013/6/23 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Mon, 17 Jun 2013 20:06:52 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> 3. No matter if MMU/D-cache is on or off, this patch
>>    always depends on previous patch:
>>
>>    arm: dma_alloc_coherent: malloc() -> memalign().
>>
>>    Because the FTGMAC100 expects the tx/rx descriptors
>>    are always be aligned to 16-bytes boundary.
>
> Nitpick: as a general rule, the commit message does not need to mention
> that a patch in a series depends on a previous one; this is implied by
> the series itself.
>
> In fact, it should even /refrain/ from doing so because even though the
> series is usually applied atomically, it is not impossible that a an
> unrelated 'hot' bugfix patch slip in the middle of it, so "previous
> patch", which makes sense at submission time, might not make sense any
> more later.
>
> Personally I like the commit message to only provide a short explanation
> of the whys and hows of the patch itself, and put any additional info
> after the commit message separator "---" below or, if using patman, in
> the cover letter.
>

Got it, thanks

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (11 preceding siblings ...)
  2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
@ 2013-07-04  3:40 ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 01/12] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
                     ` (12 more replies)
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                   ` (5 subsequent siblings)
  18 siblings, 13 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

   https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.4.0 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2013.04/u-boot

Changes for v6:
   - Drop ethernet driver updates for ftmac110&ftgmac100,
     because they are already commited.
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs
   - arch/arm/cpu/faraday/cmd_bootfa.c: fix compiler warnning
   - arch/arm/cpu/faraday/cmd_bootfa.c: use shorter paragraph
     in commit message, and move the original statement into the
     top of source file.
   - ftnandc021: update README for CONFIG_SYS_FTNANDC021_TIMING
   - ftnandc021: remove illegal type-punning

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (12):
  arm: dma_alloc_coherent: malloc() -> memalign()
  video: add Faraday FTLCDC200 LCD controller support
  nand: add Faraday FTNANDC021 NAND controller support
  cfi_flash: use buffer length in unmap_physmem()
  arm: add MMU/D-Cache support for Faraday cores
  arm: add Faraday processor core support
  arm: add Faraday FTINTC020 interrupt controller support
  arm: add Faraday FTTMR010 timer support
  arm: add Faraday FTPWMTMR010 timer support
  arm: add customized boot command for Faraday Images
  mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  arm: add Faraday A360/A369 SoC platform support

 MAINTAINERS                                   |    5 +
 README                                        |   10 +
 arch/arm/cpu/faraday/Makefile                 |   58 +++
 arch/arm/cpu/faraday/a360/Makefile            |   49 ++
 arch/arm/cpu/faraday/a369/Makefile            |   50 ++
 arch/arm/cpu/faraday/a369/cmd_fa606.c         |   86 ++++
 arch/arm/cpu/faraday/cmd_bootfa.c             |  279 +++++++++++
 arch/arm/cpu/faraday/config.mk                |   33 ++
 arch/arm/cpu/faraday/cpu.c                    |  345 ++++++++++++++
 arch/arm/cpu/faraday/ftintc020.c              |  156 ++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c            |  128 +++++
 arch/arm/cpu/faraday/fttmr010.c               |  136 ++++++
 arch/arm/cpu/faraday/fwimage.h                |   47 ++
 arch/arm/cpu/faraday/fwimage2.h               |   67 +++
 arch/arm/cpu/faraday/start.S                  |  431 +++++++++++++++++
 arch/arm/cpu/u-boot.lds                       |   11 +
 arch/arm/include/asm/arch-a360/hardware.h     |   84 ++++
 arch/arm/include/asm/arch-a360/pmu.h          |   95 ++++
 arch/arm/include/asm/arch-a360/scu.h          |   79 ++++
 arch/arm/include/asm/arch-a369/ahbc.h         |   34 ++
 arch/arm/include/asm/arch-a369/hardware.h     |   99 ++++
 arch/arm/include/asm/arch-a369/scu.h          |  224 +++++++++
 arch/arm/include/asm/arch-faraday/clock.h     |   41 ++
 arch/arm/include/asm/arch-faraday/interrupt.h |   29 ++
 arch/arm/include/asm/dma-mapping.h            |   61 ++-
 arch/arm/include/asm/global_data.h            |    4 +
 arch/arm/include/asm/io.h                     |  160 ++++++-
 arch/arm/include/asm/system.h                 |    7 +-
 arch/arm/lib/cache-cp15.c                     |   12 +
 board/faraday/a360evb/Makefile                |   49 ++
 board/faraday/a360evb/board.c                 |   72 +++
 board/faraday/a360evb/clock.c                 |   72 +++
 board/faraday/a360evb/config.mk               |   33 ++
 board/faraday/a360evb/lowlevel_init.S         |   33 ++
 board/faraday/a369evb/Makefile                |   49 ++
 board/faraday/a369evb/board.c                 |  176 +++++++
 board/faraday/a369evb/clock.c                 |   80 ++++
 board/faraday/a369evb/config.mk               |   33 ++
 board/faraday/a369evb/lowlevel_init.S         |  136 ++++++
 boards.cfg                                    |    3 +
 drivers/mmc/ftsdc010_mci.c                    |    2 +-
 drivers/mtd/cfi_flash.c                       |    2 +-
 drivers/mtd/nand/Makefile                     |    1 +
 drivers/mtd/nand/ftnandc021.c                 |  626 +++++++++++++++++++++++++
 drivers/video/Makefile                        |    1 +
 drivers/video/ftlcdc200.c                     |  148 ++++++
 drivers/video/ftlcdc200_panel.c               |  221 +++++++++
 include/common.h                              |    5 +
 include/configs/a360.h                        |   60 +++
 include/configs/a369-common.h                 |   75 +++
 include/configs/a369.h                        |   34 ++
 include/configs/a369_fa606te.h                |   31 ++
 include/configs/faraday-common.h              |  243 ++++++++++
 include/faraday/ftintc020.h                   |   37 ++
 include/faraday/ftlcdc200.h                   |  179 +++++++
 include/faraday/ftnandc021.h                  |  153 ++++++
 include/faraday/ftpwmtmr010.h                 |   41 ++
 include/faraday/ftsmc020.h                    |    1 +
 include/faraday/fttmr010.h                    |   17 +
 include/lcd.h                                 |   33 ++
 60 files changed, 5451 insertions(+), 15 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftintc020.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 arch/arm/include/asm/arch-faraday/clock.h
 create mode 100644 arch/arm/include/asm/arch-faraday/interrupt.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/faraday/ftintc020.h
 create mode 100644 include/faraday/ftlcdc200.h
 create mode 100644 include/faraday/ftnandc021.h
 create mode 100644 include/faraday/ftpwmtmr010.h

--
1.7.9.5

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

* [U-Boot] [PATCH v6 01/12] arm: dma_alloc_coherent: malloc() -> memalign()
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 02/12] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
                     ` (11 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Even though the MMU/D-cache is off, some DMA engines still
expect strict address alignment.

For example, the incoming Faraday FTMAC110 & FTGMAC100 ethernet
controllers expect the tx/rx descriptors should always be aligned
to 16-bytes boundary.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Initial commit, which is separated from
     "arm: add MMU/D-Cache support for Faraday cores"

 arch/arm/include/asm/dma-mapping.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 5bbb0a0..a11178f 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -32,7 +32,7 @@ enum dma_data_direction {

 static void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	*handle = (unsigned long)malloc(len);
+	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
 }

--
1.7.9.5

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

* [U-Boot] [PATCH v6 02/12] video: add Faraday FTLCDC200 LCD controller support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 01/12] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
                     ` (10 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTLCDC200 Color LCD controller performs translation of
pixel-coded data into the required formats and timings to
drive a variety of single/dual mono and color LCDs.

Depending on the LCD type and mode, the unpacked data can represent:
   1. an actual true display gray or color value
   2. an address to a 256 x 16 bit wide palette RAM gray or color value.

The FTLCDC200 generates 4 individual interrupts for:
   1. DMA FIFO underflow
   2. base address update
   3. vertical status
   4. bus error.

There is also a single combined interrupt that is raised when any of
the individual interrupts become active.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Anatolij Gustschin <agust@denx.de>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - Chain it back to Faraday A360/A369 patch series, because
     Faraday A369 depends on the header file of this patch
     for I2C work-around.(Enable I2C clock to prevent I2C bus hangs)

Changes for v4:
   - Nothing updates

Changes for v3:
   - Nothing updates

Changes for v2:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series

 drivers/video/Makefile          |    1 +
 drivers/video/ftlcdc200.c       |  148 ++++++++++++++++++++++++++
 drivers/video/ftlcdc200_panel.c |  221 +++++++++++++++++++++++++++++++++++++++
 include/faraday/ftlcdc200.h     |  179 +++++++++++++++++++++++++++++++
 include/lcd.h                   |   33 ++++++
 5 files changed, 582 insertions(+)
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/faraday/ftlcdc200.h

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index 68ff34b..92ab9d1 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -35,6 +35,7 @@ COBJS-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
 				exynos_mipi_dsi_lowlevel.o
 COBJS-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o
 COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
+COBJS-$(CONFIG_FTLCDC200) += ftlcdc200.o ftlcdc200_panel.o
 COBJS-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o
 COBJS-$(CONFIG_PXA_LCD) += pxa_lcd.o
 COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o
diff --git a/drivers/video/ftlcdc200.c b/drivers/video/ftlcdc200.c
new file mode 100644
index 0000000..331a35f
--- /dev/null
+++ b/drivers/video/ftlcdc200.c
@@ -0,0 +1,148 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+#ifndef CONFIG_FTLCDC200_FREQ
+#define CONFIG_FTLCDC200_FREQ	clock_get_rate(AHB_CLK)
+#endif
+
+static struct ftlcdc200_regs *regs = (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+static void ftlcdc2xx_fixup(struct vidinfo *panel)
+{
+	u_long ht, vt;
+	u_long div, clk;
+	long fps = 60;
+	long upper = 32767;
+	long lower = -32767;
+
+	if (panel->vl_fps)
+		return;
+
+	/* If it's serial mode */
+	if (panel->vl_serial & SPPR_SERIAL)
+		clk = CONFIG_FTLCDC200_FREQ / 3;
+	else
+		clk = CONFIG_FTLCDC200_FREQ;
+
+	/* Derive clock divisor */
+	ht = panel->vl_col + panel->vl_hbp + panel->vl_hfp + panel->vl_hsw;
+	vt = panel->vl_row + panel->vl_vbp + panel->vl_vfp + panel->vl_vsw;
+	for (div = 1; div <= 0x7f; ++div) {
+		long tmp = (clk / div / ht / vt);
+		if (fps > tmp) {
+			lower = tmp;
+			break;
+		}
+		upper = tmp;
+	}
+	if ((upper - fps) > (fps - lower))
+		div += 1;
+	div = (div > 1) ? (div - 1) : div;
+
+	/* Update hardware register cache */
+	panel->vl_polarity = (panel->vl_polarity & (~0x7f00))
+		| ((div - 1) << 8);
+
+	/* Derive real frame rate */
+	panel->vl_fps = (u_long)(clk / div / ht / vt);
+
+	debug("ftlcdc200: %s\n", panel->vl_name);
+	debug("ftlcdc200: fps=%u (%u < FPS < %u)\n",
+		   (unsigned int)panel->vl_fps,
+		   (unsigned int)lower,
+		   (unsigned int)upper);
+	debug("ftlcdc200: div=%u (ahb=%u MHz)\n",
+		   (unsigned int)div,
+		   (unsigned int)CONFIG_FTLCDC200_FREQ / 1000000);
+}
+
+/* setcolreg used in 8bpp/16bpp */
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+/* initcolregs used in monochrome */
+void lcd_initcolregs(void)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+	uint32_t i, v;
+
+	/*
+	 * initialize the contrast lookup table and the Red, Green, Blue
+	 * gamma lookup table, fill the straight line x-y=0 to the contrast
+	 * and gamma lookup table
+	 */
+	for (i = 0; i < 64; i++) {
+		v = 0x03020100 + 0x04040404 * i;
+		writel(v, &regs->gamma_r[i]);
+		writel(v, &regs->gamma_g[i]);
+		writel(v, &regs->gamma_b[i]);
+	}
+
+	writel(virt_to_phys(lcdbase), &regs->fb0);
+
+	debug("ftlcdc200: fb_base=0x%08X at 0x%08X\n",
+		(uint32_t)lcdbase, readl(&regs->fb0));
+}
+
+void lcd_enable(void)
+{
+	struct vidinfo *panel = &panel_info;
+
+	/* 1. derive the clock parameters at runtime */
+	ftlcdc2xx_fixup(panel);
+	/* 2. disable lcd */
+	writel(0, &regs->fer);
+	/* 3. setup panel parameters */
+	writel(panel->vl_pixel, &regs->ppr);
+	writel(HTCR_PL(panel->vl_col) | HTCR_HSYNC(panel->vl_hsw)
+		| HTCR_HBP(panel->vl_hbp) | HTCR_HFP(panel->vl_hfp),
+		&regs->htcr);
+	writel(VTCR0_LF(panel->vl_row) | VTCR0_VSYNC(panel->vl_vsw)
+		| VTCR0_VFP(panel->vl_vfp), &regs->vtcr[0]);
+	writel(VTCR1_VBP(panel->vl_vbp), &regs->vtcr[1]);
+	writel(panel->vl_polarity, &regs->pcr);
+	writel(panel->vl_serial, &regs->sppr);
+	writel(panel->vl_ccir656, &regs->ccir);
+	/* 4. default 4 cycles delay for all framebuffer */
+	writel(0x04040404, &regs->fifo);
+	/* 5. disable & clean interrupts */
+	writel(0x00, &regs->ier);
+	writel(0x0f, &regs->iscr);
+	/* 6. enable lcd */
+	writel(panel->vl_enable, &regs->fer);
+}
+
+ulong calc_fbsize(void)
+{
+	return ((panel_info.vl_col * panel_info.vl_row *
+			 NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
+}
diff --git a/drivers/video/ftlcdc200_panel.c b/drivers/video/ftlcdc200_panel.c
new file mode 100644
index 0000000..43b38c7
--- /dev/null
+++ b/drivers/video/ftlcdc200_panel.c
@@ -0,0 +1,221 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+struct vidinfo panel_info = {
+#if defined(CONFIG_FTLCDC200_320X240P_SHARP)
+	.vl_name  = "SHARP-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x10,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x10,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0f,
+	.vl_vbp   = 0x07,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBLP,
+	.vl_polarity = POL_DIV(23) | POL_IHS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240P_AUO)
+	.vl_name  = "AUO-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PWROFF,
+	.vl_polarity = POL_DIV(21) | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240S_AUO)
+	.vl_name  = "AUO-320x240s",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(1),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_640X480P_PV)
+	.vl_name  = "PV-640x480p",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x63,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2D,
+	.vl_vsw   = 0x44,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(6) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480S_TPO)
+	.vl_name  = "TPO-800x480s",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x01,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(1) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(0),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_TPO)
+	.vl_name  = "TPO-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x04,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0xD4,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x0A,
+	.vl_vbp   = 0x22,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_CPT)
+	/* Chunghwa Picture Tubes - CLAA048LA0BCT */
+	.vl_name  = "CPT-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x32,
+	.vl_hbp   = 0x31,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0E,
+	.vl_vbp   = 0x05,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X600_VGA)
+	.vl_name  = "D-SUB: VGA-800x600",
+	.vl_col   = 800,
+	.vl_row   = 600,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(3) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_1024X768_VGA)
+	.vl_name  = "D-SUB: VGA-1024x768",
+	.vl_col   = 1024,
+	.vl_row   = 768,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(2) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_720X480_NTSC)
+	.vl_name  = "A/V: NTSC-720x480",
+	.vl_col   = 720,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x06,
+	.vl_hfp   = 0x7D,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x0F,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1A,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 3,
+#elif defined(CONFIG_FTLCDC200_640X480_NTSC)
+	.vl_name  = "A/V: NTSC-640x480",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x02,
+	.vl_hfp   = 0xD1,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x10,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x19,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 1,
+#else
+#error "Please specific target LCD panel."
+#endif
+};
diff --git a/include/faraday/ftlcdc200.h b/include/faraday/ftlcdc200.h
new file mode 100644
index 0000000..35f19b7
--- /dev/null
+++ b/include/faraday/ftlcdc200.h
@@ -0,0 +1,179 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTLCDC200_H
+#define __FTLCDC200_H
+
+/* FTLCDC200 Registers */
+struct ftlcdc200_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t fer;  /* 0x000: Function Enable Register */
+	uint32_t ppr;  /* 0x004: Panel Pixel Register */
+	uint32_t ier;  /* 0x008: Interrupt Enable Register */
+	uint32_t iscr; /* 0x00C: Interrupt Status Clear Register */
+	uint32_t isr;  /* 0x010: Interrupt Status Register */
+	uint32_t rsvd0[1];
+	uint32_t fb0;  /* 0x018: Framebuffer Base Register 0 */
+	uint32_t rsvd1[2];
+	uint32_t fb1;  /* 0x024: Framebuffer Base Register 1 */
+	uint32_t rsvd2[2];
+	uint32_t fb2;  /* 0x030: Framebuffer Base Register 2 */
+	uint32_t rsvd3[2];
+	uint32_t fb3;  /* 0x03C: Framebuffer Base Register 3 */
+	uint32_t rsvd4[2];
+	uint32_t patg; /* 0x048: Pattern Generator */
+	uint32_t fifo; /* 0x04C: FIFO Threshold */
+	uint32_t gpio; /* 0x050: GPIO */
+	uint32_t rsvd5[43];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t htcr;    /* Horizontal Timing Control Register */
+	uint32_t vtcr[2]; /* Vertical Timing Control Register */
+	uint32_t pcr;     /* Polarity Control Register */
+	uint32_t rsvd6[60];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t sppr;    /* Serial Panel Pixel Register */
+	uint32_t ccir;    /* CCIR565 Register */
+	uint32_t rsvd7[62];
+
+	/* 0x300 ~ 0x3ff */
+	uint32_t pipr;    /* Picture-In-Picture Register */
+	uint32_t pip1pos; /* Sub-picture 1 position */
+	uint32_t pip1dim; /* Sub-picture 1 dimension */
+	uint32_t pip2pos; /* Sub-picture 2 position */
+	uint32_t pip2dim; /* Sub-picture 2 dimension */
+	uint32_t rsvd8[59];
+
+	/* 0x400 ~ 0x5ff */
+	uint32_t cmnt[4]; /* Color Management */
+	uint32_t rsvd9[124];
+
+	/* 0x600 ~ 0x6ff */
+	uint32_t gamma_r[64]; /* RED - Gamma Correct */
+
+	/* 0x700 ~ 0x7ff */
+	uint32_t gamma_g[64]; /* GREEN - Gamma Correct */
+
+	/* 0x800 ~ 0x8ff */
+	uint32_t gamma_b[64]; /* BLUE - Gamma Correct */
+
+	/* 0x900 ~ 0x9ff */
+	uint32_t rsvd10[64];
+
+	/* 0xa00 ~ 0xbff */
+	uint32_t palette[128];  /* Palette Write Port */
+
+	/* 0xc00 ~ 0xcff */
+	uint32_t cstn_cr;       /* CSTN Control Register */
+	uint32_t cstn_pr;       /* CSTN Parameter Register */
+	uint32_t rsvd11[62];
+
+	/* 0xd00 ~ 0xdff */
+	uint32_t cstn_bmap[16]; /* CSTN bitmap write port */
+	uint32_t rsvd12[48];
+};
+
+/* LCD Function Enable Register */
+#define FER_EN          (1 << 0)    /* chip enabled */
+#define FER_ON          (1 << 1)    /* screen on */
+#define FER_YUV420      (3 << 2)
+#define FER_YUV422      (2 << 2)
+#define FER_YUV         (1 << 3)    /* 1:YUV, 0:RGB */
+
+/* LCD Panel Pixel Register */
+#define PPR_BPP_1       (0 << 0)
+#define PPR_BPP_2       (1 << 0)
+#define PPR_BPP_4       (2 << 0)
+#define PPR_BPP_8       (3 << 0)
+#define PPR_BPP_16      (4 << 0)
+#define PPR_BPP_24      (5 << 0)
+#define PPR_BPP_MASK    (7 << 0)
+#define PPR_PWROFF      (1 << 3)
+#define PPR_BGR         (1 << 4)
+#define PPR_ENDIAN_LBLP (0 << 5)
+#define PPR_ENDIAN_BBBP (1 << 5)
+#define PPR_ENDIAN_LBBP (2 << 5)
+#define PPR_ENDIAN_MASK (3 << 5)
+#define PPR_RGB1        (PPR_BPP_1)
+#define PPR_RGB2        (PPR_BPP_2)
+#define PPR_RGB4        (PPR_BPP_4)
+#define PPR_RGB8        (PPR_BPP_8)
+#define PPR_RGB12       (PPR_BPP_16 | (2 << 7))
+#define PPR_RGB16_555   (PPR_BPP_16 | (1 << 7))
+#define PPR_RGB16_565   (PPR_BPP_16 | (0 << 7))
+#define PPR_RGB24       (PPR_BPP_24)
+#define PPR_RGB32       (PPR_BPP_24)
+#define PPR_RGB_MASK    (PPR_BPP_MASK | (3 << 7))
+#define PPR_VCOMP_VSYNC (0 << 9)
+#define PPR_VCOMP_VBP   (1 << 9)
+#define PPR_VCOMP_VAIMG (2 << 9)
+#define PPR_VCOMP_VFP   (3 << 9)
+#define PPR_VCOMP_MASK  (3 << 9)
+#define	PPR_PANEL_6BIT  (0 << 11)
+#define	PPR_PANEL_8BIT  (1 << 11)
+#define	PPR_DITHER565   (0 << 12)
+#define	PPR_DITHER555   (1 << 12)
+#define	PPR_DITHER444   (2 << 12)
+#define	PPR_HCLK_RESET  (1 << 14)
+#define	PPR_LCCLK_RESET (1 << 15)
+
+/* LCD Interrupt Enable Register */
+#define IER_FIFOUR      (1 << 0)
+#define IER_NEXTFB      (1 << 1)
+#define IER_VCOMP       (1 << 2)
+#define IER_BUSERR      (1 << 3)
+
+/* LCD Interrupt Status Register */
+#define ISR_FIFOUR      (1 << 0)
+#define ISR_NEXTFB      (1 << 1)
+#define ISR_VCOMP       (1 << 2)
+#define ISR_BUSERR      (1 << 3)
+
+/* LCD Horizontal Timing Control Register */
+#define HTCR_HBP(x)     ((((x) - 1) & 0xff) << 24)
+#define HTCR_HFP(x)     ((((x) - 1) & 0xff) << 16)
+#define HTCR_HSYNC(x)   ((((x) - 1) & 0xff) << 8)
+#define HTCR_PL(x)      (((x >> 4) - 1) & 0xff)
+
+/* LCD Vertical Timing Control Register 0 */
+#define VTCR0_VFP(x)    (((x) & 0xff) << 24)
+#define VTCR0_VSYNC(x)  ((((x) - 1) & 0x3f) << 16)
+#define VTCR0_LF(x)     (((x) - 1) & 0xfff)
+
+/* LCD Vertical Timing Control Register 1 */
+#define VTCR1_VBP(x)    ((x) & 0xff)
+
+/* LCD Polarity Control Register */
+#define PCR_IVS         (1 << 0)
+#define PCR_IHS         (1 << 1)
+#define PCR_ICK         (1 << 2)
+#define PCR_IDE         (1 << 3)
+#define PCR_IPWR        (1 << 4)
+#define PCR_DIV(x)      ((((x) - 1) & 0x7f) << 8)
+
+/* LCD Serial Panel Pixel Register */
+#define SPPR_SERIAL     (1 << 0)
+#define SPPR_DELTA      (1 << 1)
+#define SPPR_CS(x)      ((x) << 2)
+#define SPPR_CS_RGB     (0 << 2)
+#define SPPR_CS_BRG     (1 << 2)
+#define SPPR_CS_GBR     (2 << 2)
+#define SPPR_LSR        (1 << 4)
+#define SPPR_AUO052     (1 << 5)
+
+/* LCD CCIR656 Register */
+#define CCIR_PAL        (0 << 0)
+#define CCIR_NTSC       (1 << 0)
+#define CCIR_P640       (0 << 1)
+#define CCIR_P720       (1 << 1)
+#define CCIR_PHASE(x)   ((x) << 2)
+
+#endif /* __FTLCDC200_H */
diff --git a/include/lcd.h b/include/lcd.h
index 30225ed..14fa4fd 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -253,6 +253,39 @@ typedef struct vidinfo {

 void init_panel_info(vidinfo_t *vid);

+#elif defined(CONFIG_FTLCDC200)
+
+typedef struct vidinfo {
+	ushort	vl_col;		/* Number of columns (i.e. 800) */
+	ushort	vl_row;		/* Number of rows (i.e. 600) */
+
+	u_char	vl_bpix;	/* Bits per pixel, 0 = 1, 1 = 2 ... 4 = 16 */
+
+	/* Timing Parameters */
+	u_char	vl_fps;		/* Frame per second */
+
+	u_char	vl_hsw;
+	u_char	vl_hbp;
+	u_char	vl_hfp;
+
+	u_char	vl_vsw;
+	u_char	vl_vbp;
+	u_char	vl_vfp;
+
+	/* Pre-defined FTLCDC200 register values */
+	u_long	vl_enable;	/* LCDEnable */
+	u_long	vl_pixel;	/* PanelPixel */
+	u_long	vl_polarity;/* Polarity */
+	u_long	vl_serial;	/* SerialPanelPixel */
+	u_long	vl_ccir656;	/* CCIR656 */
+
+	/* Panel name */
+	char	*vl_name;
+
+	ushort	*cmap;		/* Pointer to the colormap */
+	void	*priv;		/* Pointer to driver-specific data */
+} vidinfo_t;
+
 #else

 typedef struct vidinfo {
--
1.7.9.5

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

* [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 01/12] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 02/12] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-08 23:59     ` Scott Wood
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 04/12] cfi_flash: use buffer length in unmap_physmem() Kuo-Jung Su
                     ` (9 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is a integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v6:
   - Update README for CONFIG_SYS_FTNANDC021_TIMING
   - Remove illegal type-punning by introducing
     put_unaligned() & get_unaligned().

Changes for v5 (Part of A360/A369 patch series):
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - For there is a strong dependancy between this and A360/A369 patch
     series, it had been chained back to A360/A369 patch series.
   - The latest nand_base requires the ecc.strength to be set properlly,
     so this patch adds ecc.strength setting accroding to ECC algorithm.

Changes for v5 (Standalone):
   - Update README for the description of CONFIG_SYS_FTNANDC021_TIMING.
   - Drop redundant white space. (i.e. if (mtd->writesize >= ' '4096))

Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Drop the faraday/nand.h to remove dependency to
     Faraday A36x patch series.
   - CONFIG_SYS_NAND_TIMING -> CONFIG_SYS_FTNANDC021_TIMING
   - Remove non-ECC code.
   - Implement private hwecc read/write_page functions
     to get rid of .eccpos & .eccbytes.
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Re-write this driver with ECC enabled and correct column address
     handling for OOB read/write,
   - Fix issuses addressed by Scott.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 README                        |   10 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  626 +++++++++++++++++++++++++++++++++++++++++
 include/faraday/ftnandc021.h  |  153 ++++++++++
 4 files changed, 790 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 include/faraday/ftnandc021.h

diff --git a/README b/README
index 85e5a8d..538ba85 100644
--- a/README
+++ b/README
@@ -4036,6 +4036,16 @@ Low Level (hardware related) configuration options:
 		- drivers/mtd/nand/ndfc.c
 		- drivers/mtd/nand/mxc_nand.c

+- CONFIG_SYS_FTNANDC021_TIMING
+		This option specifies an array of customized timing parameters
+		for Faraday FTNANDC021 NAND flash controller.
+		e.g.
+		#define CONFIG_SYS_FTNANDC021_TIMING \
+			{ CONFIG_NAND_K9F4G08U0B_AC1, CONFIG_NAND_K9F4G08U0B_AC2 }
+		where CONFIG_NAND_K9F4G08U0B_AC[1/2] are the optimized AC
+		timing parameters for register AC_TIMING1 and AC_TIMING2 which
+		control the timing for CLE, ALE, WE and RE signals.
+
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
 		a default value will be used.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index bb81e84..765171a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -64,6 +64,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..a24eae6
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,626 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <nand.h>
+#include <malloc.h>
+
+#include <faraday/ftnandc021.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
+
+struct ftnandc021_chip {
+	void __iomem *regs;
+	int alen;
+	int pgsz;
+	int bksz;
+
+	int col;    /* current column address */
+	int page;   /* current row address/page index */
+	int cmd;    /* current NAND command code */
+	int cmd_hc; /* current FTNANDC021 command code */
+};
+
+static struct nand_ecclayout ftnandc021_ecclayout[] = {
+	{ /* page size = 512 (oob size = 16) */
+		.oobfree = {
+			{ 9, 3 },
+		}
+	},
+	{ /* page size = 2048 (oob size = 64) */
+		.oobfree = {
+			{ 9, 3 },
+		},
+	},
+	{ /* page size = 4096 (oob size = 128) */
+		.oobfree = {
+			{ 9, 7 },
+		},
+	},
+};
+
+static inline int ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t st = readl(&regs->idr[1]);
+
+	if (st & NAND_STATUS_FAIL)
+		return -EIO;
+
+	if (!(st & NAND_STATUS_READY))
+		return -EBUSY;
+
+	if (!(st & NAND_STATUS_WP))
+		return -EIO;
+
+	return 0;
+}
+
+static inline int ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	char rc = 'c';
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			rc = 'e';
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	switch (rc) {
+	case 'e':
+		printf("ftnandc021: ecc timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	case 'c':
+		printf("ftnandc021: cmd timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	default:
+		break;
+	}
+
+	return rc ? -ETIMEDOUT : 0;
+}
+
+static int ftnandc021_read_page(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	/*
+	 * OOB has been read at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it right here.
+	 */
+	chip->read_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static void ftnandc021_write_page(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	/*
+	 * OOB has been written at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it right here.
+	 */
+	chip->write_buf(mtd, buf, mtd->writesize);
+}
+
+static int ftnandc021_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int page)
+{
+	printf("ftnandc021: read_page_raw is not supported\n");
+	return -EIO;
+}
+
+static void ftnandc021_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf)
+{
+	printf("ftnandc021: write_page_raw is not supported\n");
+}
+
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 0;
+
+	priv->cmd_hc = cmd;
+
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : (We have queued data at the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+	case FTNANDC021_CMD_WRPG:
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+static int ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t ts, bk, pg, ac, mask;
+#ifdef CONFIG_SYS_FTNANDC021_TIMING
+	uint32_t timing[] = CONFIG_SYS_FTNANDC021_TIMING;
+
+	writel(timing[0], &regs->atr[0]);
+	writel(timing[1], &regs->atr[1]);
+#endif
+
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	mask = SRR_CHIP_RESET | SRR_ECC_EN;
+	writel(mask, &regs->srr);
+	mdelay(200);
+	if (readl(&regs->srr) & SRR_CHIP_RESET) {
+		printf("ftnandc021: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* sanity check on page size */
+	if (priv->pgsz != 512 && priv->pgsz != 2048 && priv->pgsz != 4096) {
+		printf("ftnandc021: invalid page size=%d\n", priv->pgsz);
+		return -EINVAL;
+	}
+
+	bk = ffs(priv->bksz / priv->pgsz) - 5;
+	pg = (priv->pgsz < 2048) ? 0 : (ffs(priv->pgsz) - 11);
+	ac = priv->alen - 3;
+
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* IO mode = PIO */
+	writel(0, &regs->bcr);
+
+	/* ECC mode */
+	chip->ecc.layout         = ftnandc021_ecclayout + pg;
+	chip->ecc.size           = priv->pgsz;
+	chip->ecc.steps          = 1;
+	chip->ecc.read_page      = ftnandc021_read_page;
+	chip->ecc.write_page     = ftnandc021_write_page;
+	chip->ecc.read_page_raw  = ftnandc021_read_page_raw;
+	chip->ecc.write_page_raw = ftnandc021_write_page_raw;
+	chip->ecc.mode           = NAND_ECC_HW;
+	if (CFGR_ECC_TYPE(readl(&regs->cfgr)) == CFGR_ECC_BCH)
+		chip->ecc.strength = 8;
+	else
+		chip->ecc.strength = 4;
+
+	/* reset the attached flash */
+	if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+		return -ENXIO;
+
+	return 0;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv))
+		ret = 0;
+	else if (!(readl(&regs->sr) & SR_READY))
+		ret = 0;
+
+	return ret;
+}
+
+static int ftnandc021_pio_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = -ETIMEDOUT;
+	uint32_t ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
+		if (!(readl(&regs->ior) & IOR_READY))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftnandc021: pio timeout\n");
+
+	return ret;
+}
+
+static void ftnandc021_read_oob(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	memset(buf, 0xff, len);
+
+	/* bad block */
+	buf[chip->badblockpos] = readl(&regs->bbird) & 0xff;
+
+	/* data */
+	tmp = readl(&regs->crcrd);
+	buf[8] = (tmp >> 0) & 0xff;
+	buf[9] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[12] = (tmp >> 16) & 0xff;
+		buf[13] = (tmp >> 24) & 0xff;
+	}
+
+	tmp = readl(&regs->lsnrd);
+	buf[10] = (tmp >> 0) & 0xff;
+	buf[11] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[14] = (tmp >> 16) & 0xff;
+		buf[15] = (tmp >> 24) & 0xff;
+	}
+}
+
+static void ftnandc021_write_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	/* bad block */
+	tmp = buf[chip->badblockpos];
+	writel(tmp, &regs->bbiwr);
+
+	/* mark it as 'not blank' */
+	tmp = 'W' | (buf[9] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	writel(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	writel(tmp, &regs->lsnwr);
+}
+
+static uint8_t ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+		if (priv->col < 8) {
+			uint32_t idx = priv->col >> 2;
+			uint32_t pos = priv->col & 0x3;
+			uint32_t tmp = readl(&regs->idr[idx]);
+
+			ret = (uint8_t)(tmp >> (pos << 3));
+			priv->col += 1;
+		}
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint8_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: unknown cmd=0x%x in read_byte\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t ret = 0xffff;
+	uint8_t *buf = (uint8_t *)&ret;
+
+	/* LSB format */
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return ret;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void ftnandc021_read_buf(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	int off;
+
+	if (priv->col >= mtd->writesize)
+		return;
+
+	if (priv->cmd == NAND_CMD_READOOB)
+		BUG();	/* should never happen */
+
+	/* skip if it's a blank page */
+	if (chip->oob_poi[8] != 'W') {
+		memset(buf, 0xff, len);
+		return;
+	}
+
+	off = 0;
+	while (off < len && priv->col < mtd->writesize) {
+		ftnandc021_pio_wait(priv);
+#ifndef __ARMEB__
+		put_unaligned_le32(readl(&regs->dr), buf + off);
+#else
+		put_unaligned_be32(readl(&regs->dr), buf + off);
+#endif
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void ftnandc021_write_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t off, val;
+
+	/*
+	 * FTNANDC021 HW design issues:
+	 *
+	 * 1. OOB data must be set before issuing write command,
+	 *    so it's too late to do it right here
+	 * 2. Only after command issued, the data register
+	 *    could accept data.
+	 */
+	if (priv->col >= mtd->writesize)
+		return;
+
+	for (off = 0; off < len && priv->col < mtd->writesize; ) {
+		ftnandc021_pio_wait(priv);
+#ifndef __ARMEB__
+		val = get_unaligned_le32(buf + off);
+#else
+		val = get_unaligned_be32(buf + off);
+#endif
+		writel(val, &regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int ftnandc021_verify_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	int ret = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021: out of memory\n");
+		return -ENOMEM;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			ret = -EINVAL;
+	}
+
+	free(tmp);
+	return ret;
+}
+
+static void ftnandc021_cmdfunc(struct mtd_info *mtd,
+	unsigned cmd, int col, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+
+	priv->cmd = cmd;
+	priv->col = col;
+	priv->page = page;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		priv->col = 0;
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID))
+			printf("ftnandc021: RDID failed.\n");
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		priv->col = mtd->writesize;
+		/* fall-through */
+	case NAND_CMD_READ0:	/* 0x00 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* fetch oob to check if it's a blank page */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+			break;
+		}
+		ftnandc021_read_oob(mtd, chip->oob_poi, mtd->oobsize);
+		/* skip if we don't need page data */
+		if (priv->col >= mtd->writesize)
+			break;
+		/* skip if it's a blank page */
+		if (chip->oob_poi[8] != 'W') {
+			debug("ftnandc021: skip page %d\n", page);
+			break;
+		}
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG))
+			printf("ftnandc021: RDPG failed.\n");
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK))
+			printf("ftnandc021: ERBLK failed\n");
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDST))
+			printf("ftnandc021: RDST failed\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* OOB data must be set before issuing command */
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->oobsize);
+		priv->cmd_hc = (priv->col >= mtd->writesize)
+			? FTNANDC021_CMD_WROOB : FTNANDC021_CMD_WRPG;
+		if (ftnandc021_command(priv, priv->cmd_hc))
+			printf("ftnandc021: CMD_HC=%d failed\n", priv->cmd_hc);
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		/* nothing needs to be done */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+			printf("ftnandc021: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021: unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void ftnandc021_hwcontrol(struct mtd_info *mtd,
+	int cmd, unsigned int ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen)
+{
+	struct ftnandc021_chip *priv;
+
+	priv = calloc(1, sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regs = (void __iomem *)iobase;
+	priv->pgsz = 1 << chip->page_shift;
+	priv->bksz = 1 << chip->phys_erase_shift;
+	priv->alen = alen;
+
+	chip->priv = priv;
+
+	debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n",
+		   priv->pgsz, priv->bksz, priv->alen);
+
+	/* hardware reset */
+	if (ftnandc021_reset(chip))
+		return -EINVAL;
+
+	/* hwcontrol always must be implemented */
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	return 0;
+}
diff --git a/include/faraday/ftnandc021.h b/include/faraday/ftnandc021.h
new file mode 100644
index 0000000..64af806
--- /dev/null
+++ b/include/faraday/ftnandc021.h
@@ -0,0 +1,153 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __FTNANDC021_H
+#define __FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+	/* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4];/* ECC Parity Register */
+	uint32_t ecc_sr;   /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+	/* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsn;	 /* LSN Initialize */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+	/* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+	/* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* ECC Status Register */
+#define ECC_SR_CERR      (1 << 3)  /* correction error */
+#define ECC_SR_ERR       (1 << 2)  /* ecc error */
+#define ECC_SR_DEC       (1 << 1)  /* ecc decode finished */
+#define ECC_SR_ENC       (1 << 0)  /* ecc encode finished */
+
+/* Status Register */
+#define SR_BLANK         (1 << 7)  /* blanking check failed */
+#define SR_ECC           (1 << 6)  /* ecc timeout */
+#define SR_STS           (1 << 4)  /* status error */
+#define SR_CRC           (1 << 3)  /* crc error */
+#define SR_CMD           (1 << 2)  /* command finished */
+#define SR_READY         (1 << 1)  /* chip ready/busy */
+#define SR_ENA           (1 << 0)  /* chip enabled */
+
+/* Access Control Register */
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        (1 << 7)  /* command start */
+
+/* Flow Control Register */
+#define FCR_SWCRC        (1 << 8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       (1 << 7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        (1 << 4)  /* 16 bit data bus */
+#define FCR_WPROT        (1 << 3)  /* write protected */
+#define FCR_NOSC         (1 << 2)  /* bypass status check error */
+#define FCR_MICRON       (1 << 1)  /* Micron 2-plane command */
+#define FCR_NOBC         (1 << 0)  /* skip blanking check error */
+
+/* Interrupt Enable Register */
+#define IER_ENA          (1 << 7)  /* interrupt enabled */
+#define IER_ECC          (1 << 3)  /* ecc error timeout */
+#define IER_STS          (1 << 2)  /* status error */
+#define IER_CRC          (1 << 1)  /* crc error */
+#define IER_CMD          (1 << 0)  /* command finished */
+
+/* BMC PIO Status Register */
+#define IOR_READY        (1 << 0)  /* PIO ready */
+
+/* MLC Software Reset Register */
+#define SRR_ECC_EN       (1 << 8)  /* ECC enabled */
+#define SRR_NANDC_RESET  (1 << 2)  /* NANDC reset */
+#define SRR_BMC_RESET    (1 << 1)  /* BMC reset */
+#define SRR_ECC_RESET    (1 << 0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+/* Memory Configuration Register */
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* Configuration Register */
+#define CFGR_ECC_TYPE(x) (((x) >> 16) & 0xf)
+#define CFGR_ECC_RS      4
+#define CFGR_ECC_BCH     8
+#define CFGR_IOBITS(x)   (((x) >> 8) & 0xff) /* Max. data width */
+#define CFGR_MAXFLS(x)   ((x) & 0xf) /* Max. flash chips */
+
+/* FTNANDC021 built-in command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02   /* reset flash */
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen);
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v6 04/12] cfi_flash: use buffer length in unmap_physmem()
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-25 14:46     ` Stefan Roese
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 05/12] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
                     ` (8 subsequent siblings)
  12 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

While the flash_detect_legacy() of drivers/mtd/cfi_flash.c
feed unmap_physmem() with MAP_NOCACHE as 2nd parameter,
the do_spi_flash_read_write() of common/cmd_sf.c
feed unmap_physmem() with the length of the mapped buffer
as 2nd parameter.

It's apparently a bug, and I personally think the 2nd parameter
should be the length of the mapped buffer.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Stefan Roese <sr@denx.de>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Initial commit, which is separated from
     "arm: add MMU/D-Cache support for Faraday cores"

 drivers/mtd/cfi_flash.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mtd/cfi_flash.c b/drivers/mtd/cfi_flash.c
index 25a5710..616750d 100644
--- a/drivers/mtd/cfi_flash.c
+++ b/drivers/mtd/cfi_flash.c
@@ -1820,7 +1820,7 @@ static int flash_detect_legacy(phys_addr_t base, int banknum)
 					break;
 				else
 					unmap_physmem((void *)info->start[0],
-						      MAP_NOCACHE);
+						      info->portwidth);
 			}
 		}

--
1.7.9.5

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

* [U-Boot] [PATCH v6 05/12] arm: add MMU/D-Cache support for Faraday cores
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 04/12] cfi_flash: use buffer length in unmap_physmem() Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 06/12] arm: add Faraday processor core support Kuo-Jung Su
                     ` (7 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This updates the map_physmem()/unmap_physmem(), and use
them to implement dma_alloc_coherent() & dma_free_coherent().

It uses 1MB section for each mapping, and thus wastes lots of
address space, however this should still be good enough for
tiny systems (i.e. u-boot).

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Add void dram_bank_mmu_setup() into 'arch/arm/cpu/faraday/cpu.c'
     to override the weak function in "cache-cp15.c".
   - Use small page (4KB) to map relocated exception table to 0x0000

Changes for v4:
   - Coding Style cleanup.

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - Drop static non-cached region, now we use map_physmem()/unmap_physmem()
     for dynamic mappings.

Changes for v2:
   - Coding Style cleanup.
   - cache-cp15: Enable write buffer in write-through mode.

 arch/arm/include/asm/dma-mapping.h |   59 ++++++++++++-
 arch/arm/include/asm/global_data.h |    4 +
 arch/arm/include/asm/io.h          |  160 ++++++++++++++++++++++++++++++++++--
 arch/arm/include/asm/system.h      |    7 +-
 arch/arm/lib/cache-cp15.c          |   12 +++
 5 files changed, 230 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index a11178f..5a13af5 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -3,6 +3,9 @@
  * Stelian Pop <stelian@popies.net>
  * Lead Tech Design <www.leadtechdesign.com>
  *
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
+ *
  * See file CREDITS for list of people who contributed to this
  * project.
  *
@@ -24,22 +27,76 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };

-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (va && gd->arch.cpu_mmu) {
+		invalidate_dcache_range((ulong)va, (ulong)va + len);
+		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
+		if (!map)
+			free(va);
+		va = map;
+	}
+
+	if (handle)
+		*handle = virt_to_phys(va);
+
+	return va;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+}
+
+static inline void dma_free_coherent(void *vaddr, ulong len)
+{
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *tmp = (void *)virt_to_phys(vaddr);
+	unmap_physmem(vaddr, len);
+	vaddr = tmp;
+#endif
+	free(vaddr);
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (unsigned long)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 7611d0a..fc78c6a 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -42,6 +42,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..37c737e 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -2,6 +2,7 @@
  *  linux/include/asm-arm/io.h
  *
  *  Copyright (C) 1996-2000 Russell King
+ *  Copyright (C) 2009-2010 Dante Su <dantesu@faraday-tech.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -28,9 +29,36 @@
 #if 0	/* XXX###XXX */
 #include <asm/arch/hardware.h>
 #endif	/* XXX###XXX */
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/system.h>
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#ifndef CONFIG_MMAP_START
+#define CONFIG_MMAP_START   0xd0000000
+#endif
+
+#ifndef CONFIG_MMAP_END
+#define CONFIG_MMAP_END     0xfff00000
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
+/* arch/$(ARCH)/lib/cache.c */
+void invalidate_icache_all(void);
+void flush_dcache_all(void);
+void flush_dcache_range(ulong start, ulong stop);

 static inline void sync(void)
 {
+#ifndef CONFIG_SYS_DCACHE_OFF
+	flush_dcache_all();
+#endif
+#ifndef CONFIG_SYS_ICACHE_OFF
+	invalidate_icache_all();
+#endif
 }

 /*
@@ -39,27 +67,143 @@ static inline void sync(void)
  * properties specified by "flags".
  */
 #define MAP_NOCACHE	(0)
-#define MAP_WRCOMBINE	(0)
-#define MAP_WRBACK	(0)
-#define MAP_WRTHROUGH	(0)
+#define MAP_WRCOMBINE	(1)
+#define MAP_WRBACK	(2)
+#define MAP_WRTHROUGH	(3)
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+static inline void map_flush(ulong start, ulong end)
+{
+	flush_dcache_range(start, end);
+
+	/* invalidate D-TLB */
+	start &= 0xfff00000;
+	end = (end + 0x000fffff) & 0xfff00000;
+	__asm__ __volatile__ (
+		"mov r3, %0\n"
+		"1:\n"
+		"mcr p15, 0, r3, c8, c6, 1\n"
+		"add r3, r3, #4096\n"
+		"cmp r3, %1\n"
+		"blo 1b\n"
+		: /* output */
+		: "r"(start), "r"(end) /* input */
+		: "r3" /* clobber list */
+	);
+}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */

 static inline void *
-map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+map_physmem(phys_addr_t paddr, ulong len, ulong flags)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 vaddr, nattr, oattr, addr, size, end;
+
+	/* 1. check if we have to create a mapping for it */
+	vaddr = paddr;
+	addr  = page_table[vaddr >> 20] & 0xfff00000;
+	oattr = page_table[vaddr >> 20] & 0x1f;
+	switch (flags) {
+	case MAP_WRCOMBINE:
+		nattr = DCACHE_WRITECOMBINE;
+		break;
+	case MAP_WRTHROUGH:
+		nattr = DCACHE_WRITETHROUGH;
+		break;
+	case MAP_WRBACK:
+		nattr = DCACHE_WRITEBACK;
+		break;
+	default:
+		nattr = DCACHE_OFF;
+		break;
+	}
+	if ((nattr == oattr) && (vaddr == addr))
+		return (void *)paddr;
+
+	/* 2. find a contiguous region for it */
+	end = (paddr + len + 0x000fffff) & 0xfff00000;
+	len = end - (paddr & 0xfff00000);
+	size = 0;
+	addr = CONFIG_MMAP_START;
+	vaddr = addr;
+	while (addr < CONFIG_MMAP_END) {
+		/* if va == pa, then it's free to use */
+		if (addr == (page_table[addr >> 20] & 0xfff00000)) {
+			size += SZ_1M;
+		} else {
+			size = 0;
+			vaddr = addr + SZ_1M;
+		}
+		if (size >= len)
+			break;
+		addr += SZ_1M;
+	}
+	if (size < len)
+		return NULL;
+
+	/* 3. create the map */
+	map_flush(vaddr, vaddr + size);
+	addr = vaddr;
+	vaddr += paddr & 0x000fffff;
+	paddr &= 0xfff00000;
+	while (size) {
+		page_table[addr >> 20] = paddr | (3 << 10) | nattr;
+		size -= SZ_1M;
+		addr += SZ_1M;
+		paddr += SZ_1M;
+	}
+	return (void *)vaddr;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (void *)paddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
  * Take down a mapping set up by map_physmem().
  */
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
+static inline void unmap_physmem(void *vaddr, ulong len)
 {
-
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 addr, end;
+
+	/* 1. skip on NULL pointer */
+	if (!vaddr)
+		return;
+
+	/* 2. check if it's the right address map */
+	addr = (u32)vaddr;
+	if ((page_table[addr >> 20] & 0xfff00000) == addr)
+		return;
+
+	/* 3. reset the map */
+	end = (addr + len + 0x000fffff) & 0xfff00000;
+	addr &= 0xfff00000;
+	map_flush(addr, end);
+	while (addr < end) {
+		page_table[addr >> 20] = addr | (3 << 10) | DCACHE_OFF;
+		addr += SZ_1M;
+	}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

-static inline phys_addr_t virt_to_phys(void * vaddr)
+static inline phys_addr_t virt_to_phys(void *vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	phys_addr_t phys = (phys_addr_t)vaddr;
+
+	if (!gd->arch.cpu_mmu || !vaddr)
+		return phys;
+
+	phys = page_table[(u32)vaddr >> 20] & 0xfff00000;
+	phys += (u32)vaddr & 0x000fffff;
+
+	return phys;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	return (phys_addr_t)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 760345f..050b707 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -97,9 +97,10 @@ static inline void set_dacr(unsigned int val)

 /* options available for data cache on each page */
 enum dcache_option {
-	DCACHE_OFF = 0x12,
-	DCACHE_WRITETHROUGH = 0x1a,
-	DCACHE_WRITEBACK = 0x1e,
+	DCACHE_OFF = 0x12,          /* non-cached + non-buffered */
+	DCACHE_WRITECOMBINE = 0x16, /* non-cached + buffered */
+	DCACHE_WRITETHROUGH = 0x1a, /* cached + non-buffered */
+	DCACHE_WRITEBACK = 0x1e,    /* cached + buffered */
 };

 /* Size of an MMU section */
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 4abe1cf..97436f6 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -1,6 +1,8 @@
 /*
  * (C) Copyright 2002
  * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ * (C) Copyright 2010
+ * Dante Su <dantesu@faraday-tech.com>
  *
  * See file CREDITS for list of people who contributed to this
  * project.
@@ -126,6 +128,10 @@ static inline void mmu_setup(void)

 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#ifdef CONFIG_FARADAY
+	reg |= CR_W;	/* enable write buffer */
+	reg |= CR_Z;	/* enable branch prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -140,9 +146,15 @@ static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;

+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
+
 	reg = get_cr();	/* get control reg. */
 	cp_delay();
 	set_cr(reg | cache_bit);
--
1.7.9.5

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

* [U-Boot] [PATCH v6 06/12] arm: add Faraday processor core support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 05/12] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 07/12] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
                     ` (6 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds i/d-cache control, mmu setup & bootstrap code
for Faraday cores.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Initial commit which is separated from
     "arm: add Faraday common utilities"

 arch/arm/cpu/faraday/Makefile  |   55 +++++
 arch/arm/cpu/faraday/config.mk |   33 +++
 arch/arm/cpu/faraday/cpu.c     |  343 ++++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/start.S   |  431 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 862 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..ecb240a
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,55 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+src-y  := cpu.o
+
+START	= start.o
+COBJS	= $(src-y)
+
+ifdef	CONFIG_SPL_BUILD
+ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE
+START	:=
+endif
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f03030a
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
+
+PLATFORM_CPPFLAGS += -march=armv4
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..449bf0d
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,343 @@
+/*
+ * arch/arm/cpu/faraday/cpu.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+
+	disable_interrupts();
+
+	/* turn off D-cache */
+	dcache_disable();
+
+	/* flush I-cache */
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n" /* invalidate i-cache all */
+		:      /* output */
+		:      /* input */
+		: "r0" /* clobber list */
+	);
+
+	return 0;
+}
+
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#else
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c14,0\n" /* clean & invalidate d-cache all */
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n" /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n" /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c6,0\n" /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r0"/* clobber list */
+	);
+}
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c5,0\n" /* invalidate i-cache all */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
+
+void enable_caches(void)
+{
+	icache_enable();
+
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		puts("MMU:   on\n");
+		dcache_enable();
+	} else
+#endif
+		puts("MMU:   off\n");
+}
+
+#define CPUID_VID(x)        (((x) >> 24) & 0xff)
+#define CPUID_ISA(x)        (((x) >> 16) & 0xff)
+#define CPUID_PID(x)        (((x) >>  4) & 0x0fff)
+#define CPUID_REV(x)        ((x) & 0x0f) /* revision */
+#define CPUID_NOREV(x)      (((x) >>  4) & 0x0fffffff)
+
+/* Vendor ID */
+#define CPUID_VID_ARM       0x41
+#define CPUID_VID_FARADAY   0x66
+
+/* Instruction Set Architecture */
+#define CPUID_ISA_ARMV4     0x01
+#define CPUID_ISA_ARMV5TE   0x05
+#define CPUID_ISA_ARMV5TEJ  0x06
+
+/* Faraday ARMv4 cores */
+#define CPUID_FA526         0x6601526
+#define CPUID_FA626         0x6601626
+
+/* Faraday ARMv5TE cores */
+#define CPUID_FA606TE       0x6605606
+#define CPUID_FA616TE       0x6605616
+#define CPUID_FA626TE       0x6605626
+#define CPUID_FA726TE       0x6605726
+
+#ifdef CONFIG_ARCH_CPU_INIT
+
+int arch_cpu_init(void)
+{
+	unsigned int id, ctr;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		"mrc p15, 0, %1, c0, c0, 1\n"
+		: "=r"(id), "=r"(ctr) /* output */
+		: /* input */
+	);
+
+	gd->arch.cpu_id = id;
+
+	/* MMU/D-Cache */
+	switch (CPUID_NOREV(gd->arch.cpu_id)) {
+	case CPUID_FA606TE: /* FA606TE (no-mmu) */
+		/* Disable MMU/D-Cache */
+		gd->arch.cpu_mmu = 0;
+		break;
+	default:
+		/* Enable MMU/D-Cache */
+		gd->arch.cpu_mmu = 1;
+		break;
+	}
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+	uint vid = CPUID_VID(gd->arch.cpu_id);
+	uint pid = CPUID_PID(gd->arch.cpu_id);
+
+	/* build cpu_name */
+	switch (vid) {
+	case CPUID_VID_FARADAY:	/* Faraday */
+		switch (CPUID_ISA(gd->arch.cpu_id)) {
+		case CPUID_ISA_ARMV5TE:
+			sprintf(cpu_name, "FA%xTE", pid);
+			break;
+		default:
+			sprintf(cpu_name, "FA%x", pid);
+			break;
+		}
+		break;
+	case CPUID_VID_ARM:	/* ARM */
+		if ((pid & 0xff0) == 0xc00)
+			sprintf(cpu_name, "Cortex-A%u", (pid & 0x00f));
+		else if (pid >= 0xa00)
+			sprintf(cpu_name, "ARM%x", 0x1000 + (pid - 0xa00));
+		else
+			sprintf(cpu_name, "ARM%x", pid);
+		break;
+	default:
+		sprintf(cpu_name, "Unknown");
+		break;
+	}
+
+	/* print cpu_info */
+	printf("CPU:   %s %u MHz\n",
+		cpu_name, (unsigned int)(clock_get_rate(CPU_CLK) / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clock_get_rate(AHB_CLK) / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clock_get_rate(APB_CLK) / 1000000));
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+
+#undef  CACHE_SETUP
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+#define CACHE_SETUP DCACHE_WRITETHROUGH
+#else
+#define CACHE_SETUP DCACHE_WRITEBACK
+#endif
+
+#ifdef CONFIG_USE_IRQ
+static u32 page_table[256] __aligned(1024);
+#endif
+
+/*
+ * This dram_bank_mmu_setup() overrides the weak function
+ * in "cache-cp15.c".
+ */
+void dram_bank_mmu_setup(int bank)
+{
+	u32 pa, *sect_table = (u32 *)gd->arch.tlb_addr;
+	bd_t *bd = gd->bd;
+	int	i;
+
+	for (i = bd->bi_dram[bank].start >> 20;
+	     i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
+	     i++) {
+		pa = i << 20;
+		sect_table[i] = pa | (3 << 10) | CACHE_SETUP;
+	}
+
+#ifdef CONFIG_USE_IRQ
+	/* only setup exception table when bank == 0 */
+	if (bank)
+		return;
+
+	/* make sure the exception table is mapped to 0x00000000 */
+	sect_table[0] = (u32)page_table | 0x11; /* coarse page */
+	page_table[0] = gd->relocaddr | 0xff2; /* small page (4KB) */
+
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n" /* invalidate TLB */
+		"mcr p15, 0, r0, c7, c5, 0\n" /* invalidate I Cache */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+#endif /* CONFIG_USE_IRQ */
+}
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt *regs = (void __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with System Reset Function */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+#endif
+}
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..916b4a2
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,431 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * Relocate U-Boot to RAM
+	 * It's copied from the old u-boot release.
+	 */
+#ifndef CONFIG_SPL_BUILD
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq rr_exit
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+rr_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo rr_loop
+
+	/* Adjust the pc to use the correct text address */
+	adr r0, _start
+	ldr r1, _TEXT_BASE
+	sub r2, pc, r0
+	add r2, r2, #4
+	add pc, r1, r2
+
+rr_exit:
+#endif  /* !CONFIG_SPL_BUILD */
+
+	bl	_main
+
+/*---------------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
--
1.7.9.5

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

* [U-Boot] [PATCH v6 07/12] arm: add Faraday FTINTC020 interrupt controller support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (5 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 06/12] arm: add Faraday processor core support Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 08/12] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
                     ` (5 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup.
   - Now the irq is always enabled inside irq_install_handler().

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile    |    1 +
 arch/arm/cpu/faraday/ftintc020.c |  156 ++++++++++++++++++++++++++++++++++++++
 include/common.h                 |    3 +
 include/faraday/ftintc020.h      |   37 +++++++++
 4 files changed, 197 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftintc020.c
 create mode 100644 include/faraday/ftintc020.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index ecb240a..35926c2 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -26,6 +26,7 @@ include $(TOPDIR)/config.mk
 LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o
+src-$(CONFIG_FTINTC020)   += ftintc020.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/ftintc020.c b/arch/arm/cpu/faraday/ftintc020.c
new file mode 100644
index 0000000..542f616
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftintc020.c
@@ -0,0 +1,156 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftintc020.h>
+
+static struct ftintc020_regs *regs = (void __iomem *)CONFIG_FTINTC020_BASE;
+
+static struct {
+	void  *data;
+	void (*func)(void *data);
+} irq_hndl[64];
+
+static inline void irq_acknowledge(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		writel(mask, &regs->irq32.scr);
+	else
+		writel(mask, &regs->irq64.scr);
+}
+
+void irq_enable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		setbits_le32(&regs->irq32.ena, mask);
+	else
+		setbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_disable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		clrbits_le32(&regs->irq32.ena, mask);
+	else
+		clrbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_set_trigger(int irq, int edge, int low)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (edge) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tmr, mask);
+		else
+			setbits_le32(&regs->irq64.tmr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tmr, mask);
+		else
+			clrbits_le32(&regs->irq64.tmr, mask);
+	}
+
+	if (low) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tlr, mask);
+		else
+			setbits_le32(&regs->irq64.tlr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tlr, mask);
+		else
+			clrbits_le32(&regs->irq64.tlr, mask);
+	}
+}
+
+void do_irq(struct pt_regs *pt_regs)
+{
+	int irq;
+	uint32_t stat;
+
+	irq  = 32;
+	stat = readl(&regs->irq64.sr);     /* IRQ 32 ~ 63 */
+	if (!stat) {
+		irq  = 0;
+		stat = readl(&regs->irq32.sr); /* IRQ  0 ~ 31 */
+	}
+	irq += ffs(stat) - 1;
+
+	if (irq < 0) {
+		printf("interrupts: no irq!?\n");
+		return;
+	}
+
+	if (irq_hndl[irq].func)
+		irq_hndl[irq].func(irq_hndl[irq].data);
+	else
+		printf("Unhandled IRQ = %d\n", irq);
+
+	irq_acknowledge(irq);
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *hndl, void *data)
+{
+	if (irq >= 0 && irq < 64) {
+		irq_hndl[irq].func = hndl;
+		irq_hndl[irq].data = data;
+		irq_enable(irq);
+	}
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq >= 0 && irq < 64) {
+		irq_hndl[irq].func = NULL;
+		irq_hndl[irq].data = NULL;
+		irq_disable(irq);
+	}
+}
+
+int arch_interrupt_init(void)
+{
+	int i;
+
+	for (i = 0; i < 64; ++i)
+		irq_free_handler(i);
+
+	/* hardware reset */
+	writel(0x00000000, &regs->irq32.ena);
+	writel(0xffffffff, &regs->irq32.scr);
+	writel(0x00000000, &regs->irq32.tmr);
+	writel(0x00000000, &regs->irq32.tlr);
+
+	writel(0x00000000, &regs->irq64.ena);
+	writel(0xffffffff, &regs->irq64.scr);
+	writel(0x00000000, &regs->irq64.tmr);
+	writel(0x00000000, &regs->irq64.tlr);
+
+	return 0;
+}
diff --git a/include/common.h b/include/common.h
index e5220cf..ec3bf0d 100644
--- a/include/common.h
+++ b/include/common.h
@@ -110,6 +110,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_FARADAY
+#include <asm/arch-faraday/interrupt.h>
+#endif

 #include <part.h>
 #include <flash.h>
diff --git a/include/faraday/ftintc020.h b/include/faraday/ftintc020.h
new file mode 100644
index 0000000..e23d1e7
--- /dev/null
+++ b/include/faraday/ftintc020.h
@@ -0,0 +1,37 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTINTC020_H
+#define ARCH_ARM_CPU_FARADAY_FTINTC020_H
+
+struct ftintc020_pic_regs {
+	uint32_t src; /* source register */
+	uint32_t ena; /* enable register */
+	uint32_t scr; /* status clear register */
+	uint32_t tmr; /* trigger mode register */
+	uint32_t tlr; /* trigger level register */
+	uint32_t sr;  /* status register */
+	uint32_t rsvd[2];
+};
+
+struct ftintc020_regs {
+	/* IRQ/FIQ:  0 ~ 31 */
+	struct ftintc020_pic_regs irq32; /* 0x00 - 0x1C: IRQ 0 ~ 31 */
+	struct ftintc020_pic_regs fiq32; /* 0x20 - 0x3C: FIQ 0 ~ 31 */
+	uint32_t rsvd1[4];               /* 0x40 - 0x4C: Reserved */
+	uint32_t revision;               /* 0x50: Revision Register */
+	uint32_t feature;                /* 0x54: Feature Register */
+	uint32_t rsvd2[2];               /* 0x58 - 0x5C: Reserved */
+	/* IRQ/FIQ: 32 ~ 63 */
+	struct ftintc020_pic_regs irq64; /* 0x60 - 0x7C: IRQ 32 ~ 63 */
+	struct ftintc020_pic_regs fiq64; /* 0x80 - 0x9C: FIQ 32 ~ 63 */
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v6 08/12] arm: add Faraday FTTMR010 timer support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (6 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 07/12] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 09/12] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
                     ` (4 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Drop IRQ dependant implementation
   - Use gd->arch.timer_rate_hz for timer clock source
   - Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    1 +
 arch/arm/cpu/faraday/fttmr010.c |  136 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 +++++
 3 files changed, 154 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 35926c2..658d9ed 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -27,6 +27,7 @@ LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
+src-$(CONFIG_FTTMR010)    += fttmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..9d6f7ac
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,136 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 72abcb3..ef10f31 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -57,6 +57,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -70,4 +80,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v6 09/12] arm: add Faraday FTPWMTMR010 timer support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (7 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 08/12] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 10/12] arm: add customized boot command for Faraday Images Kuo-Jung Su
                     ` (3 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Drop IRQ dependant implementation
   - Use gd->arch.timer_rate_hz for timer clock source
   - Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    1 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  128 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 ++++++++++++
 3 files changed, 170 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 658d9ed..6b96e32 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -28,6 +28,7 @@ LIB	= $(obj)lib$(CPU).o
 src-y  := cpu.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
+src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..8f8185e
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,128 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+#ifdef CONFIG_A369_FA606TE_PLATFORM
+#define TIMER_ID    4
+#else
+#define TIMER_ID    0
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftpwmtmr010_regs *regs = (void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..9455577
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2010 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v6 10/12] arm: add customized boot command for Faraday Images
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (8 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 09/12] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 11/12] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
                     ` (2 subsequent siblings)
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

At the time of writting, none of Faraday NAND & SPI controllers
supports XIP (eXecute In Place), and the 1st stage bootstrap
stored in embedded ROM is not compatible to U-Boot design.

So this patch is added to support booting from Faraday Images.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6:
   - Fix compiler warnning
   - Use shorter paragraph in commit message, and move the
     original statement into the top of cmd_bootfa.c.

Changes for v5:
   - Rename from 'arm: add Faraday firmware image utility'
     into 'arm: add Faraday specific boot command'
   - Add missing CRC check to the command 'bootfa'.
   - Add rationale to the command 'bootfa'.

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.

Changes for v2:
   - Coding Style cleanup.

 arch/arm/cpu/faraday/Makefile     |    2 +-
 arch/arm/cpu/faraday/cmd_bootfa.c |  279 +++++++++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/fwimage.h    |   47 +++++++
 arch/arm/cpu/faraday/fwimage2.h   |   67 +++++++++
 arch/arm/cpu/u-boot.lds           |   11 ++
 5 files changed, 405 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 6b96e32..ef6a72e 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -25,7 +25,7 @@ include $(TOPDIR)/config.mk

 LIB	= $(obj)lib$(CPU).o

-src-y  := cpu.o
+src-y  := cpu.o cmd_bootfa.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
 src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..1645661
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,279 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * This command is used to boot faraday firmware from MMC/USB/SPI/NAND/NOR
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ * At the time of writting, none of Faraday NAND & SPI controllers
+ * supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
+ * to implement a 1st level bootstrap code stored in the embedded ROM
+ * inside the SoC.
+ *
+ * After power-on, the ROM code (1st level bootstrap code) would load
+ * the 2nd bootstrap code into SRAM without any SDRAM initialization.
+ *
+ * The 2nd bootstrap code would then initialize SDRAM and load the
+ * generic firmware (u-boot/linux) into SDRAM, and finally make
+ * a long-jump to the firmware.
+ *
+ * Which means the SPL design of U-boot would never fit to A360/A369,
+ * since it's usually not possible to alter a embedded ROM code.
+ * And because both the 1st & 2nd level bootstrap code use the private
+ * Faraday Firmware Image Format, it would be better to drop U-boot
+ * image support to simplify the design.
+ *
+ * The Faraday Firmware Image Format uses a 1 KB (1024 Bytes) header:
+ *
+ * +----------------+ 0x0000
+ * | MAGIC          | Magic number
+ * +----------------+ 0x0004
+ * | HDR LENGTH     | The size of this header
+ * +----------------+ 0x0008
+ * |                |
+ * | SYS PARAMETERS | A set of (addr, data) for 32-bit register write,
+ * |                | which is for SDRAM initialization and timing control.
+ * +----------------+ 0x0108
+ * |                |
+ * | PART TABLE     | A partition table with max. 10 entries.
+ * |                |
+ * +----------------+ 0x03D8
+ * | HDR CHECKSUM   | Header Checksum (CRC32)
+ * +----------------+ 0x03DC
+ * | HDR REVISION   | Header Revision ID
+ * +----------------+ 0x03E0
+ * | HDR TIMESTAMP  | Header Creation Timestamp
+ * +----------------+ 0x03E4
+ * | RESERVED       |
+ * +----------------+ 0x0400
+ *
+ * The entry of partitoin table is:
+ *
+ * +----------------+ 0x0000
+ * | NAME           | The name of the partition
+ * +----------------+ 0x0020
+ * | OFFSET         | The offset address of the flash memory.
+ * +----------------+ 0x0024
+ * | LENGTH         | The data length of the partition.
+ * +----------------+ 0x0028
+ * | Load Address   | The address in SDRAM to store the firmware.
+ * +----------------+ 0x002C
+ * | Quick CRC      | An optional CRC32 agains 256KB of TOP & BUTTOM.
+ * +----------------+ 0x0030
+ * | FLAGS          | The flags/attribute of the partition
+ * +----------------+ 0x0034
+ * | RESERVED       |
+ * +----------------+ 0x0040
+ * | MAGIC=0x1000   | It's always a 0x1000.
+ * +----------------+ 0x0044
+ * | MAGIC=0x0001   | It's always a 0x0001.
+ * +----------------+ 0x0048
+ *
+ * The usage of the command 'bootfa' is:
+ *
+ * bootfa <interface> <fw_name>
+ * - boot from 'interface' with the firmware named as <fw_name>
+ *   where 'interface' could be any one of <usb | mmc | nand | sf>
+ *
+ * ex: bootfa usb linux
+ *
+ * The rationale is:
+ *
+ * 1. If 'interface' is either 'usb' or 'mmc/sd', then jumps to 2-a;
+ *    else jumps to 2-b.
+ * 2-a. Translate 'fw_name' to 'filename' from the built-in rules
+ *      (i.e. 'linux' -> 'zimage'), jumps to 3-a.
+ * 2-b. Use 'nand' or 'sf' or 'cp' to load image header into SDRAM,
+ *      and the looking for the 'fw_name' in the partition table.
+ *      If part->name equals 'fw_name', then jumps to 3-b;
+ *      else report an error and exit.
+ * 3-a. Use 'fatload' to load the firmware into SDRAM by filename,
+ *      and then jumps to 4.
+ * 3-b. Use 'nand' or 'sf' or 'cp' to load the firmware into SDRAM
+ *      by .offset & .length of the corresponding partition info,
+ *      and then jumps to 4.
+ * 4. Use 'go' to shift control to the loaded firmware.
+ */
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static int hdr_invalid(struct fwimage2 *img)
+{
+	uint32_t cksum_old, cksum_new;
+
+	if (le32_to_cpu(img->revision) != FWIMAGE2_REVISION)
+		return 0;
+
+	cksum_old = le32_to_cpu(img->hcrc);
+	img->hcrc = 0;
+	cksum_new = crc32_no_comp(0xffffffff, (const uint8_t *)img,
+		sizeof(struct fwimage2));
+	img->hcrc = cpu_to_le32(cksum_old);
+
+	return (cksum_new != cksum_old);
+}
+
+static int part_invalid(struct fwpart *part, uint8_t *buf)
+{
+	uint32_t len = le32_to_cpu(part->length);
+	uint32_t cksum = 0xFFFFFFFF;
+
+	if (len <= SZ_512K) {
+		cksum = crc32_no_comp(cksum, buf, len);
+	} else {
+		cksum = crc32_no_comp(cksum, buf, SZ_256K);
+		cksum = crc32_no_comp(cksum, buf + len - SZ_256K, SZ_256K);
+	}
+
+	return (cksum != le32_to_cpu(part->qcrc));
+}
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *ppart = hdr->part;
+	static struct fwpart part_local;
+
+	if (hdr_invalid(hdr)) {
+		printf("part_lookup: bad header\n");
+		return NULL;
+	}
+
+	for (i = 0; ppart[i].length > 0 && i < 10; ++i) {
+		if (!strcmp(name, ppart[i].name)) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				ppart[i].name,
+				ppart[i].offset,
+				ppart[i].length);
+
+			memcpy(&part_local, &ppart[i], sizeof(struct fwpart));
+			return &part_local;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part = NULL;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400",
+			CONFIG_SYS_FLASH_BASE,
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x",
+			CONFIG_SYS_FLASH_BASE + part->offset,
+			CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400",
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	if (part && part_invalid(part, (void *)CONFIG_SYS_LOAD_ADDR)) {
+		printf("bad partition!\n");
+		return 1;
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..c6a3e80
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,47 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t count;
+	uint32_t version; /* ycmo100525: for firmware image version */
+	uint32_t addr[31];
+	uint32_t data[31];
+};
+
+struct fwfile {
+	char name[64];
+	uint32_t size;
+};
+
+struct fwimage {
+	uint32_t magic; /* Image Header Magic */
+	uint32_t length;/* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam param;
+
+	struct fwfile  file[1];
+};
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H */
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..52e0b94
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,67 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage2.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+
+#include "fwimage.h"
+
+struct fwpart {
+	char name[32];
+
+	uint32_t offset;
+	uint32_t length;
+
+	uint32_t load;
+	uint32_t qcrc; /* Quick checksum againsts 256KB of TOP & BOTTOM */
+
+	uint32_t flags;
+#define FWIMAGE2_PART_FILESYSTEM    0x80000000 /* Is a filesystem ? */
+
+	uint32_t rsvd[3];
+	uint32_t magic1000; /* It's always 0x1000 */
+	uint32_t magic0001; /* It's always 0x0001 */
+}; /* size = 72 bytes */
+
+struct fwimage2 {
+	uint32_t magic; /* Image Header Magic */
+#define FWIMAGE2_MAGIC  0x00484946 /* "FIH\0" */
+
+	uint32_t hlen;  /* Image Header Length */
+
+	/* 256 bytes, 32-bit memory write */
+	struct {
+		uint32_t addr;
+		uint32_t data;
+	} mw32[32];
+
+	/* 720 bytes, partition table */
+	struct fwpart part[10];
+
+	uint32_t hcrc;     /* Image Header Checksum (CRC32) */
+	uint32_t revision; /* Image Format Revision ID */
+#define FWIMAGE2_REVISION   0x00000202 /* v2.2 */
+
+	uint32_t time;     /* Image Creation Timestamp */
+	uint32_t rsvd[7];
+}; /* size = 1024 bytes */
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H */
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index 3037885..032018f 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -23,6 +23,8 @@
  * MA 02111-1307 USA
  */

+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -35,6 +37,15 @@ SECTIONS
 	{
 		*(.__image_copy_start)
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}

--
1.7.9.5

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

* [U-Boot] [PATCH v6 11/12] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (9 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 10/12] arm: add customized boot command for Faraday Images Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 12/12] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
  2013-07-25  9:07   ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Albert ARIBAUD
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This updates ftsdc010_mci.c for latest Faraday clock APIs.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Andy Fleming <afleming@gmail.com>
---
Changes for v6:
   - Nothing updates

Changes for v5:
   - Initial commit

 drivers/mmc/ftsdc010_mci.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
index 562b14a..0a0a19b 100644
--- a/drivers/mmc/ftsdc010_mci.c
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -363,7 +363,7 @@ int ftsdc010_mmc_init(int devid)
 #ifdef CONFIG_SYS_CLK_FREQ
 	chip->sclk = CONFIG_SYS_CLK_FREQ;
 #else
-	chip->sclk = clk_get_rate("SDC");
+	chip->sclk = clock_get_rate(MMC_CLK);
 #endif

 	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
--
1.7.9.5

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

* [U-Boot] [PATCH v6 12/12] arm: add Faraday A360/A369 SoC platform support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (10 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 11/12] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
@ 2013-07-04  3:40   ` Kuo-Jung Su
  2013-07-25  9:07   ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Albert ARIBAUD
  12 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-04  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds board support for the Faraday A360/A369 SoC platforms.

Working functions:
- MMU/D-cache
- SD Host controller
- USB EHCI controller
- USB Gadget controller
- Network
- NAND

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6:
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Define Faraday machine type in board's config header file
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise clock management system

Changes for v4:
   - Coding Style cleanup.
   - Break-down the interrupt, timers and common utilties.

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 MAINTAINERS                                   |    5 +
 arch/arm/cpu/faraday/a360/Makefile            |   49 +++++
 arch/arm/cpu/faraday/a369/Makefile            |   50 +++++
 arch/arm/cpu/faraday/a369/cmd_fa606.c         |   86 +++++++++
 arch/arm/cpu/faraday/cpu.c                    |    2 +
 arch/arm/include/asm/arch-a360/hardware.h     |   84 +++++++++
 arch/arm/include/asm/arch-a360/pmu.h          |   95 ++++++++++
 arch/arm/include/asm/arch-a360/scu.h          |   79 ++++++++
 arch/arm/include/asm/arch-a369/ahbc.h         |   34 ++++
 arch/arm/include/asm/arch-a369/hardware.h     |   99 ++++++++++
 arch/arm/include/asm/arch-a369/scu.h          |  224 +++++++++++++++++++++++
 arch/arm/include/asm/arch-faraday/clock.h     |   41 +++++
 arch/arm/include/asm/arch-faraday/interrupt.h |   29 +++
 board/faraday/a360evb/Makefile                |   49 +++++
 board/faraday/a360evb/board.c                 |   72 ++++++++
 board/faraday/a360evb/clock.c                 |   72 ++++++++
 board/faraday/a360evb/config.mk               |   33 ++++
 board/faraday/a360evb/lowlevel_init.S         |   33 ++++
 board/faraday/a369evb/Makefile                |   49 +++++
 board/faraday/a369evb/board.c                 |  176 ++++++++++++++++++
 board/faraday/a369evb/clock.c                 |   80 ++++++++
 board/faraday/a369evb/config.mk               |   33 ++++
 board/faraday/a369evb/lowlevel_init.S         |  136 ++++++++++++++
 boards.cfg                                    |    3 +
 include/common.h                              |    2 +
 include/configs/a360.h                        |   60 ++++++
 include/configs/a369-common.h                 |   75 ++++++++
 include/configs/a369.h                        |   34 ++++
 include/configs/a369_fa606te.h                |   31 ++++
 include/configs/faraday-common.h              |  243 +++++++++++++++++++++++++
 include/faraday/ftsmc020.h                    |    1 +
 31 files changed, 2059 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 arch/arm/include/asm/arch-faraday/clock.h
 create mode 100644 arch/arm/include/asm/arch-faraday/interrupt.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 7820375..537e09f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -643,6 +643,11 @@ Po-Yu Chuang <ratbert@faraday-tech.com>

 	a320evb		FA526 (ARM920T-like) (a320 SoC)

+Kuo-Jung Su <dantesu@faraday-tech.com>
+
+	a360evb		FA626TE (Faraday ARMv5TE) (a360 SoC)
+	a369evb		FA626TE & FA606TE (Faraday ARMv5TE) (a369 SoC)
+
 Eric Cooper <ecc@cmu.edu>

 	dockstar	ARM926EJS (Kirkwood SoC)
diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..7113f66
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..4dddd36
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,50 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+obj-$(CONFIG_CMD_FA606) += cmd_fa606.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/cmd_fa606.c b/arch/arm/cpu/faraday/a369/cmd_fa606.c
new file mode 100644
index 0000000..aa9fa6c
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/cmd_fa606.c
@@ -0,0 +1,86 @@
+/*
+ * arch/arm/cpu/faraday/a369/cmd_fa606.c
+ *
+ * This command would start the A369 slave cpu:FA606TE,
+ * and also immediately halt the master cpu:FA626TE.
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/ahbc.h>
+
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a369ahbc_regs *ahbc = (void __iomem *)CONFIG_AHBC2_BASE;
+
+static int do_fa606(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int addr = CONFIG_SYS_LOAD_ADDR;
+
+	if (argc >= 2)
+		addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("FA606TE Image at 0x%08X\n", addr);
+	printf("FA626TE is going to halt...\n");
+
+	cleanup_before_linux();
+
+	/* 1. FA606TE address offset = 0 */
+	printf("FA606 address shift disable.\n");
+	writel(0x00000000, &ahbc->cpusao);
+
+	/* 2. Generate a long-jump to 0x00000000 */
+	writel(0xEA00000A, 0x00); /* b   0x30 */
+	writel(addr,       0x20);
+	writel(0xE3A00020, 0x30); /* mov r0, #32 ; 0x20 */
+	writel(0xE590F000, 0x34); /* ldr pc, [r0] */
+
+	/* 3. Pinmux = ICE + LCD */
+	writel(GPMUX_DEFAULT, &scu->gpmux);
+	writel(SCCFG0_DEFAULT, &scu->sccfg[0]);
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+	writel(MFPMUX0_TS(1) | MFPMUX0_ISP(2) | MFPMUX0_SATA(1)
+		| MFPMUX0_EXTAHB(1), &scu->mfpmux[0]);
+	writel(MFPMUX1_SSP0(1), &scu->mfpmux[1]);
+	udelay(5000);
+
+	/* 4. FA606TE clock enable & reset */
+	writel(0x00000000, &scu->hclkgr);
+	udelay(5000);
+	writel(GPMUX_DEFAULT | GPMUX_CPUS_START, &scu->gpmux);
+
+	/* 5. FA626TE is going to halt... */
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15,0,r0,c7,c0,4\n"
+		:
+		:
+		: "r0" /* clobber list */
+	);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	fa606, 2, 0, do_fa606,
+	"launch firmware with A369's built-in fa606te\n",
+	"fa606 [address] - mov pc of fa606te to the specified address.\n"
+);
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
index 449bf0d..123ec7e 100644
--- a/arch/arm/cpu/faraday/cpu.c
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -339,5 +339,7 @@ void reset_cpu(unsigned long ignored)
 	writel(1000, &regs->wdload);
 	/* Enable WDT with System Reset Function */
 	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+	/* Kick it to force counter reloaded */
+    writel(FTWDT010_WDRESTART_MAGIC, &regs->wdrestart);
 #endif
 }
diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..770964f
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,84 @@
+/*
+ * arch/arm/include/asm/arch-a360/hardware.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC020_BASE		0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+#define CONFIG_FTSSP010_GPIO_BASE	0x98700000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+#define CONFIG_FOTG210_BASE         0x90B00000
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/pmu.h b/arch/arm/include/asm/arch-a360/pmu.h
new file mode 100644
index 0000000..d8c0e0e
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/pmu.h
@@ -0,0 +1,95 @@
+/*
+ * arch/arm/include/asm/arch-a360/pmu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_PMU_H
+#define __ASM_ARCH_PMU_H
+
+struct a360pmu_regs {
+	uint32_t idr;      /* ID register */
+	uint32_t rsvd0;
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pmr;      /* Power mode register */
+
+	uint32_t pmcr;     /* Power manager control register */
+	uint32_t peer;     /* Power manager edge detection enable register */
+	uint32_t pesr;     /* Power manager edge detection status register */
+	uint32_t rsvd1;
+
+	uint32_t pmsr;     /* Power manager status register */
+	uint32_t pgsr;     /* Power manager GPIO sleep state register */
+	uint32_t rsvd2;
+	uint32_t mcr;      /* Misc. control register */
+
+	uint32_t pdcr;     /* PLL/DLL control register */
+	uint32_t rsvd3[7];
+
+	uint32_t pspr[16]; /* Power manager scratch pad register */
+
+	uint32_t rsvd4[3];
+	uint32_t jssr;     /* Jumper setting status register */
+};
+
+#define OSCCR_STABLE    (1 << 9) /* OSCH is stable */
+#define OSCCR_DISABLE   (1 << 8) /* Disable OSCH */
+
+#define PMR_FCS         (1 << 2) /* Activate freq. change sequence */
+#define PMR_TURBO       (1 << 1) /* Activate CPU turbo mode (2 x AHB) */
+#define PMR_SLEEP       (1 << 0) /* Activate system sleep */
+
+#define PMCR_PWLOW      (1 << 5) /* Mask X_powerlow_b pin source */
+#define PMCR_WAIT       (1 << 4) /* Enable countdown for CPU power-off */
+#define PMCR_WDT        (1 << 3) /* Use WatchDog reset */
+#define PMCR_RTC        (1 << 2) /* Enable system wake-up from RTC alarm */
+#define PMCR_GPIO1      (1 << 1) /* Enable system wake-up from GPIO1 */
+#define PMCR_GPIO0      (1 << 0) /* Enable system wake-up from GPIO0 */
+
+#define PEER_GPIO1_RE   (1 << 9) /* Wake-up upon Rising-Edge of GPIO1 */
+#define PEER_GPIO0_RE   (1 << 8) /* Wake-up upon Rising-Edge of GPIO0 */
+#define PEER_GPIO1_FE   (1 << 1) /* Wake-up upon Falling-Edge of GPIO1 */
+#define PEER_GPIO0_FE   (1 << 0) /* Wake-up upon Falling-Edge of GPIO0 */
+
+#define PESR_RTC        (1 << 2) /* Wake-up from RTC */
+#define PESR_GPIO1      (1 << 1) /* Wake-up from GPIO1 */
+#define PESR_GPIO0      (1 << 0) /* Wake-up from GPIO0 */
+
+#define PMSR_PWLOW      (1 << 19)/* X_powerlow_b is pulled low */
+#define PMSR_ISR_PWLOW  (1 << 18)/* Interrupt Status: X_powerlow_b */
+#define PMSR_ISR_FCS    (1 << 17)/* Interrupt Status: FCS */
+#define PMSR_ISR_TURBO  (1 << 16)/* Interrupt Status: TURBO */
+#define PMSR_WAKEUP     (1 << 10)/* Wake-up from sleep mode */
+#define PMSR_WDT        (1 << 9) /* Reset by WatchDog */
+#define PMSR_HW         (1 << 8) /* Reset by Hardware */
+#define PMSR_NOGPI      (1 << 2) /* Disable GPIO input mode */
+#define PMSR_GPIO_HELD  (1 << 1) /* GPIO are held in sleep mode */
+
+#define PDCR_WAITDLLS   (1 << 23)/* Wait until DLL stable */
+#define PDCR_DLLS       (1 << 22)/* DLL is stable */
+#define PDCR_DDLL       (1 << 21)/* Disable DLL */
+#define PDCR_PLL1MS(x)  (((x) >> 11) & 0xf)/* PLL1 MS */
+#define PDCR_PLL1NS(x)  (((x) >> 3) & 0x3f)/* PLL1 NS */
+#define PDCR_WAITPLL1S  (1 << 2) /* Wait until PLL1 stable */
+#define PDCR_PLL1S      (1 << 1) /* PLL1 is stable */
+#define PDCR_DPLL1      (1 << 0) /* Disable PLL1 */
+
+#define JSSR_PLL1NS(x)  (((x) >> 2) & 0x3f)/* PLL1 NS */
+#define JSSR_OSC        (1 << 0) /* PLL1/DLL are disabled */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/scu.h b/arch/arm/include/asm/arch-a360/scu.h
new file mode 100644
index 0000000..70560c6
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/scu.h
@@ -0,0 +1,79 @@
+/*
+ * arch/arm/include/asm/arch-a360/scu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a360scu_regs {
+	uint32_t idr;      /* 0x00: ID Register */
+	uint32_t gcr;      /* 0x04: General Control Register */
+	uint32_t ccr;      /* 0x08: Clock Configuration Register */
+	uint32_t hcer;     /* 0x0C: AHB Clock Enable Register */
+	uint32_t pcer;     /* 0x10: APB Clock Enable Register */
+	uint32_t csr;      /* 0x14: Configuration Strap Register */
+	uint32_t iomcr[4]; /* IO Mux Control Register */
+	uint32_t iopcr[2]; /* IO Parameter Control Register */
+	uint32_t cescr;    /* CPU Edge Sync Control Register */
+	uint32_t expcr[3]; /* PCI-Express Control Register */
+};
+
+#define GCR_LVBC_IRQ3       (1 << 25) /* LVBC interrupt 3 propagation */
+#define GCR_LVBC_IRQ2       (1 << 24) /* LVBC interrupt 2 propagation */
+#define GCR_LVTX_RATE(x)    (((x) & 0x1f) << 16) /* LVTX clock rate */
+#define GCR_LVTX_CLK_OUT    (1 << 13) /* Enable LVTX clock out */
+#define GCR_USBH1_PLL_ALIVE (1 << 11) /* USB Host PLL alive */
+#define GCR_USBH0_PLL_ALIVE (1 << 10) /* USB Host PLL alive */
+#define GCR_USBH1_CLK_OUT   (1 << 9) /* Enable USB Host clock out */
+#define GCR_USBH0_CLK_OUT   (1 << 8) /* Enable USB Host clock out */
+#define GCR_DEBUG           (1 << 7) /* Enable debug mode */
+#define GCR_DEBUG_SW        (1 << 6) /* Enable software debug mode */
+#define GCR_IM              (1 << 5) /* Interrupt mask */
+#define GCR_RESET           (1 << 4) /* Software reset */
+
+#define CCR_LVDSTX_DSEL(x)  (((x) >> 21) & 0x1f) /* LVDS Tx Clock Select */
+#define CCR_LVDSRX_DSEL(x)  (((x) >> 16) & 0x1f) /* LVDS Rx Clock Select */
+#define CCR_SSP1_CKFQ(x)    (((x) >> 12) & 0xf) /* SSP1 Clock Freq. */
+#define CCR_SSP0_CKFQ(x)    (((x) >> 8) & 0xf) /* SSP0 Clock Freq. */
+#define CCR_SSP1_EXTCLK     (1 << 7) /* SSP1 use external clock */
+#define CCR_SSP1_PCLK       (0 << 7) /* SSP1 use APB clock */
+#define CCR_SSP0_EXTCLK     (1 << 6) /* SSP0 use external clock */
+#define CCR_SSP0_PCLK       (0 << 6) /* SSP0 use APB clock */
+#define CCR_LVDSTX_HCLK     (0 << 4) /* LVDS Tx clock select */
+#define CCR_LVDSTX_PCLK     (1 << 4)
+#define CCR_LVDSTX_EXTCLK   (2 << 4)
+#define CCR_SDC_HCLK        (2 << 2) /* SD/MMC clock select */
+#define CCR_SDC_MCLK        (1 << 2)
+#define CCR_SDC_DCLK        (0 << 2)
+#define CCR_LCD_EXTCLK      (2 << 0) /* LCD clock select */
+#define CCR_LCD_MCLK        (1 << 0)
+#define CCR_LCD_HCLK        (0 << 0)
+
+#define CSR_PLL_PRESCALE    (1 << 9)
+#define CSR_PCIE_MODE1      (1 << 8)
+#define CSR_PCIE_MODE0      (1 << 7)
+#define CSR_DBG_SW          (1 << 6)
+#define CSR_DBG_EN          (1 << 5)
+#define CSR_NAND_LP         (1 << 4)         /* NAND: Large Page */
+#define CSR_NAND_AL(x)      (((x) >> 2) & 3) /* NAND: Address Length */
+#define CSR_NAND_16X        (1 << 1)         /* NAND: 16-bits */
+#define CSR_SPIBOOT         (1 << 0)         /* Boot from SPI(1)/NAND(0) */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/ahbc.h b/arch/arm/include/asm/arch-a369/ahbc.h
new file mode 100644
index 0000000..5a77825
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/ahbc.h
@@ -0,0 +1,34 @@
+/*
+ * arch/arm/include/asm/arch-a369/ahbc.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_AHBC_H
+#define __ASM_ARCH_AHBC_H
+
+struct a369ahbc_regs {
+	uint32_t slave[32];/* Slave Device Configurations */
+	uint32_t priority; /* Priority */
+	uint32_t idle_cnt; /* IDLE Counter */
+	uint32_t control;  /* Control Register */
+	uint32_t revision; /* Revision ID */
+	uint32_t cpusao;   /* CPUS (FA606TE) Address Offset */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..e71fc10
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,99 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDR_BASE             0x93100000
+#define CONFIG_AHB_BASE             0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/scu.h b/arch/arm/include/asm/arch-a369/scu.h
new file mode 100644
index 0000000..ca6f44f
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/scu.h
@@ -0,0 +1,224 @@
+/*
+ * arch/arm/include/asm/arch-a369/scu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a369scu_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)   (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x) ((((x) >> 3) & 0x3) > 2 ? 2 : (((x) >> 3) & 0x3))
+#define HWCFG_DLL_OFF     (1 << 2)
+#define HWCFG_PLL_OFF     (1 << 1)
+#define HWCFG_OSCHCNT_OFF (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 0x3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 0x3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 0x3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif
diff --git a/arch/arm/include/asm/arch-faraday/clock.h b/arch/arm/include/asm/arch-faraday/clock.h
new file mode 100644
index 0000000..74db551
--- /dev/null
+++ b/arch/arm/include/asm/arch-faraday/clock.h
@@ -0,0 +1,41 @@
+/*
+ * asm/arch-faraday/clock.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ASM_ARCH_FARADAY_CLOCK_H
+#define _ASM_ARCH_FARADAY_CLOCK_H
+
+/* Clock identifiers */
+enum clk_id {
+	SYS_CLK,
+	AHB_CLK,
+	APB_CLK,
+	CPU_CLK,
+	I2C_CLK,
+	MMC_CLK,
+	SDC_CLK,
+	SPI_CLK,
+	SSP_CLK,
+};
+
+void  clock_init(void);
+ulong clock_get_rate(enum clk_id id);
+
+#endif	/* _ASM_ARCH_FARADAY_CLOCK_H */
diff --git a/arch/arm/include/asm/arch-faraday/interrupt.h b/arch/arm/include/asm/arch-faraday/interrupt.h
new file mode 100644
index 0000000..8a38946
--- /dev/null
+++ b/arch/arm/include/asm/arch-faraday/interrupt.h
@@ -0,0 +1,29 @@
+/*
+ * asm/arch-faraday/interrupt.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _ASM_ARCH_FARADAY_INTERRUPT_H
+#define _ASM_ARCH_FARADAY_INTERRUPT_H
+
+void irq_set_trigger(int irq, int edge, int low);
+void irq_enable(int irq);
+void irq_disable(int irq);
+
+#endif	/* _ASM_ARCH_FARADAY_INTERRUPT_H */
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..75a5668
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clock.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..f241bb3
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,72 @@
+/*
+ * board/faraday/a360evb/board.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <asm/arch/scu.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a360scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+/*
+ * pinmux
+ */
+static void pinmux_init(void)
+{
+	writel(0x00555500, &scu->iomcr[3]);
+	setbits_le32(&scu->iomcr[0], 0x800002AA);
+	setbits_le32(&scu->iomcr[1], 0x82AAAAAA);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_early_init_f(void)
+{
+	pinmux_init();
+	clock_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	return ftmac110_initialize(bd);
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a360evb/clock.c b/board/faraday/a360evb/clock.c
new file mode 100644
index 0000000..a52ff09
--- /dev/null
+++ b/board/faraday/a360evb/clock.c
@@ -0,0 +1,72 @@
+/*
+ * board/faraday/a360evb/clock.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/pmu.h>
+#include <asm/arch-faraday/clock.h>
+
+static struct a360scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a360pmu_regs *pmu = (void __iomem *)CONFIG_PMU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 40000000; /* 40 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return clk_get_rate_sys() * ((readl(&pmu->pdcr) >> 3) & 0x3f) / 8;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	uint32_t s = readl(&scu->csr);
+	uint32_t p = readl(&pmu->pmr);
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (s & CSR_PLL_PRESCALE) ? 2 : 4;
+
+	return (p & PMR_TURBO) ? (clk * mul) : clk;
+}
+
+ulong clock_get_rate(enum clk_id id)
+{
+	switch (id) {
+	case SYS_CLK:
+		return clk_get_rate_sys();
+	case AHB_CLK:
+		return clk_get_rate_ahb();
+	case APB_CLK:
+		return clk_get_rate_apb();
+	case CPU_CLK:
+		return clk_get_rate_cpu();
+	case I2C_CLK:
+		return clk_get_rate_apb();
+	case MMC_CLK:
+	case SDC_CLK:
+		return clk_get_rate_ahb();
+	case SPI_CLK:
+	case SSP_CLK:
+		return clk_get_rate_apb();
+	default:
+		return 0;
+	}
+}
+
+void clock_init(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate_apb();
+}
diff --git a/board/faraday/a360evb/config.mk b/board/faraday/a360evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a360evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..0d6c43f
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,33 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..75a5668
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2003-2008
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# (C) Copyright 2008
+# Stelian Pop <stelian@popies.net>
+# Lead Tech Design <www.leadtechdesign.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clock.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..260cac3
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,176 @@
+/*
+ * board/faraday/a369evb/board.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/scu.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftlcdc200.h>
+#include <faraday/ftsdc010.h>
+#include <faraday/ftnandc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct ftlcdc200_regs *lcd = (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+/* System Control Uint (pinmux) */
+static void scu_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&scu->hclkgr);
+		setbits_le32(&scu->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_SUPP_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &scu->hclkgr);
+		writel(GPMUX_DEFAULT, &scu->gpmux);
+		clrbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &scu->mfpmux[0]);
+#endif
+	}
+
+	/* Clock Setup: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+
+	/* Enable LCD for I2C/TVEncode work-around */
+	/* ... Clock DIV=32 */
+	writel(PCR_DIV(32), &lcd->pcr);
+	/* ... Enable LCD */
+	writel(FER_EN | FER_ON, &lcd->fer);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	/* 1. NOR flash */
+	/* Bank 0: base=0x00000000, size=64MB, 16bits */
+	writel(FTSMC020_BANK_ENABLE | FTSMC020_BANK_BASE(0)
+		| FTSMC020_BANK_SIZE_64M | FTSMC020_BANK_MBW_16,
+		&smc->bank[0].cr);
+	/* Bank 0: worst timing */
+	writel(FTSMC020_TPR_WORST, &smc->bank[0].tpr);
+
+	/* 2. Unused Area */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	scu_init();
+	smc_init();
+	clock_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_SYS_NAND_SELF_INIT
+void board_nand_init(void)
+{
+	int alen, devnum = 0;
+	struct mtd_info *mtd = &nand_info[devnum];
+	struct nand_chip *chip;
+	uint32_t iobase = CONFIG_SYS_NAND_BASE;
+	uint32_t ehwcfg = readl(&scu->ehwcfg);
+
+	chip = calloc(1, sizeof(*chip));
+	if (!chip)
+		return;
+	mtd->priv = chip;
+
+	/* page size */
+	switch (EHWCFG_NAND_PS(ehwcfg)) {
+	case 0:
+		chip->page_shift = 9;	/* 512 */
+		break;
+	case 1:
+		chip->page_shift = 11;	/* 2048 */
+		break;
+	default:
+		chip->page_shift = 12;	/* 4096 */
+		break;
+	}
+
+	/* block size */
+	chip->phys_erase_shift = chip->page_shift + 4
+		+ EHWCFG_NAND_BK(ehwcfg);
+
+	/* address length/cycle */
+	alen = 3 + EHWCFG_NAND_AC(ehwcfg);
+
+	if (ftnandc021_init(chip, iobase, alen))
+		goto bni_err;
+
+	if (nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS))
+		goto bni_err;
+
+	nand_register(devnum);
+
+	return;
+
+bni_err:
+	free(chip);
+}
+#endif /* #ifdef CONFIG_SYS_NAND_SELF_INIT */
diff --git a/board/faraday/a369evb/clock.c b/board/faraday/a369evb/clock.c
new file mode 100644
index 0000000..843a41f
--- /dev/null
+++ b/board/faraday/a369evb/clock.c
@@ -0,0 +1,80 @@
+/*
+ * board/faraday/a369evb/clock.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch-faraday/clock.h>
+
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 33000000; /* 33 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return (clk_get_rate_sys() * PLLCR_NS(readl(&scu->pllcr))) >> 3;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+#ifndef CONFIG_A369_FA606TE_PLATFORM
+	/* If it's an internal CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after
+	 * kicking off slave cpu, so we could check the
+	 * GPMUX_CPUS_START to determine if it's a master.
+	 */
+	if (!(readl(&scu->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&scu->hwcfg));
+#endif
+
+	return clk;
+}
+
+ulong clock_get_rate(enum clk_id id)
+{
+	switch (id) {
+	case SYS_CLK:
+		return clk_get_rate_sys();
+	case AHB_CLK:
+		return clk_get_rate_ahb();
+	case APB_CLK:
+		return clk_get_rate_apb();
+	case CPU_CLK:
+		return clk_get_rate_cpu();
+	case I2C_CLK:
+		return clk_get_rate_apb();
+	case MMC_CLK:
+	case SDC_CLK:
+		return clk_get_rate_ahb();
+	case SPI_CLK:
+	case SSP_CLK:
+		return clk_get_rate_apb();
+	default:
+		return 0;
+	}
+}
+
+void clock_init(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate_apb();
+}
diff --git a/board/faraday/a369evb/config.mk b/board/faraday/a369evb/config.mk
new file mode 100644
index 0000000..eb1a258
--- /dev/null
+++ b/board/faraday/a369evb/config.mk
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2010
+# Dante Su <dantesu@faraday-tech.com>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# 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
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..0e02636
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,136 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Inc. <www.faraday-tech.com>
+ * Dante Su <dantesu@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+	.macro	_v3_mw32
+
+	ldr r0, =0x1008
+	ldr r3, =0x1108
+_v3_mw32_loop:
+	cmp   r0, r3
+	movhs r1, #0
+	ldrlo r1, [r0, #0]
+	ldrlo r2, [r0, #4]
+	teq   r1, #0
+	strne r2, [r1, #0]
+	addne r0, #8
+	bne   _v3_mw32_loop
+
+	.endm	/* _v3_mw32 */
+
+	.macro	_sdram_enable
+
+	/* Clear SDRAM CKE, GPIO Hold, READ Hold */
+	ldr r0, =CONFIG_SCU_BASE
+	mov r1, #7
+	str r1, [r0, #0x14]
+
+	/* Wait until sdram ready */
+	ldr r0, =CONFIG_DDR_BASE
+_sdram_wait:
+	ldr r1, [r0, #0x04]
+	teq r1, #0x100
+	bne _sdram_wait
+
+	.endm	/* _sdram_enable */
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	/* Check image header */
+	ldr   r1, =0x1000
+	ldr   r0, [r1, #0]
+	ldr   r1, =0x00484946	/* "FIH\0" */
+	ldr   r2, =0x33333639	/* "3369" */
+	teq   r0, r1
+	teqne r0, r2
+	bne _exit
+	_v3_mw32
+	_sdram_enable
+
+#if 1
+	/* Create a shadow copy onto SDRAM (limited to 512K) */
+	mov	r0, #0               /* r0 <- start of source */
+	ldr	r1, =CONFIG_AHB_BASE
+	ldr r2, [r1,#0x18]
+	bic r1, r2, #0x000f0000  /* r1 <- SDRAM base */
+	mov	r2, #0x80000         /* r2 <- source end address (512KB) */
+
+_copy_loop:
+	ldmia	r0!, {r3-r10} /* copy from source address [r0] */
+	stmia	r1!, {r3-r10} /* copy to   target address [r1] */
+	cmp	r0, r2            /* until source end addreee [r2] */
+	ble	_copy_loop
+#else
+	/* Adjust lr(r14) to the remapped address */
+	ldr r0, =CONFIG_AHB_BASE
+	ldr r1, [r0,#0x18]    /* r1 = AHB slave 6 */
+	bic r1, r1, #0xff000000
+	bic r1, r1, #0x00f00000
+	lsr r1, r1, #16
+	add r1, r1, #20
+	mov r2, #1
+	lsl r2, r2, r1
+	add lr, lr, r2
+#endif
+
+	/* AHB remap */
+	mov r0, #0
+	ldr r1, =CONFIG_AHB_BASE
+	ldr r2, =CONFIG_DDR_BASE
+	/* magic (r5) = REG32(0x00) XOR 0xFFFFFFFF */
+	ldr r5, [r0, #0]
+	ldr r3, =0xffffffff
+	eor r5, r5, r3
+	/* r3 = REG32(CONFIG_IOBASE_DDR + 0x10) & 0x00FFFFFF */
+	ldr r3, [r2, #0x10]
+	bic r3, #0xff000000
+	/* r4 = 0x00100f01 */
+	ldr r4, =0x00100f01
+
+	/*
+	 * invalidate i-cache all to make sure the codes bellow
+	 * to be fetched into a single 32-bytes cache line
+	 */
+	mcr p15, 0, r0, c7, c5, 0
+
+	.align 5
+
+	str r3, [r2, #0x10] /* REG32(CONFIG_IOBASE_DDR + 0x10) &= 0x00FFFFFF */
+	str r4, [r1, #0x88] /* REG32(CONFIG_IOBASE_AHB + 0x88)  = 0x00100F01 */
+
+_remap_wait:
+	str r5, [r0, #0]
+	ldr r1, [r0, #0]
+	teq r1, r5
+	bne _remap_wait		/* while(magic != REG32(addr)) */
+
+_exit:
+	mov	pc, lr
diff --git a/boards.cfg b/boards.cfg
index c0c4282..23a0448 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -72,6 +72,9 @@ mini2440                     arm         arm920t     mini2440            friendl
 VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
 smdk2410                     arm         arm920t     -                   samsung        s3c24x0
 omap1510inn                  arm         arm925t     -                   ti
+a360                         arm         faraday     a360evb             faraday        a360
+a369                         arm         faraday     a369evb             faraday        a369
+a369_fa606te                 arm         faraday     a369evb             faraday        a369
 integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap:CM926EJ_S
 integratorcp_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorcp:CM924EJ_S
 aspenite                     arm         arm926ejs   -                   Marvell        armada100
diff --git a/include/common.h b/include/common.h
index ec3bf0d..514c531 100644
--- a/include/common.h
+++ b/include/common.h
@@ -111,6 +111,8 @@ typedef volatile unsigned char	vu_char;
 #include <asm/arch/hardware.h>
 #endif
 #ifdef CONFIG_FARADAY
+#include <asm/arch/hardware.h>
+#include <asm/arch-faraday/clock.h>
 #include <asm/arch-faraday/interrupt.h>
 #endif

diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..7d11734
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,60 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/*
+ * Memory Configuration
+ */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_64M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_PIN    26
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369-common.h b/include/configs/a369-common.h
new file mode 100644
index 0000000..06d6cb0
--- /dev/null
+++ b/include/configs/a369-common.h
@@ -0,0 +1,75 @@
+#ifndef __CONFIG_A369_COMMON_H
+#define __CONFIG_A369_COMMON_H
+
+#include <asm/hardware.h>
+
+/* A369 Platform Common Configuration */
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_512M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* Interrupt controler */
+#ifndef CONFIG_FTINTC020_BASE
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+#endif
+
+/* NAND Flash */
+#define CONFIG_NAND_K9F4G08U0B_AC1  0x02240264
+#define CONFIG_NAND_K9F4G08U0B_AC2  0x42054209
+#define CONFIG_SYS_MAX_NAND_DEVICE  1 /* Max. num. of devices */
+#define CONFIG_SYS_FTNANDC021_TIMING \
+	{ CONFIG_NAND_K9F4G08U0B_AC1, CONFIG_NAND_K9F4G08U0B_AC2 }
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_BASE   0x92600000 /* GPIO 1 */
+#define CONFIG_FTSSP010_GPIO_PIN    27
+
+/* NOR Flash */
+/*
+#define PHYS_FLASH_SIZE             SZ_64M
+#define CONFIG_SYS_FLASH_BASE       0x20000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH  FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS  1
+#define CONFIG_SYS_MAX_FLASH_SECT   1024
+*/
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_IN_NAND
+#define CONFIG_ENV_OFFSET           0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND    0x07FE0000
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..da7856e
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,34 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_PLATFORM
+
+/* Support USB-EHCI */
+#define CONFIG_SUPP_EHCI_FARADAY
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Support runtime switching to built-in slave core: FA606TE */
+#define CONFIG_CMD_FA606
+
+/* Autoboot */
+#define CONFIG_BOOTDELAY            3
+#define CONFIG_BOOTCOMMAND          "bootfa nand linux"
+
+/* A369 common configuration */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/a369_fa606te.h b/include/configs/a369_fa606te.h
new file mode 100644
index 0000000..c549edb
--- /dev/null
+++ b/include/configs/a369_fa606te.h
@@ -0,0 +1,31 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_FA606TE_PLATFORM
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Disable I-CACHE */
+#define CONFIG_SYS_ICACHE_OFF
+
+/* Set interrupt controler to FTINCT020:1 */
+#undef  CONFIG_FTINTC020_BASE
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE1
+
+/* A369 common configuration */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..64e8a71
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,243 @@
+/*
+ * include/configs/faraday-common.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * This file is released under the terms of GPL v2 and any later version.
+ * See the file COPYING in the root directory of the source tree for details.
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+#include <asm/mach-types.h>
+
+#ifndef MACH_TYPE_FARADAY
+#define MACH_TYPE_FARADAY           758
+#endif
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+#define CONFIG_BOARD_EARLY_INIT_F   1
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_8M
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+/*
+ * CPU
+ */
+#define CONFIG_FARADAY
+#define CONFIG_ARCH_CPU_INIT
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_SYS_CACHELINE_SIZE	32
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+/*
+ * Interrupt
+ */
+#if defined(CONFIG_USE_IRQ) && defined(CONFIG_FTI2C010_BASE)
+# define CONFIG_FTINTC020
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_SYS_HZ               1000
+
+#ifdef CONFIG_FTTMR010_BASE
+# define CONFIG_FTTMR010
+#endif /* CONFIG_FTTMR010_BASE */
+
+#ifdef CONFIG_FTPWMTMR010_BASE
+# define CONFIG_FTPWMTMR010
+#endif /* CONFIG_FTPWMTMR010_BASE */
+
+/*
+ * Serial Info
+ */
+#ifdef CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# ifndef CONFIG_SYS_NS16550_CLK
+#  define CONFIG_SYS_NS16550_CLK     18432000
+# endif
+# define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE -4
+# define CONFIG_CONS_INDEX           1
+# define CONFIG_BAUDRATE             38400
+# undef  CONFIG_HWFLOW
+# undef  CONFIG_MODEM_SUPPORT
+#endif /* #ifdef CONFIG_FTUART010_BASE */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTMAC110_BASE
+# define CONFIG_FTMAC110
+#endif
+#ifdef CONFIG_FTGMAC100_BASE
+# define CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA    /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR    32 /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT 20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif
+
+/*
+ * NOR Flash
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* print 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * NAND Flash
+ */
+#ifdef CONFIG_FTNANDC021_BASE
+# define CONFIG_SYS_NAND_SELF_INIT
+# define CONFIG_NAND_FTNANDC021
+# define CONFIG_SYS_NAND_BASE           CONFIG_FTNANDC021_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+#endif
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010_BASE
+# define CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* The hardware core supports SDIO */
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if defined(CONFIG_SUPP_EHCI_FARADAY) && (CONFIG_USB_MAX_CONTROLLER_COUNT > 0)
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#if defined(CONFIG_SUPP_USB_RNDIS) && defined(CONFIG_FOTG210_BASE)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+#endif
+
+/*
+ * LCD
+ */
+#if defined(CONFIG_SUPP_VGA_CONSOLE) && defined(CONFIG_FTLCDC200_BASE)
+# define CONFIG_FTLCDC200
+# define CONFIG_FTLCDC200_800X480S_TPO
+# define LCD_BPP                    4 /* 16-bit per pixel */
+# define CONFIG_LCD
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+#ifndef CONFIG_SYS_LOAD_ADDR        /* Default load address */
+# define CONFIG_SYS_LOAD_ADDR       (CONFIG_SYS_SDRAM_BASE + SZ_1M)
+#endif
+/* Console Baud-Rate Table */
+#define CONFIG_SYS_BAUDRATE_TABLE   { 115200, 57600, 38400, 19200, 9600 }
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 59c6f8e..aa02717 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -82,5 +82,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_WORST	0x0f1ff3ff /* worst but safe */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v4] net: add Faraday FTMAC110 10/100Mbps ethernet support
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
@ 2013-07-08 16:19             ` Joe Hershberger
  0 siblings, 0 replies; 311+ messages in thread
From: Joe Hershberger @ 2013-07-08 16:19 UTC (permalink / raw)
  To: u-boot

On Tue, May 7, 2013 at 1:33 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> Faraday FTMAC110 10/100Mbps supports half-word data transfer for Linux.
> However it has a weird DMA alignment issue:
>
> (1) Tx DMA Buffer Address:
>     1 bytes aligned: Invalid
>     2 bytes aligned: O.K
>     4 bytes aligned: O.K
>
> (2) Rx DMA Buffer Address:
>     1 bytes aligned: Invalid
>     2 bytes aligned: O.K
>     4 bytes aligned: Invalid!!!
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Joe Hershberger <joe.hershberger@gmail.com>
> CC: Tom Rini <trini@ti.com>

Applied, Thanks.
-Joe

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

* [U-Boot] [PATCH v4] net: update FTGMAC100 for MMU/D-cache support
  2013-05-07  6:33           ` [U-Boot] [PATCH v4] net: update FTGMAC100 for " Kuo-Jung Su
@ 2013-07-08 16:21             ` Joe Hershberger
  0 siblings, 0 replies; 311+ messages in thread
From: Joe Hershberger @ 2013-07-08 16:21 UTC (permalink / raw)
  To: u-boot

On Tue, May 7, 2013 at 1:33 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Joe Hershberger <joe.hershberger@gmail.com>
> CC: Tom Rini <trini@ti.com>

Applied, Thanks.
-Joe

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

* [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
@ 2013-07-08 23:59     ` Scott Wood
  2013-07-09  1:42       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-07-08 23:59 UTC (permalink / raw)
  To: u-boot

On 07/03/2013 10:40:35 PM, Kuo-Jung Su wrote:
> +#ifndef __ARMEB__
> +		put_unaligned_le32(readl(&regs->dr), buf + off);
> +#else
> +		put_unaligned_be32(readl(&regs->dr), buf + off);
> +#endif

Can't you just use plain put_unaligned()?  Be sure to cast buf + off to  
a 32-bit pointer.

Also, when you *do* need to have an if/else, use positive logic --  
ifdef rather than ifndef, with the if/else swapped.

-Scott

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

* [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-08 23:59     ` Scott Wood
@ 2013-07-09  1:42       ` Kuo-Jung Su
  2013-07-09  1:48         ` Scott Wood
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-09  1:42 UTC (permalink / raw)
  To: u-boot

2013/7/9 Scott Wood <scottwood@freescale.com>:
> On 07/03/2013 10:40:35 PM, Kuo-Jung Su wrote:
>>
>> +#ifndef __ARMEB__
>> +               put_unaligned_le32(readl(&regs->dr), buf + off);
>> +#else
>> +               put_unaligned_be32(readl(&regs->dr), buf + off);
>> +#endif
>
>
> Can't you just use plain put_unaligned()?  Be sure to cast buf + off to a
> 32-bit pointer.
>

Ummm...  I think it'll be better to replace put_unaligned() with memcpy(),
just like what your suggested before.

So that we don't even have to worry about this endian issue and pointer cast.

> Also, when you *do* need to have an if/else, use positive logic -- ifdef
> rather than ifndef, with the if/else swapped.
>

Got it, thanks

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-09  1:42       ` Kuo-Jung Su
@ 2013-07-09  1:48         ` Scott Wood
  2013-07-09  1:57           ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-07-09  1:48 UTC (permalink / raw)
  To: u-boot

On 07/08/2013 08:42:01 PM, Kuo-Jung Su wrote:
> 2013/7/9 Scott Wood <scottwood@freescale.com>:
> > On 07/03/2013 10:40:35 PM, Kuo-Jung Su wrote:
> >>
> >> +#ifndef __ARMEB__
> >> +               put_unaligned_le32(readl(&regs->dr), buf + off);
> >> +#else
> >> +               put_unaligned_be32(readl(&regs->dr), buf + off);
> >> +#endif
> >
> >
> > Can't you just use plain put_unaligned()?  Be sure to cast buf +  
> off to a
> > 32-bit pointer.
> >
> 
> Ummm...  I think it'll be better to replace put_unaligned() with  
> memcpy(),
> just like what your suggested before.
> 
> So that we don't even have to worry about this endian issue and  
> pointer cast.

OK.  BTW, it'd be nice if there were a native-endian, fixed-size  
put_unaligned32() -- having a u8 pointer seems like it'd be a common  
situation when dealing with unaligned things (and it's what the  
underlying implementation takes).

-Scott

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

* [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-09  1:48         ` Scott Wood
@ 2013-07-09  1:57           ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-09  1:57 UTC (permalink / raw)
  To: u-boot

2013/7/9 Scott Wood <scottwood@freescale.com>:
> On 07/08/2013 08:42:01 PM, Kuo-Jung Su wrote:
>>
>> 2013/7/9 Scott Wood <scottwood@freescale.com>:
>> > On 07/03/2013 10:40:35 PM, Kuo-Jung Su wrote:
>> >>
>> >> +#ifndef __ARMEB__
>> >> +               put_unaligned_le32(readl(&regs->dr), buf + off);
>> >> +#else
>> >> +               put_unaligned_be32(readl(&regs->dr), buf + off);
>> >> +#endif
>> >
>> >
>> > Can't you just use plain put_unaligned()?  Be sure to cast buf + off to
>> > a
>> > 32-bit pointer.
>> >
>>
>> Ummm...  I think it'll be better to replace put_unaligned() with memcpy(),
>> just like what your suggested before.
>>
>> So that we don't even have to worry about this endian issue and pointer
>> cast.
>
>
> OK.  BTW, it'd be nice if there were a native-endian, fixed-size
> put_unaligned32() -- having a u8 pointer seems like it'd be a common
> situation when dealing with unaligned things (and it's what the underlying
> implementation takes).
>

Got it, thanks



--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x SoC platform support
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
                     ` (11 preceding siblings ...)
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 12/12] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
@ 2013-07-25  9:07   ` Albert ARIBAUD
  2013-07-26 14:15     ` Kuo-Jung Su
  12 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-07-25  9:07 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Thu,  4 Jul 2013 11:40:32 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> These patches introduce Faraday A36x SoC platform support.

So where are we on this series? Seems like there were a few comments
about V6, and I haven't seen a V7 to address them.

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v6 04/12] cfi_flash: use buffer length in unmap_physmem()
  2013-07-04  3:40   ` [U-Boot] [PATCH v6 04/12] cfi_flash: use buffer length in unmap_physmem() Kuo-Jung Su
@ 2013-07-25 14:46     ` Stefan Roese
  0 siblings, 0 replies; 311+ messages in thread
From: Stefan Roese @ 2013-07-25 14:46 UTC (permalink / raw)
  To: u-boot

On 07/04/2013 05:40 AM, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> While the flash_detect_legacy() of drivers/mtd/cfi_flash.c
> feed unmap_physmem() with MAP_NOCACHE as 2nd parameter,
> the do_spi_flash_read_write() of common/cmd_sf.c
> feed unmap_physmem() with the length of the mapped buffer
> as 2nd parameter.
> 
> It's apparently a bug, and I personally think the 2nd parameter
> should be the length of the mapped buffer.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> CC: Stefan Roese <sr@denx.de>

Applied to u-boot-cfi-flash.

Thanks,
Stefan

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

* [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x SoC platform support
  2013-07-25  9:07   ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Albert ARIBAUD
@ 2013-07-26 14:15     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-26 14:15 UTC (permalink / raw)
  To: u-boot

2013/7/25 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Thu,  4 Jul 2013 11:40:32 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> These patches introduce Faraday A36x SoC platform support.
>
> So where are we on this series? Seems like there were a few comments
> about V6, and I haven't seen a V7 to address them.
>

The V7 would be released by next Tuesday.
It looks to me that only the NAND flash controller needs a trivial update. :)

--
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v7 00/11] arm: add Faraday A36x SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (12 preceding siblings ...)
  2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
@ 2013-07-29  5:51 ` Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 01/11] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
                     ` (11 more replies)
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (4 subsequent siblings)
  18 siblings, 12 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

   https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.5.1 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2013.07/u-boot

Changes for v7:
   - Update license to use SPDX identifiers.
   - cfi_flash: drop the patch to unmap_physmem(),
     because it's already applied.
   - ftnandc021: put_unaligned() -> memcpy()
   - ftnandc021: update ecc relatived function prototypes to fix
     compile warnnings.

Changes for v6:
   - Drop ethernet driver updates for ftmac110&ftgmac100,
     because they are already commited.
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs
   - arch/arm/cpu/faraday/cmd_bootfa.c: fix compiler warnning
   - arch/arm/cpu/faraday/cmd_bootfa.c: use shorter paragraph
     in commit message, and move the original statement into the
     top of source file.
   - ftnandc021: update README for CONFIG_SYS_FTNANDC021_TIMING
   - ftnandc021: remove illegal type-punning

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (11):
  arm: dma_alloc_coherent: malloc() -> memalign()
  video: add Faraday FTLCDC200 LCD controller support
  nand: add Faraday FTNANDC021 NAND controller support
  arm: add MMU/D-Cache support for Faraday cores
  arm: add Faraday processor core support
  arm: add Faraday FTINTC020 interrupt controller support
  arm: add Faraday FTTMR010 timer support
  arm: add Faraday FTPWMTMR010 timer support
  arm: add customized boot command for Faraday Images
  mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  arm: add Faraday A360/A369 SoC platform support

 MAINTAINERS                                   |    5 +
 README                                        |   10 +
 arch/arm/cpu/faraday/Makefile                 |   42 ++
 arch/arm/cpu/faraday/a360/Makefile            |   33 ++
 arch/arm/cpu/faraday/a369/Makefile            |   34 ++
 arch/arm/cpu/faraday/a369/cmd_fa606.c         |   74 +++
 arch/arm/cpu/faraday/cmd_bootfa.c             |  267 +++++++++++
 arch/arm/cpu/faraday/config.mk                |   17 +
 arch/arm/cpu/faraday/cpu.c                    |  333 ++++++++++++++
 arch/arm/cpu/faraday/ftintc020.c              |  144 ++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c            |  116 +++++
 arch/arm/cpu/faraday/fttmr010.c               |  124 +++++
 arch/arm/cpu/faraday/fwimage.h                |   35 ++
 arch/arm/cpu/faraday/fwimage2.h               |   55 +++
 arch/arm/cpu/faraday/start.S                  |  419 +++++++++++++++++
 arch/arm/cpu/u-boot.lds                       |   11 +
 arch/arm/include/asm/arch-a360/hardware.h     |   72 +++
 arch/arm/include/asm/arch-a360/pmu.h          |   83 ++++
 arch/arm/include/asm/arch-a360/scu.h          |   67 +++
 arch/arm/include/asm/arch-a369/ahbc.h         |   22 +
 arch/arm/include/asm/arch-a369/hardware.h     |   86 ++++
 arch/arm/include/asm/arch-a369/scu.h          |  212 +++++++++
 arch/arm/include/asm/arch-faraday/clock.h     |   29 ++
 arch/arm/include/asm/arch-faraday/interrupt.h |   17 +
 arch/arm/include/asm/dma-mapping.h            |   58 ++-
 arch/arm/include/asm/global_data.h            |    4 +
 arch/arm/include/asm/io.h                     |  159 ++++++-
 arch/arm/include/asm/system.h                 |    7 +-
 arch/arm/lib/cache-cp15.c                     |    9 +
 board/faraday/a360evb/Makefile                |   29 ++
 board/faraday/a360evb/board.c                 |   71 +++
 board/faraday/a360evb/clock.c                 |   71 +++
 board/faraday/a360evb/config.mk               |   17 +
 board/faraday/a360evb/lowlevel_init.S         |   16 +
 board/faraday/a369evb/Makefile                |   29 ++
 board/faraday/a369evb/board.c                 |  175 +++++++
 board/faraday/a369evb/clock.c                 |   81 ++++
 board/faraday/a369evb/config.mk               |   17 +
 board/faraday/a369evb/lowlevel_init.S         |  119 +++++
 boards.cfg                                    |    3 +
 drivers/mmc/ftsdc010_mci.c                    |    2 +-
 drivers/mtd/nand/Makefile                     |    1 +
 drivers/mtd/nand/ftnandc021.c                 |  609 +++++++++++++++++++++++++
 drivers/video/Makefile                        |    1 +
 drivers/video/ftlcdc200.c                     |  136 ++++++
 drivers/video/ftlcdc200_panel.c               |  209 +++++++++
 include/common.h                              |    5 +
 include/configs/a360.h                        |   70 +++
 include/configs/a369-common.h                 |   85 ++++
 include/configs/a369.h                        |   47 ++
 include/configs/a369_fa606te.h                |   40 ++
 include/configs/faraday-common.h              |  242 ++++++++++
 include/faraday/ftintc020.h                   |   36 ++
 include/faraday/ftlcdc200.h                   |  178 ++++++++
 include/faraday/ftnandc021.h                  |  152 ++++++
 include/faraday/ftpwmtmr010.h                 |   40 ++
 include/faraday/ftsmc020.h                    |    1 +
 include/faraday/fttmr010.h                    |   17 +
 include/lcd.h                                 |   33 ++
 59 files changed, 5062 insertions(+), 14 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftintc020.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 arch/arm/include/asm/arch-faraday/clock.h
 create mode 100644 arch/arm/include/asm/arch-faraday/interrupt.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/faraday/ftintc020.h
 create mode 100644 include/faraday/ftlcdc200.h
 create mode 100644 include/faraday/ftnandc021.h
 create mode 100644 include/faraday/ftpwmtmr010.h

--
1.7.9.5

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

* [U-Boot] [PATCH v7 01/11] arm: dma_alloc_coherent: malloc() -> memalign()
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-09-14 10:09     ` Albert ARIBAUD
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 02/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
                     ` (10 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Even though the MMU/D-cache is off, some DMA engines still
expect strict address alignment.

For example, the incoming Faraday FTMAC110 & FTGMAC100 ethernet
controllers expect the tx/rx descriptors should always be aligned
to 16-bytes boundary.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
---
Changes for v6, v7:
   - Nothing updates

Changes for v5:
   - Initial commit, which is separated from
     "arm: add MMU/D-Cache support for Faraday cores"

 arch/arm/include/asm/dma-mapping.h |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 009863b..55a4e26 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -16,7 +16,7 @@ enum dma_data_direction {

 static void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
-	*handle = (unsigned long)malloc(len);
+	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
 }

--
1.7.9.5

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

* [U-Boot] [PATCH v7 02/11] video: add Faraday FTLCDC200 LCD controller support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 01/11] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-08-09 19:33     ` Anatolij Gustschin
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 03/11] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
                     ` (9 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTLCDC200 Color LCD controller performs translation of
pixel-coded data into the required formats and timings to
drive a variety of single/dual mono and color LCDs.

Depending on the LCD type and mode, the unpacked data can represent:
   1. an actual true display gray or color value
   2. an address to a 256 x 16 bit wide palette RAM gray or color value.

The FTLCDC200 generates 4 individual interrupts for:
   1. DMA FIFO underflow
   2. base address update
   3. vertical status
   4. bus error.

There is also a single combined interrupt that is raised when any of
the individual interrupts become active.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Anatolij Gustschin <agust@denx.de>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - Chain it back to Faraday A360/A369 patch series, because
     Faraday A369 depends on the header file of this patch
     for I2C work-around.(Enable I2C clock to prevent I2C bus hangs)

Changes for v4:
   - Nothing updates

Changes for v3:
   - Nothing updates

Changes for v2:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series

 drivers/video/Makefile          |    1 +
 drivers/video/ftlcdc200.c       |  136 +++++++++++++++++++++++++
 drivers/video/ftlcdc200_panel.c |  209 +++++++++++++++++++++++++++++++++++++++
 include/faraday/ftlcdc200.h     |  178 +++++++++++++++++++++++++++++++++
 include/lcd.h                   |   33 +++++++
 5 files changed, 557 insertions(+)
 create mode 100644 drivers/video/ftlcdc200.c
 create mode 100644 drivers/video/ftlcdc200_panel.c
 create mode 100644 include/faraday/ftlcdc200.h

diff --git a/drivers/video/Makefile b/drivers/video/Makefile
index f1fb26c..873ee26 100644
--- a/drivers/video/Makefile
+++ b/drivers/video/Makefile
@@ -19,6 +19,7 @@ COBJS-$(CONFIG_EXYNOS_MIPI_DSIM) += exynos_mipi_dsi.o exynos_mipi_dsi_common.o \
 				exynos_mipi_dsi_lowlevel.o
 COBJS-$(CONFIG_EXYNOS_PWM_BL) += exynos_pwm_bl.o
 COBJS-$(CONFIG_FSL_DIU_FB) += fsl_diu_fb.o videomodes.o
+COBJS-$(CONFIG_FTLCDC200) += ftlcdc200.o ftlcdc200_panel.o
 COBJS-$(CONFIG_MPC8XX_LCD) += mpc8xx_lcd.o
 COBJS-$(CONFIG_PXA_LCD) += pxa_lcd.o
 COBJS-$(CONFIG_S6E8AX0) += s6e8ax0.o
diff --git a/drivers/video/ftlcdc200.c b/drivers/video/ftlcdc200.c
new file mode 100644
index 0000000..774a060
--- /dev/null
+++ b/drivers/video/ftlcdc200.c
@@ -0,0 +1,136 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+#ifndef CONFIG_FTLCDC200_FREQ
+#define CONFIG_FTLCDC200_FREQ	clock_get_rate(AHB_CLK)
+#endif
+
+static struct ftlcdc200_regs *regs = (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+static void ftlcdc2xx_fixup(struct vidinfo *panel)
+{
+	u_long ht, vt;
+	u_long div, clk;
+	long fps = 60;
+	long upper = 32767;
+	long lower = -32767;
+
+	if (panel->vl_fps)
+		return;
+
+	/* If it's serial mode */
+	if (panel->vl_serial & SPPR_SERIAL)
+		clk = CONFIG_FTLCDC200_FREQ / 3;
+	else
+		clk = CONFIG_FTLCDC200_FREQ;
+
+	/* Derive clock divisor */
+	ht = panel->vl_col + panel->vl_hbp + panel->vl_hfp + panel->vl_hsw;
+	vt = panel->vl_row + panel->vl_vbp + panel->vl_vfp + panel->vl_vsw;
+	for (div = 1; div <= 0x7f; ++div) {
+		long tmp = (clk / div / ht / vt);
+		if (fps > tmp) {
+			lower = tmp;
+			break;
+		}
+		upper = tmp;
+	}
+	if ((upper - fps) > (fps - lower))
+		div += 1;
+	div = (div > 1) ? (div - 1) : div;
+
+	/* Update hardware register cache */
+	panel->vl_polarity = (panel->vl_polarity & (~0x7f00))
+		| ((div - 1) << 8);
+
+	/* Derive real frame rate */
+	panel->vl_fps = (u_long)(clk / div / ht / vt);
+
+	debug("ftlcdc200: %s\n", panel->vl_name);
+	debug("ftlcdc200: fps=%u (%u < FPS < %u)\n",
+		   (unsigned int)panel->vl_fps,
+		   (unsigned int)lower,
+		   (unsigned int)upper);
+	debug("ftlcdc200: div=%u (ahb=%u MHz)\n",
+		   (unsigned int)div,
+		   (unsigned int)CONFIG_FTLCDC200_FREQ / 1000000);
+}
+
+/* setcolreg used in 8bpp/16bpp */
+void lcd_setcolreg(ushort regno, ushort red, ushort green, ushort blue)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+/* initcolregs used in monochrome */
+void lcd_initcolregs(void)
+{
+	/* nothing needs to be done, we use true color */
+}
+
+void lcd_ctrl_init(void *lcdbase)
+{
+	uint32_t i, v;
+
+	/*
+	 * initialize the contrast lookup table and the Red, Green, Blue
+	 * gamma lookup table, fill the straight line x-y=0 to the contrast
+	 * and gamma lookup table
+	 */
+	for (i = 0; i < 64; i++) {
+		v = 0x03020100 + 0x04040404 * i;
+		writel(v, &regs->gamma_r[i]);
+		writel(v, &regs->gamma_g[i]);
+		writel(v, &regs->gamma_b[i]);
+	}
+
+	writel(virt_to_phys(lcdbase), &regs->fb0);
+
+	debug("ftlcdc200: fb_base=0x%08X at 0x%08X\n",
+		(uint32_t)lcdbase, readl(&regs->fb0));
+}
+
+void lcd_enable(void)
+{
+	struct vidinfo *panel = &panel_info;
+
+	/* 1. derive the clock parameters at runtime */
+	ftlcdc2xx_fixup(panel);
+	/* 2. disable lcd */
+	writel(0, &regs->fer);
+	/* 3. setup panel parameters */
+	writel(panel->vl_pixel, &regs->ppr);
+	writel(HTCR_PL(panel->vl_col) | HTCR_HSYNC(panel->vl_hsw)
+		| HTCR_HBP(panel->vl_hbp) | HTCR_HFP(panel->vl_hfp),
+		&regs->htcr);
+	writel(VTCR0_LF(panel->vl_row) | VTCR0_VSYNC(panel->vl_vsw)
+		| VTCR0_VFP(panel->vl_vfp), &regs->vtcr[0]);
+	writel(VTCR1_VBP(panel->vl_vbp), &regs->vtcr[1]);
+	writel(panel->vl_polarity, &regs->pcr);
+	writel(panel->vl_serial, &regs->sppr);
+	writel(panel->vl_ccir656, &regs->ccir);
+	/* 4. default 4 cycles delay for all framebuffer */
+	writel(0x04040404, &regs->fifo);
+	/* 5. disable & clean interrupts */
+	writel(0x00, &regs->ier);
+	writel(0x0f, &regs->iscr);
+	/* 6. enable lcd */
+	writel(panel->vl_enable, &regs->fer);
+}
+
+ulong calc_fbsize(void)
+{
+	return ((panel_info.vl_col * panel_info.vl_row *
+			 NBITS(panel_info.vl_bpix)) / 8) + PAGE_SIZE;
+}
diff --git a/drivers/video/ftlcdc200_panel.c b/drivers/video/ftlcdc200_panel.c
new file mode 100644
index 0000000..f6f8498
--- /dev/null
+++ b/drivers/video/ftlcdc200_panel.c
@@ -0,0 +1,209 @@
+/*
+ * Faraday LCD Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <lcd.h>
+#include <faraday/ftlcdc200.h>
+
+struct vidinfo panel_info = {
+#if defined(CONFIG_FTLCDC200_320X240P_SHARP)
+	.vl_name  = "SHARP-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x10,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x10,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0f,
+	.vl_vbp   = 0x07,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBLP,
+	.vl_polarity = POL_DIV(23) | POL_IHS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240P_AUO)
+	.vl_name  = "AUO-320x240p",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PWROFF,
+	.vl_polarity = POL_DIV(21) | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_320X240S_AUO)
+	.vl_name  = "AUO-320x240s",
+	.vl_col   = 320,
+	.vl_row   = 240,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x17,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2A,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x0D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(1),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_640X480P_PV)
+	.vl_name  = "PV-640x480p",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x63,
+	.vl_hfp   = 0x01,
+	.vl_hbp   = 0x2D,
+	.vl_vsw   = 0x44,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1D,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(6) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480S_TPO)
+	.vl_name  = "TPO-800x480s",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x01,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(1) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = SPPR_SERIAL | SPPR_CS(0),
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_TPO)
+	.vl_name  = "TPO-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x04,
+	.vl_hfp   = 0x2C,
+	.vl_hbp   = 0xD4,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x0A,
+	.vl_vbp   = 0x22,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_BGR | PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X480P_CPT)
+	/* Chunghwa Picture Tubes - CLAA048LA0BCT */
+	.vl_name  = "CPT-800x480p",
+	.vl_col   = 800,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x01,
+	.vl_hfp   = 0x32,
+	.vl_hbp   = 0x31,
+	.vl_vsw   = 0x01,
+	.vl_vfp   = 0x0E,
+	.vl_vbp   = 0x05,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_PANEL_8BIT
+		| PPR_ENDIAN_LBBP,
+	.vl_polarity = POL_DIV(7) | POL_IHS | POL_IVS | POL_ICK,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_800X600_VGA)
+	.vl_name  = "D-SUB: VGA-800x600",
+	.vl_col   = 800,
+	.vl_row   = 600,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(3) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_1024X768_VGA)
+	.vl_name  = "D-SUB: VGA-1024x768",
+	.vl_col   = 1024,
+	.vl_row   = 768,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 0,    /* drived at runtime */
+	.vl_hsw   = 0x7E,
+	.vl_hfp   = 0x26,
+	.vl_hbp   = 0x56,
+	.vl_vsw   = 0x02,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x16,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_PANEL_8BIT | PPR_BPP_16,
+	.vl_polarity = POL_DIV(2) | POL_IVS | POL_IHS,
+	.vl_serial   = 0,
+	.vl_ccir656  = 0,
+#elif defined(CONFIG_FTLCDC200_720X480_NTSC)
+	.vl_name  = "A/V: NTSC-720x480",
+	.vl_col   = 720,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x06,
+	.vl_hfp   = 0x7D,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x0F,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x1A,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 3,
+#elif defined(CONFIG_FTLCDC200_640X480_NTSC)
+	.vl_name  = "A/V: NTSC-640x480",
+	.vl_col   = 640,
+	.vl_row   = 480,
+	.vl_bpix  = 4,    /* Bits per pixel, 0 = 1, ... 4 = 16 */
+	.vl_fps   = 30,   /* Frame per second */
+	.vl_hsw   = 0x02,
+	.vl_hfp   = 0xD1,
+	.vl_hbp   = 0x01,
+	.vl_vsw   = 0x10,
+	.vl_vfp   = 0x01,
+	.vl_vbp   = 0x19,
+	.vl_enable   = FER_EN | FER_ON,
+	.vl_pixel    = PPR_BPP_16 | PPR_PWROFF | PPR_ENDIAN_LBBP,
+	.vl_polarity = 0,
+	.vl_serial   = 0,
+	.vl_ccir656  = 1,
+#else
+#error "Please specific target LCD panel."
+#endif
+};
diff --git a/include/faraday/ftlcdc200.h b/include/faraday/ftlcdc200.h
new file mode 100644
index 0000000..e84bd9b
--- /dev/null
+++ b/include/faraday/ftlcdc200.h
@@ -0,0 +1,178 @@
+/*
+ * Faraday FTLCDC200 LCD Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __FTLCDC200_H
+#define __FTLCDC200_H
+
+/* FTLCDC200 Registers */
+struct ftlcdc200_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t fer;  /* 0x000: Function Enable Register */
+	uint32_t ppr;  /* 0x004: Panel Pixel Register */
+	uint32_t ier;  /* 0x008: Interrupt Enable Register */
+	uint32_t iscr; /* 0x00C: Interrupt Status Clear Register */
+	uint32_t isr;  /* 0x010: Interrupt Status Register */
+	uint32_t rsvd0[1];
+	uint32_t fb0;  /* 0x018: Framebuffer Base Register 0 */
+	uint32_t rsvd1[2];
+	uint32_t fb1;  /* 0x024: Framebuffer Base Register 1 */
+	uint32_t rsvd2[2];
+	uint32_t fb2;  /* 0x030: Framebuffer Base Register 2 */
+	uint32_t rsvd3[2];
+	uint32_t fb3;  /* 0x03C: Framebuffer Base Register 3 */
+	uint32_t rsvd4[2];
+	uint32_t patg; /* 0x048: Pattern Generator */
+	uint32_t fifo; /* 0x04C: FIFO Threshold */
+	uint32_t gpio; /* 0x050: GPIO */
+	uint32_t rsvd5[43];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t htcr;    /* Horizontal Timing Control Register */
+	uint32_t vtcr[2]; /* Vertical Timing Control Register */
+	uint32_t pcr;     /* Polarity Control Register */
+	uint32_t rsvd6[60];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t sppr;    /* Serial Panel Pixel Register */
+	uint32_t ccir;    /* CCIR565 Register */
+	uint32_t rsvd7[62];
+
+	/* 0x300 ~ 0x3ff */
+	uint32_t pipr;    /* Picture-In-Picture Register */
+	uint32_t pip1pos; /* Sub-picture 1 position */
+	uint32_t pip1dim; /* Sub-picture 1 dimension */
+	uint32_t pip2pos; /* Sub-picture 2 position */
+	uint32_t pip2dim; /* Sub-picture 2 dimension */
+	uint32_t rsvd8[59];
+
+	/* 0x400 ~ 0x5ff */
+	uint32_t cmnt[4]; /* Color Management */
+	uint32_t rsvd9[124];
+
+	/* 0x600 ~ 0x6ff */
+	uint32_t gamma_r[64]; /* RED - Gamma Correct */
+
+	/* 0x700 ~ 0x7ff */
+	uint32_t gamma_g[64]; /* GREEN - Gamma Correct */
+
+	/* 0x800 ~ 0x8ff */
+	uint32_t gamma_b[64]; /* BLUE - Gamma Correct */
+
+	/* 0x900 ~ 0x9ff */
+	uint32_t rsvd10[64];
+
+	/* 0xa00 ~ 0xbff */
+	uint32_t palette[128];  /* Palette Write Port */
+
+	/* 0xc00 ~ 0xcff */
+	uint32_t cstn_cr;       /* CSTN Control Register */
+	uint32_t cstn_pr;       /* CSTN Parameter Register */
+	uint32_t rsvd11[62];
+
+	/* 0xd00 ~ 0xdff */
+	uint32_t cstn_bmap[16]; /* CSTN bitmap write port */
+	uint32_t rsvd12[48];
+};
+
+/* LCD Function Enable Register */
+#define FER_EN          (1 << 0)    /* chip enabled */
+#define FER_ON          (1 << 1)    /* screen on */
+#define FER_YUV420      (3 << 2)
+#define FER_YUV422      (2 << 2)
+#define FER_YUV         (1 << 3)    /* 1:YUV, 0:RGB */
+
+/* LCD Panel Pixel Register */
+#define PPR_BPP_1       (0 << 0)
+#define PPR_BPP_2       (1 << 0)
+#define PPR_BPP_4       (2 << 0)
+#define PPR_BPP_8       (3 << 0)
+#define PPR_BPP_16      (4 << 0)
+#define PPR_BPP_24      (5 << 0)
+#define PPR_BPP_MASK    (7 << 0)
+#define PPR_PWROFF      (1 << 3)
+#define PPR_BGR         (1 << 4)
+#define PPR_ENDIAN_LBLP (0 << 5)
+#define PPR_ENDIAN_BBBP (1 << 5)
+#define PPR_ENDIAN_LBBP (2 << 5)
+#define PPR_ENDIAN_MASK (3 << 5)
+#define PPR_RGB1        (PPR_BPP_1)
+#define PPR_RGB2        (PPR_BPP_2)
+#define PPR_RGB4        (PPR_BPP_4)
+#define PPR_RGB8        (PPR_BPP_8)
+#define PPR_RGB12       (PPR_BPP_16 | (2 << 7))
+#define PPR_RGB16_555   (PPR_BPP_16 | (1 << 7))
+#define PPR_RGB16_565   (PPR_BPP_16 | (0 << 7))
+#define PPR_RGB24       (PPR_BPP_24)
+#define PPR_RGB32       (PPR_BPP_24)
+#define PPR_RGB_MASK    (PPR_BPP_MASK | (3 << 7))
+#define PPR_VCOMP_VSYNC (0 << 9)
+#define PPR_VCOMP_VBP   (1 << 9)
+#define PPR_VCOMP_VAIMG (2 << 9)
+#define PPR_VCOMP_VFP   (3 << 9)
+#define PPR_VCOMP_MASK  (3 << 9)
+#define	PPR_PANEL_6BIT  (0 << 11)
+#define	PPR_PANEL_8BIT  (1 << 11)
+#define	PPR_DITHER565   (0 << 12)
+#define	PPR_DITHER555   (1 << 12)
+#define	PPR_DITHER444   (2 << 12)
+#define	PPR_HCLK_RESET  (1 << 14)
+#define	PPR_LCCLK_RESET (1 << 15)
+
+/* LCD Interrupt Enable Register */
+#define IER_FIFOUR      (1 << 0)
+#define IER_NEXTFB      (1 << 1)
+#define IER_VCOMP       (1 << 2)
+#define IER_BUSERR      (1 << 3)
+
+/* LCD Interrupt Status Register */
+#define ISR_FIFOUR      (1 << 0)
+#define ISR_NEXTFB      (1 << 1)
+#define ISR_VCOMP       (1 << 2)
+#define ISR_BUSERR      (1 << 3)
+
+/* LCD Horizontal Timing Control Register */
+#define HTCR_HBP(x)     ((((x) - 1) & 0xff) << 24)
+#define HTCR_HFP(x)     ((((x) - 1) & 0xff) << 16)
+#define HTCR_HSYNC(x)   ((((x) - 1) & 0xff) << 8)
+#define HTCR_PL(x)      (((x >> 4) - 1) & 0xff)
+
+/* LCD Vertical Timing Control Register 0 */
+#define VTCR0_VFP(x)    (((x) & 0xff) << 24)
+#define VTCR0_VSYNC(x)  ((((x) - 1) & 0x3f) << 16)
+#define VTCR0_LF(x)     (((x) - 1) & 0xfff)
+
+/* LCD Vertical Timing Control Register 1 */
+#define VTCR1_VBP(x)    ((x) & 0xff)
+
+/* LCD Polarity Control Register */
+#define PCR_IVS         (1 << 0)
+#define PCR_IHS         (1 << 1)
+#define PCR_ICK         (1 << 2)
+#define PCR_IDE         (1 << 3)
+#define PCR_IPWR        (1 << 4)
+#define PCR_DIV(x)      ((((x) - 1) & 0x7f) << 8)
+
+/* LCD Serial Panel Pixel Register */
+#define SPPR_SERIAL     (1 << 0)
+#define SPPR_DELTA      (1 << 1)
+#define SPPR_CS(x)      ((x) << 2)
+#define SPPR_CS_RGB     (0 << 2)
+#define SPPR_CS_BRG     (1 << 2)
+#define SPPR_CS_GBR     (2 << 2)
+#define SPPR_LSR        (1 << 4)
+#define SPPR_AUO052     (1 << 5)
+
+/* LCD CCIR656 Register */
+#define CCIR_PAL        (0 << 0)
+#define CCIR_NTSC       (1 << 0)
+#define CCIR_P640       (0 << 1)
+#define CCIR_P720       (1 << 1)
+#define CCIR_PHASE(x)   ((x) << 2)
+
+#endif /* __FTLCDC200_H */
diff --git a/include/lcd.h b/include/lcd.h
index b54255a..37dbc79 100644
--- a/include/lcd.h
+++ b/include/lcd.h
@@ -237,6 +237,39 @@ typedef struct vidinfo {

 void init_panel_info(vidinfo_t *vid);

+#elif defined(CONFIG_FTLCDC200)
+
+typedef struct vidinfo {
+	ushort	vl_col;		/* Number of columns (i.e. 800) */
+	ushort	vl_row;		/* Number of rows (i.e. 600) */
+
+	u_char	vl_bpix;	/* Bits per pixel, 0 = 1, 1 = 2 ... 4 = 16 */
+
+	/* Timing Parameters */
+	u_char	vl_fps;		/* Frame per second */
+
+	u_char	vl_hsw;
+	u_char	vl_hbp;
+	u_char	vl_hfp;
+
+	u_char	vl_vsw;
+	u_char	vl_vbp;
+	u_char	vl_vfp;
+
+	/* Pre-defined FTLCDC200 register values */
+	u_long	vl_enable;	/* LCDEnable */
+	u_long	vl_pixel;	/* PanelPixel */
+	u_long	vl_polarity;/* Polarity */
+	u_long	vl_serial;	/* SerialPanelPixel */
+	u_long	vl_ccir656;	/* CCIR656 */
+
+	/* Panel name */
+	char	*vl_name;
+
+	ushort	*cmap;		/* Pointer to the colormap */
+	void	*priv;		/* Pointer to driver-specific data */
+} vidinfo_t;
+
 #else

 typedef struct vidinfo {
--
1.7.9.5

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

* [U-Boot] [PATCH v7 03/11] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 01/11] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 02/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-07-29 22:59     ` Scott Wood
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 04/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
                     ` (8 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is an integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v7:
   - ftnandc021.[ch]: Update license to use SPDX identifiers.
   - ftnandc021.c: put_unaligned() -> memcpy()
   - ftnandc021.c: update ecc relatived function prototypes to
     fix compile warnnings.

Changes for v6:
   - Update README for CONFIG_SYS_FTNANDC021_TIMING
   - Remove illegal type-punning by introducing
     put_unaligned() & get_unaligned().

Changes for v5 (Part of A360/A369 patch series):
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - For there is a strong dependancy between this and A360/A369 patch
     series, it had been chained back to A360/A369 patch series.
   - The latest nand_base requires the ecc.strength to be set properlly,
     so this patch adds ecc.strength setting accroding to ECC algorithm.

Changes for v5 (Standalone):
   - Update README for the description of CONFIG_SYS_FTNANDC021_TIMING.
   - Drop redundant white space. (i.e. if (mtd->writesize >= ' '4096))

Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Drop the faraday/nand.h to remove dependency to
     Faraday A36x patch series.
   - CONFIG_SYS_NAND_TIMING -> CONFIG_SYS_FTNANDC021_TIMING
   - Remove non-ECC code.
   - Implement private hwecc read/write_page functions
     to get rid of .eccpos & .eccbytes.
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Re-write this driver with ECC enabled and correct column address
     handling for OOB read/write,
   - Fix issuses addressed by Scott.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 README                        |   10 +
 drivers/mtd/nand/Makefile     |    1 +
 drivers/mtd/nand/ftnandc021.c |  609 +++++++++++++++++++++++++++++++++++++++++
 include/faraday/ftnandc021.h  |  152 ++++++++++
 4 files changed, 772 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 include/faraday/ftnandc021.h

diff --git a/README b/README
index a5c3e8d..f4b0dbe 100644
--- a/README
+++ b/README
@@ -4076,6 +4076,16 @@ Low Level (hardware related) configuration options:
 		- drivers/mtd/nand/ndfc.c
 		- drivers/mtd/nand/mxc_nand.c

+- CONFIG_SYS_FTNANDC021_TIMING
+		This option specifies an array of customized timing parameters
+		for Faraday FTNANDC021 NAND flash controller.
+		e.g.
+		#define CONFIG_SYS_FTNANDC021_TIMING \
+			{ CONFIG_NAND_K9F4G08U0B_AC1, CONFIG_NAND_K9F4G08U0B_AC2 }
+		where CONFIG_NAND_K9F4G08U0B_AC[1/2] are the optimized AC
+		timing parameters for register AC_TIMING1 and AC_TIMING2 which
+		control the timing for CLE, ALE, WE and RE signals.
+
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
 		a default value will be used.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index e27e0b7..ee85b8a 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -48,6 +48,7 @@ COBJS-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 COBJS-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 COBJS-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 COBJS-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+COBJS-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 COBJS-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..9d249f7
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,609 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <nand.h>
+#include <malloc.h>
+
+#include <faraday/ftnandc021.h>
+
+#define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 2) /* 250 ms */
+#define CFG_PIO_TIMEOUT (CONFIG_SYS_HZ >> 3) /* 125 ms */
+
+struct ftnandc021_chip {
+	void __iomem *regs;
+	int alen;
+	int pgsz;
+	int bksz;
+
+	int col;    /* current column address */
+	int page;   /* current row address/page index */
+	int cmd;    /* current NAND command code */
+	int cmd_hc; /* current FTNANDC021 command code */
+};
+
+static struct nand_ecclayout ftnandc021_ecclayout[] = {
+	{ /* page size = 512 (oob size = 16) */
+		.oobfree = {
+			{ 9, 3 },
+		}
+	},
+	{ /* page size = 2048 (oob size = 64) */
+		.oobfree = {
+			{ 9, 3 },
+		},
+	},
+	{ /* page size = 4096 (oob size = 128) */
+		.oobfree = {
+			{ 9, 7 },
+		},
+	},
+};
+
+static inline int ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t st = readl(&regs->idr[1]);
+
+	if (st & NAND_STATUS_FAIL)
+		return -EIO;
+
+	if (!(st & NAND_STATUS_READY))
+		return -EBUSY;
+
+	if (!(st & NAND_STATUS_WP))
+		return -EIO;
+
+	return 0;
+}
+
+static inline int ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	char rc = 'c';
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			rc = 'e';
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			rc = 0;
+			break;
+		}
+	}
+
+	switch (rc) {
+	case 'e':
+		printf("ftnandc021: ecc timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	case 'c':
+		printf("ftnandc021: cmd timeout, cmd_hc=%d\n",
+			priv->cmd_hc);
+		break;
+	default:
+		break;
+	}
+
+	return rc ? -ETIMEDOUT : 0;
+}
+
+static int ftnandc021_read_page(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+	/*
+	 * OOB has been read at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it right here.
+	 */
+	chip->read_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static int ftnandc021_write_page(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	/*
+	 * OOB has been written at ftnandc021_cmdfunc(),
+	 * so we don't have to handle it right here.
+	 */
+	chip->write_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static int ftnandc021_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+	printf("ftnandc021: read_page_raw is not supported\n");
+	return -EIO;
+}
+
+static int ftnandc021_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	printf("ftnandc021: write_page_raw is not supported\n");
+	return 0;
+}
+
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 0;
+
+	priv->cmd_hc = cmd;
+
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	/*
+	 * pgread    : (We have queued data at the IO port)
+	 * pgwrite   : (We have queued data at the IO port)
+	 * bkerase   : nand_wait + nand_ckst
+	 * oobwr     : nand_wait + nand_ckst
+	 * otherwise : nand_wait
+	 */
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+	case FTNANDC021_CMD_WRPG:
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+static int ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t bk, pg, ac, mask;
+#ifdef CONFIG_SYS_FTNANDC021_TIMING
+	uint32_t timing[] = CONFIG_SYS_FTNANDC021_TIMING;
+
+	writel(timing[0], &regs->atr[0]);
+	writel(timing[1], &regs->atr[1]);
+#endif
+
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	mask = SRR_CHIP_RESET | SRR_ECC_EN;
+	writel(mask, &regs->srr);
+	mdelay(200);
+	if (readl(&regs->srr) & SRR_CHIP_RESET) {
+		printf("ftnandc021: reset failed\n");
+		return -ENXIO;
+	}
+
+	/* sanity check on page size */
+	if (priv->pgsz != 512 && priv->pgsz != 2048 && priv->pgsz != 4096) {
+		printf("ftnandc021: invalid page size=%d\n", priv->pgsz);
+		return -EINVAL;
+	}
+
+	bk = ffs(priv->bksz / priv->pgsz) - 5;
+	pg = (priv->pgsz < 2048) ? 0 : (ffs(priv->pgsz) - 11);
+	ac = priv->alen - 3;
+
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* IO mode = PIO */
+	writel(0, &regs->bcr);
+
+	/* ECC mode */
+	chip->ecc.layout         = ftnandc021_ecclayout + pg;
+	chip->ecc.size           = priv->pgsz;
+	chip->ecc.steps          = 1;
+	chip->ecc.read_page      = ftnandc021_read_page;
+	chip->ecc.write_page     = ftnandc021_write_page;
+	chip->ecc.read_page_raw  = ftnandc021_read_page_raw;
+	chip->ecc.write_page_raw = ftnandc021_write_page_raw;
+	chip->ecc.mode           = NAND_ECC_HW;
+	if (CFGR_ECC_TYPE(readl(&regs->cfgr)) == CFGR_ECC_BCH)
+		chip->ecc.strength = 8;
+	else
+		chip->ecc.strength = 4;
+
+	/* reset the attached flash */
+	if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+		return -ENXIO;
+
+	return 0;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv))
+		ret = 0;
+	else if (!(readl(&regs->sr) & SR_READY))
+		ret = 0;
+
+	return ret;
+}
+
+static int ftnandc021_pio_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = -ETIMEDOUT;
+	uint32_t ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_PIO_TIMEOUT; ) {
+		if (!(readl(&regs->ior) & IOR_READY))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftnandc021: pio timeout\n");
+
+	return ret;
+}
+
+static void ftnandc021_read_oob(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	memset(buf, 0xff, len);
+
+	/* bad block */
+	buf[chip->badblockpos] = readl(&regs->bbird) & 0xff;
+
+	/* data */
+	tmp = readl(&regs->crcrd);
+	buf[8] = (tmp >> 0) & 0xff;
+	buf[9] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[12] = (tmp >> 16) & 0xff;
+		buf[13] = (tmp >> 24) & 0xff;
+	}
+
+	tmp = readl(&regs->lsnrd);
+	buf[10] = (tmp >> 0) & 0xff;
+	buf[11] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[14] = (tmp >> 16) & 0xff;
+		buf[15] = (tmp >> 24) & 0xff;
+	}
+}
+
+static void ftnandc021_write_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	/* bad block */
+	tmp = buf[chip->badblockpos];
+	writel(tmp, &regs->bbiwr);
+
+	/* mark it as 'not blank' */
+	tmp = 'W' | (buf[9] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	writel(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize >= 4096)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	writel(tmp, &regs->lsnwr);
+}
+
+static uint8_t ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+		if (priv->col < 8) {
+			uint32_t idx = priv->col >> 2;
+			uint32_t pos = priv->col & 0x3;
+			uint32_t tmp = readl(&regs->idr[idx]);
+
+			ret = (uint8_t)(tmp >> (pos << 3));
+			priv->col += 1;
+		}
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint8_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: unknown cmd=0x%x in read_byte\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t ftnandc021_read_word(struct mtd_info *mtd)
+{
+	uint16_t ret = 0xffff;
+	uint8_t *buf = (uint8_t *)&ret;
+
+	/* LSB format */
+	buf[0] = ftnandc021_read_byte(mtd);
+	buf[1] = ftnandc021_read_byte(mtd);
+
+	return ret;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void ftnandc021_read_buf(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t val, off;
+
+	if (priv->col >= mtd->writesize)
+		return;
+
+	if (priv->cmd == NAND_CMD_READOOB)
+		BUG();	/* should never happen */
+
+	/* skip if it's a blank page */
+	if (chip->oob_poi[8] != 'W') {
+		memset(buf, 0xff, len);
+		return;
+	}
+
+	off = 0;
+	while (off < len && priv->col < mtd->writesize) {
+		ftnandc021_pio_wait(priv);
+		val = readl(&regs->dr);
+		memcpy(buf + off, &val, 4);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void ftnandc021_write_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t off, val;
+
+	/*
+	 * FTNANDC021 HW design issues:
+	 *
+	 * 1. OOB data must be set before issuing write command,
+	 *    so it's too late to do it right here
+	 * 2. Only after command issued, the data register
+	 *    could accept data.
+	 */
+	if (priv->col >= mtd->writesize)
+		return;
+
+	for (off = 0; off < len && priv->col < mtd->writesize; ) {
+		ftnandc021_pio_wait(priv);
+		memcpy(&val, buf + off, 4);
+		writel(val, &regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int ftnandc021_verify_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	int ret = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021: out of memory\n");
+		return -ENOMEM;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			ret = -EINVAL;
+	}
+
+	free(tmp);
+	return ret;
+}
+
+static void ftnandc021_cmdfunc(struct mtd_info *mtd,
+	unsigned cmd, int col, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+
+	priv->cmd = cmd;
+	priv->col = col;
+	priv->page = page;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		priv->col = 0;
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDID))
+			printf("ftnandc021: RDID failed.\n");
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		priv->col = mtd->writesize;
+		/* fall-through */
+	case NAND_CMD_READ0:	/* 0x00 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* fetch oob to check if it's a blank page */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDOOB)) {
+			printf("ftnandc021: RDOOB failed.\n");
+			break;
+		}
+		ftnandc021_read_oob(mtd, chip->oob_poi, mtd->oobsize);
+		/* skip if we don't need page data */
+		if (priv->col >= mtd->writesize)
+			break;
+		/* skip if it's a blank page */
+		if (chip->oob_poi[8] != 'W') {
+			debug("ftnandc021: skip page %d\n", page);
+			break;
+		}
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDPG))
+			printf("ftnandc021: RDPG failed.\n");
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_ERBLK))
+			printf("ftnandc021: ERBLK failed\n");
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RDST))
+			printf("ftnandc021: RDST failed\n");
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* OOB data must be set before issuing command */
+		ftnandc021_write_oob(mtd, chip->oob_poi, mtd->oobsize);
+		priv->cmd_hc = (priv->col >= mtd->writesize)
+			? FTNANDC021_CMD_WROOB : FTNANDC021_CMD_WRPG;
+		if (ftnandc021_command(priv, priv->cmd_hc))
+			printf("ftnandc021: CMD_HC=%d failed\n", priv->cmd_hc);
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		/* nothing needs to be done */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		if (ftnandc021_command(priv, FTNANDC021_CMD_RESET))
+			printf("ftnandc021: RESET failed.\n");
+		break;
+
+	default:
+		printf("ftnandc021: unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void ftnandc021_hwcontrol(struct mtd_info *mtd,
+	int cmd, unsigned int ctrl)
+{
+	/* nothing needs to be done */
+}
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen)
+{
+	struct ftnandc021_chip *priv;
+
+	priv = calloc(1, sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -ENOMEM;
+
+	priv->regs = (void __iomem *)iobase;
+	priv->pgsz = 1 << chip->page_shift;
+	priv->bksz = 1 << chip->phys_erase_shift;
+	priv->alen = alen;
+
+	chip->priv = priv;
+
+	debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n",
+		   priv->pgsz, priv->bksz, priv->alen);
+
+	/* hardware reset */
+	if (ftnandc021_reset(chip))
+		return -EINVAL;
+
+	/* hwcontrol always must be implemented */
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	return 0;
+}
diff --git a/include/faraday/ftnandc021.h b/include/faraday/ftnandc021.h
new file mode 100644
index 0000000..a5b0d28
--- /dev/null
+++ b/include/faraday/ftnandc021.h
@@ -0,0 +1,152 @@
+/*
+ * Faraday FTNANDC021 NAND Flash Controller
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __FTNANDC021_H
+#define __FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+	/* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4];/* ECC Parity Register */
+	uint32_t ecc_sr;   /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+	/* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsn;	 /* LSN Initialize */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+	/* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+	/* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* ECC Status Register */
+#define ECC_SR_CERR      (1 << 3)  /* correction error */
+#define ECC_SR_ERR       (1 << 2)  /* ecc error */
+#define ECC_SR_DEC       (1 << 1)  /* ecc decode finished */
+#define ECC_SR_ENC       (1 << 0)  /* ecc encode finished */
+
+/* Status Register */
+#define SR_BLANK         (1 << 7)  /* blanking check failed */
+#define SR_ECC           (1 << 6)  /* ecc timeout */
+#define SR_STS           (1 << 4)  /* status error */
+#define SR_CRC           (1 << 3)  /* crc error */
+#define SR_CMD           (1 << 2)  /* command finished */
+#define SR_READY         (1 << 1)  /* chip ready/busy */
+#define SR_ENA           (1 << 0)  /* chip enabled */
+
+/* Access Control Register */
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        (1 << 7)  /* command start */
+
+/* Flow Control Register */
+#define FCR_SWCRC        (1 << 8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       (1 << 7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        (1 << 4)  /* 16 bit data bus */
+#define FCR_WPROT        (1 << 3)  /* write protected */
+#define FCR_NOSC         (1 << 2)  /* bypass status check error */
+#define FCR_MICRON       (1 << 1)  /* Micron 2-plane command */
+#define FCR_NOBC         (1 << 0)  /* skip blanking check error */
+
+/* Interrupt Enable Register */
+#define IER_ENA          (1 << 7)  /* interrupt enabled */
+#define IER_ECC          (1 << 3)  /* ecc error timeout */
+#define IER_STS          (1 << 2)  /* status error */
+#define IER_CRC          (1 << 1)  /* crc error */
+#define IER_CMD          (1 << 0)  /* command finished */
+
+/* BMC PIO Status Register */
+#define IOR_READY        (1 << 0)  /* PIO ready */
+
+/* MLC Software Reset Register */
+#define SRR_ECC_EN       (1 << 8)  /* ECC enabled */
+#define SRR_NANDC_RESET  (1 << 2)  /* NANDC reset */
+#define SRR_BMC_RESET    (1 << 1)  /* BMC reset */
+#define SRR_ECC_RESET    (1 << 0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+/* Memory Configuration Register */
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* Configuration Register */
+#define CFGR_ECC_TYPE(x) (((x) >> 16) & 0xf)
+#define CFGR_ECC_RS      4
+#define CFGR_ECC_BCH     8
+#define CFGR_IOBITS(x)   (((x) >> 8) & 0xff) /* Max. data width */
+#define CFGR_MAXFLS(x)   ((x) & 0xf) /* Max. flash chips */
+
+/* FTNANDC021 built-in command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02   /* reset flash */
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t iobase, int alen);
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v7 04/11] arm: add MMU/D-Cache support for Faraday cores
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 03/11] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 05/11] arm: add Faraday processor core support Kuo-Jung Su
                     ` (7 subsequent siblings)
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This updates the map_physmem()/unmap_physmem(), and use
them to implement dma_alloc_coherent() & dma_free_coherent().

It uses 1MB section for each mapping, and thus wastes lots of
address space, however this should still be good enough for
tiny systems (i.e. u-boot).

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v6, v7:
   - Nothing updates

Changes for v5:
   - Add void dram_bank_mmu_setup() into 'arch/arm/cpu/faraday/cpu.c'
     to override the weak function in "cache-cp15.c".
   - Use small page (4KB) to map relocated exception table to 0x0000

Changes for v4:
   - Coding Style cleanup.

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - Drop static non-cached region, now we use map_physmem()/unmap_physmem()
     for dynamic mappings.

Changes for v2:
   - Coding Style cleanup.
   - cache-cp15: Enable write buffer in write-through mode.

 arch/arm/include/asm/dma-mapping.h |   56 ++++++++++++-
 arch/arm/include/asm/global_data.h |    4 +
 arch/arm/include/asm/io.h          |  159 ++++++++++++++++++++++++++++++++++--
 arch/arm/include/asm/system.h      |    7 +-
 arch/arm/lib/cache-cp15.c          |    9 ++
 5 files changed, 223 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 55a4e26..e066204 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -8,22 +8,76 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+#include <asm/io.h>
+#include <malloc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
 	DMA_FROM_DEVICE		= 2,
 };

-static void *dma_alloc_coherent(size_t len, unsigned long *handle)
+static inline void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *map, *va = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (va && gd->arch.cpu_mmu) {
+		invalidate_dcache_range((ulong)va, (ulong)va + len);
+		map = map_physmem((phys_addr_t)va, len, MAP_NOCACHE);
+		if (!map)
+			free(va);
+		va = map;
+	}
+
+	if (handle)
+		*handle = virt_to_phys(va);
+
+	return va;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
 	return (void *)*handle;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+}
+
+static inline void dma_free_coherent(void *vaddr, ulong len)
+{
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	void *tmp = (void *)virt_to_phys(vaddr);
+	unmap_physmem(vaddr, len);
+	vaddr = tmp;
+#endif
+	free(vaddr);
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+	}
+	return virt_to_phys((void *)vaddr);
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (unsigned long)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 static inline void dma_unmap_single(volatile void *vaddr, size_t len,
diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index 79a9597..587ecbc 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -26,6 +26,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_FARADAY
+	unsigned long   cpu_id;
+	unsigned long   cpu_mmu;	/* has mmu */
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..6edb53a 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -28,9 +28,36 @@
 #if 0	/* XXX###XXX */
 #include <asm/arch/hardware.h>
 #endif	/* XXX###XXX */
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <asm/system.h>
+#include <asm/u-boot.h>
+#include <asm/global_data.h>
+
+#ifndef CONFIG_MMAP_START
+#define CONFIG_MMAP_START   0xd0000000
+#endif
+
+#ifndef CONFIG_MMAP_END
+#define CONFIG_MMAP_END     0xfff00000
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
+/* arch/$(ARCH)/lib/cache.c */
+void invalidate_icache_all(void);
+void flush_dcache_all(void);
+void flush_dcache_range(ulong start, ulong stop);

 static inline void sync(void)
 {
+#ifndef CONFIG_SYS_DCACHE_OFF
+	flush_dcache_all();
+#endif
+#ifndef CONFIG_SYS_ICACHE_OFF
+	invalidate_icache_all();
+#endif
 }

 /*
@@ -39,27 +66,143 @@ static inline void sync(void)
  * properties specified by "flags".
  */
 #define MAP_NOCACHE	(0)
-#define MAP_WRCOMBINE	(0)
-#define MAP_WRBACK	(0)
-#define MAP_WRTHROUGH	(0)
+#define MAP_WRCOMBINE	(1)
+#define MAP_WRBACK	(2)
+#define MAP_WRTHROUGH	(3)
+
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+static inline void map_flush(ulong start, ulong end)
+{
+	flush_dcache_range(start, end);
+
+	/* invalidate D-TLB */
+	start &= 0xfff00000;
+	end = (end + 0x000fffff) & 0xfff00000;
+	__asm__ __volatile__ (
+		"mov r3, %0\n"
+		"1:\n"
+		"mcr p15, 0, r3, c8, c6, 1\n"
+		"add r3, r3, #4096\n"
+		"cmp r3, %1\n"
+		"blo 1b\n"
+		: /* output */
+		: "r"(start), "r"(end) /* input */
+		: "r3" /* clobber list */
+	);
+}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */

 static inline void *
-map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
+map_physmem(phys_addr_t paddr, ulong len, ulong flags)
 {
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 vaddr, nattr, oattr, addr, size, end;
+
+	/* 1. check if we have to create a mapping for it */
+	vaddr = paddr;
+	addr  = page_table[vaddr >> 20] & 0xfff00000;
+	oattr = page_table[vaddr >> 20] & 0x1f;
+	switch (flags) {
+	case MAP_WRCOMBINE:
+		nattr = DCACHE_WRITECOMBINE;
+		break;
+	case MAP_WRTHROUGH:
+		nattr = DCACHE_WRITETHROUGH;
+		break;
+	case MAP_WRBACK:
+		nattr = DCACHE_WRITEBACK;
+		break;
+	default:
+		nattr = DCACHE_OFF;
+		break;
+	}
+	if ((nattr == oattr) && (vaddr == addr))
+		return (void *)paddr;
+
+	/* 2. find a contiguous region for it */
+	end = (paddr + len + 0x000fffff) & 0xfff00000;
+	len = end - (paddr & 0xfff00000);
+	size = 0;
+	addr = CONFIG_MMAP_START;
+	vaddr = addr;
+	while (addr < CONFIG_MMAP_END) {
+		/* if va == pa, then it's free to use */
+		if (addr == (page_table[addr >> 20] & 0xfff00000)) {
+			size += SZ_1M;
+		} else {
+			size = 0;
+			vaddr = addr + SZ_1M;
+		}
+		if (size >= len)
+			break;
+		addr += SZ_1M;
+	}
+	if (size < len)
+		return NULL;
+
+	/* 3. create the map */
+	map_flush(vaddr, vaddr + size);
+	addr = vaddr;
+	vaddr += paddr & 0x000fffff;
+	paddr &= 0xfff00000;
+	while (size) {
+		page_table[addr >> 20] = paddr | (3 << 10) | nattr;
+		size -= SZ_1M;
+		addr += SZ_1M;
+		paddr += SZ_1M;
+	}
+	return (void *)vaddr;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (void *)paddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
  * Take down a mapping set up by map_physmem().
  */
-static inline void unmap_physmem(void *vaddr, unsigned long flags)
+static inline void unmap_physmem(void *vaddr, ulong len)
 {
-
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	u32 addr, end;
+
+	/* 1. skip on NULL pointer */
+	if (!vaddr)
+		return;
+
+	/* 2. check if it's the right address map */
+	addr = (u32)vaddr;
+	if ((page_table[addr >> 20] & 0xfff00000) == addr)
+		return;
+
+	/* 3. reset the map */
+	end = (addr + len + 0x000fffff) & 0xfff00000;
+	addr &= 0xfff00000;
+	map_flush(addr, end);
+	while (addr < end) {
+		page_table[addr >> 20] = addr | (3 << 10) | DCACHE_OFF;
+		addr += SZ_1M;
+	}
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

-static inline phys_addr_t virt_to_phys(void * vaddr)
+static inline phys_addr_t virt_to_phys(void *vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	u32 *page_table = (u32 *)gd->arch.tlb_addr;
+	phys_addr_t phys = (phys_addr_t)vaddr;
+
+	if (!gd->arch.cpu_mmu || !vaddr)
+		return phys;
+
+	phys = page_table[(u32)vaddr >> 20] & 0xfff00000;
+	phys += (u32)vaddr & 0x000fffff;
+
+	return phys;
+#else  /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	return (phys_addr_t)vaddr;
+#endif /* CONFIG_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
diff --git a/arch/arm/include/asm/system.h b/arch/arm/include/asm/system.h
index 760345f..050b707 100644
--- a/arch/arm/include/asm/system.h
+++ b/arch/arm/include/asm/system.h
@@ -97,9 +97,10 @@ static inline void set_dacr(unsigned int val)

 /* options available for data cache on each page */
 enum dcache_option {
-	DCACHE_OFF = 0x12,
-	DCACHE_WRITETHROUGH = 0x1a,
-	DCACHE_WRITEBACK = 0x1e,
+	DCACHE_OFF = 0x12,          /* non-cached + non-buffered */
+	DCACHE_WRITECOMBINE = 0x16, /* non-cached + buffered */
+	DCACHE_WRITETHROUGH = 0x1a, /* cached + non-buffered */
+	DCACHE_WRITEBACK = 0x1e,    /* cached + buffered */
 };

 /* Size of an MMU section */
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 8642010..3259a33 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -110,6 +110,10 @@ static inline void mmu_setup(void)

 	/* and enable the mmu */
 	reg = get_cr();	/* get control reg. */
+#ifdef CONFIG_FARADAY
+	reg |= CR_W;	/* enable write buffer */
+	reg |= CR_Z;	/* enable branch prediction */
+#endif
 	cp_delay();
 	set_cr(reg | CR_M);
 }
@@ -124,6 +128,11 @@ static void cache_enable(uint32_t cache_bit)
 {
 	uint32_t reg;

+#ifdef CONFIG_FARADAY
+	if (!gd->arch.cpu_mmu && (cache_bit == CR_C))
+		return;
+#endif
+
 	/* The data cache is not active unless the mmu is enabled too */
 	if ((cache_bit == CR_C) && !mmu_enabled())
 		mmu_setup();
--
1.7.9.5

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

* [U-Boot] [PATCH v7 05/11] arm: add Faraday processor core support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 04/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 06/11] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
                     ` (6 subsequent siblings)
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds i/d-cache control, mmu setup & bootstrap code
for Faraday cores.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - Nothing updates

Changes for v5:
   - Initial commit which is separated from
     "arm: add Faraday common utilities"

 arch/arm/cpu/faraday/Makefile  |   39 ++++
 arch/arm/cpu/faraday/config.mk |   17 ++
 arch/arm/cpu/faraday/cpu.c     |  333 +++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/start.S   |  419 ++++++++++++++++++++++++++++++++++++++++
 4 files changed, 808 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..acc09eb
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,39 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(CPU).o
+
+src-y  := cpu.o
+
+START	= start.o
+COBJS	= $(src-y)
+
+ifdef	CONFIG_SPL_BUILD
+ifdef	CONFIG_SPL_NO_CPU_SUPPORT_CODE
+START	:=
+endif
+endif
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(START) $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..eed9c81
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,17 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+PLATFORM_RELFLAGS += -fno-common -ffixed-r8 -msoft-float
+
+PLATFORM_CPPFLAGS += -march=armv4
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..874334a
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,333 @@
+/*
+ * arch/arm/cpu/faraday/cpu.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * CPU specific code
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+
+	disable_interrupts();
+
+	/* turn off D-cache */
+	dcache_disable();
+
+	/* flush I-cache */
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n" /* invalidate i-cache all */
+		:      /* output */
+		:      /* input */
+		: "r0" /* clobber list */
+	);
+
+	return 0;
+}
+
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+#else
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c14,0\n" /* clean & invalidate d-cache all */
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n" /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n" /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c6,0\n" /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r0"/* clobber list */
+	);
+}
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c5,0\n" /* invalidate i-cache all */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
+
+void enable_caches(void)
+{
+	icache_enable();
+
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	if (gd->arch.cpu_mmu) {
+		puts("MMU:   on\n");
+		dcache_enable();
+	} else
+#endif
+		puts("MMU:   off\n");
+}
+
+#define CPUID_VID(x)        (((x) >> 24) & 0xff)
+#define CPUID_ISA(x)        (((x) >> 16) & 0xff)
+#define CPUID_PID(x)        (((x) >>  4) & 0x0fff)
+#define CPUID_REV(x)        ((x) & 0x0f) /* revision */
+#define CPUID_NOREV(x)      (((x) >>  4) & 0x0fffffff)
+
+/* Vendor ID */
+#define CPUID_VID_ARM       0x41
+#define CPUID_VID_FARADAY   0x66
+
+/* Instruction Set Architecture */
+#define CPUID_ISA_ARMV4     0x01
+#define CPUID_ISA_ARMV5TE   0x05
+#define CPUID_ISA_ARMV5TEJ  0x06
+
+/* Faraday ARMv4 cores */
+#define CPUID_FA526         0x6601526
+#define CPUID_FA626         0x6601626
+
+/* Faraday ARMv5TE cores */
+#define CPUID_FA606TE       0x6605606
+#define CPUID_FA616TE       0x6605616
+#define CPUID_FA626TE       0x6605626
+#define CPUID_FA726TE       0x6605726
+
+#ifdef CONFIG_ARCH_CPU_INIT
+
+int arch_cpu_init(void)
+{
+	unsigned int id, ctr;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		"mrc p15, 0, %1, c0, c0, 1\n"
+		: "=r"(id), "=r"(ctr) /* output */
+		: /* input */
+	);
+
+	gd->arch.cpu_id = id;
+
+	/* MMU/D-Cache */
+	switch (CPUID_NOREV(gd->arch.cpu_id)) {
+	case CPUID_FA606TE: /* FA606TE (no-mmu) */
+		/* Disable MMU/D-Cache */
+		gd->arch.cpu_mmu = 0;
+		break;
+	default:
+		/* Enable MMU/D-Cache */
+		gd->arch.cpu_mmu = 1;
+		break;
+	}
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+	uint vid = CPUID_VID(gd->arch.cpu_id);
+	uint pid = CPUID_PID(gd->arch.cpu_id);
+
+	/* build cpu_name */
+	switch (vid) {
+	case CPUID_VID_FARADAY:	/* Faraday */
+		switch (CPUID_ISA(gd->arch.cpu_id)) {
+		case CPUID_ISA_ARMV5TE:
+			sprintf(cpu_name, "FA%xTE", pid);
+			break;
+		default:
+			sprintf(cpu_name, "FA%x", pid);
+			break;
+		}
+		break;
+	case CPUID_VID_ARM:	/* ARM */
+		if ((pid & 0xff0) == 0xc00)
+			sprintf(cpu_name, "Cortex-A%u", (pid & 0x00f));
+		else if (pid >= 0xa00)
+			sprintf(cpu_name, "ARM%x", 0x1000 + (pid - 0xa00));
+		else
+			sprintf(cpu_name, "ARM%x", pid);
+		break;
+	default:
+		sprintf(cpu_name, "Unknown");
+		break;
+	}
+
+	/* print cpu_info */
+	printf("CPU:   %s %u MHz\n",
+		cpu_name, (unsigned int)(clock_get_rate(CPU_CLK) / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clock_get_rate(AHB_CLK) / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clock_get_rate(APB_CLK) / 1000000));
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+
+#undef  CACHE_SETUP
+#if defined(CONFIG_SYS_ARM_CACHE_WRITETHROUGH)
+#define CACHE_SETUP DCACHE_WRITETHROUGH
+#else
+#define CACHE_SETUP DCACHE_WRITEBACK
+#endif
+
+#ifdef CONFIG_USE_IRQ
+static u32 page_table[256] __aligned(1024);
+#endif
+
+/*
+ * This dram_bank_mmu_setup() overrides the weak function
+ * in "cache-cp15.c".
+ */
+void dram_bank_mmu_setup(int bank)
+{
+	u32 pa, *sect_table = (u32 *)gd->arch.tlb_addr;
+	bd_t *bd = gd->bd;
+	int	i;
+
+	for (i = bd->bi_dram[bank].start >> 20;
+	     i < (bd->bi_dram[bank].start + bd->bi_dram[bank].size) >> 20;
+	     i++) {
+		pa = i << 20;
+		sect_table[i] = pa | (3 << 10) | CACHE_SETUP;
+	}
+
+#ifdef CONFIG_USE_IRQ
+	/* only setup exception table when bank == 0 */
+	if (bank)
+		return;
+
+	/* make sure the exception table is mapped to 0x00000000 */
+	sect_table[0] = (u32)page_table | 0x11; /* coarse page */
+	page_table[0] = gd->relocaddr | 0xff2; /* small page (4KB) */
+
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n" /* invalidate TLB */
+		"mcr p15, 0, r0, c7, c5, 0\n" /* invalidate I Cache */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+#endif /* CONFIG_USE_IRQ */
+}
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt *regs = (void __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with System Reset Function */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+	/* Kick it to force counter reloaded */
+	writel(FTWDT010_WDRESTART_MAGIC, &regs->wdrestart);
+#endif
+}
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..8108925
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,419 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * Relocate U-Boot to RAM
+	 * It's copied from the old u-boot release.
+	 */
+#ifndef CONFIG_SPL_BUILD
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq rr_exit
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+rr_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo rr_loop
+
+	/* Adjust the pc to use the correct text address */
+	adr r0, _start
+	ldr r1, _TEXT_BASE
+	sub r2, pc, r0
+	add r2, r2, #4
+	add pc, r1, r2
+
+rr_exit:
+#endif  /* !CONFIG_SPL_BUILD */
+
+	bl	_main
+
+/*---------------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+
+	bx	lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
--
1.7.9.5

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

* [U-Boot] [PATCH v7 06/11] arm: add Faraday FTINTC020 interrupt controller support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 05/11] arm: add Faraday processor core support Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 07/11] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
                     ` (5 subsequent siblings)
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - Nothing updates

Changes for v5:
   - Coding Style cleanup.
   - Now the irq is always enabled inside irq_install_handler().

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile    |    1 +
 arch/arm/cpu/faraday/ftintc020.c |  144 ++++++++++++++++++++++++++++++++++++++
 include/common.h                 |    3 +
 include/faraday/ftintc020.h      |   36 ++++++++++
 4 files changed, 184 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftintc020.c
 create mode 100644 include/faraday/ftintc020.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index acc09eb..6302a1d 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -10,6 +10,7 @@ include $(TOPDIR)/config.mk
 LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o
+src-$(CONFIG_FTINTC020)   += ftintc020.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/ftintc020.c b/arch/arm/cpu/faraday/ftintc020.c
new file mode 100644
index 0000000..bc36674
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftintc020.c
@@ -0,0 +1,144 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftintc020.h>
+
+static struct ftintc020_regs *regs = (void __iomem *)CONFIG_FTINTC020_BASE;
+
+static struct {
+	void  *data;
+	void (*func)(void *data);
+} irq_hndl[64];
+
+static inline void irq_acknowledge(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		writel(mask, &regs->irq32.scr);
+	else
+		writel(mask, &regs->irq64.scr);
+}
+
+void irq_enable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		setbits_le32(&regs->irq32.ena, mask);
+	else
+		setbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_disable(int irq)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (irq < 32)
+		clrbits_le32(&regs->irq32.ena, mask);
+	else
+		clrbits_le32(&regs->irq64.ena, mask);
+}
+
+void irq_set_trigger(int irq, int edge, int low)
+{
+	uint32_t mask = BIT_MASK(irq);
+
+	if (edge) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tmr, mask);
+		else
+			setbits_le32(&regs->irq64.tmr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tmr, mask);
+		else
+			clrbits_le32(&regs->irq64.tmr, mask);
+	}
+
+	if (low) {
+		if (irq < 32)
+			setbits_le32(&regs->irq32.tlr, mask);
+		else
+			setbits_le32(&regs->irq64.tlr, mask);
+	} else {
+		if (irq < 32)
+			clrbits_le32(&regs->irq32.tlr, mask);
+		else
+			clrbits_le32(&regs->irq64.tlr, mask);
+	}
+}
+
+void do_irq(struct pt_regs *pt_regs)
+{
+	int irq;
+	uint32_t stat;
+
+	irq  = 32;
+	stat = readl(&regs->irq64.sr);     /* IRQ 32 ~ 63 */
+	if (!stat) {
+		irq  = 0;
+		stat = readl(&regs->irq32.sr); /* IRQ  0 ~ 31 */
+	}
+	irq += ffs(stat) - 1;
+
+	if (irq < 0) {
+		printf("interrupts: no irq!?\n");
+		return;
+	}
+
+	if (irq_hndl[irq].func)
+		irq_hndl[irq].func(irq_hndl[irq].data);
+	else
+		printf("Unhandled IRQ = %d\n", irq);
+
+	irq_acknowledge(irq);
+}
+
+void irq_install_handler(int irq, interrupt_handler_t *hndl, void *data)
+{
+	if (irq >= 0 && irq < 64) {
+		irq_hndl[irq].func = hndl;
+		irq_hndl[irq].data = data;
+		irq_enable(irq);
+	}
+}
+
+void irq_free_handler(int irq)
+{
+	if (irq >= 0 && irq < 64) {
+		irq_hndl[irq].func = NULL;
+		irq_hndl[irq].data = NULL;
+		irq_disable(irq);
+	}
+}
+
+int arch_interrupt_init(void)
+{
+	int i;
+
+	for (i = 0; i < 64; ++i)
+		irq_free_handler(i);
+
+	/* hardware reset */
+	writel(0x00000000, &regs->irq32.ena);
+	writel(0xffffffff, &regs->irq32.scr);
+	writel(0x00000000, &regs->irq32.tmr);
+	writel(0x00000000, &regs->irq32.tlr);
+
+	writel(0x00000000, &regs->irq64.ena);
+	writel(0xffffffff, &regs->irq64.scr);
+	writel(0x00000000, &regs->irq64.tmr);
+	writel(0x00000000, &regs->irq64.tlr);
+
+	return 0;
+}
diff --git a/include/common.h b/include/common.h
index 8addf43..dbebecf 100644
--- a/include/common.h
+++ b/include/common.h
@@ -94,6 +94,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_FARADAY
+#include <asm/arch-faraday/interrupt.h>
+#endif

 #include <part.h>
 #include <flash.h>
diff --git a/include/faraday/ftintc020.h b/include/faraday/ftintc020.h
new file mode 100644
index 0000000..1afeb7c
--- /dev/null
+++ b/include/faraday/ftintc020.h
@@ -0,0 +1,36 @@
+/*
+ * arch/arm/cpu/faraday/ftintc020.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTINTC020_H
+#define ARCH_ARM_CPU_FARADAY_FTINTC020_H
+
+struct ftintc020_pic_regs {
+	uint32_t src; /* source register */
+	uint32_t ena; /* enable register */
+	uint32_t scr; /* status clear register */
+	uint32_t tmr; /* trigger mode register */
+	uint32_t tlr; /* trigger level register */
+	uint32_t sr;  /* status register */
+	uint32_t rsvd[2];
+};
+
+struct ftintc020_regs {
+	/* IRQ/FIQ:  0 ~ 31 */
+	struct ftintc020_pic_regs irq32; /* 0x00 - 0x1C: IRQ 0 ~ 31 */
+	struct ftintc020_pic_regs fiq32; /* 0x20 - 0x3C: FIQ 0 ~ 31 */
+	uint32_t rsvd1[4];               /* 0x40 - 0x4C: Reserved */
+	uint32_t revision;               /* 0x50: Revision Register */
+	uint32_t feature;                /* 0x54: Feature Register */
+	uint32_t rsvd2[2];               /* 0x58 - 0x5C: Reserved */
+	/* IRQ/FIQ: 32 ~ 63 */
+	struct ftintc020_pic_regs irq64; /* 0x60 - 0x7C: IRQ 32 ~ 63 */
+	struct ftintc020_pic_regs fiq64; /* 0x80 - 0x9C: FIQ 32 ~ 63 */
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v7 07/11] arm: add Faraday FTTMR010 timer support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (5 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 06/11] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 08/11] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
                     ` (4 subsequent siblings)
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - Nothing updates

Changes for v5:
   - Drop IRQ dependant implementation
   - Use gd->arch.timer_rate_hz for timer clock source
   - Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    1 +
 arch/arm/cpu/faraday/fttmr010.c |  124 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 ++++++
 3 files changed, 142 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 6302a1d..df28792 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -11,6 +11,7 @@ LIB	= $(obj)lib$(CPU).o

 src-y  := cpu.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
+src-$(CONFIG_FTTMR010)    += fttmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..f80f90f
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,124 @@
+/*
+ * arch/arm/cpu/faraday/fttmr010.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 2ab68d1..21ab113 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -45,6 +45,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -58,4 +68,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v7 08/11] arm: add Faraday FTPWMTMR010 timer support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (6 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 07/11] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images Kuo-Jung Su
                     ` (3 subsequent siblings)
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - Nothing updates

Changes for v5:
   - Drop IRQ dependant implementation
   - Use gd->arch.timer_rate_hz for timer clock source
   - Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    1 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  116 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   40 +++++++++++++
 3 files changed, 157 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index df28792..715bb5d 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -12,6 +12,7 @@ LIB	= $(obj)lib$(CPU).o
 src-y  := cpu.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
+src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o

 START	= start.o
 COBJS	= $(src-y)
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..db49d39
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,116 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+#ifdef CONFIG_A369_FA606TE_PLATFORM
+#define TIMER_ID    4
+#else
+#define TIMER_ID    0
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftpwmtmr010_regs *regs = (void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..806f4c0
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,40 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (7 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 08/11] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-09-14 10:28     ` Albert ARIBAUD
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 10/11] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
                     ` (2 subsequent siblings)
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

At the time of writting, none of Faraday NAND & SPI controllers
supports XIP (eXecute In Place), and the 1st stage bootstrap
stored in embedded ROM is not compatible to U-Boot design.

So this patch is added to support booting from Faraday Images.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - Fix compiler warnning
   - Use shorter paragraph in commit message, and move the
     original statement into the top of cmd_bootfa.c.

Changes for v5:
   - Rename from 'arm: add Faraday firmware image utility'
     into 'arm: add Faraday specific boot command'
   - Add missing CRC check to the command 'bootfa'.
   - Add rationale to the command 'bootfa'.

Changes for v4:
   - Coding Style cleanup.
   - Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
   - Coding Style cleanup.
   - Always insert a blank line between declarations and code.

Changes for v2:
   - Coding Style cleanup.

 arch/arm/cpu/faraday/Makefile     |    2 +-
 arch/arm/cpu/faraday/cmd_bootfa.c |  267 +++++++++++++++++++++++++++++++++++++
 arch/arm/cpu/faraday/fwimage.h    |   35 +++++
 arch/arm/cpu/faraday/fwimage2.h   |   55 ++++++++
 arch/arm/cpu/u-boot.lds           |   11 ++
 5 files changed, 369 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/cpu/faraday/cmd_bootfa.c
 create mode 100644 arch/arm/cpu/faraday/fwimage.h
 create mode 100644 arch/arm/cpu/faraday/fwimage2.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 715bb5d..289823c 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -9,7 +9,7 @@ include $(TOPDIR)/config.mk

 LIB	= $(obj)lib$(CPU).o

-src-y  := cpu.o
+src-y  := cpu.o cmd_bootfa.o
 src-$(CONFIG_FTINTC020)   += ftintc020.o
 src-$(CONFIG_FTTMR010)    += fttmr010.o
 src-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/cmd_bootfa.c b/arch/arm/cpu/faraday/cmd_bootfa.c
new file mode 100644
index 0000000..fa1f7df
--- /dev/null
+++ b/arch/arm/cpu/faraday/cmd_bootfa.c
@@ -0,0 +1,267 @@
+/*
+ * arch/arm/cpu/faraday/cmd_bootfa.c
+ *
+ * This command is used to boot faraday firmware from MMC/USB/SPI/NAND/NOR
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+/*
+ * At the time of writting, none of Faraday NAND & SPI controllers
+ * supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
+ * to implement a 1st level bootstrap code stored in the embedded ROM
+ * inside the SoC.
+ *
+ * After power-on, the ROM code (1st level bootstrap code) would load
+ * the 2nd bootstrap code into SRAM without any SDRAM initialization.
+ *
+ * The 2nd bootstrap code would then initialize SDRAM and load the
+ * generic firmware (u-boot/linux) into SDRAM, and finally make
+ * a long-jump to the firmware.
+ *
+ * Which means the SPL design of U-boot would never fit to A360/A369,
+ * since it's usually not possible to alter a embedded ROM code.
+ * And because both the 1st & 2nd level bootstrap code use the private
+ * Faraday Firmware Image Format, it would be better to drop U-boot
+ * image support to simplify the design.
+ *
+ * The Faraday Firmware Image Format uses a 1 KB (1024 Bytes) header:
+ *
+ * +----------------+ 0x0000
+ * | MAGIC          | Magic number
+ * +----------------+ 0x0004
+ * | HDR LENGTH     | The size of this header
+ * +----------------+ 0x0008
+ * |                |
+ * | SYS PARAMETERS | A set of (addr, data) for 32-bit register write,
+ * |                | which is for SDRAM initialization and timing control.
+ * +----------------+ 0x0108
+ * |                |
+ * | PART TABLE     | A partition table with max. 10 entries.
+ * |                |
+ * +----------------+ 0x03D8
+ * | HDR CHECKSUM   | Header Checksum (CRC32)
+ * +----------------+ 0x03DC
+ * | HDR REVISION   | Header Revision ID
+ * +----------------+ 0x03E0
+ * | HDR TIMESTAMP  | Header Creation Timestamp
+ * +----------------+ 0x03E4
+ * | RESERVED       |
+ * +----------------+ 0x0400
+ *
+ * The entry of partitoin table is:
+ *
+ * +----------------+ 0x0000
+ * | NAME           | The name of the partition
+ * +----------------+ 0x0020
+ * | OFFSET         | The offset address of the flash memory.
+ * +----------------+ 0x0024
+ * | LENGTH         | The data length of the partition.
+ * +----------------+ 0x0028
+ * | Load Address   | The address in SDRAM to store the firmware.
+ * +----------------+ 0x002C
+ * | Quick CRC      | An optional CRC32 agains 256KB of TOP & BUTTOM.
+ * +----------------+ 0x0030
+ * | FLAGS          | The flags/attribute of the partition
+ * +----------------+ 0x0034
+ * | RESERVED       |
+ * +----------------+ 0x0040
+ * | MAGIC=0x1000   | It's always a 0x1000.
+ * +----------------+ 0x0044
+ * | MAGIC=0x0001   | It's always a 0x0001.
+ * +----------------+ 0x0048
+ *
+ * The usage of the command 'bootfa' is:
+ *
+ * bootfa <interface> <fw_name>
+ * - boot from 'interface' with the firmware named as <fw_name>
+ *   where 'interface' could be any one of <usb | mmc | nand | sf>
+ *
+ * ex: bootfa usb linux
+ *
+ * The rationale is:
+ *
+ * 1. If 'interface' is either 'usb' or 'mmc/sd', then jumps to 2-a;
+ *    else jumps to 2-b.
+ * 2-a. Translate 'fw_name' to 'filename' from the built-in rules
+ *      (i.e. 'linux' -> 'zimage'), jumps to 3-a.
+ * 2-b. Use 'nand' or 'sf' or 'cp' to load image header into SDRAM,
+ *      and the looking for the 'fw_name' in the partition table.
+ *      If part->name equals 'fw_name', then jumps to 3-b;
+ *      else report an error and exit.
+ * 3-a. Use 'fatload' to load the firmware into SDRAM by filename,
+ *      and then jumps to 4.
+ * 3-b. Use 'nand' or 'sf' or 'cp' to load the firmware into SDRAM
+ *      by .offset & .length of the corresponding partition info,
+ *      and then jumps to 4.
+ * 4. Use 'go' to shift control to the loaded firmware.
+ */
+#include <common.h>
+#include <command.h>
+
+#include "fwimage2.h"
+
+#undef  ROUNDUP
+#define ROUNDUP(len, blksz) \
+	((len) % (blksz)) ? ((len) + (blksz) - ((len) % (blksz))) : (len)
+
+static int hdr_invalid(struct fwimage2 *img)
+{
+	uint32_t cksum_old, cksum_new;
+
+	if (le32_to_cpu(img->revision) != FWIMAGE2_REVISION)
+		return 0;
+
+	cksum_old = le32_to_cpu(img->hcrc);
+	img->hcrc = 0;
+	cksum_new = crc32_no_comp(0xffffffff, (const uint8_t *)img,
+		sizeof(struct fwimage2));
+	img->hcrc = cpu_to_le32(cksum_old);
+
+	return (cksum_new != cksum_old);
+}
+
+static int part_invalid(struct fwpart *part, uint8_t *buf)
+{
+	uint32_t len = le32_to_cpu(part->length);
+	uint32_t cksum = 0xFFFFFFFF;
+
+	if (len <= SZ_512K) {
+		cksum = crc32_no_comp(cksum, buf, len);
+	} else {
+		cksum = crc32_no_comp(cksum, buf, SZ_256K);
+		cksum = crc32_no_comp(cksum, buf + len - SZ_256K, SZ_256K);
+	}
+
+	return (cksum != le32_to_cpu(part->qcrc));
+}
+
+static struct fwpart *part_lookup(struct fwimage2 *hdr, char *name)
+{
+	int i;
+	struct fwpart *ppart = hdr->part;
+	static struct fwpart part_local;
+
+	if (hdr_invalid(hdr)) {
+		printf("part_lookup: bad header\n");
+		return NULL;
+	}
+
+	for (i = 0; ppart[i].length > 0 && i < 10; ++i) {
+		if (!strcmp(name, ppart[i].name)) {
+			printf("part_lookup: name=%s, offset=0x%x, size=0x%x\n",
+				ppart[i].name,
+				ppart[i].offset,
+				ppart[i].length);
+
+			memcpy(&part_local, &ppart[i], sizeof(struct fwpart));
+			return &part_local;
+		}
+	}
+
+	return NULL;
+}
+
+static int do_bootfa(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	char *inf, *name , cmd[256];
+	struct fwpart *part = NULL;
+
+	if (argc < 3) {
+#ifdef CONFIG_SYS_LONGHELP
+		printf("Usage:\n"
+			"%s %s\n", argv[0], cmdtp->help);
+#else
+		printf("Usage:\n"
+			"bootfa <interface> <fw_name>\n"
+			"    - boot from 'interface' with the firmware named as <fw_name>\n"
+			"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+			"ex: bootfa usb linux");
+#endif
+		return 1;
+	}
+
+	inf  = argv[1];
+	name = argv[2];
+
+	if (!strcmp(inf, "usb")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "usb start;fatload usb 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "mmc") || !strcmp(inf, "sd")) {
+		if (!strcmp(name, "linux"))
+			name = "zimage";
+		else if (!strcmp(name, "wince"))
+			name = "nk.nb0";
+		sprintf(cmd, "mmcinfo;fatload mmc 0 0x%x %s",
+			CONFIG_SYS_LOAD_ADDR, name);
+		run_command(cmd, 0);
+#ifdef CONFIG_SYS_FLASH_BASE
+	} else if (!strcmp(inf, "nor")) {
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x400",
+			CONFIG_SYS_FLASH_BASE,
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "cp.l 0x%x 0x%x 0x%x",
+			CONFIG_SYS_FLASH_BASE + part->offset,
+			CONFIG_SYS_LOAD_ADDR, part->length);
+		run_command(cmd, 0);
+#endif
+	} else if (!strcmp(inf, "nand")) {
+		sprintf(cmd, "nand read 0x%x 0 0x400", CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "nand read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	} else if (!strcmp(inf, "sf")) {
+		sprintf(cmd, "sf probe 0:0 25000000;sf read 0x%x 0 0x400",
+			CONFIG_SYS_LOAD_ADDR);
+		run_command(cmd, 0);
+		part = part_lookup((void *)CONFIG_SYS_LOAD_ADDR, name);
+		if (!part) {
+			printf("firmware not found!\n");
+			return 1;
+		}
+		sprintf(cmd, "sf read 0x%x 0x%x 0x%x",
+			CONFIG_SYS_LOAD_ADDR,
+			part->offset, part->length);
+		run_command(cmd, 0);
+	}
+
+	if (part && part_invalid(part, (void *)CONFIG_SYS_LOAD_ADDR)) {
+		printf("bad partition!\n");
+		return 1;
+	}
+
+	sprintf(cmd, "go 0x%x", CONFIG_SYS_LOAD_ADDR);
+	run_command(cmd, 0);
+
+	return 1;
+}
+
+U_BOOT_CMD(
+	bootfa,    3,    1,    do_bootfa,
+	"boot faraday firmware image",
+	"<interface> <fw_name>\n"
+	"    - boot from 'interface' with the firmware named as <fw_name>\n"
+	"      where 'interface' could be any one of <usb | mmc | nand | sf>\n"
+	"ex: bootfa usb linux"
+);
diff --git a/arch/arm/cpu/faraday/fwimage.h b/arch/arm/cpu/faraday/fwimage.h
new file mode 100644
index 0000000..c01799b
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage.h
@@ -0,0 +1,35 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H
+
+struct fwparam {
+	uint32_t count;
+	uint32_t version; /* ycmo100525: for firmware image version */
+	uint32_t addr[31];
+	uint32_t data[31];
+};
+
+struct fwfile {
+	char name[64];
+	uint32_t size;
+};
+
+struct fwimage {
+	uint32_t magic; /* Image Header Magic */
+	uint32_t length;/* Image Header Length */
+
+	/* 256 bytes, embedded paramters area */
+	struct fwparam param;
+
+	struct fwfile  file[1];
+};
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE_H */
diff --git a/arch/arm/cpu/faraday/fwimage2.h b/arch/arm/cpu/faraday/fwimage2.h
new file mode 100644
index 0000000..6a33111
--- /dev/null
+++ b/arch/arm/cpu/faraday/fwimage2.h
@@ -0,0 +1,55 @@
+/*
+ * linux/arch/arm/plat-faraday/fwimage2.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+#define _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H
+
+#include "fwimage.h"
+
+struct fwpart {
+	char name[32];
+
+	uint32_t offset;
+	uint32_t length;
+
+	uint32_t load;
+	uint32_t qcrc; /* Quick checksum againsts 256KB of TOP & BOTTOM */
+
+	uint32_t flags;
+#define FWIMAGE2_PART_FILESYSTEM    0x80000000 /* Is a filesystem ? */
+
+	uint32_t rsvd[3];
+	uint32_t magic1000; /* It's always 0x1000 */
+	uint32_t magic0001; /* It's always 0x0001 */
+}; /* size = 72 bytes */
+
+struct fwimage2 {
+	uint32_t magic; /* Image Header Magic */
+#define FWIMAGE2_MAGIC  0x00484946 /* "FIH\0" */
+
+	uint32_t hlen;  /* Image Header Length */
+
+	/* 256 bytes, 32-bit memory write */
+	struct {
+		uint32_t addr;
+		uint32_t data;
+	} mw32[32];
+
+	/* 720 bytes, partition table */
+	struct fwpart part[10];
+
+	uint32_t hcrc;     /* Image Header Checksum (CRC32) */
+	uint32_t revision; /* Image Format Revision ID */
+#define FWIMAGE2_REVISION   0x00000202 /* v2.2 */
+
+	uint32_t time;     /* Image Creation Timestamp */
+	uint32_t rsvd[7];
+}; /* size = 1024 bytes */
+
+#endif /* _ARCH_ARM_PLAT_FARADAY_FWIMAGE2_H */
diff --git a/arch/arm/cpu/u-boot.lds b/arch/arm/cpu/u-boot.lds
index 490aed2..f3ea681 100644
--- a/arch/arm/cpu/u-boot.lds
+++ b/arch/arm/cpu/u-boot.lds
@@ -7,6 +7,8 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */

+#include <config.h>
+
 OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
 OUTPUT_ARCH(arm)
 ENTRY(_start)
@@ -19,6 +21,15 @@ SECTIONS
 	{
 		*(.__image_copy_start)
 		CPUDIR/start.o (.text*)
+#ifdef CONFIG_FARADAY
+		/*
+		 * Dante Su 2012.10.09:
+		 * Reserved for the faimage v2.1.
+		 * 1. CPUDIR/start.o: It shall never be > 4KB.
+		 * 2. faimage header: It shall always be stored at 0x1000, and <= 1KB.
+		 */
+		. = 0x00001400;
+#endif
 		*(.text*)
 	}

--
1.7.9.5

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

* [U-Boot] [PATCH v7 10/11] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate()
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (8 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 11/11] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
  2013-11-28  2:48   ` [U-Boot] [PATCH v8] nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This updates ftsdc010_mci.c for latest Faraday clock APIs.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Andy Fleming <afleming@gmail.com>
---
Changes for v6, v7:
   - Nothing updates

Changes for v5:
   - Initial commit

 drivers/mmc/ftsdc010_mci.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
index 7600d5c..54976b0 100644
--- a/drivers/mmc/ftsdc010_mci.c
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -366,7 +366,7 @@ int ftsdc010_mmc_init(int devid)
 #ifdef CONFIG_SYS_CLK_FREQ
 	chip->sclk = CONFIG_SYS_CLK_FREQ;
 #else
-	chip->sclk = clk_get_rate("SDC");
+	chip->sclk = clock_get_rate(MMC_CLK);
 #endif

 	mmc->voltages  = MMC_VDD_32_33 | MMC_VDD_33_34;
--
1.7.9.5

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

* [U-Boot] [PATCH v7 11/11] arm: add Faraday A360/A369 SoC platform support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (9 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 10/11] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
@ 2013-07-29  5:51   ` Kuo-Jung Su
  2013-11-28  2:48   ` [U-Boot] [PATCH v8] nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
  11 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-29  5:51 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds board support for the Faraday A360/A369 SoC platforms.

Working functions:
- MMU/D-cache
- SD Host controller
- USB EHCI controller
- USB Gadget controller
- Network
- NAND

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v7:
   - Update license to use SPDX identifiers.

Changes for v6:
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Define Faraday machine type in board's config header file
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise clock management system

Changes for v4:
   - Coding Style cleanup.
   - Break-down the interrupt, timers and common utilties.

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Add '__iomem' to all the declaration of HW register pointers.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 MAINTAINERS                                   |    5 +
 arch/arm/cpu/faraday/a360/Makefile            |   33 ++++
 arch/arm/cpu/faraday/a369/Makefile            |   34 ++++
 arch/arm/cpu/faraday/a369/cmd_fa606.c         |   74 ++++++++
 arch/arm/include/asm/arch-a360/hardware.h     |   72 ++++++++
 arch/arm/include/asm/arch-a360/pmu.h          |   83 +++++++++
 arch/arm/include/asm/arch-a360/scu.h          |   67 +++++++
 arch/arm/include/asm/arch-a369/ahbc.h         |   22 +++
 arch/arm/include/asm/arch-a369/hardware.h     |   86 +++++++++
 arch/arm/include/asm/arch-a369/scu.h          |  212 ++++++++++++++++++++++
 arch/arm/include/asm/arch-faraday/clock.h     |   29 +++
 arch/arm/include/asm/arch-faraday/interrupt.h |   17 ++
 board/faraday/a360evb/Makefile                |   29 +++
 board/faraday/a360evb/board.c                 |   71 ++++++++
 board/faraday/a360evb/clock.c                 |   71 ++++++++
 board/faraday/a360evb/config.mk               |   17 ++
 board/faraday/a360evb/lowlevel_init.S         |   16 ++
 board/faraday/a369evb/Makefile                |   29 +++
 board/faraday/a369evb/board.c                 |  175 ++++++++++++++++++
 board/faraday/a369evb/clock.c                 |   81 +++++++++
 board/faraday/a369evb/config.mk               |   17 ++
 board/faraday/a369evb/lowlevel_init.S         |  119 ++++++++++++
 boards.cfg                                    |    3 +
 include/common.h                              |    2 +
 include/configs/a360.h                        |   70 +++++++
 include/configs/a369-common.h                 |   85 +++++++++
 include/configs/a369.h                        |   47 +++++
 include/configs/a369_fa606te.h                |   40 ++++
 include/configs/faraday-common.h              |  242 +++++++++++++++++++++++++
 include/faraday/ftsmc020.h                    |    1 +
 30 files changed, 1849 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/cmd_fa606.c
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/pmu.h
 create mode 100644 arch/arm/include/asm/arch-a360/scu.h
 create mode 100644 arch/arm/include/asm/arch-a369/ahbc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/scu.h
 create mode 100644 arch/arm/include/asm/arch-faraday/clock.h
 create mode 100644 arch/arm/include/asm/arch-faraday/interrupt.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/config.mk
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/config.mk
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369-common.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/a369_fa606te.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 081cf96..c0d4417 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -644,6 +644,11 @@ Po-Yu Chuang <ratbert@faraday-tech.com>

 	a320evb		FA526 (ARM920T-like) (a320 SoC)

+Kuo-Jung Su <dantesu@faraday-tech.com>
+
+	a360evb		FA626TE (Faraday ARMv5TE) (a360 SoC)
+	a369evb		FA626TE & FA606TE (Faraday ARMv5TE) (a369 SoC)
+
 Eric Cooper <ecc@cmu.edu>

 	dockstar	ARM926EJS (Kirkwood SoC)
diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..aecae59
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,33 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..69376c3
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,34 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(SOC).o
+
+obj-y   :=
+obj-$(CONFIG_CMD_FA606) += cmd_fa606.o
+
+COBJS	:= $(obj-y)
+SOBJS	:=
+
+SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS) $(SOBJS))
+START	:= $(addprefix $(obj),$(START))
+
+all:	$(obj).depend $(LIB)
+
+$(LIB):	$(OBJS)
+	$(call cmd_link_o_target, $(OBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/arch/arm/cpu/faraday/a369/cmd_fa606.c b/arch/arm/cpu/faraday/a369/cmd_fa606.c
new file mode 100644
index 0000000..e23dc3c
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/cmd_fa606.c
@@ -0,0 +1,74 @@
+/*
+ * arch/arm/cpu/faraday/a369/cmd_fa606.c
+ *
+ * This command would activate the slave cpu (FA606TE)
+ * and then immediately halt the master cpu (FA626TE).
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/ahbc.h>
+
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a369ahbc_regs *ahbc = (void __iomem *)CONFIG_AHBC2_BASE;
+
+static int do_fa606(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	unsigned int addr = CONFIG_SYS_LOAD_ADDR;
+
+	if (argc >= 2)
+		addr = simple_strtoul(argv[1], NULL, 16);
+
+	printf("FA606TE Image at 0x%08X\n", addr);
+	printf("FA626TE is going to halt...\n");
+
+	cleanup_before_linux();
+
+	/* 1. FA606TE address offset = 0 */
+	printf("FA606 address shift disable.\n");
+	writel(0x00000000, &ahbc->cpusao);
+
+	/* 2. Generate a long-jump to 0x00000000 */
+	writel(0xEA00000A, 0x00); /* b   0x30 */
+	writel(addr,       0x20);
+	writel(0xE3A00020, 0x30); /* mov r0, #32 ; 0x20 */
+	writel(0xE590F000, 0x34); /* ldr pc, [r0] */
+
+	/* 3. Pinmux = ICE + LCD */
+	writel(GPMUX_DEFAULT, &scu->gpmux);
+	writel(SCCFG0_DEFAULT, &scu->sccfg[0]);
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+	writel(MFPMUX0_TS(1) | MFPMUX0_ISP(2) | MFPMUX0_SATA(1)
+		| MFPMUX0_EXTAHB(1), &scu->mfpmux[0]);
+	writel(MFPMUX1_SSP0(1), &scu->mfpmux[1]);
+	udelay(5000);
+
+	/* 4. FA606TE clock enable & reset */
+	writel(0x00000000, &scu->hclkgr);
+	udelay(5000);
+	writel(GPMUX_DEFAULT | GPMUX_CPUS_START, &scu->gpmux);
+
+	/* 5. FA626TE is going to halt... */
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15,0,r0,c7,c0,4\n"
+		:
+		:
+		: "r0" /* clobber list */
+	);
+
+	return 0;
+}
+
+U_BOOT_CMD(
+	fa606, 2, 0, do_fa606,
+	"launch firmware with A369's built-in fa606te\n",
+	"fa606 [address] - mov pc of fa606te to the specified address.\n"
+);
diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..7037988
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,72 @@
+/*
+ * arch/arm/include/asm/arch-a360/hardware.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC020_BASE		0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+#define CONFIG_FTSSP010_GPIO_BASE	0x98700000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+#define CONFIG_FOTG210_BASE         0x90B00000
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/pmu.h b/arch/arm/include/asm/arch-a360/pmu.h
new file mode 100644
index 0000000..300e1ea
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/pmu.h
@@ -0,0 +1,83 @@
+/*
+ * arch/arm/include/asm/arch-a360/pmu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_PMU_H
+#define __ASM_ARCH_PMU_H
+
+struct a360pmu_regs {
+	uint32_t idr;      /* ID register */
+	uint32_t rsvd0;
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pmr;      /* Power mode register */
+
+	uint32_t pmcr;     /* Power manager control register */
+	uint32_t peer;     /* Power manager edge detection enable register */
+	uint32_t pesr;     /* Power manager edge detection status register */
+	uint32_t rsvd1;
+
+	uint32_t pmsr;     /* Power manager status register */
+	uint32_t pgsr;     /* Power manager GPIO sleep state register */
+	uint32_t rsvd2;
+	uint32_t mcr;      /* Misc. control register */
+
+	uint32_t pdcr;     /* PLL/DLL control register */
+	uint32_t rsvd3[7];
+
+	uint32_t pspr[16]; /* Power manager scratch pad register */
+
+	uint32_t rsvd4[3];
+	uint32_t jssr;     /* Jumper setting status register */
+};
+
+#define OSCCR_STABLE    (1 << 9) /* OSCH is stable */
+#define OSCCR_DISABLE   (1 << 8) /* Disable OSCH */
+
+#define PMR_FCS         (1 << 2) /* Activate freq. change sequence */
+#define PMR_TURBO       (1 << 1) /* Activate CPU turbo mode (2 x AHB) */
+#define PMR_SLEEP       (1 << 0) /* Activate system sleep */
+
+#define PMCR_PWLOW      (1 << 5) /* Mask X_powerlow_b pin source */
+#define PMCR_WAIT       (1 << 4) /* Enable countdown for CPU power-off */
+#define PMCR_WDT        (1 << 3) /* Use WatchDog reset */
+#define PMCR_RTC        (1 << 2) /* Enable system wake-up from RTC alarm */
+#define PMCR_GPIO1      (1 << 1) /* Enable system wake-up from GPIO1 */
+#define PMCR_GPIO0      (1 << 0) /* Enable system wake-up from GPIO0 */
+
+#define PEER_GPIO1_RE   (1 << 9) /* Wake-up upon Rising-Edge of GPIO1 */
+#define PEER_GPIO0_RE   (1 << 8) /* Wake-up upon Rising-Edge of GPIO0 */
+#define PEER_GPIO1_FE   (1 << 1) /* Wake-up upon Falling-Edge of GPIO1 */
+#define PEER_GPIO0_FE   (1 << 0) /* Wake-up upon Falling-Edge of GPIO0 */
+
+#define PESR_RTC        (1 << 2) /* Wake-up from RTC */
+#define PESR_GPIO1      (1 << 1) /* Wake-up from GPIO1 */
+#define PESR_GPIO0      (1 << 0) /* Wake-up from GPIO0 */
+
+#define PMSR_PWLOW      (1 << 19)/* X_powerlow_b is pulled low */
+#define PMSR_ISR_PWLOW  (1 << 18)/* Interrupt Status: X_powerlow_b */
+#define PMSR_ISR_FCS    (1 << 17)/* Interrupt Status: FCS */
+#define PMSR_ISR_TURBO  (1 << 16)/* Interrupt Status: TURBO */
+#define PMSR_WAKEUP     (1 << 10)/* Wake-up from sleep mode */
+#define PMSR_WDT        (1 << 9) /* Reset by WatchDog */
+#define PMSR_HW         (1 << 8) /* Reset by Hardware */
+#define PMSR_NOGPI      (1 << 2) /* Disable GPIO input mode */
+#define PMSR_GPIO_HELD  (1 << 1) /* GPIO are held in sleep mode */
+
+#define PDCR_WAITDLLS   (1 << 23)/* Wait until DLL stable */
+#define PDCR_DLLS       (1 << 22)/* DLL is stable */
+#define PDCR_DDLL       (1 << 21)/* Disable DLL */
+#define PDCR_PLL1MS(x)  (((x) >> 11) & 0xf)/* PLL1 MS */
+#define PDCR_PLL1NS(x)  (((x) >> 3) & 0x3f)/* PLL1 NS */
+#define PDCR_WAITPLL1S  (1 << 2) /* Wait until PLL1 stable */
+#define PDCR_PLL1S      (1 << 1) /* PLL1 is stable */
+#define PDCR_DPLL1      (1 << 0) /* Disable PLL1 */
+
+#define JSSR_PLL1NS(x)  (((x) >> 2) & 0x3f)/* PLL1 NS */
+#define JSSR_OSC        (1 << 0) /* PLL1/DLL are disabled */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/scu.h b/arch/arm/include/asm/arch-a360/scu.h
new file mode 100644
index 0000000..37c23eb
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/scu.h
@@ -0,0 +1,67 @@
+/*
+ * arch/arm/include/asm/arch-a360/scu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a360scu_regs {
+	uint32_t idr;      /* 0x00: ID Register */
+	uint32_t gcr;      /* 0x04: General Control Register */
+	uint32_t ccr;      /* 0x08: Clock Configuration Register */
+	uint32_t hcer;     /* 0x0C: AHB Clock Enable Register */
+	uint32_t pcer;     /* 0x10: APB Clock Enable Register */
+	uint32_t csr;      /* 0x14: Configuration Strap Register */
+	uint32_t iomcr[4]; /* IO Mux Control Register */
+	uint32_t iopcr[2]; /* IO Parameter Control Register */
+	uint32_t cescr;    /* CPU Edge Sync Control Register */
+	uint32_t expcr[3]; /* PCI-Express Control Register */
+};
+
+#define GCR_LVBC_IRQ3       (1 << 25) /* LVBC interrupt 3 propagation */
+#define GCR_LVBC_IRQ2       (1 << 24) /* LVBC interrupt 2 propagation */
+#define GCR_LVTX_RATE(x)    (((x) & 0x1f) << 16) /* LVTX clock rate */
+#define GCR_LVTX_CLK_OUT    (1 << 13) /* Enable LVTX clock out */
+#define GCR_USBH1_PLL_ALIVE (1 << 11) /* USB Host PLL alive */
+#define GCR_USBH0_PLL_ALIVE (1 << 10) /* USB Host PLL alive */
+#define GCR_USBH1_CLK_OUT   (1 << 9) /* Enable USB Host clock out */
+#define GCR_USBH0_CLK_OUT   (1 << 8) /* Enable USB Host clock out */
+#define GCR_DEBUG           (1 << 7) /* Enable debug mode */
+#define GCR_DEBUG_SW        (1 << 6) /* Enable software debug mode */
+#define GCR_IM              (1 << 5) /* Interrupt mask */
+#define GCR_RESET           (1 << 4) /* Software reset */
+
+#define CCR_LVDSTX_DSEL(x)  (((x) >> 21) & 0x1f) /* LVDS Tx Clock Select */
+#define CCR_LVDSRX_DSEL(x)  (((x) >> 16) & 0x1f) /* LVDS Rx Clock Select */
+#define CCR_SSP1_CKFQ(x)    (((x) >> 12) & 0xf) /* SSP1 Clock Freq. */
+#define CCR_SSP0_CKFQ(x)    (((x) >> 8) & 0xf) /* SSP0 Clock Freq. */
+#define CCR_SSP1_EXTCLK     (1 << 7) /* SSP1 use external clock */
+#define CCR_SSP1_PCLK       (0 << 7) /* SSP1 use APB clock */
+#define CCR_SSP0_EXTCLK     (1 << 6) /* SSP0 use external clock */
+#define CCR_SSP0_PCLK       (0 << 6) /* SSP0 use APB clock */
+#define CCR_LVDSTX_HCLK     (0 << 4) /* LVDS Tx clock select */
+#define CCR_LVDSTX_PCLK     (1 << 4)
+#define CCR_LVDSTX_EXTCLK   (2 << 4)
+#define CCR_SDC_HCLK        (2 << 2) /* SD/MMC clock select */
+#define CCR_SDC_MCLK        (1 << 2)
+#define CCR_SDC_DCLK        (0 << 2)
+#define CCR_LCD_EXTCLK      (2 << 0) /* LCD clock select */
+#define CCR_LCD_MCLK        (1 << 0)
+#define CCR_LCD_HCLK        (0 << 0)
+
+#define CSR_PLL_PRESCALE    (1 << 9)
+#define CSR_PCIE_MODE1      (1 << 8)
+#define CSR_PCIE_MODE0      (1 << 7)
+#define CSR_DBG_SW          (1 << 6)
+#define CSR_DBG_EN          (1 << 5)
+#define CSR_NAND_LP         (1 << 4)         /* NAND: Large Page */
+#define CSR_NAND_AL(x)      (((x) >> 2) & 3) /* NAND: Address Length */
+#define CSR_NAND_16X        (1 << 1)         /* NAND: 16-bits */
+#define CSR_SPIBOOT         (1 << 0)         /* Boot from SPI(1)/NAND(0) */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/ahbc.h b/arch/arm/include/asm/arch-a369/ahbc.h
new file mode 100644
index 0000000..30e6724
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/ahbc.h
@@ -0,0 +1,22 @@
+/*
+ * arch/arm/include/asm/arch-a369/ahbc.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_AHBC_H
+#define __ASM_ARCH_AHBC_H
+
+struct a369ahbc_regs {
+	uint32_t slave[32];/* Slave Device Configurations */
+	uint32_t priority; /* Priority */
+	uint32_t idle_cnt; /* IDLE Counter */
+	uint32_t control;  /* Control Register */
+	uint32_t revision; /* Revision ID */
+	uint32_t cpusao;   /* CPUS (FA606TE) Address Offset */
+};
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..5b7695d
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,86 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDR_BASE             0x93100000
+#define CONFIG_AHB_BASE             0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/scu.h b/arch/arm/include/asm/arch-a369/scu.h
new file mode 100644
index 0000000..763a015
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/scu.h
@@ -0,0 +1,212 @@
+/*
+ * arch/arm/include/asm/arch-a369/scu.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_SCU_H
+#define __ASM_ARCH_SCU_H
+
+struct a369scu_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)   (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x) ((((x) >> 3) & 0x3) > 2 ? 2 : (((x) >> 3) & 0x3))
+#define HWCFG_DLL_OFF     (1 << 2)
+#define HWCFG_PLL_OFF     (1 << 1)
+#define HWCFG_OSCHCNT_OFF (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 0x3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 0x3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 0x3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif
diff --git a/arch/arm/include/asm/arch-faraday/clock.h b/arch/arm/include/asm/arch-faraday/clock.h
new file mode 100644
index 0000000..6c10415
--- /dev/null
+++ b/arch/arm/include/asm/arch-faraday/clock.h
@@ -0,0 +1,29 @@
+/*
+ * asm/arch-faraday/clock.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_FARADAY_CLOCK_H
+#define _ASM_ARCH_FARADAY_CLOCK_H
+
+/* Clock identifiers */
+enum clk_id {
+	SYS_CLK,
+	AHB_CLK,
+	APB_CLK,
+	CPU_CLK,
+	I2C_CLK,
+	MMC_CLK,
+	SDC_CLK,
+	SPI_CLK,
+	SSP_CLK,
+};
+
+void  clock_init(void);
+ulong clock_get_rate(enum clk_id id);
+
+#endif	/* _ASM_ARCH_FARADAY_CLOCK_H */
diff --git a/arch/arm/include/asm/arch-faraday/interrupt.h b/arch/arm/include/asm/arch-faraday/interrupt.h
new file mode 100644
index 0000000..5eb406c
--- /dev/null
+++ b/arch/arm/include/asm/arch-faraday/interrupt.h
@@ -0,0 +1,17 @@
+/*
+ * asm/arch-faraday/interrupt.h
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_FARADAY_INTERRUPT_H
+#define _ASM_ARCH_FARADAY_INTERRUPT_H
+
+void irq_set_trigger(int irq, int edge, int low);
+void irq_enable(int irq);
+void irq_disable(int irq);
+
+#endif	/* _ASM_ARCH_FARADAY_INTERRUPT_H */
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..233f6d3
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,29 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clock.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..d622579
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,71 @@
+/*
+ * board/faraday/a360evb/board.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <asm/arch/scu.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a360scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+/*
+ * pinmux
+ */
+static void pinmux_init(void)
+{
+	writel(0x00555500, &scu->iomcr[3]);
+	setbits_le32(&scu->iomcr[0], 0x800002AA);
+	setbits_le32(&scu->iomcr[1], 0x82AAAAAA);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_early_init_f(void)
+{
+	pinmux_init();
+	clock_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	return ftmac110_initialize(bd);
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a360evb/clock.c b/board/faraday/a360evb/clock.c
new file mode 100644
index 0000000..a100a44
--- /dev/null
+++ b/board/faraday/a360evb/clock.c
@@ -0,0 +1,71 @@
+/*
+ * board/faraday/a360evb/clock.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch/pmu.h>
+#include <asm/arch-faraday/clock.h>
+
+static struct a360scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct a360pmu_regs *pmu = (void __iomem *)CONFIG_PMU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 40000000; /* 40 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return clk_get_rate_sys() * ((readl(&pmu->pdcr) >> 3) & 0x3f) / 8;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	uint32_t s = readl(&scu->csr);
+	uint32_t p = readl(&pmu->pmr);
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (s & CSR_PLL_PRESCALE) ? 2 : 4;
+
+	return (p & PMR_TURBO) ? (clk * mul) : clk;
+}
+
+ulong clock_get_rate(enum clk_id id)
+{
+	switch (id) {
+	case SYS_CLK:
+		return clk_get_rate_sys();
+	case AHB_CLK:
+		return clk_get_rate_ahb();
+	case APB_CLK:
+		return clk_get_rate_apb();
+	case CPU_CLK:
+		return clk_get_rate_cpu();
+	case I2C_CLK:
+		return clk_get_rate_apb();
+	case MMC_CLK:
+	case SDC_CLK:
+		return clk_get_rate_ahb();
+	case SPI_CLK:
+	case SSP_CLK:
+		return clk_get_rate_apb();
+	default:
+		return 0;
+	}
+}
+
+void clock_init(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate_apb();
+}
diff --git a/board/faraday/a360evb/config.mk b/board/faraday/a360evb/config.mk
new file mode 100644
index 0000000..bbc18c8
--- /dev/null
+++ b/board/faraday/a360evb/config.mk
@@ -0,0 +1,17 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..90480aa
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,16 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..233f6d3
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,29 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+include $(TOPDIR)/config.mk
+
+LIB	= $(obj)lib$(BOARD).o
+
+COBJS	:= board.o clock.o
+SOBJS	:= lowlevel_init.o
+
+SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS	:= $(addprefix $(obj),$(COBJS))
+SOBJS	:= $(addprefix $(obj),$(SOBJS))
+
+$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
+	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..b00d2f4
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,175 @@
+/*
+ * board/faraday/a369evb/board.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/scu.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftlcdc200.h>
+#include <faraday/ftsdc010.h>
+#include <faraday/ftnandc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+static struct ftlcdc200_regs *lcd = (void __iomem *)CONFIG_FTLCDC200_BASE;
+
+/* System Control Uint (pinmux) */
+static void scu_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&scu->hclkgr);
+		setbits_le32(&scu->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_SUPP_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &scu->hclkgr);
+		writel(GPMUX_DEFAULT, &scu->gpmux);
+		clrbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&scu->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &scu->mfpmux[0]);
+#endif
+	}
+
+	/* Clock Setup: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &scu->sccfg[1]);
+
+	/* Enable LCD for I2C/TVEncode work-around */
+	/* ... Clock DIV=32 */
+	writel(PCR_DIV(32), &lcd->pcr);
+	/* ... Enable LCD */
+	writel(FER_EN | FER_ON, &lcd->fer);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	/* 1. NOR flash */
+	/* Bank 0: base=0x00000000, size=64MB, 16bits */
+	writel(FTSMC020_BANK_ENABLE | FTSMC020_BANK_BASE(0)
+		| FTSMC020_BANK_SIZE_64M | FTSMC020_BANK_MBW_16,
+		&smc->bank[0].cr);
+	/* Bank 0: worst timing */
+	writel(FTSMC020_TPR_WORST, &smc->bank[0].tpr);
+
+	/* 2. Unused Area */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_WORST, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	scu_init();
+	smc_init();
+	clock_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = MACH_TYPE_FARADAY;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
+
+#ifdef CONFIG_SYS_NAND_SELF_INIT
+void board_nand_init(void)
+{
+	int alen, devnum = 0;
+	struct mtd_info *mtd = &nand_info[devnum];
+	struct nand_chip *chip;
+	uint32_t iobase = CONFIG_SYS_NAND_BASE;
+	uint32_t ehwcfg = readl(&scu->ehwcfg);
+
+	chip = calloc(1, sizeof(*chip));
+	if (!chip)
+		return;
+	mtd->priv = chip;
+
+	/* page size */
+	switch (EHWCFG_NAND_PS(ehwcfg)) {
+	case 0:
+		chip->page_shift = 9;	/* 512 */
+		break;
+	case 1:
+		chip->page_shift = 11;	/* 2048 */
+		break;
+	default:
+		chip->page_shift = 12;	/* 4096 */
+		break;
+	}
+
+	/* block size */
+	chip->phys_erase_shift = chip->page_shift + 4
+		+ EHWCFG_NAND_BK(ehwcfg);
+
+	/* address length/cycle */
+	alen = 3 + EHWCFG_NAND_AC(ehwcfg);
+
+	if (ftnandc021_init(chip, iobase, alen))
+		goto bni_err;
+
+	if (nand_scan(mtd, CONFIG_SYS_NAND_MAX_CHIPS))
+		goto bni_err;
+
+	nand_register(devnum);
+
+	return;
+
+bni_err:
+	free(chip);
+}
+#endif /* #ifdef CONFIG_SYS_NAND_SELF_INIT */
diff --git a/board/faraday/a369evb/clock.c b/board/faraday/a369evb/clock.c
new file mode 100644
index 0000000..890aecc
--- /dev/null
+++ b/board/faraday/a369evb/clock.c
@@ -0,0 +1,81 @@
+/*
+ * board/faraday/a369evb/clock.c
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/scu.h>
+#include <asm/arch-faraday/clock.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct a369scu_regs *scu = (void __iomem *)CONFIG_SCU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 33000000; /* 33 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return (clk_get_rate_sys() * PLLCR_NS(readl(&scu->pllcr))) >> 3;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+#ifndef CONFIG_A369_FA606TE_PLATFORM
+	/* If it's an internal CPU */
+	if (readl(&scu->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after
+	 * kicking off slave cpu, so we could check the
+	 * GPMUX_CPUS_START to determine if it's a master.
+	 */
+	if (!(readl(&scu->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&scu->hwcfg));
+#endif
+
+	return clk;
+}
+
+ulong clock_get_rate(enum clk_id id)
+{
+	switch (id) {
+	case SYS_CLK:
+		return clk_get_rate_sys();
+	case AHB_CLK:
+		return clk_get_rate_ahb();
+	case APB_CLK:
+		return clk_get_rate_apb();
+	case CPU_CLK:
+		return clk_get_rate_cpu();
+	case I2C_CLK:
+		return clk_get_rate_apb();
+	case MMC_CLK:
+	case SDC_CLK:
+		return clk_get_rate_ahb();
+	case SPI_CLK:
+	case SSP_CLK:
+		return clk_get_rate_apb();
+	default:
+		return 0;
+	}
+}
+
+void clock_init(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate_apb();
+}
diff --git a/board/faraday/a369evb/config.mk b/board/faraday/a369evb/config.mk
new file mode 100644
index 0000000..bbc18c8
--- /dev/null
+++ b/board/faraday/a369evb/config.mk
@@ -0,0 +1,17 @@
+#
+# (C) Copyright 2013 Faraday Technology
+# Dante Su <dantesu@faraday-tech.com>
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+#########################################################################
+
+ALL += $(obj)u-boot.img
+
+# Environment variables in NAND
+#ifeq ($(ENV),NAND)
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_NAND
+#else
+#PLATFORM_RELFLAGS += -DCONFIG_ENV_IS_IN_FLASH
+#endif
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..e7cbcad
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,119 @@
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+	.macro	_v3_mw32
+
+	ldr r0, =0x1008
+	ldr r3, =0x1108
+_v3_mw32_loop:
+	cmp   r0, r3
+	movhs r1, #0
+	ldrlo r1, [r0, #0]
+	ldrlo r2, [r0, #4]
+	teq   r1, #0
+	strne r2, [r1, #0]
+	addne r0, #8
+	bne   _v3_mw32_loop
+
+	.endm	/* _v3_mw32 */
+
+	.macro	_sdram_enable
+
+	/* Clear SDRAM CKE, GPIO Hold, READ Hold */
+	ldr r0, =CONFIG_SCU_BASE
+	mov r1, #7
+	str r1, [r0, #0x14]
+
+	/* Wait until sdram ready */
+	ldr r0, =CONFIG_DDR_BASE
+_sdram_wait:
+	ldr r1, [r0, #0x04]
+	teq r1, #0x100
+	bne _sdram_wait
+
+	.endm	/* _sdram_enable */
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	/* Check image header */
+	ldr   r1, =0x1000
+	ldr   r0, [r1, #0]
+	ldr   r1, =0x00484946	/* "FIH\0" */
+	ldr   r2, =0x33333639	/* "3369" */
+	teq   r0, r1
+	teqne r0, r2
+	bne _exit
+	_v3_mw32
+	_sdram_enable
+
+#if 1
+	/* Create a shadow copy onto SDRAM (limited to 512K) */
+	mov	r0, #0               /* r0 <- start of source */
+	ldr	r1, =CONFIG_AHB_BASE
+	ldr r2, [r1,#0x18]
+	bic r1, r2, #0x000f0000  /* r1 <- SDRAM base */
+	mov	r2, #0x80000         /* r2 <- source end address (512KB) */
+
+_copy_loop:
+	ldmia	r0!, {r3-r10} /* copy from source address [r0] */
+	stmia	r1!, {r3-r10} /* copy to   target address [r1] */
+	cmp	r0, r2            /* until source end addreee [r2] */
+	ble	_copy_loop
+#else
+	/* Adjust lr(r14) to the remapped address */
+	ldr r0, =CONFIG_AHB_BASE
+	ldr r1, [r0,#0x18]    /* r1 = AHB slave 6 */
+	bic r1, r1, #0xff000000
+	bic r1, r1, #0x00f00000
+	lsr r1, r1, #16
+	add r1, r1, #20
+	mov r2, #1
+	lsl r2, r2, r1
+	add lr, lr, r2
+#endif
+
+	/* AHB remap */
+	mov r0, #0
+	ldr r1, =CONFIG_AHB_BASE
+	ldr r2, =CONFIG_DDR_BASE
+	/* magic (r5) = REG32(0x00) XOR 0xFFFFFFFF */
+	ldr r5, [r0, #0]
+	ldr r3, =0xffffffff
+	eor r5, r5, r3
+	/* r3 = REG32(CONFIG_IOBASE_DDR + 0x10) & 0x00FFFFFF */
+	ldr r3, [r2, #0x10]
+	bic r3, #0xff000000
+	/* r4 = 0x00100f01 */
+	ldr r4, =0x00100f01
+
+	/*
+	 * invalidate i-cache all to make sure the codes bellow
+	 * to be fetched into a single 32-bytes cache line
+	 */
+	mcr p15, 0, r0, c7, c5, 0
+
+	.align 5
+
+	str r3, [r2, #0x10] /* REG32(CONFIG_IOBASE_DDR + 0x10) &= 0x00FFFFFF */
+	str r4, [r1, #0x88] /* REG32(CONFIG_IOBASE_AHB + 0x88)  = 0x00100F01 */
+
+_remap_wait:
+	str r5, [r0, #0]
+	ldr r1, [r0, #0]
+	teq r1, r5
+	bne _remap_wait		/* while(magic != REG32(addr)) */
+
+_exit:
+	mov	pc, lr
diff --git a/boards.cfg b/boards.cfg
index 944ed4c..ed45524 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -72,6 +72,9 @@ mini2440                     arm         arm920t     mini2440            friendl
 VCMA9                        arm         arm920t     vcma9               mpl            s3c24x0
 smdk2410                     arm         arm920t     -                   samsung        s3c24x0
 omap1510inn                  arm         arm925t     -                   ti
+a360                         arm         faraday     a360evb             faraday        a360
+a369                         arm         faraday     a369evb             faraday        a369
+a369_fa606te                 arm         faraday     a369evb             faraday        a369
 integratorap_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorap:CM926EJ_S
 integratorcp_cm926ejs        arm         arm926ejs   integrator          armltd         -           integratorcp:CM924EJ_S
 aspenite                     arm         arm926ejs   -                   Marvell        armada100
diff --git a/include/common.h b/include/common.h
index dbebecf..ab9f0d2 100644
--- a/include/common.h
+++ b/include/common.h
@@ -95,6 +95,8 @@ typedef volatile unsigned char	vu_char;
 #include <asm/arch/hardware.h>
 #endif
 #ifdef CONFIG_FARADAY
+#include <asm/arch/hardware.h>
+#include <asm/arch-faraday/clock.h>
 #include <asm/arch-faraday/interrupt.h>
 #endif

diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..3ad0b8f
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,70 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * Support for Faraday A360(FIE3360) boards.
+ * Tested on A360 EVB2 with 256MB SDRAM and 128MB nand flash.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/*
+ * Memory Configuration
+ */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_64M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_PIN    26
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369-common.h b/include/configs/a369-common.h
new file mode 100644
index 0000000..330639d
--- /dev/null
+++ b/include/configs/a369-common.h
@@ -0,0 +1,85 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * Support for Faraday A369(FIE3369) boards.
+ * Tested on A369 EVB2 with 512MB SDRAM and 256MB nand flash.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __CONFIG_A369_COMMON_H
+#define __CONFIG_A369_COMMON_H
+
+#include <asm/hardware.h>
+
+/* A369 Platform Common Configuration */
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS        1
+#define CONFIG_SYS_SDRAM_BASE       0x00000000
+#define CONFIG_SYS_SDRAM_SIZE       SZ_512M
+
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_16M)
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+
+/* Interrupt controler */
+#ifndef CONFIG_FTINTC020_BASE
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+#endif
+
+/* NAND Flash */
+#define CONFIG_NAND_K9F4G08U0B_AC1  0x02240264
+#define CONFIG_NAND_K9F4G08U0B_AC2  0x42054209
+#define CONFIG_SYS_MAX_NAND_DEVICE  1 /* Max. num. of devices */
+#define CONFIG_SYS_FTNANDC021_TIMING \
+	{ CONFIG_NAND_K9F4G08U0B_AC1, CONFIG_NAND_K9F4G08U0B_AC2 }
+
+/* SPI Flash (FTSSP010 v1.18) */
+#define CONFIG_FTSSP010_GPIO_BASE   0x92600000 /* GPIO 1 */
+#define CONFIG_FTSSP010_GPIO_PIN    27
+
+/* NOR Flash */
+/*
+#define PHYS_FLASH_SIZE             SZ_64M
+#define CONFIG_SYS_FLASH_BASE       0x20000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH  FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS  1
+#define CONFIG_SYS_MAX_FLASH_SECT   1024
+*/
+
+/* EEPROM */
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/*
+ * USB Configuration
+ */
+#define CONFIG_USB_EHCI_BASE        CONFIG_FUSBH200_BASE
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/*
+ * Environment
+ */
+#define CONFIG_ENV_IS_IN_NAND
+#define CONFIG_ENV_OFFSET           0x07FC0000
+#define CONFIG_ENV_OFFSET_REDUND    0x07FE0000
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/*
+ * Faraday Common Configuration
+ */
+#include "faraday-common.h"
+
+#endif
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..fd28629
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,47 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * Support for Faraday A369(FIE3369) boards.
+ * Tested on A369 EVB2 with 512MB SDRAM and 256MB nand flash.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_PLATFORM
+
+/* Support USB-EHCI */
+#define CONFIG_SUPP_EHCI_FARADAY
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Support runtime switching to built-in slave core: FA606TE */
+#define CONFIG_CMD_FA606
+
+/* Autoboot */
+#define CONFIG_BOOTDELAY            3
+#define CONFIG_BOOTCOMMAND          "bootfa nand linux"
+
+/* Set interrupt controler to FTINCT020.0 */
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/* A369 common configuration */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/a369_fa606te.h b/include/configs/a369_fa606te.h
new file mode 100644
index 0000000..521f14e
--- /dev/null
+++ b/include/configs/a369_fa606te.h
@@ -0,0 +1,40 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * Support for Faraday A369(FIE3369) boards.
+ * Tested on A369 EVB2 with 512MB SDRAM and 256MB nand flash.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_A369_FA606TE_PLATFORM
+
+/* Support external AHB */
+/* #define CONFIG_SUPP_EXTAHB */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support VGA Console */
+/* #define CONFIG_SUPP_VGA_CONSOLE */
+
+/* Support interrupt */
+/* #define CONFIG_USE_IRQ */
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Disable I-CACHE */
+#define CONFIG_SYS_ICACHE_OFF
+
+/* Set interrupt controler to FTINCT020.1 */
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE1
+
+/* A369 common configuration */
+#include "a369-common.h"
+
+#endif
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..7f97042
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,242 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * Support for Faraday SoC platforms.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+#include <asm/mach-types.h>
+
+#ifndef MACH_TYPE_FARADAY
+#define MACH_TYPE_FARADAY           758
+#endif
+
+/*
+ * Warning: changing CONFIG_SYS_TEXT_BASE requires
+ * adapting the initial boot program.
+ * Since the linker has to swallow that define, we must use a pure
+ * hex number here!
+ */
+#define CONFIG_SYS_TEXT_BASE        0x00800000
+#define CONFIG_BOARD_EARLY_INIT_F   1
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+#define CONFIG_STACKSIZE            SZ_512K
+#define CONFIG_STACKSIZE_IRQ        SZ_32K
+#define CONFIG_STACKSIZE_FIQ        SZ_32K
+
+#define CONFIG_SYS_MALLOC_LEN       SZ_8M
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+/*
+ * CPU
+ */
+#define CONFIG_FARADAY
+#define CONFIG_ARCH_CPU_INIT
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_SYS_CACHELINE_SIZE	32
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+/*
+ * Interrupt
+ */
+#if defined(CONFIG_USE_IRQ) && defined(CONFIG_FTI2C010_BASE)
+# define CONFIG_FTINTC020
+#endif
+
+/*
+ * Timer
+ */
+#define CONFIG_SYS_HZ               1000
+
+#ifdef CONFIG_FTTMR010_BASE
+# define CONFIG_FTTMR010
+#endif /* CONFIG_FTTMR010_BASE */
+
+#ifdef CONFIG_FTPWMTMR010_BASE
+# define CONFIG_FTPWMTMR010
+#endif /* CONFIG_FTPWMTMR010_BASE */
+
+/*
+ * Serial Info
+ */
+#ifdef CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# ifndef CONFIG_SYS_NS16550_CLK
+#  define CONFIG_SYS_NS16550_CLK     18432000
+# endif
+# define CONFIG_SYS_NS16550_COM1     CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE -4
+# define CONFIG_CONS_INDEX           1
+# define CONFIG_BAUDRATE             38400
+# undef  CONFIG_HWFLOW
+# undef  CONFIG_MODEM_SUPPORT
+#endif /* #ifdef CONFIG_FTUART010_BASE */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTMAC110_BASE
+# define CONFIG_FTMAC110
+#endif
+#ifdef CONFIG_FTGMAC100_BASE
+# define CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA    /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR    32 /* Used by Ratbert's ftgmac100 only */
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT 20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif
+
+/*
+ * NOR Flash
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* print 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * NAND Flash
+ */
+#ifdef CONFIG_FTNANDC021_BASE
+# define CONFIG_SYS_NAND_SELF_INIT
+# define CONFIG_NAND_FTNANDC021
+# define CONFIG_SYS_NAND_BASE           CONFIG_FTNANDC021_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+#endif
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010_BASE
+# define CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* The hardware core supports SDIO */
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if defined(CONFIG_SUPP_EHCI_FARADAY) && (CONFIG_USB_MAX_CONTROLLER_COUNT > 0)
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#if defined(CONFIG_SUPP_USB_RNDIS) && defined(CONFIG_FOTG210_BASE)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+#endif
+
+/*
+ * LCD
+ */
+#if defined(CONFIG_SUPP_VGA_CONSOLE) && defined(CONFIG_FTLCDC200_BASE)
+# define CONFIG_FTLCDC200
+# define CONFIG_FTLCDC200_800X480S_TPO
+# define LCD_BPP                    4 /* 16-bit per pixel */
+# define CONFIG_LCD
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+#ifndef CONFIG_SYS_LOAD_ADDR        /* Default load address */
+# define CONFIG_SYS_LOAD_ADDR       (CONFIG_SYS_SDRAM_BASE + SZ_1M)
+#endif
+/* Console Baud-Rate Table */
+#define CONFIG_SYS_BAUDRATE_TABLE   { 115200, 57600, 38400, 19200, 9600 }
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux kernel command line options
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG /* enable passing of ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 54120ab..89809b6 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -70,5 +70,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_WORST	0x0f1ff3ff /* worst but safe */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v7 03/11] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 03/11] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
@ 2013-07-29 22:59     ` Scott Wood
  2013-07-30  0:39       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Scott Wood @ 2013-07-29 22:59 UTC (permalink / raw)
  To: u-boot

On 07/29/2013 12:51:45 AM, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTNANDC021 is an integrated NAND flash controller.
> It use a build-in command table to abstract the underlying
> NAND flash control logic.
> 
> For example:
> 
> Issuing a command 0x10 to FTNANDC021 would result in
> a page write + a read status operation.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
> CC: Scott Wood <scottwood@freescale.com>
> ---
> Changes for v7:
>    - ftnandc021.[ch]: Update license to use SPDX identifiers.
>    - ftnandc021.c: put_unaligned() -> memcpy()
>    - ftnandc021.c: update ecc relatived function prototypes to
>      fix compile warnnings.
[snip]
> +#include <common.h>
> +#include <asm/errno.h>
> +#include <asm/io.h>
> +#include <asm/unaligned.h>
> +#include <nand.h>
> +#include <malloc.h>

asm/unaligned.h can come out now that you've switched to memcpy()...

In any case:
Acked-by: Scott Wood <scottwood@freescale.com>

-Scott

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

* [U-Boot] [PATCH v7 03/11] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-29 22:59     ` Scott Wood
@ 2013-07-30  0:39       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-07-30  0:39 UTC (permalink / raw)
  To: u-boot

2013/7/30 Scott Wood <scottwood@freescale.com>:
> On 07/29/2013 12:51:45 AM, Kuo-Jung Su wrote:
>>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday FTNANDC021 is an integrated NAND flash controller.
>> It use a build-in command table to abstract the underlying
>> NAND flash control logic.
>>
>> For example:
>>
>> Issuing a command 0x10 to FTNANDC021 would result in
>> a page write + a read status operation.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
>> CC: Scott Wood <scottwood@freescale.com>
>> ---
>> Changes for v7:
>>    - ftnandc021.[ch]: Update license to use SPDX identifiers.
>>    - ftnandc021.c: put_unaligned() -> memcpy()
>>    - ftnandc021.c: update ecc relatived function prototypes to
>>      fix compile warnnings.
>
> [snip]
>>
>> +#include <common.h>
>> +#include <asm/errno.h>
>> +#include <asm/io.h>
>> +#include <asm/unaligned.h>
>> +#include <nand.h>
>> +#include <malloc.h>
>
>
> asm/unaligned.h can come out now that you've switched to memcpy()...
>
> In any case:
> Acked-by: Scott Wood <scottwood@freescale.com>
>

Got it, thanks.
I'll make a separate cosmetic patch for it. (or probably in V8)

-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-04-18  9:25     ` [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
  2013-04-18 10:56       ` Wolfgang Denk
@ 2013-08-08 13:38       ` Jagan Teki
  2013-08-09  0:47         ` Kuo-Jung Su
  1 sibling, 1 reply; 311+ messages in thread
From: Jagan Teki @ 2013-08-08 13:38 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung Su,

Please fix the comments I sent on v4.
http://patchwork.ozlabs.org/patch/242023/

Feel free to ask for any quires.

Thanks,
Jagan.

On Thu, Apr 18, 2013 at 2:55 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>
> The Faraday FTSSP010 is a multi-function controller
> which supports I2S/SPI/SSP/AC97/SPDIF.
> This patch simpily implements the SPI mode only.
> BTW the DMA and CS/Clock control logic has been
> altered since revision 1.19.0. So this patch
> would 1st detects the revision id of the underlying
> chip, and then switch to the corresponding control
> routines.
>
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> ---
>  drivers/spi/Makefile       |    1 +
>  drivers/spi/ftssp010_spi.c |  337 ++++++++++++++++++++++++++++++++++++++++++++
>  drivers/spi/ftssp010_spi.h |   86 +++++++++++
>  3 files changed, 424 insertions(+)
>  create mode 100644 drivers/spi/ftssp010_spi.c
>  create mode 100644 drivers/spi/ftssp010_spi.h
>
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index d08609e..947d60e 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
>  COBJS-$(CONFIG_CF_SPI) += cf_spi.o
>  COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
>  COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
> +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
>  COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
>  COBJS-$(CONFIG_ICH_SPI) +=  ich.o
>  COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
> diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
> new file mode 100644
> index 0000000..4247c8c
> --- /dev/null
> +++ b/drivers/spi/ftssp010_spi.c
> @@ -0,0 +1,337 @@
> +/*
> + * Faraday Multi-function Controller - SPI Mode
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later version.
> + * See the file COPYING in the root directory of the source tree for details.
> + */
> +
> +#include <common.h>
> +#include <asm/io.h>
> +#include <spi.h>
> +#include <malloc.h>
> +
> +#include "ftssp010_spi.h"
> +
> +struct ftssp010_chip {
> +       void    *iobase;
> +       uint32_t fifo;
> +       uint32_t rev;
> +       uint32_t div;
> +       uint32_t mode;
> +
> +       struct {
> +               uint32_t iobase;
> +               uint32_t pin;
> +       } gpio;
> +};
> +
> +static struct ftssp010_chip chip_list[] = {
> +#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0)
> +       {
> +               .iobase = (void *)CONFIG_FTSSP010_BASE,
> +#ifdef CONFIG_FTSSP010_GPIO_BASE
> +               .gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN },
> +#endif
> +       },
> +#endif
> +#ifdef CONFIG_FTSSP010_BASE1
> +       { .iobase = (void *)CONFIG_FTSSP010_BASE1, },
> +#endif
> +#ifdef CONFIG_FTSSP010_BASE2
> +       { .iobase = (void *)CONFIG_FTSSP010_BASE2, },
> +#endif
> +#ifdef CONFIG_FTSSP010_BASE3
> +       { .iobase = (void *)CONFIG_FTSSP010_BASE3, },
> +#endif
> +};
> +
> +/* Register access macros */
> +#define SPI_READ(r)                    le32_to_cpu(readl(r))
> +#define SPI_WRITE(v, r)                writel(cpu_to_le32(v), r)
> +#define SPI_SETBITS(m, r)      setbits_le32(r, m)
> +#define SPI_CLRBITS(m, r)      clrbits_le32(r, m)
> +
> +#ifdef CONFIG_FTSSP010_GPIO_BASE
> +#define SPI_GPIO_READ(p, r)    \
> +       le32_to_cpu(readl((p)->gpio.iobase + (r)))
> +#define SPI_GPIO_WRITE(p, v, r)        \
> +       writel(cpu_to_le32(v), (p)->gpio.iobase + (r))
> +#define SPI_GPIO_SETBITS(p, m, r)      \
> +       setbits_le32((p)->gpio.iobase + (r), m)
> +#define SPI_GPIO_CLRBITS(p, m, r)      \
> +       clrbits_le32((p)->gpio.iobase + (r), m)
> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */
> +
> +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
> +       const void *tx_buf, void *rx_buf, int len, uint flags)
> +{
> +       struct ftssp010_regs *regs = chip->iobase;
> +       const uint8_t *txb = tx_buf;
> +       uint8_t       *rxb = rx_buf;
> +
> +       while (len > 0) {
> +               int i, depth = min(chip->fifo >> 2, len);
> +               uint32_t xmsk = 0;
> +
> +               if (tx_buf) {
> +                       for (i = 0; i < depth; ++i) {
> +                               while (!(SPI_READ(&regs->sr) & SR_TFNF))
> +                                       ;
> +                               SPI_WRITE(*txb++, &regs->dr);
> +                       }
> +                       xmsk |= CR2_TXEN | CR2_TXDOE;
> +                       if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
> +                               SPI_SETBITS(xmsk, &regs->cr[2]);
> +               }
> +               if (rx_buf) {
> +                       xmsk |= CR2_RXEN;
> +                       if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
> +                               SPI_SETBITS(xmsk, &regs->cr[2]);
> +                       for (i = 0; i < depth; ++i) {
> +                               while (!SR_RFVE(SPI_READ(&regs->sr)))
> +                                       ;
> +                               *rxb++ = (uint8_t)SPI_READ(&regs->dr);
> +                       }
> +               }
> +
> +               len -= depth;
> +       }
> +
> +       return 0;
> +}
> +
> +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
> +       const void *tx_buf, void *rx_buf, int len, uint flags)
> +{
> +       struct ftssp010_regs *regs = chip->iobase;
> +       const uint8_t *txb = tx_buf;
> +       uint8_t       *rxb = rx_buf;
> +
> +       while (len > 0) {
> +               int i, depth = min(chip->fifo >> 2, len);
> +               uint32_t tmp;
> +
> +               for (i = 0; i < depth; ++i) {
> +                       while (!(SPI_READ(&regs->sr) & SR_TFNF))
> +                               ;
> +                       SPI_WRITE(txb ? (*txb++) : 0, &regs->dr);
> +               }
> +               for (i = 0; i < depth; ++i) {
> +                       while (!SR_RFVE(SPI_READ(&regs->sr)))
> +                               ;
> +                       tmp = SPI_READ(&regs->dr);
> +                       if (rxb)
> +                               *rxb++ = (uint8_t)tmp;
> +               }
> +
> +               len -= depth;
> +       }
> +
> +       return 0;
> +}
> +
> +/*=====================================================================*/
> +/*                         Public Functions                            */
> +/*=====================================================================*/
> +
> +/*-----------------------------------------------------------------------
> + * Determine if a SPI chipselect is valid.
> + * This function is provided by the board if the low-level SPI driver
> + * needs it to determine if a given chipselect is actually valid.
> + *
> + * Returns: 1 if bus:cs identifies a valid chip on this board, 0
> + * otherwise.
> + */
> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
> +{
> +       struct ftssp010_chip *chip;
> +       struct ftssp010_regs *regs;
> +       uint32_t txfifo, rxfifo;
> +
> +       if (bus >= ARRAY_SIZE(chip_list))
> +               return 0;
> +
> +       chip = chip_list + bus;
> +       regs = chip->iobase;
> +       chip->rev = SPI_READ(&regs->revr);
> +       txfifo = FEAR_TXFIFO(SPI_READ(&regs->fear));
> +       rxfifo = FEAR_RXFIFO(SPI_READ(&regs->fear));
> +       chip->fifo = min(txfifo, rxfifo);
> +
> +       printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
> +
> +       if (chip->rev >= 0x00011900) {
> +               if (cs > 3)
> +                       return 0;
> +       } else {
> +#ifdef CONFIG_FTSSP010_GPIO_BASE
> +               if (cs > 0)
> +                       return 0;
> +               /* setup gpio pin as an output pin */
> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08);
> +#else
> +               return 0;
> +#endif
> +       }
> +
> +       return 1;
> +}
> +
> +/*-----------------------------------------------------------------------
> + * Activate a SPI chipselect.
> + * This function is provided by the board code when using a driver
> + * that can't control its chipselects automatically (e.g.
> + * common/soft_spi.c). When called, it should activate the chip select
> + * to the device identified by "slave".
> + */
> +void spi_cs_activate(struct spi_slave *slave)
> +{
> +       struct ftssp010_chip *chip = chip_list + slave->bus;
> +       struct ftssp010_regs *regs = chip->iobase;
> +
> +       /* cs pull low */
> +       if (chip->rev >= 0x00011900) {
> +               SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
> +                       | CR2_RXFCLR, &regs->cr[2]);
> +       } else {
> +#ifdef CONFIG_FTSSP010_GPIO_BASE
> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14);
> +#endif
> +       }
> +       udelay_masked(1);
> +}
> +
> +/*-----------------------------------------------------------------------
> + * Deactivate a SPI chipselect.
> + * This function is provided by the board code when using a driver
> + * that can't control its chipselects automatically (e.g.
> + * common/soft_spi.c). When called, it should deactivate the chip
> + * select to the device identified by "slave".
> + */
> +void spi_cs_deactivate(struct spi_slave *slave)
> +{
> +       struct ftssp010_chip *chip = chip_list + slave->bus;
> +       struct ftssp010_regs *regs = chip->iobase;
> +
> +       /* wait until device idle */
> +       while (SPI_READ(&regs->sr) & SR_BUSY)
> +               ;
> +
> +       /* cs pull high */
> +       if (chip->rev >= 0x00011900) {
> +               SPI_WRITE((slave->cs << 10) | CR2_FS, &regs->cr[2]);
> +       } else {
> +#ifdef CONFIG_FTSSP010_GPIO_BASE
> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10);
> +#endif
> +       }
> +       udelay_masked(1);
> +}
> +
> +void spi_init(void)
> +{
> +}
> +
> +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
> +{
> +       uint32_t clk, div;
> +       struct spi_slave *ss;
> +       struct ftssp010_chip *chip;
> +
> +       if (!spi_cs_is_valid(bus, cs))
> +               return NULL;
> +
> +       if (mode != SPI_MODE_0) {
> +               printf("ftssp010: MODE%d is not supported\n", mode);
> +               return NULL;
> +       }
> +
> +       ss = malloc(sizeof(struct spi_slave));
> +       if (!ss)
> +               return NULL;
> +
> +       ss->bus = bus;
> +       ss->cs  = cs;
> +
> +#ifdef CONFIG_FTSSP010_SCLK
> +       clk = CONFIG_FTSSP010_SCLK;
> +#else
> +       clk = clk_get_rate("SSP");
> +#endif
> +       if (max_hz > 0) {
> +               for (div = 0; div < 0xFFFF; ++div) {
> +                       if ((clk / (2 * (div + 1))) <= max_hz)
> +                               break;
> +               }
> +       } else {
> +               div = 7;
> +       }
> +
> +       chip = chip_list + bus;
> +       chip->div  = div;
> +       chip->mode = mode;
> +
> +       printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
> +
> +       return ss;
> +}
> +
> +void spi_free_slave(struct spi_slave *slave)
> +{
> +       free(slave);
> +}
> +
> +int spi_claim_bus(struct spi_slave *slave)
> +{
> +       struct ftssp010_chip *chip = chip_list + slave->bus;
> +       struct ftssp010_regs *regs = chip->iobase;
> +
> +       SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
> +
> +       if (chip->rev >= 0x00011900) {
> +               SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
> +                       &regs->cr[0]);
> +               SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR,
> +                       &regs->cr[2]);
> +       } else {
> +               SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
> +                       &regs->cr[0]);
> +               SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
> +                       &regs->cr[2]);
> +       }
> +
> +       spi_cs_deactivate(slave);
> +
> +       return 0;
> +}
> +
> +void spi_release_bus(struct spi_slave *slave)
> +{
> +       struct ftssp010_chip *chip = chip_list + slave->bus;
> +       struct ftssp010_regs *regs = chip->iobase;
> +
> +       SPI_WRITE(0, &regs->cr[2]);
> +}
> +
> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
> +                        const void *dout, void *din, unsigned long flags)
> +{
> +       struct ftssp010_chip *chip = chip_list + slave->bus;
> +       uint32_t len = bitlen >> 3;
> +
> +       if (flags & SPI_XFER_BEGIN)
> +               spi_cs_activate(slave);
> +
> +       if (chip->rev >= 0x00011900)
> +               ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags);
> +       else
> +               ftssp010_spi_work_transfer(chip, dout, din, len, flags);
> +
> +       if (flags & SPI_XFER_END)
> +               spi_cs_deactivate(slave);
> +
> +       return 0;
> +}
> diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
> new file mode 100644
> index 0000000..5ad7c47
> --- /dev/null
> +++ b/drivers/spi/ftssp010_spi.h
> @@ -0,0 +1,86 @@
> +/*
> + * Faraday Multi-function Controller - SPI Mode
> + *
> + * (C) Copyright 2010 Faraday Technology
> + * Dante Su <dantesu@faraday-tech.com>
> + *
> + * This file is released under the terms of GPL v2 and any later version.
> + * See the file COPYING in the root directory of the source tree for details.
> + */
> +
> +#ifndef _FTSSP010_H
> +#define _FTSSP010_H
> +
> +/* FTSSP010 HW Registers */
> +struct ftssp010_regs {
> +       uint32_t cr[3];/* control register */
> +       uint32_t sr;   /* status register */
> +       uint32_t icr;  /* interrupt control register */
> +       uint32_t isr;  /* interrupt status register */
> +       uint32_t dr;   /* data register */
> +       uint32_t rsvd[17];
> +       uint32_t revr; /* revision register */
> +       uint32_t fear; /* feature register */
> +};
> +
> +/* Control register 0  */
> +#define CR0_FFMT_MASK       (7 << 12)
> +#define CR0_FFMT_SSP        (0 << 12)
> +#define CR0_FFMT_SPI        (1 << 12)
> +#define CR0_FFMT_MICROWIRE  (2 << 12)
> +#define CR0_FFMT_I2S        (3 << 12)
> +#define CR0_FFMT_AC97       (4 << 12)
> +#define CR0_FLASH           (1 << 11)
> +#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
> +#define CR0_LBM             (1 << 7)  /* Loopback mode */
> +#define CR0_LSB             (1 << 6)  /* LSB first */
> +#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
> +#define CR0_FSJUSTIFY       (1 << 4)
> +#define CR0_OPM_SLAVE       (0 << 2)
> +#define CR0_OPM_MASTER      (3 << 2)
> +#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
> +#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
> +#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
> +#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
> +#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
> +#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
> +
> +/* Control Register 1 */
> +
> +#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
> +#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
> +#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
> +
> +/* Control Register 2 */
> +#define CR2_FSOS(x)         (((x) & 0x03) << 10)       /* FS/CS Select */
> +#define CR2_FS              (1 << 9)   /* FS/CS Signal Level */
> +#define CR2_TXEN            (1 << 8)   /* Tx Enable */
> +#define CR2_RXEN            (1 << 7)   /* Rx Enable */
> +#define CR2_SSPRST          (1 << 6)   /* SSP reset */
> +#define CR2_TXFCLR          (1 << 3)   /* TX FIFO Clear */
> +#define CR2_RXFCLR          (1 << 2)   /* RX FIFO Clear */
> +#define CR2_TXDOE           (1 << 1)   /* TX Data Output Enable */
> +#define CR2_SSPEN           (1 << 0)   /* SSP Enable */
> +
> +/*
> + * Status Register
> + */
> +#define SR_RFF       (1 << 0) /* receive FIFO full */
> +#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
> +#define SR_BUSY      (1 << 2) /* bus is busy */
> +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid entries */
> +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */
> +
> +/*
> + * Feature Register
> + */
> +#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
> +#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
> +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
> +#define FEAR_AC97        (1 << 24)
> +#define FEAR_I2S         (1 << 25)
> +#define FEAR_SPI_MWR     (1 << 26)
> +#define FEAR_SSP         (1 << 27)
> +#define FEAR_SPDIF       (1 << 28)
> +
> +#endif
> --
> 1.7.9.5
>
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> http://lists.denx.de/mailman/listinfo/u-boot

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-08-08 13:38       ` Jagan Teki
@ 2013-08-09  0:47         ` Kuo-Jung Su
  2013-08-09 11:27           ` Jagan Teki
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-08-09  0:47 UTC (permalink / raw)
  To: u-boot

Hi Jagan:

Thanks for the comments, but the [spi bus controller: ftssp010]

has been scheduled after the [Faraday A36x platform support] get approved.

In this way, the entire patch itself looks much better & clean.

Best Wishes

Dante Su

2013/8/8 Jagan Teki <jagannadh.teki@gmail.com>:
> Hi Kuo-Jung Su,
>
> Please fix the comments I sent on v4.
> http://patchwork.ozlabs.org/patch/242023/
>
> Feel free to ask for any quires.
>
> Thanks,
> Jagan.
>
> On Thu, Apr 18, 2013 at 2:55 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> The Faraday FTSSP010 is a multi-function controller
>> which supports I2S/SPI/SSP/AC97/SPDIF.
>> This patch simpily implements the SPI mode only.
>> BTW the DMA and CS/Clock control logic has been
>> altered since revision 1.19.0. So this patch
>> would 1st detects the revision id of the underlying
>> chip, and then switch to the corresponding control
>> routines.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> ---
>>  drivers/spi/Makefile       |    1 +
>>  drivers/spi/ftssp010_spi.c |  337 ++++++++++++++++++++++++++++++++++++++++++++
>>  drivers/spi/ftssp010_spi.h |   86 +++++++++++
>>  3 files changed, 424 insertions(+)
>>  create mode 100644 drivers/spi/ftssp010_spi.c
>>  create mode 100644 drivers/spi/ftssp010_spi.h
>>
>> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
>> index d08609e..947d60e 100644
>> --- a/drivers/spi/Makefile
>> +++ b/drivers/spi/Makefile
>> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
>>  COBJS-$(CONFIG_CF_SPI) += cf_spi.o
>>  COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
>>  COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
>> +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
>>  COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
>>  COBJS-$(CONFIG_ICH_SPI) +=  ich.o
>>  COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
>> diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
>> new file mode 100644
>> index 0000000..4247c8c
>> --- /dev/null
>> +++ b/drivers/spi/ftssp010_spi.c
>> @@ -0,0 +1,337 @@
>> +/*
>> + * Faraday Multi-function Controller - SPI Mode
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for details.
>> + */
>> +
>> +#include <common.h>
>> +#include <asm/io.h>
>> +#include <spi.h>
>> +#include <malloc.h>
>> +
>> +#include "ftssp010_spi.h"
>> +
>> +struct ftssp010_chip {
>> +       void    *iobase;
>> +       uint32_t fifo;
>> +       uint32_t rev;
>> +       uint32_t div;
>> +       uint32_t mode;
>> +
>> +       struct {
>> +               uint32_t iobase;
>> +               uint32_t pin;
>> +       } gpio;
>> +};
>> +
>> +static struct ftssp010_chip chip_list[] = {
>> +#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0)
>> +       {
>> +               .iobase = (void *)CONFIG_FTSSP010_BASE,
>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>> +               .gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN },
>> +#endif
>> +       },
>> +#endif
>> +#ifdef CONFIG_FTSSP010_BASE1
>> +       { .iobase = (void *)CONFIG_FTSSP010_BASE1, },
>> +#endif
>> +#ifdef CONFIG_FTSSP010_BASE2
>> +       { .iobase = (void *)CONFIG_FTSSP010_BASE2, },
>> +#endif
>> +#ifdef CONFIG_FTSSP010_BASE3
>> +       { .iobase = (void *)CONFIG_FTSSP010_BASE3, },
>> +#endif
>> +};
>> +
>> +/* Register access macros */
>> +#define SPI_READ(r)                    le32_to_cpu(readl(r))
>> +#define SPI_WRITE(v, r)                writel(cpu_to_le32(v), r)
>> +#define SPI_SETBITS(m, r)      setbits_le32(r, m)
>> +#define SPI_CLRBITS(m, r)      clrbits_le32(r, m)
>> +
>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>> +#define SPI_GPIO_READ(p, r)    \
>> +       le32_to_cpu(readl((p)->gpio.iobase + (r)))
>> +#define SPI_GPIO_WRITE(p, v, r)        \
>> +       writel(cpu_to_le32(v), (p)->gpio.iobase + (r))
>> +#define SPI_GPIO_SETBITS(p, m, r)      \
>> +       setbits_le32((p)->gpio.iobase + (r), m)
>> +#define SPI_GPIO_CLRBITS(p, m, r)      \
>> +       clrbits_le32((p)->gpio.iobase + (r), m)
>> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */
>> +
>> +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
>> +       const void *tx_buf, void *rx_buf, int len, uint flags)
>> +{
>> +       struct ftssp010_regs *regs = chip->iobase;
>> +       const uint8_t *txb = tx_buf;
>> +       uint8_t       *rxb = rx_buf;
>> +
>> +       while (len > 0) {
>> +               int i, depth = min(chip->fifo >> 2, len);
>> +               uint32_t xmsk = 0;
>> +
>> +               if (tx_buf) {
>> +                       for (i = 0; i < depth; ++i) {
>> +                               while (!(SPI_READ(&regs->sr) & SR_TFNF))
>> +                                       ;
>> +                               SPI_WRITE(*txb++, &regs->dr);
>> +                       }
>> +                       xmsk |= CR2_TXEN | CR2_TXDOE;
>> +                       if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
>> +                               SPI_SETBITS(xmsk, &regs->cr[2]);
>> +               }
>> +               if (rx_buf) {
>> +                       xmsk |= CR2_RXEN;
>> +                       if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
>> +                               SPI_SETBITS(xmsk, &regs->cr[2]);
>> +                       for (i = 0; i < depth; ++i) {
>> +                               while (!SR_RFVE(SPI_READ(&regs->sr)))
>> +                                       ;
>> +                               *rxb++ = (uint8_t)SPI_READ(&regs->dr);
>> +                       }
>> +               }
>> +
>> +               len -= depth;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
>> +       const void *tx_buf, void *rx_buf, int len, uint flags)
>> +{
>> +       struct ftssp010_regs *regs = chip->iobase;
>> +       const uint8_t *txb = tx_buf;
>> +       uint8_t       *rxb = rx_buf;
>> +
>> +       while (len > 0) {
>> +               int i, depth = min(chip->fifo >> 2, len);
>> +               uint32_t tmp;
>> +
>> +               for (i = 0; i < depth; ++i) {
>> +                       while (!(SPI_READ(&regs->sr) & SR_TFNF))
>> +                               ;
>> +                       SPI_WRITE(txb ? (*txb++) : 0, &regs->dr);
>> +               }
>> +               for (i = 0; i < depth; ++i) {
>> +                       while (!SR_RFVE(SPI_READ(&regs->sr)))
>> +                               ;
>> +                       tmp = SPI_READ(&regs->dr);
>> +                       if (rxb)
>> +                               *rxb++ = (uint8_t)tmp;
>> +               }
>> +
>> +               len -= depth;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +/*=====================================================================*/
>> +/*                         Public Functions                            */
>> +/*=====================================================================*/
>> +
>> +/*-----------------------------------------------------------------------
>> + * Determine if a SPI chipselect is valid.
>> + * This function is provided by the board if the low-level SPI driver
>> + * needs it to determine if a given chipselect is actually valid.
>> + *
>> + * Returns: 1 if bus:cs identifies a valid chip on this board, 0
>> + * otherwise.
>> + */
>> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
>> +{
>> +       struct ftssp010_chip *chip;
>> +       struct ftssp010_regs *regs;
>> +       uint32_t txfifo, rxfifo;
>> +
>> +       if (bus >= ARRAY_SIZE(chip_list))
>> +               return 0;
>> +
>> +       chip = chip_list + bus;
>> +       regs = chip->iobase;
>> +       chip->rev = SPI_READ(&regs->revr);
>> +       txfifo = FEAR_TXFIFO(SPI_READ(&regs->fear));
>> +       rxfifo = FEAR_RXFIFO(SPI_READ(&regs->fear));
>> +       chip->fifo = min(txfifo, rxfifo);
>> +
>> +       printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
>> +
>> +       if (chip->rev >= 0x00011900) {
>> +               if (cs > 3)
>> +                       return 0;
>> +       } else {
>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>> +               if (cs > 0)
>> +                       return 0;
>> +               /* setup gpio pin as an output pin */
>> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08);
>> +#else
>> +               return 0;
>> +#endif
>> +       }
>> +
>> +       return 1;
>> +}
>> +
>> +/*-----------------------------------------------------------------------
>> + * Activate a SPI chipselect.
>> + * This function is provided by the board code when using a driver
>> + * that can't control its chipselects automatically (e.g.
>> + * common/soft_spi.c). When called, it should activate the chip select
>> + * to the device identified by "slave".
>> + */
>> +void spi_cs_activate(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs *regs = chip->iobase;
>> +
>> +       /* cs pull low */
>> +       if (chip->rev >= 0x00011900) {
>> +               SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
>> +                       | CR2_RXFCLR, &regs->cr[2]);
>> +       } else {
>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14);
>> +#endif
>> +       }
>> +       udelay_masked(1);
>> +}
>> +
>> +/*-----------------------------------------------------------------------
>> + * Deactivate a SPI chipselect.
>> + * This function is provided by the board code when using a driver
>> + * that can't control its chipselects automatically (e.g.
>> + * common/soft_spi.c). When called, it should deactivate the chip
>> + * select to the device identified by "slave".
>> + */
>> +void spi_cs_deactivate(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs *regs = chip->iobase;
>> +
>> +       /* wait until device idle */
>> +       while (SPI_READ(&regs->sr) & SR_BUSY)
>> +               ;
>> +
>> +       /* cs pull high */
>> +       if (chip->rev >= 0x00011900) {
>> +               SPI_WRITE((slave->cs << 10) | CR2_FS, &regs->cr[2]);
>> +       } else {
>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10);
>> +#endif
>> +       }
>> +       udelay_masked(1);
>> +}
>> +
>> +void spi_init(void)
>> +{
>> +}
>> +
>> +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
>> +{
>> +       uint32_t clk, div;
>> +       struct spi_slave *ss;
>> +       struct ftssp010_chip *chip;
>> +
>> +       if (!spi_cs_is_valid(bus, cs))
>> +               return NULL;
>> +
>> +       if (mode != SPI_MODE_0) {
>> +               printf("ftssp010: MODE%d is not supported\n", mode);
>> +               return NULL;
>> +       }
>> +
>> +       ss = malloc(sizeof(struct spi_slave));
>> +       if (!ss)
>> +               return NULL;
>> +
>> +       ss->bus = bus;
>> +       ss->cs  = cs;
>> +
>> +#ifdef CONFIG_FTSSP010_SCLK
>> +       clk = CONFIG_FTSSP010_SCLK;
>> +#else
>> +       clk = clk_get_rate("SSP");
>> +#endif
>> +       if (max_hz > 0) {
>> +               for (div = 0; div < 0xFFFF; ++div) {
>> +                       if ((clk / (2 * (div + 1))) <= max_hz)
>> +                               break;
>> +               }
>> +       } else {
>> +               div = 7;
>> +       }
>> +
>> +       chip = chip_list + bus;
>> +       chip->div  = div;
>> +       chip->mode = mode;
>> +
>> +       printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
>> +
>> +       return ss;
>> +}
>> +
>> +void spi_free_slave(struct spi_slave *slave)
>> +{
>> +       free(slave);
>> +}
>> +
>> +int spi_claim_bus(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs *regs = chip->iobase;
>> +
>> +       SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
>> +
>> +       if (chip->rev >= 0x00011900) {
>> +               SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
>> +                       &regs->cr[0]);
>> +               SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR,
>> +                       &regs->cr[2]);
>> +       } else {
>> +               SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
>> +                       &regs->cr[0]);
>> +               SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
>> +                       &regs->cr[2]);
>> +       }
>> +
>> +       spi_cs_deactivate(slave);
>> +
>> +       return 0;
>> +}
>> +
>> +void spi_release_bus(struct spi_slave *slave)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       struct ftssp010_regs *regs = chip->iobase;
>> +
>> +       SPI_WRITE(0, &regs->cr[2]);
>> +}
>> +
>> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>> +                        const void *dout, void *din, unsigned long flags)
>> +{
>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>> +       uint32_t len = bitlen >> 3;
>> +
>> +       if (flags & SPI_XFER_BEGIN)
>> +               spi_cs_activate(slave);
>> +
>> +       if (chip->rev >= 0x00011900)
>> +               ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags);
>> +       else
>> +               ftssp010_spi_work_transfer(chip, dout, din, len, flags);
>> +
>> +       if (flags & SPI_XFER_END)
>> +               spi_cs_deactivate(slave);
>> +
>> +       return 0;
>> +}
>> diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
>> new file mode 100644
>> index 0000000..5ad7c47
>> --- /dev/null
>> +++ b/drivers/spi/ftssp010_spi.h
>> @@ -0,0 +1,86 @@
>> +/*
>> + * Faraday Multi-function Controller - SPI Mode
>> + *
>> + * (C) Copyright 2010 Faraday Technology
>> + * Dante Su <dantesu@faraday-tech.com>
>> + *
>> + * This file is released under the terms of GPL v2 and any later version.
>> + * See the file COPYING in the root directory of the source tree for details.
>> + */
>> +
>> +#ifndef _FTSSP010_H
>> +#define _FTSSP010_H
>> +
>> +/* FTSSP010 HW Registers */
>> +struct ftssp010_regs {
>> +       uint32_t cr[3];/* control register */
>> +       uint32_t sr;   /* status register */
>> +       uint32_t icr;  /* interrupt control register */
>> +       uint32_t isr;  /* interrupt status register */
>> +       uint32_t dr;   /* data register */
>> +       uint32_t rsvd[17];
>> +       uint32_t revr; /* revision register */
>> +       uint32_t fear; /* feature register */
>> +};
>> +
>> +/* Control register 0  */
>> +#define CR0_FFMT_MASK       (7 << 12)
>> +#define CR0_FFMT_SSP        (0 << 12)
>> +#define CR0_FFMT_SPI        (1 << 12)
>> +#define CR0_FFMT_MICROWIRE  (2 << 12)
>> +#define CR0_FFMT_I2S        (3 << 12)
>> +#define CR0_FFMT_AC97       (4 << 12)
>> +#define CR0_FLASH           (1 << 11)
>> +#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
>> +#define CR0_LBM             (1 << 7)  /* Loopback mode */
>> +#define CR0_LSB             (1 << 6)  /* LSB first */
>> +#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
>> +#define CR0_FSJUSTIFY       (1 << 4)
>> +#define CR0_OPM_SLAVE       (0 << 2)
>> +#define CR0_OPM_MASTER      (3 << 2)
>> +#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
>> +#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
>> +#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
>> +#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
>> +#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
>> +#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
>> +
>> +/* Control Register 1 */
>> +
>> +#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
>> +#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
>> +#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
>> +
>> +/* Control Register 2 */
>> +#define CR2_FSOS(x)         (((x) & 0x03) << 10)       /* FS/CS Select */
>> +#define CR2_FS              (1 << 9)   /* FS/CS Signal Level */
>> +#define CR2_TXEN            (1 << 8)   /* Tx Enable */
>> +#define CR2_RXEN            (1 << 7)   /* Rx Enable */
>> +#define CR2_SSPRST          (1 << 6)   /* SSP reset */
>> +#define CR2_TXFCLR          (1 << 3)   /* TX FIFO Clear */
>> +#define CR2_RXFCLR          (1 << 2)   /* RX FIFO Clear */
>> +#define CR2_TXDOE           (1 << 1)   /* TX Data Output Enable */
>> +#define CR2_SSPEN           (1 << 0)   /* SSP Enable */
>> +
>> +/*
>> + * Status Register
>> + */
>> +#define SR_RFF       (1 << 0) /* receive FIFO full */
>> +#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
>> +#define SR_BUSY      (1 << 2) /* bus is busy */
>> +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid entries */
>> +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */
>> +
>> +/*
>> + * Feature Register
>> + */
>> +#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
>> +#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
>> +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
>> +#define FEAR_AC97        (1 << 24)
>> +#define FEAR_I2S         (1 << 25)
>> +#define FEAR_SPI_MWR     (1 << 26)
>> +#define FEAR_SSP         (1 << 27)
>> +#define FEAR_SPDIF       (1 << 28)
>> +
>> +#endif
>> --
>> 1.7.9.5
>>
>> _______________________________________________
>> U-Boot mailing list
>> U-Boot at lists.denx.de
>> http://lists.denx.de/mailman/listinfo/u-boot



-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-08-09  0:47         ` Kuo-Jung Su
@ 2013-08-09 11:27           ` Jagan Teki
  2013-08-12  0:37             ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Jagan Teki @ 2013-08-09 11:27 UTC (permalink / raw)
  To: u-boot

On Fri, Aug 9, 2013 at 6:17 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
> Hi Jagan:
>
> Thanks for the comments, but the [spi bus controller: ftssp010]
>
> has been scheduled after the [Faraday A36x platform support] get approved.
>
> In this way, the entire patch itself looks much better & clean.
>
> Best Wishes
>
> Dante Su
>
> 2013/8/8 Jagan Teki <jagannadh.teki@gmail.com>:
>> Hi Kuo-Jung Su,
>>
>> Please fix the comments I sent on v4.
>> http://patchwork.ozlabs.org/patch/242023/
>>
>> Feel free to ask for any quires.
>>
>> Thanks,
>> Jagan.
>>
>> On Thu, Apr 18, 2013 at 2:55 PM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>>
>>> The Faraday FTSSP010 is a multi-function controller
>>> which supports I2S/SPI/SSP/AC97/SPDIF.
>>> This patch simpily implements the SPI mode only.
>>> BTW the DMA and CS/Clock control logic has been
>>> altered since revision 1.19.0. So this patch
>>> would 1st detects the revision id of the underlying
>>> chip, and then switch to the corresponding control
>>> routines.
>>>
>>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>>> ---
>>>  drivers/spi/Makefile       |    1 +
>>>  drivers/spi/ftssp010_spi.c |  337 ++++++++++++++++++++++++++++++++++++++++++++
>>>  drivers/spi/ftssp010_spi.h |   86 +++++++++++
>>>  3 files changed, 424 insertions(+)
>>>  create mode 100644 drivers/spi/ftssp010_spi.c
>>>  create mode 100644 drivers/spi/ftssp010_spi.h
>>>
>>> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
>>> index d08609e..947d60e 100644
>>> --- a/drivers/spi/Makefile
>>> +++ b/drivers/spi/Makefile
>>> @@ -38,6 +38,7 @@ COBJS-$(CONFIG_BFIN_SPI6XX) += bfin_spi6xx.o
>>>  COBJS-$(CONFIG_CF_SPI) += cf_spi.o
>>>  COBJS-$(CONFIG_CF_QSPI) += cf_qspi.o
>>>  COBJS-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
>>> +COBJS-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
>>>  COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
>>>  COBJS-$(CONFIG_ICH_SPI) +=  ich.o
>>>  COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
>>> diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
>>> new file mode 100644
>>> index 0000000..4247c8c
>>> --- /dev/null
>>> +++ b/drivers/spi/ftssp010_spi.c
>>> @@ -0,0 +1,337 @@
>>> +/*
>>> + * Faraday Multi-function Controller - SPI Mode
>>> + *
>>> + * (C) Copyright 2010 Faraday Technology
>>> + * Dante Su <dantesu@faraday-tech.com>
>>> + *
>>> + * This file is released under the terms of GPL v2 and any later version.
>>> + * See the file COPYING in the root directory of the source tree for details.
>>> + */
>>> +
>>> +#include <common.h>
>>> +#include <asm/io.h>
>>> +#include <spi.h>
>>> +#include <malloc.h>
>>> +
>>> +#include "ftssp010_spi.h"
>>> +
>>> +struct ftssp010_chip {
>>> +       void    *iobase;
>>> +       uint32_t fifo;
>>> +       uint32_t rev;
>>> +       uint32_t div;
>>> +       uint32_t mode;
>>> +
>>> +       struct {
>>> +               uint32_t iobase;
>>> +               uint32_t pin;
>>> +       } gpio;
>>> +};
>>> +
>>> +static struct ftssp010_chip chip_list[] = {
>>> +#if defined(CONFIG_FTSSP010_BASE) || defined(CONFIG_FTSSP010_BASE0)
>>> +       {
>>> +               .iobase = (void *)CONFIG_FTSSP010_BASE,
>>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>>> +               .gpio = { CONFIG_FTSSP010_GPIO_BASE, CONFIG_FTSSP010_GPIO_PIN },
>>> +#endif
>>> +       },
>>> +#endif
>>> +#ifdef CONFIG_FTSSP010_BASE1
>>> +       { .iobase = (void *)CONFIG_FTSSP010_BASE1, },
>>> +#endif
>>> +#ifdef CONFIG_FTSSP010_BASE2
>>> +       { .iobase = (void *)CONFIG_FTSSP010_BASE2, },
>>> +#endif
>>> +#ifdef CONFIG_FTSSP010_BASE3
>>> +       { .iobase = (void *)CONFIG_FTSSP010_BASE3, },
>>> +#endif
>>> +};
>>> +
>>> +/* Register access macros */
>>> +#define SPI_READ(r)                    le32_to_cpu(readl(r))
>>> +#define SPI_WRITE(v, r)                writel(cpu_to_le32(v), r)
>>> +#define SPI_SETBITS(m, r)      setbits_le32(r, m)
>>> +#define SPI_CLRBITS(m, r)      clrbits_le32(r, m)
>>> +
>>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>>> +#define SPI_GPIO_READ(p, r)    \
>>> +       le32_to_cpu(readl((p)->gpio.iobase + (r)))
>>> +#define SPI_GPIO_WRITE(p, v, r)        \
>>> +       writel(cpu_to_le32(v), (p)->gpio.iobase + (r))
>>> +#define SPI_GPIO_SETBITS(p, m, r)      \
>>> +       setbits_le32((p)->gpio.iobase + (r), m)
>>> +#define SPI_GPIO_CLRBITS(p, m, r)      \
>>> +       clrbits_le32((p)->gpio.iobase + (r), m)
>>> +#endif /* #ifdef CONFIG_FTSSP010_GPIO_BASE */
>>> +
>>> +static int ftssp010_spi_work_transfer_v1_19(struct ftssp010_chip *chip,
>>> +       const void *tx_buf, void *rx_buf, int len, uint flags)
>>> +{
>>> +       struct ftssp010_regs *regs = chip->iobase;
>>> +       const uint8_t *txb = tx_buf;
>>> +       uint8_t       *rxb = rx_buf;
>>> +
>>> +       while (len > 0) {
>>> +               int i, depth = min(chip->fifo >> 2, len);
>>> +               uint32_t xmsk = 0;
>>> +
>>> +               if (tx_buf) {
>>> +                       for (i = 0; i < depth; ++i) {
>>> +                               while (!(SPI_READ(&regs->sr) & SR_TFNF))
>>> +                                       ;
>>> +                               SPI_WRITE(*txb++, &regs->dr);
>>> +                       }
>>> +                       xmsk |= CR2_TXEN | CR2_TXDOE;
>>> +                       if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
>>> +                               SPI_SETBITS(xmsk, &regs->cr[2]);
>>> +               }
>>> +               if (rx_buf) {
>>> +                       xmsk |= CR2_RXEN;
>>> +                       if ((SPI_READ(&regs->cr[2]) & xmsk) != xmsk)
>>> +                               SPI_SETBITS(xmsk, &regs->cr[2]);
>>> +                       for (i = 0; i < depth; ++i) {
>>> +                               while (!SR_RFVE(SPI_READ(&regs->sr)))
>>> +                                       ;
>>> +                               *rxb++ = (uint8_t)SPI_READ(&regs->dr);
>>> +                       }
>>> +               }
>>> +
>>> +               len -= depth;
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +static int ftssp010_spi_work_transfer(struct ftssp010_chip *chip,
>>> +       const void *tx_buf, void *rx_buf, int len, uint flags)
>>> +{
>>> +       struct ftssp010_regs *regs = chip->iobase;
>>> +       const uint8_t *txb = tx_buf;
>>> +       uint8_t       *rxb = rx_buf;
>>> +
>>> +       while (len > 0) {
>>> +               int i, depth = min(chip->fifo >> 2, len);
>>> +               uint32_t tmp;
>>> +
>>> +               for (i = 0; i < depth; ++i) {
>>> +                       while (!(SPI_READ(&regs->sr) & SR_TFNF))
>>> +                               ;
>>> +                       SPI_WRITE(txb ? (*txb++) : 0, &regs->dr);
>>> +               }
>>> +               for (i = 0; i < depth; ++i) {
>>> +                       while (!SR_RFVE(SPI_READ(&regs->sr)))
>>> +                               ;
>>> +                       tmp = SPI_READ(&regs->dr);
>>> +                       if (rxb)
>>> +                               *rxb++ = (uint8_t)tmp;
>>> +               }
>>> +
>>> +               len -= depth;
>>> +       }
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +/*=====================================================================*/
>>> +/*                         Public Functions                            */
>>> +/*=====================================================================*/
>>> +
>>> +/*-----------------------------------------------------------------------
>>> + * Determine if a SPI chipselect is valid.
>>> + * This function is provided by the board if the low-level SPI driver
>>> + * needs it to determine if a given chipselect is actually valid.
>>> + *
>>> + * Returns: 1 if bus:cs identifies a valid chip on this board, 0
>>> + * otherwise.
>>> + */
>>> +int spi_cs_is_valid(unsigned int bus, unsigned int cs)
>>> +{
>>> +       struct ftssp010_chip *chip;
>>> +       struct ftssp010_regs *regs;
>>> +       uint32_t txfifo, rxfifo;
>>> +
>>> +       if (bus >= ARRAY_SIZE(chip_list))
>>> +               return 0;
>>> +
>>> +       chip = chip_list + bus;
>>> +       regs = chip->iobase;
>>> +       chip->rev = SPI_READ(&regs->revr);
>>> +       txfifo = FEAR_TXFIFO(SPI_READ(&regs->fear));
>>> +       rxfifo = FEAR_RXFIFO(SPI_READ(&regs->fear));
>>> +       chip->fifo = min(txfifo, rxfifo);
>>> +
>>> +       printf("ftssp010: rev.=0x%08X, fifo=%d\n", chip->rev, chip->fifo);
>>> +
>>> +       if (chip->rev >= 0x00011900) {
>>> +               if (cs > 3)
>>> +                       return 0;
>>> +       } else {
>>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>>> +               if (cs > 0)
>>> +                       return 0;
>>> +               /* setup gpio pin as an output pin */
>>> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x08);
>>> +#else
>>> +               return 0;
>>> +#endif
>>> +       }
>>> +
>>> +       return 1;
>>> +}
>>> +
>>> +/*-----------------------------------------------------------------------
>>> + * Activate a SPI chipselect.
>>> + * This function is provided by the board code when using a driver
>>> + * that can't control its chipselects automatically (e.g.
>>> + * common/soft_spi.c). When called, it should activate the chip select
>>> + * to the device identified by "slave".
>>> + */
>>> +void spi_cs_activate(struct spi_slave *slave)
>>> +{
>>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>>> +       struct ftssp010_regs *regs = chip->iobase;
>>> +
>>> +       /* cs pull low */
>>> +       if (chip->rev >= 0x00011900) {
>>> +               SPI_WRITE((slave->cs << 10) | CR2_SSPEN | CR2_TXFCLR
>>> +                       | CR2_RXFCLR, &regs->cr[2]);
>>> +       } else {
>>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>>> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x14);
>>> +#endif
>>> +       }
>>> +       udelay_masked(1);
>>> +}
>>> +
>>> +/*-----------------------------------------------------------------------
>>> + * Deactivate a SPI chipselect.
>>> + * This function is provided by the board code when using a driver
>>> + * that can't control its chipselects automatically (e.g.
>>> + * common/soft_spi.c). When called, it should deactivate the chip
>>> + * select to the device identified by "slave".
>>> + */
>>> +void spi_cs_deactivate(struct spi_slave *slave)
>>> +{
>>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>>> +       struct ftssp010_regs *regs = chip->iobase;
>>> +
>>> +       /* wait until device idle */
>>> +       while (SPI_READ(&regs->sr) & SR_BUSY)
>>> +               ;
>>> +
>>> +       /* cs pull high */
>>> +       if (chip->rev >= 0x00011900) {
>>> +               SPI_WRITE((slave->cs << 10) | CR2_FS, &regs->cr[2]);
>>> +       } else {
>>> +#ifdef CONFIG_FTSSP010_GPIO_BASE
>>> +               SPI_GPIO_SETBITS(chip, 1 << chip->gpio.pin, 0x10);
>>> +#endif
>>> +       }
>>> +       udelay_masked(1);
>>> +}
>>> +
>>> +void spi_init(void)
>>> +{
>>> +}
>>> +
>>> +struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
>>> +{
>>> +       uint32_t clk, div;
>>> +       struct spi_slave *ss;
>>> +       struct ftssp010_chip *chip;
>>> +
>>> +       if (!spi_cs_is_valid(bus, cs))
>>> +               return NULL;
>>> +
>>> +       if (mode != SPI_MODE_0) {
>>> +               printf("ftssp010: MODE%d is not supported\n", mode);
>>> +               return NULL;
>>> +       }
>>> +
>>> +       ss = malloc(sizeof(struct spi_slave));
>>> +       if (!ss)
>>> +               return NULL;
>>> +
>>> +       ss->bus = bus;
>>> +       ss->cs  = cs;
>>> +
>>> +#ifdef CONFIG_FTSSP010_SCLK
>>> +       clk = CONFIG_FTSSP010_SCLK;
>>> +#else
>>> +       clk = clk_get_rate("SSP");
>>> +#endif
>>> +       if (max_hz > 0) {
>>> +               for (div = 0; div < 0xFFFF; ++div) {
>>> +                       if ((clk / (2 * (div + 1))) <= max_hz)
>>> +                               break;
>>> +               }
>>> +       } else {
>>> +               div = 7;
>>> +       }
>>> +
>>> +       chip = chip_list + bus;
>>> +       chip->div  = div;
>>> +       chip->mode = mode;
>>> +
>>> +       printf("ftssp010: bus=%d, hz=%u\n", bus, (clk / (2 * (div + 1))));
>>> +
>>> +       return ss;
>>> +}
>>> +
>>> +void spi_free_slave(struct spi_slave *slave)
>>> +{
>>> +       free(slave);
>>> +}
>>> +
>>> +int spi_claim_bus(struct spi_slave *slave)
>>> +{
>>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>>> +       struct ftssp010_regs *regs = chip->iobase;
>>> +
>>> +       SPI_WRITE(CR1_SDL(8) | CR1_CLKDIV(chip->div), &regs->cr[1]);
>>> +
>>> +       if (chip->rev >= 0x00011900) {
>>> +               SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
>>> +                       &regs->cr[0]);
>>> +               SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR,
>>> +                       &regs->cr[2]);
>>> +       } else {
>>> +               SPI_WRITE(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
>>> +                       &regs->cr[0]);
>>> +               SPI_WRITE(CR2_TXFCLR | CR2_RXFCLR | CR2_SSPEN | CR2_TXDOE,
>>> +                       &regs->cr[2]);
>>> +       }
>>> +
>>> +       spi_cs_deactivate(slave);
>>> +
>>> +       return 0;
>>> +}
>>> +
>>> +void spi_release_bus(struct spi_slave *slave)
>>> +{
>>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>>> +       struct ftssp010_regs *regs = chip->iobase;
>>> +
>>> +       SPI_WRITE(0, &regs->cr[2]);
>>> +}
>>> +
>>> +int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
>>> +                        const void *dout, void *din, unsigned long flags)
>>> +{
>>> +       struct ftssp010_chip *chip = chip_list + slave->bus;
>>> +       uint32_t len = bitlen >> 3;
>>> +
>>> +       if (flags & SPI_XFER_BEGIN)
>>> +               spi_cs_activate(slave);
>>> +
>>> +       if (chip->rev >= 0x00011900)
>>> +               ftssp010_spi_work_transfer_v1_19(chip, dout, din, len, flags);
>>> +       else
>>> +               ftssp010_spi_work_transfer(chip, dout, din, len, flags);
>>> +
>>> +       if (flags & SPI_XFER_END)
>>> +               spi_cs_deactivate(slave);
>>> +
>>> +       return 0;
>>> +}
>>> diff --git a/drivers/spi/ftssp010_spi.h b/drivers/spi/ftssp010_spi.h
>>> new file mode 100644
>>> index 0000000..5ad7c47
>>> --- /dev/null
>>> +++ b/drivers/spi/ftssp010_spi.h
>>> @@ -0,0 +1,86 @@
>>> +/*
>>> + * Faraday Multi-function Controller - SPI Mode
>>> + *
>>> + * (C) Copyright 2010 Faraday Technology
>>> + * Dante Su <dantesu@faraday-tech.com>
>>> + *
>>> + * This file is released under the terms of GPL v2 and any later version.
>>> + * See the file COPYING in the root directory of the source tree for details.
>>> + */
>>> +
>>> +#ifndef _FTSSP010_H
>>> +#define _FTSSP010_H
>>> +
>>> +/* FTSSP010 HW Registers */
>>> +struct ftssp010_regs {
>>> +       uint32_t cr[3];/* control register */
>>> +       uint32_t sr;   /* status register */
>>> +       uint32_t icr;  /* interrupt control register */
>>> +       uint32_t isr;  /* interrupt status register */
>>> +       uint32_t dr;   /* data register */
>>> +       uint32_t rsvd[17];
>>> +       uint32_t revr; /* revision register */
>>> +       uint32_t fear; /* feature register */
>>> +};
>>> +
>>> +/* Control register 0  */
>>> +#define CR0_FFMT_MASK       (7 << 12)
>>> +#define CR0_FFMT_SSP        (0 << 12)
>>> +#define CR0_FFMT_SPI        (1 << 12)
>>> +#define CR0_FFMT_MICROWIRE  (2 << 12)
>>> +#define CR0_FFMT_I2S        (3 << 12)
>>> +#define CR0_FFMT_AC97       (4 << 12)
>>> +#define CR0_FLASH           (1 << 11)
>>> +#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
>>> +#define CR0_LBM             (1 << 7)  /* Loopback mode */
>>> +#define CR0_LSB             (1 << 6)  /* LSB first */
>>> +#define CR0_FSPO            (1 << 5)  /* Frame sync atcive low */
>>> +#define CR0_FSJUSTIFY       (1 << 4)
>>> +#define CR0_OPM_SLAVE       (0 << 2)
>>> +#define CR0_OPM_MASTER      (3 << 2)
>>> +#define CR0_OPM_I2S_MSST    (3 << 2)  /* Master stereo mode */
>>> +#define CR0_OPM_I2S_MSMO    (2 << 2)  /* Master mono mode */
>>> +#define CR0_OPM_I2S_SLST    (1 << 2)  /* Slave stereo mode */
>>> +#define CR0_OPM_I2S_SLMO    (0 << 2)  /* Slave mono mode */
>>> +#define CR0_SCLKPO          (1 << 1)  /* SCLK Remain HIGH */
>>> +#define CR0_SCLKPH          (1 << 0)  /* Half CLK cycle */
>>> +
>>> +/* Control Register 1 */
>>> +
>>> +#define CR1_PDL(x)          (((x) & 0xff) << 24) /* padding length */
>>> +#define CR1_SDL(x)          ((((x) - 1) & 0x1f) << 16) /* data length */
>>> +#define CR1_CLKDIV(x)       ((x) & 0xffff) /*  clk divider */
>>> +
>>> +/* Control Register 2 */
>>> +#define CR2_FSOS(x)         (((x) & 0x03) << 10)       /* FS/CS Select */
>>> +#define CR2_FS              (1 << 9)   /* FS/CS Signal Level */
>>> +#define CR2_TXEN            (1 << 8)   /* Tx Enable */
>>> +#define CR2_RXEN            (1 << 7)   /* Rx Enable */
>>> +#define CR2_SSPRST          (1 << 6)   /* SSP reset */
>>> +#define CR2_TXFCLR          (1 << 3)   /* TX FIFO Clear */
>>> +#define CR2_RXFCLR          (1 << 2)   /* RX FIFO Clear */
>>> +#define CR2_TXDOE           (1 << 1)   /* TX Data Output Enable */
>>> +#define CR2_SSPEN           (1 << 0)   /* SSP Enable */
>>> +
>>> +/*
>>> + * Status Register
>>> + */
>>> +#define SR_RFF       (1 << 0) /* receive FIFO full */
>>> +#define SR_TFNF      (1 << 1) /* transmit FIFO not full */
>>> +#define SR_BUSY      (1 << 2) /* bus is busy */
>>> +#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* receive  FIFO valid entries */
>>> +#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* transmit FIFO valid entries */
>>> +
>>> +/*
>>> + * Feature Register
>>> + */
>>> +#define FEAR_WIDTH(reg)  ((((reg) >>  0) & 0xff) + 1)
>>> +#define FEAR_RXFIFO(reg) ((((reg) >>  8) & 0xff) + 1)
>>> +#define FEAR_TXFIFO(reg) ((((reg) >> 16) & 0xff) + 1)
>>> +#define FEAR_AC97        (1 << 24)
>>> +#define FEAR_I2S         (1 << 25)
>>> +#define FEAR_SPI_MWR     (1 << 26)
>>> +#define FEAR_SSP         (1 << 27)
>>> +#define FEAR_SPDIF       (1 << 28)
>>> +
>>> +#endif
>>> --
>>> 1.7.9.5
>>>
>>> _______________________________________________
>>> U-Boot mailing list
>>> U-Boot at lists.denx.de
>>> http://lists.denx.de/mailman/listinfo/u-boot

Please see the comments on below patch
http://patchwork.ozlabs.org/patch/265683/

--
Thanks,
Jagan.

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

* [U-Boot] [PATCH v7 02/11] video: add Faraday FTLCDC200 LCD controller support
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 02/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
@ 2013-08-09 19:33     ` Anatolij Gustschin
  0 siblings, 0 replies; 311+ messages in thread
From: Anatolij Gustschin @ 2013-08-09 19:33 UTC (permalink / raw)
  To: u-boot

On Mon, 29 Jul 2013 13:51:44 +0800
Kuo-Jung Su <dantesu@gmail.com> wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTLCDC200 Color LCD controller performs translation of
> pixel-coded data into the required formats and timings to
> drive a variety of single/dual mono and color LCDs.
> 
> Depending on the LCD type and mode, the unpacked data can represent:
>    1. an actual true display gray or color value
>    2. an address to a 256 x 16 bit wide palette RAM gray or color value.
> 
> The FTLCDC200 generates 4 individual interrupts for:
>    1. DMA FIFO underflow
>    2. base address update
>    3. vertical status
>    4. bus error.
> 
> There is also a single combined interrupt that is raised when any of
> the individual interrupts become active.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> CC: Anatolij Gustschin <agust@denx.de>
> ---
> Changes for v7:
>    - Update license to use SPDX identifiers.
> 
> Changes for v6:
>    - Nothing updates
> 
> Changes for v5:
>    - Coding Style cleanup:
>      struct chip_regs __iomem *regs -> struct chip_regs *regs
>    - Chain it back to Faraday A360/A369 patch series, because
>      Faraday A369 depends on the header file of this patch
>      for I2C work-around.(Enable I2C clock to prevent I2C bus hangs)
> 
> Changes for v4:
>    - Nothing updates
> 
> Changes for v3:
>    - Nothing updates
> 
> Changes for v2:
>    - Make it a separate patch, rather then a part of
>      Faraday A36x patch series
> 
>  drivers/video/Makefile          |    1 +
>  drivers/video/ftlcdc200.c       |  136 +++++++++++++++++++++++++
>  drivers/video/ftlcdc200_panel.c |  209 +++++++++++++++++++++++++++++++++++++++
>  include/faraday/ftlcdc200.h     |  178 +++++++++++++++++++++++++++++++++
>  include/lcd.h                   |   33 +++++++
>  5 files changed, 557 insertions(+)
>  create mode 100644 drivers/video/ftlcdc200.c
>  create mode 100644 drivers/video/ftlcdc200_panel.c
>  create mode 100644 include/faraday/ftlcdc200.h

Acked-by: Anatolij Gustschin <agust@denx.de>

Thanks,

Anatolij

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-08-09 11:27           ` Jagan Teki
@ 2013-08-12  0:37             ` Kuo-Jung Su
  2013-10-03 19:53               ` Jagan Teki
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-08-12  0:37 UTC (permalink / raw)
  To: u-boot

>
> Please see the comments on below patch
> http://patchwork.ozlabs.org/patch/265683/
>
> --

Got it, thanks


-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v7 01/11] arm: dma_alloc_coherent: malloc() -> memalign()
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 01/11] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
@ 2013-09-14 10:09     ` Albert ARIBAUD
  0 siblings, 0 replies; 311+ messages in thread
From: Albert ARIBAUD @ 2013-09-14 10:09 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Mon, 29 Jul 2013 13:51:43 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Even though the MMU/D-cache is off, some DMA engines still
> expect strict address alignment.
> 
> For example, the incoming Faraday FTMAC110 & FTGMAC100 ethernet
> controllers expect the tx/rx descriptors should always be aligned
> to 16-bytes boundary.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
> ---
> Changes for v6, v7:
>    - Nothing updates
> 
> Changes for v5:
>    - Initial commit, which is separated from
>      "arm: add MMU/D-Cache support for Faraday cores"
> 
>  arch/arm/include/asm/dma-mapping.h |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
> index 009863b..55a4e26 100644
> --- a/arch/arm/include/asm/dma-mapping.h
> +++ b/arch/arm/include/asm/dma-mapping.h
> @@ -16,7 +16,7 @@ enum dma_data_direction {
> 
>  static void *dma_alloc_coherent(size_t len, unsigned long *handle)
>  {
> -	*handle = (unsigned long)malloc(len);
> +	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
>  	return (void *)*handle;
>  }
> 
> --
> 1.7.9.5
> 

Applied to u-boot-arm/master, thanks!

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images Kuo-Jung Su
@ 2013-09-14 10:28     ` Albert ARIBAUD
  2013-10-02  0:53       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2013-09-14 10:28 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Mon, 29 Jul 2013 13:51:51 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> + * At the time of writting, none of Faraday NAND & SPI controllers
> + * supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
> + * to implement a 1st level bootstrap code stored in the embedded ROM
> + * inside the SoC.
> + *
> + * After power-on, the ROM code (1st level bootstrap code) would load
> + * the 2nd bootstrap code into SRAM without any SDRAM initialization.
> + *
> + * The 2nd bootstrap code would then initialize SDRAM and load the
> + * generic firmware (u-boot/linux) into SDRAM, and finally make
> + * a long-jump to the firmware.
> + *
> + * Which means the SPL design of U-boot would never fit to A360/A369,
> + * since it's usually not possible to alter a embedded ROM code.

Sorry, but I don't see why SPL could not run in SRAM as the 2nd
bootloader in your description; SPL certainly does not try to "alter a
embedded ROM". So, please rewrite the paragraph with the correct reason
why SPL cannot be the 2nd bootloader, e.g., is it

- because the 2nd bootloader is actually in ROM?
- because the SRAM is too small?
- ...

In any case:

> + * And because both the 1st & 2nd level bootstrap code use the private
> + * Faraday Firmware Image Format, it would be better to drop U-boot
> + * image support to simplify the design.

"Drop"? Certainly not. "Introduce a new image format where U-Boot is
prepended with a header defined as follow...", yes -- you can even
make a case that, if SPL cannot be the 2nd bootloader, then SPL is
actually "dropped" for this platform. Please rewrite.

Also: could the whole description and rationale be moved to some
README.* file either arch/arm/cpu/faraday or in doc/ so that readers
oof the C file can see the start of the actual code without having to
scroll through hundreds of comment lines?

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images
  2013-09-14 10:28     ` Albert ARIBAUD
@ 2013-10-02  0:53       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-10-02  0:53 UTC (permalink / raw)
  To: u-boot

2013/9/14 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Mon, 29 Jul 2013 13:51:51 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> + * At the time of writting, none of Faraday NAND & SPI controllers
>> + * supports XIP (eXecute In Place). So the Faraday A360/A369 SoC has
>> + * to implement a 1st level bootstrap code stored in the embedded ROM
>> + * inside the SoC.
>> + *
>> + * After power-on, the ROM code (1st level bootstrap code) would load
>> + * the 2nd bootstrap code into SRAM without any SDRAM initialization.
>> + *
>> + * The 2nd bootstrap code would then initialize SDRAM and load the
>> + * generic firmware (u-boot/linux) into SDRAM, and finally make
>> + * a long-jump to the firmware.
>> + *
>> + * Which means the SPL design of U-boot would never fit to A360/A369,
>> + * since it's usually not possible to alter a embedded ROM code.
>
> Sorry, but I don't see why SPL could not run in SRAM as the 2nd
> bootloader in your description; SPL certainly does not try to "alter a
> embedded ROM". So, please rewrite the paragraph with the correct reason
> why SPL cannot be the 2nd bootloader, e.g., is it
>
> - because the 2nd bootloader is actually in ROM?
> - because the SRAM is too small?
> - ...
>
> In any case:
>

Got it, thanks.
I'll try to study the SPL again, and rewrite the paragraph.

>> + * And because both the 1st & 2nd level bootstrap code use the private
>> + * Faraday Firmware Image Format, it would be better to drop U-boot
>> + * image support to simplify the design.
>
> "Drop"? Certainly not. "Introduce a new image format where U-Boot is
> prepended with a header defined as follow...", yes -- you can even
> make a case that, if SPL cannot be the 2nd bootloader, then SPL is
> actually "dropped" for this platform. Please rewrite.
>

Got it, thanks

> Also: could the whole description and rationale be moved to some
> README.* file either arch/arm/cpu/faraday or in doc/ so that readers
> oof the C file can see the start of the actual code without having to
> scroll through hundreds of comment lines?
>

Got it, thanks

> Amicalement,
> --
> Albert.



-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI controller support
  2013-08-12  0:37             ` Kuo-Jung Su
@ 2013-10-03 19:53               ` Jagan Teki
  0 siblings, 0 replies; 311+ messages in thread
From: Jagan Teki @ 2013-10-03 19:53 UTC (permalink / raw)
  To: u-boot

Any update on this.

On Mon, Aug 12, 2013 at 6:07 AM, Kuo-Jung Su <dantesu@gmail.com> wrote:
>>
>> Please see the comments on below patch
>> http://patchwork.ozlabs.org/patch/265683/
>>
>> --
>
> Got it, thanks
>
>
> --
> Best wishes,
> Kuo-Jung Su



-- 
Thanks,
Jagan.
--------
Jagannadha Sutradharudu Teki,
E: jagannadh.teki at gmail.com, P: +91-9676773388
Engineer - System Software Hacker
U-boot - SPI Custodian and Zynq APSOC
Ln: http://www.linkedin.com/in/jaganteki

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

* [U-Boot] [PATCH v5] spi: ftssp010_spi: add Faraday SPI controller support
  2013-05-07  6:34           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  2013-06-12 18:56             ` [U-Boot] [U-Boot, " Jagan Teki
@ 2013-11-22  7:44             ` Kuo-Jung Su
  2013-11-28  2:46             ` [U-Boot] [PATCH v6] " Kuo-Jung Su
  2 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-11-22  7:44 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FTSSP010 is a multi-function controller
which supports I2S/SPI/SSP/AC97/SPDIF. However This
patch implements only the SPI mode.

NOTE:
The DMA and CS/Clock control logic has been altered
since hardware revision 1.19.0. So this patch
would first detects the revision id of the underlying
chip, and then switch to the corresponding software
control routines.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Jagan Teki <jagannadh.teki@gmail.com>
CC: Tom Rini <trini@ti.com>
---
Changes for v5:
   - Use SPDX-License-Identifier
   - Add SPI mode checking & setup
   - Coding Style cleanup

Changes for v4:
   - Coding Style cleanup.
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 drivers/spi/Makefile       |    1 +
 drivers/spi/ftssp010_spi.c |  513 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 514 insertions(+)
 create mode 100644 drivers/spi/ftssp010_spi.c

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 27902fe..ccc8f2f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_CF_SPI) += cf_spi.o
 obj-$(CONFIG_CF_QSPI) += cf_qspi.o
 obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
 obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
+obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
 obj-$(CONFIG_ICH_SPI) +=  ich.o
 obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
 obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
new file mode 100644
index 0000000..b9273a3
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.c
@@ -0,0 +1,513 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+
+#ifndef CONFIG_FTSSP010_BASE_LIST
+#define CONFIG_FTSSP010_BASE_LIST   { CONFIG_FTSSP010_BASE }
+#endif
+
+#ifndef CONFIG_FTSSP010_GPIO_BASE
+#define CONFIG_FTSSP010_GPIO_BASE   0
+#endif
+
+#ifndef CONFIG_FTSSP010_GPIO_LIST
+#define CONFIG_FTSSP010_GPIO_LIST   { CONFIG_FTSSP010_GPIO_BASE }
+#endif
+
+#ifndef CONFIG_FTSSP010_CLOCK
+#define CONFIG_FTSSP010_CLOCK       clk_get_rate("SSP");
+#endif
+
+#ifndef CONFIG_FTSSP010_TIMEOUT
+#define CONFIG_FTSSP010_TIMEOUT     100
+#endif
+
+/* FTSSP010 chip registers */
+struct ftssp010_regs {
+	uint32_t cr[3];/* control register */
+	uint32_t sr;   /* status register */
+	uint32_t icr;  /* interrupt control register */
+	uint32_t isr;  /* interrupt status register */
+	uint32_t dr;   /* data register */
+	uint32_t rsvd[17];
+	uint32_t revr; /* revision register */
+	uint32_t fear; /* feature register */
+};
+
+/* Control Register 0  */
+#define CR0_FFMT_MASK       (7 << 12)
+#define CR0_FFMT_SSP        (0 << 12)
+#define CR0_FFMT_SPI        (1 << 12)
+#define CR0_FFMT_MICROWIRE  (2 << 12)
+#define CR0_FFMT_I2S        (3 << 12)
+#define CR0_FFMT_AC97       (4 << 12)
+#define CR0_FLASH           (1 << 11)
+#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
+#define CR0_LOOP            (1 << 7)  /* loopback mode */
+#define CR0_LSB             (1 << 6)  /* LSB */
+#define CR0_FSPO            (1 << 5)  /* fs atcive low (I2S only) */
+#define CR0_FSJUSTIFY       (1 << 4)
+#define CR0_OPM_SLAVE       (0 << 2)
+#define CR0_OPM_MASTER      (3 << 2)
+#define CR0_OPM_I2S_MSST    (3 << 2)  /* master stereo mode */
+#define CR0_OPM_I2S_MSMO    (2 << 2)  /* master mono mode */
+#define CR0_OPM_I2S_SLST    (1 << 2)  /* slave stereo mode */
+#define CR0_OPM_I2S_SLMO    (0 << 2)  /* slave mono mode */
+#define CR0_SCLKPO          (1 << 1)  /* clock polarity */
+#define CR0_SCLKPH          (1 << 0)  /* clock phase */
+
+/* Control Register 1 */
+#define CR1_PDL(x)   (((x) & 0xff) << 24) /* padding length */
+#define CR1_SDL(x)   ((((x) - 1) & 0x1f) << 16) /* data length */
+#define CR1_DIV(x)   (((x) - 1) & 0xffff) /* clock divider */
+
+/* Control Register 2 */
+#define CR2_CS(x)    (((x) & 3) << 10) /* CS/FS select */
+#define CR2_FS       (1 << 9) /* CS/FS signal level */
+#define CR2_TXEN     (1 << 8) /* tx enable */
+#define CR2_RXEN     (1 << 7) /* rx enable */
+#define CR2_RESET    (1 << 6) /* chip reset */
+#define CR2_TXFC     (1 << 3) /* tx fifo Clear */
+#define CR2_RXFC     (1 << 2) /* rx fifo Clear */
+#define CR2_TXDOE    (1 << 1) /* tx data output enable */
+#define CR2_EN       (1 << 0) /* chip enable */
+
+/* Status Register */
+#define SR_RFF       (1 << 0) /* rx fifo full */
+#define SR_TFNF      (1 << 1) /* tx fifo not full */
+#define SR_BUSY      (1 << 2) /* chip busy */
+#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* rx fifo valid entries */
+#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* tx fifo valid entries */
+
+/* Feature Register */
+#define FEAR_BITS(reg)   ((((reg) >>  0) & 0xff) + 1) /* data width */
+#define FEAR_RFSZ(reg)   ((((reg) >>  8) & 0xff) + 1) /* rx fifo size */
+#define FEAR_TFSZ(reg)   ((((reg) >> 16) & 0xff) + 1) /* tx fifo size */
+#define FEAR_AC97        (1 << 24)
+#define FEAR_I2S         (1 << 25)
+#define FEAR_SPI_MWR     (1 << 26)
+#define FEAR_SSP         (1 << 27)
+#define FEAR_SPDIF       (1 << 28)
+
+/* FTGPIO010 chip registers */
+struct ftgpio010_regs {
+	uint32_t out;     /* 0x00: Data Output */
+	uint32_t in;      /* 0x04: Data Input */
+	uint32_t dir;     /* 0x08: Direction */
+	uint32_t bypass;  /* 0x0c: Bypass */
+	uint32_t set;     /* 0x10: Data Set */
+	uint32_t clr;     /* 0x14: Data Clear */
+	uint32_t pull_up; /* 0x18: Pull-Up Enabled */
+	uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */
+};
+
+struct ftssp010_gpio {
+	struct ftgpio010_regs *regs;
+	uint32_t pin;
+};
+
+struct ftssp010_spi {
+	struct spi_slave slave;
+	struct ftssp010_gpio gpio;
+	struct ftssp010_regs *regs;
+	uint32_t fifo;
+	uint32_t mode;
+	uint32_t div;
+	uint32_t clk;
+	uint32_t speed;
+	uint32_t revision;
+};
+
+static inline struct ftssp010_spi *to_ftssp010_spi(struct spi_slave *slave)
+{
+	return container_of(slave, struct ftssp010_spi, slave);
+}
+
+static inline int get_spi_chip(int bus, struct ftssp010_spi *chip)
+{
+	uint32_t fear, base[] = CONFIG_FTSSP010_BASE_LIST;
+
+	if (bus >= ARRAY_SIZE(base) || !base[bus])
+		return -1;
+
+	chip->regs = (struct ftssp010_regs *)base[bus];
+
+	chip->revision = readl(&chip->regs->revr);
+
+	fear = readl(&chip->regs->fear);
+	chip->fifo = min_t(uint32_t, FEAR_TFSZ(fear), FEAR_RFSZ(fear));
+
+	return 0;
+}
+
+static inline int get_spi_gpio(int bus, struct ftssp010_gpio *chip)
+{
+	uint32_t base[] = CONFIG_FTSSP010_GPIO_LIST;
+
+	if (bus >= ARRAY_SIZE(base) || !base[bus])
+		return -1;
+
+	chip->regs = (struct ftgpio010_regs *)(base[bus] & 0xfff00000);
+	chip->pin = base[bus] & 0x1f;
+
+	/* make it an output pin */
+	setbits_le32(&chip->regs->dir, 1 << chip->pin);
+
+	return 0;
+}
+
+static inline int ftssp010_wait(struct ftssp010_spi *chip)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	int ret = -1;
+	ulong t;
+
+	/* wait until device idle */
+	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_BUSY)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		puts("ftspi010: busy timeout\n");
+
+	return ret;
+}
+
+static inline int ftssp010_wait_tx(struct ftssp010_spi *chip)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	int ret = -1;
+	ulong t;
+
+	/* wait until tx fifo not full */
+	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
+		if (!(readl(&regs->sr) & SR_TFNF))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		puts("ftssp010: tx timeout\n");
+
+	return ret;
+}
+
+static inline int ftssp010_wait_rx(struct ftssp010_spi *chip)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	int ret = -1;
+	ulong t;
+
+	/* wait until rx fifo not empty */
+	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
+		if (!SR_RFVE(readl(&regs->sr)))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		puts("ftssp010: rx timeout\n");
+
+	return ret;
+}
+
+static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t xmsk = 0;
+
+		if (tx_buf) {
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_tx(chip);
+				writel(*txb++, &regs->dr);
+			}
+			xmsk |= CR2_TXEN | CR2_TXDOE;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+		}
+		if (rx_buf) {
+			xmsk |= CR2_RXEN;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_rx(chip);
+				*rxb++ = (uint8_t)readl(&regs->dr);
+			}
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static int ftssp010_spi_work_transfer_v1(struct ftssp010_spi *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t tmp;
+
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_tx(chip);
+			writel(txb ? (*txb++) : 0, &regs->dr);
+		}
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_rx(chip);
+			tmp = readl(&regs->dr);
+			if (rxb)
+				*rxb++ = (uint8_t)tmp;
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static void ftssp010_cs_set(struct ftssp010_spi *chip, int high)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	struct ftssp010_gpio *gpio = &chip->gpio;
+
+	if (high) {
+		/* cs pull high */
+		if (chip->revision >= 0x11900) {
+			writel(CR2_CS(chip->slave.cs) | CR2_FS,
+				&regs->cr[2]);
+		} else if (gpio->regs) {
+			writel(1 << gpio->pin, &gpio->regs->set);
+		}
+	} else {
+		/* cs pull low */
+		if (chip->revision >= 0x11900) {
+			writel(CR2_CS(chip->slave.cs) | CR2_EN |
+				CR2_TXFC | CR2_RXFC, &regs->cr[2]);
+		} else if (gpio->regs) {
+			writel(1 << gpio->pin, &gpio->regs->clr);
+		}
+	}
+
+	/* extra delay for signal propagation */
+	udelay_masked(1);
+}
+
+/*
+ * Determine if a SPI chipselect is valid.
+ * This function is provided by the board if the low-level SPI driver
+ * needs it to determine if a given chipselect is actually valid.
+ *
+ * Returns: 1 if bus:cs identifies a valid chip on this board, 0
+ * otherwise.
+ */
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	struct ftssp010_spi chip;
+
+	if (get_spi_chip(bus, &chip))
+		return 0;
+
+	if (!cs)
+		return 1;
+	else if ((cs < 4) && (chip.revision >= 0x11900))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Activate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should activate the chip select
+ * to the device identified by "slave".
+ */
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+
+	/* cs pull */
+	if (chip->mode & SPI_CS_HIGH)
+		ftssp010_cs_set(chip, 1);
+	else
+		ftssp010_cs_set(chip, 0);
+}
+
+/*
+ * Deactivate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should deactivate the chip
+ * select to the device identified by "slave".
+ */
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+
+	/* wait until chip idle */
+	ftssp010_wait(chip);
+
+	/* cs pull */
+	if (chip->mode & SPI_CS_HIGH)
+		ftssp010_cs_set(chip, 0);
+	else
+		ftssp010_cs_set(chip, 1);
+}
+
+void spi_init(void)
+{
+	/* nothing to do */
+}
+
+struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
+{
+	struct ftssp010_spi *chip;
+
+	if (mode & SPI_3WIRE) {
+		puts("ftssp010: can't do 3-wire\n");
+		return NULL;
+	}
+
+	if (mode & SPI_SLAVE) {
+		puts("ftssp010: can't do slave mode\n");
+		return NULL;
+	}
+
+	if (mode & SPI_PREAMBLE) {
+		puts("ftssp010: can't skip preamble bytes\n");
+		return NULL;
+	}
+
+	if (!spi_cs_is_valid(bus, cs)) {
+		puts("ftssp010: invalid (bus, cs)\n");
+		return NULL;
+	}
+
+	chip = spi_alloc_slave(struct ftssp010_spi, bus, cs);
+	if (!chip)
+		return NULL;
+
+	if (get_spi_chip(bus, chip))
+		goto free_out;
+
+	if (chip->revision < 0x11900 && get_spi_gpio(bus, &chip->gpio)) {
+		puts("ftssp010: "
+		"Before revision 1.19.0, its clock & cs are controlled\n"
+		"by tx engine which is not synced with rx engine,\n"
+		"so the clock & cs might be shutdown before rx engine\n"
+		"finishs its jobs.\n"
+		"If possible, please add a dedicated gpio for it.\n");
+	}
+
+	chip->mode = mode;
+	chip->clk = CONFIG_FTSSP010_CLOCK;
+	chip->div = 2;
+	if (max_hz) {
+		while (chip->div < 0xffff) {
+			if ((chip->clk / (2 * chip->div)) <= max_hz)
+				break;
+			chip->div += 1;
+		}
+	}
+	chip->speed = chip->clk / (2 * chip->div);
+
+	return &chip->slave;
+
+free_out:
+	free(chip);
+	return NULL;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+	struct ftssp010_regs *regs = chip->regs;
+
+	writel(CR1_SDL(8) | CR1_DIV(chip->div), &regs->cr[1]);
+
+	if (chip->revision >= 0x11900) {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
+			&regs->cr[0]);
+		writel(CR2_TXFC | CR2_RXFC,
+			&regs->cr[2]);
+	} else {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
+			&regs->cr[0]);
+		writel(CR2_TXFC | CR2_RXFC | CR2_EN | CR2_TXDOE,
+			&regs->cr[2]);
+	}
+
+	if (chip->mode & SPI_LOOP)
+		setbits_le32(&regs->cr[0], CR0_LOOP);
+
+	if (chip->mode & SPI_LSB_FIRST)
+		setbits_le32(&regs->cr[0], CR0_LSB);
+
+	if (chip->mode & SPI_CPOL)
+		setbits_le32(&regs->cr[0], CR0_SCLKPO);
+
+	if (chip->mode & SPI_CPHA)
+		setbits_le32(&regs->cr[0], CR0_SCLKPH);
+
+	spi_cs_deactivate(slave);
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+	struct ftssp010_regs *regs = chip->regs;
+
+	writel(0, &regs->cr[2]);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+			 const void *dout, void *din, unsigned long flags)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+	uint32_t len = bitlen >> 3;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(slave);
+
+	if (chip->revision >= 0x11900)
+		ftssp010_spi_work_transfer_v2(chip, dout, din, len, flags);
+	else
+		ftssp010_spi_work_transfer_v1(chip, dout, din, len, flags);
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(slave);
+
+	return 0;
+}
--
1.7.9.5

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

* [U-Boot] [PATCH v6] spi: ftssp010_spi: add Faraday SPI controller support
  2013-05-07  6:34           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
  2013-06-12 18:56             ` [U-Boot] [U-Boot, " Jagan Teki
  2013-11-22  7:44             ` [U-Boot] [PATCH v5] spi: ftssp010_spi: add Faraday " Kuo-Jung Su
@ 2013-11-28  2:46             ` Kuo-Jung Su
  2 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-11-28  2:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The Faraday FTSSP010 is a multi-function controller
which supports I2S/SPI/SSP/AC97/SPDIF. However This
patch implements only the SPI mode.

NOTE:
The DMA and CS/Clock control logic has been altered
since hardware revision 1.19.0. So this patch
would first detects the revision id of the underlying
chip, and then switch to the corresponding software
control routines.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Jagan Teki <jagannadh.teki@gmail.com>
CC: Tom Rini <trini@ti.com>
---
Changes for v6:
   - Drop SPI_LSB_FIRST support, because this driver
     supports only 8-bit mode access.
   - Bug fix: Move chip enable from ftssp010_cs_set()
     to spi_cs_activate(), because ftssp010_cs_set()
     is supposed to update only the cs signal.

Changes for v5:
   - Use SPDX-License-Identifier
   - Add SPI mode checking & setup
   - Coding Style cleanup

Changes for v4:
   - Coding Style cleanup.
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
 drivers/spi/Makefile       |    1 +
 drivers/spi/ftssp010_spi.c |  509 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 510 insertions(+)
 create mode 100644 drivers/spi/ftssp010_spi.c

diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 27902fe..ccc8f2f 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_CF_SPI) += cf_spi.o
 obj-$(CONFIG_CF_QSPI) += cf_qspi.o
 obj-$(CONFIG_DAVINCI_SPI) += davinci_spi.o
 obj-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
+obj-$(CONFIG_FTSSP010_SPI) += ftssp010_spi.o
 obj-$(CONFIG_ICH_SPI) +=  ich.o
 obj-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
 obj-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
new file mode 100644
index 0000000..cf37053
--- /dev/null
+++ b/drivers/spi/ftssp010_spi.c
@@ -0,0 +1,509 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/compat.h>
+#include <asm/io.h>
+#include <malloc.h>
+#include <spi.h>
+
+#ifndef CONFIG_FTSSP010_BASE_LIST
+#define CONFIG_FTSSP010_BASE_LIST   { CONFIG_FTSSP010_BASE }
+#endif
+
+#ifndef CONFIG_FTSSP010_GPIO_BASE
+#define CONFIG_FTSSP010_GPIO_BASE   0
+#endif
+
+#ifndef CONFIG_FTSSP010_GPIO_LIST
+#define CONFIG_FTSSP010_GPIO_LIST   { CONFIG_FTSSP010_GPIO_BASE }
+#endif
+
+#ifndef CONFIG_FTSSP010_CLOCK
+#define CONFIG_FTSSP010_CLOCK       clk_get_rate("SSP");
+#endif
+
+#ifndef CONFIG_FTSSP010_TIMEOUT
+#define CONFIG_FTSSP010_TIMEOUT     100
+#endif
+
+/* FTSSP010 chip registers */
+struct ftssp010_regs {
+	uint32_t cr[3];/* control register */
+	uint32_t sr;   /* status register */
+	uint32_t icr;  /* interrupt control register */
+	uint32_t isr;  /* interrupt status register */
+	uint32_t dr;   /* data register */
+	uint32_t rsvd[17];
+	uint32_t revr; /* revision register */
+	uint32_t fear; /* feature register */
+};
+
+/* Control Register 0  */
+#define CR0_FFMT_MASK       (7 << 12)
+#define CR0_FFMT_SSP        (0 << 12)
+#define CR0_FFMT_SPI        (1 << 12)
+#define CR0_FFMT_MICROWIRE  (2 << 12)
+#define CR0_FFMT_I2S        (3 << 12)
+#define CR0_FFMT_AC97       (4 << 12)
+#define CR0_FLASH           (1 << 11)
+#define CR0_FSDIST(x)       (((x) & 0x03) << 8)
+#define CR0_LOOP            (1 << 7)  /* loopback mode */
+#define CR0_LSB             (1 << 6)  /* LSB */
+#define CR0_FSPO            (1 << 5)  /* fs atcive low (I2S only) */
+#define CR0_FSJUSTIFY       (1 << 4)
+#define CR0_OPM_SLAVE       (0 << 2)
+#define CR0_OPM_MASTER      (3 << 2)
+#define CR0_OPM_I2S_MSST    (3 << 2)  /* master stereo mode */
+#define CR0_OPM_I2S_MSMO    (2 << 2)  /* master mono mode */
+#define CR0_OPM_I2S_SLST    (1 << 2)  /* slave stereo mode */
+#define CR0_OPM_I2S_SLMO    (0 << 2)  /* slave mono mode */
+#define CR0_SCLKPO          (1 << 1)  /* clock polarity */
+#define CR0_SCLKPH          (1 << 0)  /* clock phase */
+
+/* Control Register 1 */
+#define CR1_PDL(x)   (((x) & 0xff) << 24) /* padding length */
+#define CR1_SDL(x)   ((((x) - 1) & 0x1f) << 16) /* data length */
+#define CR1_DIV(x)   (((x) - 1) & 0xffff) /* clock divider */
+
+/* Control Register 2 */
+#define CR2_CS(x)    (((x) & 3) << 10) /* CS/FS select */
+#define CR2_FS       (1 << 9) /* CS/FS signal level */
+#define CR2_TXEN     (1 << 8) /* tx enable */
+#define CR2_RXEN     (1 << 7) /* rx enable */
+#define CR2_RESET    (1 << 6) /* chip reset */
+#define CR2_TXFC     (1 << 3) /* tx fifo Clear */
+#define CR2_RXFC     (1 << 2) /* rx fifo Clear */
+#define CR2_TXDOE    (1 << 1) /* tx data output enable */
+#define CR2_EN       (1 << 0) /* chip enable */
+
+/* Status Register */
+#define SR_RFF       (1 << 0) /* rx fifo full */
+#define SR_TFNF      (1 << 1) /* tx fifo not full */
+#define SR_BUSY      (1 << 2) /* chip busy */
+#define SR_RFVE(reg) (((reg) >> 4) & 0x1f)  /* rx fifo valid entries */
+#define SR_TFVE(reg) (((reg) >> 12) & 0x1f) /* tx fifo valid entries */
+
+/* Feature Register */
+#define FEAR_BITS(reg)   ((((reg) >>  0) & 0xff) + 1) /* data width */
+#define FEAR_RFSZ(reg)   ((((reg) >>  8) & 0xff) + 1) /* rx fifo size */
+#define FEAR_TFSZ(reg)   ((((reg) >> 16) & 0xff) + 1) /* tx fifo size */
+#define FEAR_AC97        (1 << 24)
+#define FEAR_I2S         (1 << 25)
+#define FEAR_SPI_MWR     (1 << 26)
+#define FEAR_SSP         (1 << 27)
+#define FEAR_SPDIF       (1 << 28)
+
+/* FTGPIO010 chip registers */
+struct ftgpio010_regs {
+	uint32_t out;     /* 0x00: Data Output */
+	uint32_t in;      /* 0x04: Data Input */
+	uint32_t dir;     /* 0x08: Direction */
+	uint32_t bypass;  /* 0x0c: Bypass */
+	uint32_t set;     /* 0x10: Data Set */
+	uint32_t clr;     /* 0x14: Data Clear */
+	uint32_t pull_up; /* 0x18: Pull-Up Enabled */
+	uint32_t pull_st; /* 0x1c: Pull State (0=pull-down, 1=pull-up) */
+};
+
+struct ftssp010_gpio {
+	struct ftgpio010_regs *regs;
+	uint32_t pin;
+};
+
+struct ftssp010_spi {
+	struct spi_slave slave;
+	struct ftssp010_gpio gpio;
+	struct ftssp010_regs *regs;
+	uint32_t fifo;
+	uint32_t mode;
+	uint32_t div;
+	uint32_t clk;
+	uint32_t speed;
+	uint32_t revision;
+};
+
+static inline struct ftssp010_spi *to_ftssp010_spi(struct spi_slave *slave)
+{
+	return container_of(slave, struct ftssp010_spi, slave);
+}
+
+static inline int get_spi_chip(int bus, struct ftssp010_spi *chip)
+{
+	uint32_t fear, base[] = CONFIG_FTSSP010_BASE_LIST;
+
+	if (bus >= ARRAY_SIZE(base) || !base[bus])
+		return -1;
+
+	chip->regs = (struct ftssp010_regs *)base[bus];
+
+	chip->revision = readl(&chip->regs->revr);
+
+	fear = readl(&chip->regs->fear);
+	chip->fifo = min_t(uint32_t, FEAR_TFSZ(fear), FEAR_RFSZ(fear));
+
+	return 0;
+}
+
+static inline int get_spi_gpio(int bus, struct ftssp010_gpio *chip)
+{
+	uint32_t base[] = CONFIG_FTSSP010_GPIO_LIST;
+
+	if (bus >= ARRAY_SIZE(base) || !base[bus])
+		return -1;
+
+	chip->regs = (struct ftgpio010_regs *)(base[bus] & 0xfff00000);
+	chip->pin = base[bus] & 0x1f;
+
+	/* make it an output pin */
+	setbits_le32(&chip->regs->dir, 1 << chip->pin);
+
+	return 0;
+}
+
+static inline int ftssp010_wait(struct ftssp010_spi *chip)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	int ret = -1;
+	ulong t;
+
+	/* wait until device idle */
+	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_BUSY)
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		puts("ftspi010: busy timeout\n");
+
+	return ret;
+}
+
+static inline int ftssp010_wait_tx(struct ftssp010_spi *chip)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	int ret = -1;
+	ulong t;
+
+	/* wait until tx fifo not full */
+	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
+		if (!(readl(&regs->sr) & SR_TFNF))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		puts("ftssp010: tx timeout\n");
+
+	return ret;
+}
+
+static inline int ftssp010_wait_rx(struct ftssp010_spi *chip)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	int ret = -1;
+	ulong t;
+
+	/* wait until rx fifo not empty */
+	for (t = get_timer(0); get_timer(t) < CONFIG_FTSSP010_TIMEOUT; ) {
+		if (!SR_RFVE(readl(&regs->sr)))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		puts("ftssp010: rx timeout\n");
+
+	return ret;
+}
+
+static int ftssp010_spi_work_transfer_v2(struct ftssp010_spi *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t xmsk = 0;
+
+		if (tx_buf) {
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_tx(chip);
+				writel(*txb++, &regs->dr);
+			}
+			xmsk |= CR2_TXEN | CR2_TXDOE;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+		}
+		if (rx_buf) {
+			xmsk |= CR2_RXEN;
+			if ((readl(&regs->cr[2]) & xmsk) != xmsk)
+				setbits_le32(&regs->cr[2], xmsk);
+			for (i = 0; i < depth; ++i) {
+				ftssp010_wait_rx(chip);
+				*rxb++ = (uint8_t)readl(&regs->dr);
+			}
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static int ftssp010_spi_work_transfer_v1(struct ftssp010_spi *chip,
+	const void *tx_buf, void *rx_buf, int len, uint flags)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	const uint8_t *txb = tx_buf;
+	uint8_t       *rxb = rx_buf;
+
+	while (len > 0) {
+		int i, depth = min(chip->fifo >> 2, len);
+		uint32_t tmp;
+
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_tx(chip);
+			writel(txb ? (*txb++) : 0, &regs->dr);
+		}
+		for (i = 0; i < depth; ++i) {
+			ftssp010_wait_rx(chip);
+			tmp = readl(&regs->dr);
+			if (rxb)
+				*rxb++ = (uint8_t)tmp;
+		}
+
+		len -= depth;
+	}
+
+	return 0;
+}
+
+static void ftssp010_cs_set(struct ftssp010_spi *chip, int high)
+{
+	struct ftssp010_regs *regs = chip->regs;
+	struct ftssp010_gpio *gpio = &chip->gpio;
+	uint32_t mask;
+
+	/* cs pull high/low */
+	if (chip->revision >= 0x11900) {
+		mask = CR2_CS(chip->slave.cs) | (high ? CR2_FS : 0);
+		writel(mask, &regs->cr[2]);
+	} else if (gpio->regs) {
+		mask = 1 << gpio->pin;
+		if (high)
+			writel(mask, &gpio->regs->set);
+		else
+			writel(mask, &gpio->regs->clr);
+	}
+
+	/* extra delay for signal propagation */
+	udelay_masked(1);
+}
+
+/*
+ * Determine if a SPI chipselect is valid.
+ * This function is provided by the board if the low-level SPI driver
+ * needs it to determine if a given chipselect is actually valid.
+ *
+ * Returns: 1 if bus:cs identifies a valid chip on this board, 0
+ * otherwise.
+ */
+int spi_cs_is_valid(unsigned int bus, unsigned int cs)
+{
+	struct ftssp010_spi chip;
+
+	if (get_spi_chip(bus, &chip))
+		return 0;
+
+	if (!cs)
+		return 1;
+	else if ((cs < 4) && (chip.revision >= 0x11900))
+		return 1;
+
+	return 0;
+}
+
+/*
+ * Activate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should activate the chip select
+ * to the device identified by "slave".
+ */
+void spi_cs_activate(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+	struct ftssp010_regs *regs = chip->regs;
+
+	/* cs pull */
+	if (chip->mode & SPI_CS_HIGH)
+		ftssp010_cs_set(chip, 1);
+	else
+		ftssp010_cs_set(chip, 0);
+
+	/* chip enable + fifo clear */
+	setbits_le32(&regs->cr[2], CR2_EN | CR2_TXFC | CR2_RXFC);
+}
+
+/*
+ * Deactivate a SPI chipselect.
+ * This function is provided by the board code when using a driver
+ * that can't control its chipselects automatically (e.g.
+ * common/soft_spi.c). When called, it should deactivate the chip
+ * select to the device identified by "slave".
+ */
+void spi_cs_deactivate(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+
+	/* wait until chip idle */
+	ftssp010_wait(chip);
+
+	/* cs pull */
+	if (chip->mode & SPI_CS_HIGH)
+		ftssp010_cs_set(chip, 0);
+	else
+		ftssp010_cs_set(chip, 1);
+}
+
+void spi_init(void)
+{
+	/* nothing to do */
+}
+
+struct spi_slave *spi_setup_slave(uint bus, uint cs, uint max_hz, uint mode)
+{
+	struct ftssp010_spi *chip;
+
+	if (mode & SPI_3WIRE) {
+		puts("ftssp010: can't do 3-wire\n");
+		return NULL;
+	}
+
+	if (mode & SPI_SLAVE) {
+		puts("ftssp010: can't do slave mode\n");
+		return NULL;
+	}
+
+	if (mode & SPI_PREAMBLE) {
+		puts("ftssp010: can't skip preamble bytes\n");
+		return NULL;
+	}
+
+	if (!spi_cs_is_valid(bus, cs)) {
+		puts("ftssp010: invalid (bus, cs)\n");
+		return NULL;
+	}
+
+	chip = spi_alloc_slave(struct ftssp010_spi, bus, cs);
+	if (!chip)
+		return NULL;
+
+	if (get_spi_chip(bus, chip))
+		goto free_out;
+
+	if (chip->revision < 0x11900 && get_spi_gpio(bus, &chip->gpio)) {
+		puts("ftssp010: "
+		"Before revision 1.19.0, its clock & cs are controlled\n"
+		"by tx engine which is not synced with rx engine,\n"
+		"so the clock & cs might be shutdown before rx engine\n"
+		"finishs its jobs.\n"
+		"If possible, please add a dedicated gpio for it.\n");
+	}
+
+	chip->mode = mode;
+	chip->clk = CONFIG_FTSSP010_CLOCK;
+	chip->div = 2;
+	if (max_hz) {
+		while (chip->div < 0xffff) {
+			if ((chip->clk / (2 * chip->div)) <= max_hz)
+				break;
+			chip->div += 1;
+		}
+	}
+	chip->speed = chip->clk / (2 * chip->div);
+
+	return &chip->slave;
+
+free_out:
+	free(chip);
+	return NULL;
+}
+
+void spi_free_slave(struct spi_slave *slave)
+{
+	free(slave);
+}
+
+int spi_claim_bus(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+	struct ftssp010_regs *regs = chip->regs;
+
+	writel(CR1_SDL(8) | CR1_DIV(chip->div), &regs->cr[1]);
+
+	if (chip->revision >= 0x11900) {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO | CR0_FLASH,
+			&regs->cr[0]);
+		writel(CR2_TXFC | CR2_RXFC,
+			&regs->cr[2]);
+	} else {
+		writel(CR0_OPM_MASTER | CR0_FFMT_SPI | CR0_FSPO,
+			&regs->cr[0]);
+		writel(CR2_TXFC | CR2_RXFC | CR2_EN | CR2_TXDOE,
+			&regs->cr[2]);
+	}
+
+	if (chip->mode & SPI_LOOP)
+		setbits_le32(&regs->cr[0], CR0_LOOP);
+
+	if (chip->mode & SPI_CPOL)
+		setbits_le32(&regs->cr[0], CR0_SCLKPO);
+
+	if (chip->mode & SPI_CPHA)
+		setbits_le32(&regs->cr[0], CR0_SCLKPH);
+
+	spi_cs_deactivate(slave);
+
+	return 0;
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+	struct ftssp010_regs *regs = chip->regs;
+
+	writel(0, &regs->cr[2]);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+			 const void *dout, void *din, unsigned long flags)
+{
+	struct ftssp010_spi *chip = to_ftssp010_spi(slave);
+	uint32_t len = bitlen >> 3;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(slave);
+
+	if (chip->revision >= 0x11900)
+		ftssp010_spi_work_transfer_v2(chip, dout, din, len, flags);
+	else
+		ftssp010_spi_work_transfer_v1(chip, dout, din, len, flags);
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(slave);
+
+	return 0;
+}
--
1.7.9.5

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

* [U-Boot] [PATCH v8] nand: add Faraday FTNANDC021 NAND controller support
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
                     ` (10 preceding siblings ...)
  2013-07-29  5:51   ` [U-Boot] [PATCH v7 11/11] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
@ 2013-11-28  2:48   ` Kuo-Jung Su
  2014-03-04  2:17     ` [U-Boot] [U-Boot, " Scott Wood
  11 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2013-11-28  2:48 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTNANDC021 is an integrated NAND flash controller.
It use a build-in command table to abstract the underlying
NAND flash control logic.

For example:

Issuing a command 0x10 to FTNANDC021 would result in
a page write + a read status operation.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
CC: Scott Wood <scottwood@freescale.com>
---
Changes for v8:
   - Add ftnandc021 spl driver
   - Drop '#include <asm/unaligned.h>'
   - Coding style cleanup
   - Update NAND flash ecc layout
   - Split from Faraday A36x patch series

Changes for v7:
   - ftnandc021.[ch]: Update license to use SPDX identifiers.
   - ftnandc021.c: put_unaligned() -> memcpy()
   - ftnandc021.c: update ecc relatived function prototypes to
     fix compile warnnings.

Changes for v6:
   - Update README for CONFIG_SYS_FTNANDC021_TIMING
   - Remove illegal type-punning by introducing
     put_unaligned() & get_unaligned().

Changes for v5 (Part of A360/A369 patch series):
   - Coding Style cleanup:
     struct chip_regs __iomem *regs -> struct chip_regs *regs
   - For there is a strong dependancy between this and A360/A369 patch
     series, it had been chained back to A360/A369 patch series.
   - The latest nand_base requires the ecc.strength to be set properlly,
     so this patch adds ecc.strength setting accroding to ECC algorithm.

Changes for v5 (Standalone):
   - Update README for the description of CONFIG_SYS_FTNANDC021_TIMING.
   - Drop redundant white space. (i.e. if (mtd->writesize >= ' '4096))

Changes for v4:
   - Make it a separate patch, rather then a part of
     Faraday A36x patch series
   - Drop the faraday/nand.h to remove dependency to
     Faraday A36x patch series.
   - CONFIG_SYS_NAND_TIMING -> CONFIG_SYS_FTNANDC021_TIMING
   - Remove non-ECC code.
   - Implement private hwecc read/write_page functions
     to get rid of .eccpos & .eccbytes.
   - Use macro constants for timeout control

Changes for v3:
   - Coding Style cleanup.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - Re-write this driver with ECC enabled and correct column address
     handling for OOB read/write.
   - Fix issuses addressed by Scott.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().

 README                            |    6 +
 drivers/mtd/nand/Makefile         |    2 +
 drivers/mtd/nand/ftnandc021.c     |  608 +++++++++++++++++++++++++++++++++++++
 drivers/mtd/nand/ftnandc021_spl.c |  203 +++++++++++++
 include/faraday/ftnandc021.h      |  151 +++++++++
 5 files changed, 970 insertions(+)
 create mode 100644 drivers/mtd/nand/ftnandc021.c
 create mode 100644 drivers/mtd/nand/ftnandc021_spl.c
 create mode 100644 include/faraday/ftnandc021.h

diff --git a/README b/README
index 5def773..a8d3039 100644
--- a/README
+++ b/README
@@ -4227,6 +4227,12 @@ Low Level (hardware related) configuration options:
 		- drivers/mtd/nand/ndfc.c
 		- drivers/mtd/nand/mxc_nand.c

+- CONFIG_SYS_FTNANDC021_TIMING
+		This option specifies an array of customized timing parameters
+		for Faraday FTNANDC021 NAND flash controller.
+		e.g.
+		#define CONFIG_SYS_FTNANDC021_TIMING { 0x02240264, 0x42054209 }
+
 - CONFIG_SYS_NDFC_EBC0_CFG
 		Sets the EBC0_CFG register for the NDFC. If not defined
 		a default value will be used.
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index e145cd1..7e6d441 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -45,6 +45,7 @@ obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_nand.o
 obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_nand.o
 obj-$(CONFIG_NAND_FSL_UPM) += fsl_upm.o
 obj-$(CONFIG_NAND_FSMC) += fsmc_nand.o
+obj-$(CONFIG_NAND_FTNANDC021) += ftnandc021.o
 obj-$(CONFIG_NAND_JZ4740) += jz4740_nand.o
 obj-$(CONFIG_NAND_KB9202) += kb9202_nand.o
 obj-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
@@ -66,6 +67,7 @@ else  # minimal SPL drivers

 obj-$(CONFIG_NAND_FSL_ELBC) += fsl_elbc_spl.o
 obj-$(CONFIG_NAND_FSL_IFC) += fsl_ifc_spl.o
+obj-$(CONFIG_NAND_FTNANDC021) += ftnandc021_spl.o
 obj-$(CONFIG_NAND_MXC) += mxc_nand_spl.o

 endif # drivers
diff --git a/drivers/mtd/nand/ftnandc021.c b/drivers/mtd/nand/ftnandc021.c
new file mode 100644
index 0000000..71b1dc3
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021.c
@@ -0,0 +1,608 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <nand.h>
+#include <malloc.h>
+#include <faraday/ftnandc021.h>
+
+#define CFG_CMD_TIMEOUT     200
+
+struct ftnandc021_chip {
+	struct mtd_info *mtd;
+	struct ftnandc021_regs *regs;
+	int col;    /* current column address */
+	int row;    /* current row address/page index */
+	int cmd;    /* current NAND command code */
+};
+
+static struct nand_ecclayout nand_ecclayout = {
+	.oobavail = 3,
+	.oobfree = {
+		{ 9, 3 },
+	},
+};
+
+static struct nand_ecclayout nand_4k_ecclayout = {
+	.oobavail = 7,
+	.oobfree = {
+		{ 9, 7 },
+	},
+};
+
+static int ftnandc021_ckst(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t st = readl(&regs->idr[1]);
+
+	if (st & NAND_STATUS_FAIL)
+		return -EIO;
+
+	if (!(st & NAND_STATUS_READY))
+		return -EBUSY;
+
+	if (!(st & NAND_STATUS_WP))
+		return -EIO;
+
+	return 0;
+}
+
+static int ftnandc021_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int err = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			err = -2;
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			err = 0;
+			break;
+		}
+	}
+
+	switch (err) {
+	case -2:
+		printf("ftnandc021: ecc timeout\n");
+		break;
+	case -1:
+		printf("ftnandc021: cmd timeout\n");
+		break;
+	default:
+		break;
+	}
+
+	return err ? -ETIMEDOUT : 0;
+}
+
+static int ftnandc021_read_page(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+	chip->read_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static int ftnandc021_write_page(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	chip->write_buf(mtd, buf, mtd->writesize);
+	return 0;
+}
+
+static int ftnandc021_read_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+	printf("ftnandc021: read_page_raw is not supported\n");
+	return -EIO;
+}
+
+static int ftnandc021_write_page_raw(struct mtd_info *mtd,
+	struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+	printf("ftnandc021: write_page_raw is not supported\n");
+	return -EIO;
+}
+
+static int ftnandc021_command(struct ftnandc021_chip *priv, uint32_t cmd)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 0;
+
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	switch (cmd) {
+	case FTNANDC021_CMD_RDPG:
+	case FTNANDC021_CMD_WRPG:
+		break;
+	case FTNANDC021_CMD_ERBLK:
+	case FTNANDC021_CMD_WROOB:
+		ret = ftnandc021_wait(priv) || ftnandc021_ckst(priv);
+		break;
+	default:
+		ret = ftnandc021_wait(priv);
+	}
+
+	return ret;
+}
+
+/*
+ * Check hardware register for wait status. Returns 1 if device is ready,
+ * 0 if it is still busy.
+ */
+static int ftnandc021_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = 1;
+
+	if (ftnandc021_wait(priv))
+		ret = 0;
+	else if (!(readl(&regs->sr) & SR_READY))
+		ret = 0;
+
+	return ret;
+}
+
+static int ftnandc021_pio_wait(struct ftnandc021_chip *priv)
+{
+	struct ftnandc021_regs *regs = priv->regs;
+	int ret = -ETIMEDOUT;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (!(readl(&regs->ior) & IOR_READY))
+			continue;
+		ret = 0;
+		break;
+	}
+
+	if (ret)
+		printf("ftnandc021: pio timeout\n");
+
+	return ret;
+}
+
+static void ftnandc021_get_oob(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	memset(buf, 0xff, len);
+
+	/* bad block */
+	buf[chip->badblockpos] = readl(&regs->bbird) & 0xff;
+
+	/* data */
+	tmp = readl(&regs->crcrd);
+	buf[8] = (tmp >> 0) & 0xff;
+	buf[9] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[12] = (tmp >> 16) & 0xff;
+		buf[13] = (tmp >> 24) & 0xff;
+	}
+
+	tmp = readl(&regs->lsnrd);
+	buf[10] = (tmp >> 0) & 0xff;
+	buf[11] = (tmp >> 8) & 0xff;
+	if (mtd->writesize >= 4096) {
+		buf[14] = (tmp >> 16) & 0xff;
+		buf[15] = (tmp >> 24) & 0xff;
+	}
+}
+
+static void ftnandc021_set_oob(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t tmp;
+
+	/* bad block */
+	tmp = buf[chip->badblockpos];
+	writel(tmp, &regs->bbiwr);
+
+	/* use 'W' to mark it as a non-blank page/block */
+	tmp = 'W' | (buf[9] << 8);
+	if (mtd->writesize > 2048)
+		tmp |= (buf[12] << 16) | (buf[13] << 24);
+	writel(tmp, &regs->crcwr);
+
+	tmp = buf[10] | (buf[11] << 8);
+	if (mtd->writesize > 2048)
+		tmp |= (buf[14] << 16) | (buf[15] << 24);
+	writel(tmp, &regs->lsnwr);
+}
+
+static uint8_t ftnandc021_read_byte(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint8_t ret = 0xff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+		if (priv->col < 8) {
+			uint32_t idx = priv->col / 4;
+			uint32_t pos = priv->col & 3;
+			uint32_t tmp = readl(&regs->idr[idx]);
+
+			ret = (uint8_t)(tmp >> (pos << 3));
+			priv->col += 1;
+		}
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint8_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: bad cmd=0x%x in read_byte\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+static uint16_t ftnandc021_read_word(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint16_t ret = 0xffff;
+
+	switch (priv->cmd) {
+	case NAND_CMD_READID:
+		if (priv->col < 8) {
+			uint32_t idx = priv->col / 4;
+			uint32_t pos = priv->col & 3;
+			uint32_t tmp = readl(&regs->idr[idx]);
+
+			ret = (uint16_t)(tmp >> (pos << 3));
+			priv->col += 2;
+		}
+		break;
+	case NAND_CMD_STATUS:
+		ret = (uint16_t)(readl(&regs->idr[1]) & 0xff);
+		break;
+	default:
+		printf("ftnandc021: bad cmd=0x%x in read_word\n",
+			priv->cmd);
+		break;
+	}
+
+	return ret;
+}
+
+/**
+ * Read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void ftnandc021_read_buf(struct mtd_info *mtd,
+	uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t off, val;
+
+	if (priv->col >= mtd->writesize)
+		return;
+
+	if (priv->cmd == NAND_CMD_READOOB)
+		BUG();	/* should never happen */
+
+	/* skip if it's a blank page */
+	if (chip->oob_poi[8] != 'W') {
+		memset(buf, 0xff, len);
+		return;
+	}
+
+	off = 0;
+	while (off < len && priv->col < mtd->writesize) {
+		ftnandc021_pio_wait(priv);
+		val = readl(&regs->dr);
+		memcpy(buf + off, &val, 4);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void ftnandc021_write_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+	uint32_t off, val;
+
+	/*
+	 * FTNANDC021 HW design issues:
+	 *
+	 * 1. OOB data must be set before issuing write command,
+	 *    so it's too late to do it right here
+	 * 2. Only after command issued, the data register
+	 *    could accept data.
+	 */
+	if (priv->col >= mtd->writesize)
+		return;
+
+	for (off = 0; off < len && priv->col < mtd->writesize; ) {
+		ftnandc021_pio_wait(priv);
+		memcpy(&val, buf + off, 4);
+		writel(val, &regs->dr);
+		priv->col += 4;
+		off += 4;
+	}
+
+	ftnandc021_wait(priv);
+}
+
+/**
+ * Verify chip data against buffer
+ * @mtd: MTD device structure
+ * @buf: buffer containing the data to compare
+ * @len: number of bytes to compare
+ */
+static int ftnandc021_verify_buf(struct mtd_info *mtd,
+	const uint8_t *buf, int len)
+{
+	int ret = 0;
+	uint8_t *tmp;
+
+	len = min_t(int, len, mtd->writesize);
+	tmp = malloc(mtd->writesize);
+
+	if (!tmp) {
+		printf("ftnandc021: out of memory\n");
+		return -ENOMEM;
+	} else {
+		ftnandc021_read_buf(mtd, tmp, len);
+		if (memcmp(tmp, buf, len))
+			ret = -EINVAL;
+	}
+
+	free(tmp);
+	return ret;
+}
+
+static void ftnandc021_cmdfunc(struct mtd_info *mtd,
+	unsigned cmd, int col, int page)
+{
+	struct nand_chip *chip = mtd->priv;
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+
+	priv->cmd = cmd;
+	priv->col = col;
+	priv->row = page;
+
+	switch (cmd) {
+	case NAND_CMD_READID:	/* 0x90 */
+		priv->col = 0;
+		ftnandc021_command(priv, FTNANDC021_CMD_RDID);
+		break;
+
+	case NAND_CMD_READOOB:	/* 0x50 */
+		priv->col = mtd->writesize;
+		/* fall-through */
+	case NAND_CMD_READ0:	/* 0x00 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* get oob so that we cound do blank check later */
+		ftnandc021_command(priv, FTNANDC021_CMD_RDOOB);
+		ftnandc021_get_oob(mtd, chip->oob_poi, mtd->oobsize);
+		/* skip if we don't need page data */
+		if (priv->col >= mtd->writesize)
+			break;
+		/* skip if it's a blank page */
+		if (chip->oob_poi[8] != 'W') {
+			debug("ftnandc021: skip page %d\n", page);
+			break;
+		}
+		ftnandc021_command(priv, FTNANDC021_CMD_RDPG);
+		break;
+
+	case NAND_CMD_ERASE1:	/* 0x60 */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		break;
+
+	case NAND_CMD_ERASE2:	/* 0xD0 */
+		ftnandc021_command(priv, FTNANDC021_CMD_ERBLK);
+		break;
+
+	case NAND_CMD_STATUS:	/* 0x70 */
+		ftnandc021_command(priv, FTNANDC021_CMD_RDST);
+		break;
+
+	case NAND_CMD_SEQIN:	/* 0x80 (Write Stage 1.) */
+		writel(page, &regs->pir);
+		writel(1, &regs->pcr);
+		/* OOB data must be set before issuing command */
+		ftnandc021_set_oob(mtd, chip->oob_poi, mtd->oobsize);
+		if (priv->col >= mtd->writesize)
+			ftnandc021_command(priv, FTNANDC021_CMD_WROOB);
+		else
+			ftnandc021_command(priv, FTNANDC021_CMD_WRPG);
+		break;
+
+	case NAND_CMD_PAGEPROG:	/* 0x10 (Write Stage 2.) */
+		/* nothing needs to be done */
+		break;
+
+	case NAND_CMD_RESET:	/* 0xFF */
+		ftnandc021_command(priv, FTNANDC021_CMD_RESET);
+		break;
+
+	default:
+		printf("ftnandc021: unknown cmd=0x%x\n", cmd);
+	}
+}
+
+/**
+ * hardware specific access to control-lines
+ * @mtd: MTD device structure
+ * @cmd: command to device
+ * @ctrl:
+ * NAND_NCE: bit 0 -> don't care
+ * NAND_CLE: bit 1 -> Command Latch
+ * NAND_ALE: bit 2 -> Address Latch
+ *
+ * NOTE: boards may use different bits for these!!
+ */
+static void ftnandc021_hwcontrol(struct mtd_info *mtd,
+	int cmd, unsigned int ctrl)
+{
+	/* nothing needs to be done */
+}
+
+static int ftnandc021_reset(struct nand_chip *chip)
+{
+	struct ftnandc021_chip *priv = chip->priv;
+	struct ftnandc021_regs *regs = priv->regs;
+
+#ifdef CONFIG_SYS_FTNANDC021_TIMING
+	uint32_t timing[] = CONFIG_SYS_FTNANDC021_TIMING;
+
+	writel(timing[0], &regs->atr[0]);
+	writel(timing[1], &regs->atr[1]);
+#endif
+
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	if (chip->options & NAND_BUSWIDTH_16)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* chip reset */
+	writel(SRR_CHIP_RESET | SRR_ECC_EN, &regs->srr);
+	while (readl(&regs->srr) & SRR_CHIP_RESET)
+		/* nothing to do */;
+
+	/* pio mode */
+	writel(0, &regs->bcr);
+
+	/* reset the underlying flash */
+	ftnandc021_command(priv, FTNANDC021_CMD_RESET);
+
+	return 0;
+}
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t mmio)
+{
+	struct mtd_info *mtd = &nand_info[0];
+	struct ftnandc021_chip *priv;
+	struct ftnandc021_regs *regs = (void __iomem *)mmio;
+	uint32_t bk, pg, ac, alen;
+
+	priv = calloc(1, sizeof(struct ftnandc021_chip));
+	if (!priv)
+		return -ENOMEM;
+
+	priv->mtd = mtd;
+	priv->regs = regs;
+
+	chip->priv = priv;
+
+	/* hwcontrol is mandatory */
+	chip->cmd_ctrl   = ftnandc021_hwcontrol;
+	chip->cmdfunc    = ftnandc021_cmdfunc;
+	chip->dev_ready  = ftnandc021_dev_ready;
+	chip->chip_delay = 0;
+
+	chip->read_byte  = ftnandc021_read_byte;
+	chip->read_word  = ftnandc021_read_word;
+	chip->read_buf   = ftnandc021_read_buf;
+	chip->write_buf  = ftnandc021_write_buf;
+	chip->verify_buf = ftnandc021_verify_buf;
+
+	chip->ecc.read_page      = ftnandc021_read_page;
+	chip->ecc.write_page     = ftnandc021_write_page;
+	chip->ecc.read_page_raw  = ftnandc021_read_page_raw;
+	chip->ecc.write_page_raw = ftnandc021_write_page_raw;
+
+	/* hardware reset */
+	if (ftnandc021_reset(chip))
+		return -EINVAL;
+
+	/* Detect NAND chips */
+	if (nand_scan_ident(mtd, CONFIG_SYS_MAX_NAND_DEVICE, NULL))
+		return -ENXIO;
+
+	/* Setup NAND flash parameters */
+	alen = (mtd->writesize < 2048) ? 1 : 2;
+	if (lldiv(mtd->size, mtd->writesize) > 0x10000)
+		alen += 3;
+	else if (lldiv(mtd->size, mtd->writesize) > 0x100)
+		alen += 2;
+	else
+		alen += 1;
+
+	debug("ftnandc021: pg=%dK, bk=%dK, alen=%d\n",
+		mtd->writesize >> 10, mtd->erasesize >> 10, alen);
+
+	/* Sanity checks */
+	switch (mtd->writesize) {
+	case 512:
+	case 2048:
+	case 4096:
+		break;
+	default:
+		printf("ftnandc021: %d bytes per page is not supported\n",
+			mtd->writesize);
+		return -EINVAL;
+	}
+
+	/* Update hardware register */
+	bk = ffs(mtd->erasesize / mtd->writesize) - 5;
+	pg = (mtd->writesize < 2048) ? 0 : (ffs(mtd->writesize) - 11);
+	ac = alen - 3;
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+
+	/* Update ECC parameters */
+	chip->ecc.mode = NAND_ECC_HW;
+	chip->ecc.size = mtd->writesize;
+	chip->ecc.steps = 1;
+	chip->ecc.strength = CFGR_ECC_BITS(readl(&regs->cfgr));
+	if (mtd->writesize > 2048)
+		chip->ecc.layout = &nand_4k_ecclayout;
+	else
+		chip->ecc.layout = &nand_ecclayout;
+
+	/* Finish the scan process */
+	if (nand_scan_tail(mtd))
+		return -ENXIO;
+
+	return 0;
+}
diff --git a/drivers/mtd/nand/ftnandc021_spl.c b/drivers/mtd/nand/ftnandc021_spl.c
new file mode 100644
index 0000000..9f84a98
--- /dev/null
+++ b/drivers/mtd/nand/ftnandc021_spl.c
@@ -0,0 +1,203 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <nand.h>
+#include <spl.h>
+#include <faraday/ftnandc021.h>
+
+#define CFG_CMD_TIMEOUT     200
+
+struct ftnandc021_chip {
+	struct ftnandc021_regs *regs;
+	int bits;
+	int alen;
+	int page_shift;
+	int block_shift;
+};
+
+static struct ftnandc021_chip this_chip = {
+	.regs = (void __iomem *)CONFIG_SYS_NAND_BASE,
+	.bits = 8,
+	.alen = 4,
+	.page_shift = 11,  /* 2KB page */
+	.block_shift = 17, /* 128KB block */
+};
+
+static struct ftnandc021_chip *chip = &this_chip;
+
+static int ftnandc021_wait(void)
+{
+	struct ftnandc021_regs *regs = chip->regs;
+	int ret = -1;
+	ulong ts;
+
+	for (ts = get_timer(0); get_timer(ts) < CFG_CMD_TIMEOUT; ) {
+		if (readl(&regs->sr) & SR_ECC) {
+			ret = -2;
+			break;
+		}
+		if (!(readl(&regs->acr) & ACR_START)) {
+			ret = 0;
+			break;
+		}
+	}
+
+	switch (ret) {
+	case -2:
+		puts("ecc failed\n");
+		break;
+	case -1:
+		puts("cmd timeout\n");
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+static int ftnandc021_command(uint32_t page, uint32_t cmd)
+{
+	struct ftnandc021_regs *regs = chip->regs;
+	int ret = 0;
+
+	writel(1, &regs->pcr);
+	writel(page, &regs->pir);
+	writel(ACR_START | ACR_CMD(cmd), &regs->acr);
+
+	if (cmd != FTNANDC021_CMD_RDPG)
+		ret = ftnandc021_wait();
+
+	return ret;
+}
+
+static int ftnandc021_bad_block(uint32_t off)
+{
+	struct ftnandc021_regs *regs = chip->regs;
+	uint32_t block_mask = (1 << chip->block_shift) - 1;
+	uint32_t page = (off & ~block_mask) >> chip->page_shift;
+
+	if (ftnandc021_command(page, FTNANDC021_CMD_RDOOB))
+		return 1;
+
+	if ((readl(&regs->bbird) & 0xff) != 0xff)
+		return 1;
+
+	return 0;
+}
+
+static void ftnandc021_reset(void)
+{
+	struct ftnandc021_regs *regs = chip->regs;
+	uint32_t bk, pg, ac;
+
+	/* chip reset */
+	writel(SRR_CHIP_RESET | SRR_ECC_EN, &regs->srr);
+	while ((readl(&regs->srr) & SRR_CHIP_RESET))
+		/* nothing to do */;
+	writel(0, &regs->ier);
+	writel(0, &regs->pir);
+	writel(0xff, &regs->bbiwr);
+	writel(0xffffffff, &regs->lsnwr);
+	writel(0xffffffff, &regs->crcwr);
+
+	/* bus width */
+	if (chip->bits > 8)
+		writel(FCR_SWCRC | FCR_IGNCRC | FCR_16BIT, &regs->fcr);
+	else
+		writel(FCR_SWCRC | FCR_IGNCRC, &regs->fcr);
+
+	/* pio mode */
+	writel(0, &regs->bcr);
+
+	/* NAND flash configuration */
+	ac = chip->alen - 3;
+	bk = chip->block_shift - chip->page_shift - 4;
+	pg = (chip->page_shift <= 9) ? 0 : (chip->page_shift - 10);
+	writel(MCR_ME(0) | MCR_32GB | (bk << 16) | (pg << 8) | (ac << 10),
+		&regs->mcr);
+}
+
+/* nand_init() - initialize data to make nand usable by SPL */
+void nand_init(void)
+{
+	struct spl_flash_info *info = &spl_flash;
+
+	chip->alen = info->col_adrc + info->row_adrc;
+	chip->bits = info->bits;
+	chip->page_shift = info->pg_shift;
+	chip->block_shift = info->bk_shift;
+
+	ftnandc021_reset();
+}
+
+/* Unselect after operation */
+void nand_deselect(void)
+{
+	ftnandc021_reset();
+}
+
+int nand_spl_load_image(uint32_t off, unsigned int len, void *dst)
+{
+	struct ftnandc021_regs *regs = chip->regs;
+	uint32_t page_mask = (1 << chip->page_shift) - 1;
+	uint32_t block_mask = (1 << chip->block_shift) - 1;
+	uint32_t i, w;
+	uint8_t *pw = (uint8_t *)&w;
+	uint8_t *buf = dst;
+
+	if ((off & page_mask) || (len & 3)) {
+		puts("nand: bad offset or length\n");
+		return -1;
+	}
+
+	while (len > 0) {
+		/* skip bad block */
+		if (ftnandc021_bad_block(off)) {
+			off += 1 << chip->block_shift;
+			continue;
+		}
+		/* block read */
+		do {
+			/* page read */
+			if (ftnandc021_command(
+				off >> chip->page_shift, FTNANDC021_CMD_RDPG))
+				return -1;
+
+			for (i = 0; i < (1 << chip->page_shift); i += 4) {
+				/* pio wait */
+				while (!(readl(&regs->ior) & 1))
+					;
+				/* pio read */
+				w = readl(&regs->dr);
+				if (len > 0) {
+					/* alignment safe */
+					buf[0] = pw[0];
+					buf[1] = pw[1];
+					buf[2] = pw[2];
+					buf[3] = pw[3];
+					/* advance the pointer */
+					buf += 4;
+					len -= 4;
+				}
+			}
+
+			/* wait until command finished */
+			if (ftnandc021_wait())
+				return -1;
+
+			off += 1 << chip->page_shift;
+
+		} while (len > 0 && (off & block_mask));
+	}
+
+	return 0;
+}
diff --git a/include/faraday/ftnandc021.h b/include/faraday/ftnandc021.h
new file mode 100644
index 0000000..2caebb6
--- /dev/null
+++ b/include/faraday/ftnandc021.h
@@ -0,0 +1,151 @@
+/*
+ * Faraday NAND Flash Controller
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __FTNANDC021_H
+#define __FTNANDC021_H
+
+/* NANDC control registers */
+struct ftnandc021_regs {
+	/* 0x000 ~ 0x0fc */
+	uint32_t ecc_pr[4];/* ECC Parity Register */
+	uint32_t ecc_sr;   /* ECC Status Register */
+	uint32_t rsvd0[59];
+
+	/* 0x100 ~ 0x1fc */
+	uint32_t sr;	 /* Status Register */
+	uint32_t acr;	 /* Access Control Register */
+	uint32_t fcr;	 /* Flow Control Register */
+	uint32_t pir;	 /* Page Index Register */
+	uint32_t mcr;	 /* Memory Configuration Register */
+	uint32_t atr[2]; /* AC Timing Register */
+	uint32_t rsvd1[1];
+	uint32_t idr[2]; /* Device ID Register */
+	uint32_t ier;	 /* Interrupt Enable Register */
+	uint32_t iscr;	 /* Interrupt Status Clear Register */
+	uint32_t rsvd2[4];
+	uint32_t bbiwr;	 /* Bad Block Info Write */
+	uint32_t lsn;	 /* LSN Initialize */
+	uint32_t crcwr;	 /* LSN CRC Write */
+	uint32_t lsnwr;	 /* LSN Write */
+	uint32_t bbird;	 /* Bad Block Info Read */
+	uint32_t lsnrd;	 /* LSN Read */
+	uint32_t crcrd;	 /* CRC Read */
+	uint32_t rsvd3[41];
+
+	/* 0x200 ~ 0x2fc */
+	uint32_t rsvd4[1];
+	uint32_t icr;	 /* BMC Interrupt Control Register */
+	uint32_t ior;	 /* BMC PIO Status Register */
+	uint32_t bcr;	 /* BMC Burst Control Register */
+	uint32_t rsvd5[60];
+
+	/* 0x300 ~ 0x3fc */
+	uint32_t dr;	 /* MLC Data Register */
+	uint32_t isr;	 /* MLC Interrupt Status Register */
+	uint32_t pcr;	 /* Page Count Register */
+	uint32_t srr;	 /* MLC Software Reset Register */
+	uint32_t rsvd7[58];
+	uint32_t revr;	 /* Revision Register */
+	uint32_t cfgr;	 /* Configuration Register */
+};
+
+/* ECC Status Register */
+#define ECC_SR_CERR      (1 << 3)  /* correction error */
+#define ECC_SR_ERR       (1 << 2)  /* ecc error */
+#define ECC_SR_DEC       (1 << 1)  /* ecc decode finished */
+#define ECC_SR_ENC       (1 << 0)  /* ecc encode finished */
+
+/* Status Register */
+#define SR_BLANK         (1 << 7)  /* blanking check failed */
+#define SR_ECC           (1 << 6)  /* ecc timeout */
+#define SR_STS           (1 << 4)  /* status error */
+#define SR_CRC           (1 << 3)  /* crc error */
+#define SR_CMD           (1 << 2)  /* command finished */
+#define SR_READY         (1 << 1)  /* chip ready/busy */
+#define SR_ENA           (1 << 0)  /* chip enabled */
+
+/* Access Control Register */
+#define ACR_CMD(x)       (((x) & 0x1f) << 8) /* command code */
+#define ACR_START        (1 << 7)  /* command start */
+
+/* Flow Control Register */
+#define FCR_SWCRC        (1 << 8)  /* CRC controlled by Software */
+#define FCR_IGNCRC       (1 << 7)  /* Bypass/Ignore CRC checking */
+#define FCR_16BIT        (1 << 4)  /* 16 bit data bus */
+#define FCR_WPROT        (1 << 3)  /* write protected */
+#define FCR_NOSC         (1 << 2)  /* bypass status check error */
+#define FCR_MICRON       (1 << 1)  /* Micron 2-plane command */
+#define FCR_NOBC         (1 << 0)  /* skip blanking check error */
+
+/* Interrupt Enable Register */
+#define IER_ENA          (1 << 7)  /* interrupt enabled */
+#define IER_ECC          (1 << 3)  /* ecc error timeout */
+#define IER_STS          (1 << 2)  /* status error */
+#define IER_CRC          (1 << 1)  /* crc error */
+#define IER_CMD          (1 << 0)  /* command finished */
+
+/* BMC PIO Status Register */
+#define IOR_READY        (1 << 0)  /* PIO ready */
+
+/* MLC Software Reset Register */
+#define SRR_ECC_EN       (1 << 8)  /* ECC enabled */
+#define SRR_NANDC_RESET  (1 << 2)  /* NANDC reset */
+#define SRR_BMC_RESET    (1 << 1)  /* BMC reset */
+#define SRR_ECC_RESET    (1 << 0)  /* ECC reset */
+#define SRR_CHIP_RESET   (SRR_NANDC_RESET | SRR_BMC_RESET | SRR_ECC_RESET)
+
+/* Memory Configuration Register */
+#define MCR_BS16P        (0 << 16) /* page count per block */
+#define MCR_BS32P        (1 << 16)
+#define MCR_BS64P        (2 << 16)
+#define MCR_BS128P       (3 << 16)
+#define MCR_1PLANE       (0 << 14) /* memory architecture */
+#define MCR_2PLANE       (1 << 14)
+#define MCR_SERIAL       (0 << 12) /* interleaving: off, 2 flash, 4 flash */
+#define MCR_IL2          (1 << 12)
+#define MCR_IL4          (2 << 12)
+#define MCR_ALEN3        (0 << 10) /* address length */
+#define MCR_ALEN4        (1 << 10)
+#define MCR_ALEN5        (2 << 10)
+#define MCR_PS512        (0 << 8)  /* size per page (bytes) */
+#define MCR_PS2048       (1 << 8)
+#define MCR_PS4096       (2 << 8)
+#define MCR_16MB         (0 << 4)  /* flash size */
+#define MCR_32MB         (1 << 4)
+#define MCR_64MB         (2 << 4)
+#define MCR_128MB        (3 << 4)
+#define MCR_256MB        (4 << 4)
+#define MCR_512MB        (5 << 4)
+#define MCR_1GB          (6 << 4)
+#define MCR_2GB          (7 << 4)
+#define MCR_4GB          (8 << 4)
+#define MCR_8GB          (9 << 4)
+#define MCR_16GB         (10 << 4)
+#define MCR_32GB         (11 << 4)
+#define MCR_ME(n)        (1 << (n)) /* module enable, 0 <= n <= 3 */
+
+/* Configuration Register */
+#define CFGR_ECC_BITS(x)     (((x) >> 16) & 0x0f) /* 4 or 8 */
+#define CFGR_BUS_WIDTH(x)    (((x) >> 8) & 0xff) /* 8 or 16 */
+#define CFGR_MAX_MODULE(x)   ((x) & 0x0f) /* max. module(flash) */
+
+/* FTNANDC021 built-in command set */
+#define FTNANDC021_CMD_RDID  0x01   /* read id */
+#define FTNANDC021_CMD_RESET 0x02   /* reset flash */
+#define FTNANDC021_CMD_RDST  0x04   /* read status */
+#define FTNANDC021_CMD_RDPG  0x05   /* read page (data + oob) */
+#define FTNANDC021_CMD_RDOOB 0x06   /* read oob */
+#define FTNANDC021_CMD_WRPG  0x10   /* write page (data + oob) */
+#define FTNANDC021_CMD_ERBLK 0x11   /* erase block */
+#define FTNANDC021_CMD_WROOB 0x13   /* write oob */
+
+int ftnandc021_init(struct nand_chip *chip, uint32_t mmio);
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (13 preceding siblings ...)
  2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
@ 2013-12-30  9:23 ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 1/8] arm: global_data: prepare for Faraday SoC support Kuo-Jung Su
                     ` (7 more replies)
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
                   ` (3 subsequent siblings)
  18 siblings, 8 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A36x SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/documentation/index.html

There is also a A369 QEMU emulator available at my github account:

   https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.5.1 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2014.01/u-boot

Changes for v8:
   - Revise MMU/D-cache support
   - Revise Faraday SoC common configurations.
   - Drop FTINTC020 interrupt controller support.
   - Drop FTLCDC200 LCD controller support.
   - Drop FTNANDC021 NAND flash controller support, it would be latter submitted
     as a standalone patch set.
   - Drop proprietary Faraday SPL support, the u-boot-spl would be adapted instead.
     However because it depends on the FTNANDC021 patch set, so it would be submitted
     after the FTNANDC021 patch set get committed.

Changes for v7:
   - Update license to use SPDX identifiers.
   - cfi_flash: drop the patch to unmap_physmem(),
     because it's already applied.
   - ftnandc021: put_unaligned() -> memcpy()
   - ftnandc021: update ecc relatived function prototypes to fix
     compile warnnings.

Changes for v6:
   - Drop ethernet driver updates for ftmac110&ftgmac100,
     because they are already commited.
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs
   - arch/arm/cpu/faraday/cmd_bootfa.c: fix compiler warnning
   - arch/arm/cpu/faraday/cmd_bootfa.c: use shorter paragraph
     in commit message, and move the original statement into the
     top of source file.
   - ftnandc021: update README for CONFIG_SYS_FTNANDC021_TIMING
   - ftnandc021: remove illegal type-punning

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (8):
  arm: global_data: prepare for Faraday SoC support
  arm: make mmu_enabled() a global function
  arm: add Faraday ARM cores support
  arm: faraday: revise the DMA API
  arm: faraday: add FTPWMTMR010 timer support
  arm: faraday: add FTTMR010 timer support
  arm: faraday: add A360 SoC support
  arm: faraday: add A369 SoC support

 arch/arm/cpu/faraday/Makefile             |   13 +
 arch/arm/cpu/faraday/a360/Makefile        |    8 +
 arch/arm/cpu/faraday/a369/Makefile        |    8 +
 arch/arm/cpu/faraday/cache.c              |  190 ++++++++++++++
 arch/arm/cpu/faraday/config.mk            |   15 ++
 arch/arm/cpu/faraday/cpu.c                |  206 +++++++++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  112 ++++++++
 arch/arm/cpu/faraday/fttmr010.c           |  123 +++++++++
 arch/arm/cpu/faraday/start.S              |  407 +++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-a360/hardware.h |   70 +++++
 arch/arm/include/asm/arch-a360/sysc.h     |   68 +++++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++
 arch/arm/include/asm/config.h             |   12 +
 arch/arm/include/asm/dma-mapping.h        |   37 +++
 arch/arm/include/asm/faraday-common.h     |   13 +
 arch/arm/include/asm/global_data.h        |    4 +
 arch/arm/include/asm/io.h                 |   19 +-
 arch/arm/lib/cache-cp15.c                 |    7 +-
 board/faraday/a360evb/Makefile            |    9 +
 board/faraday/a360evb/board.c             |   70 +++++
 board/faraday/a360evb/clock.c             |   62 +++++
 board/faraday/a360evb/lowlevel_init.S     |   15 ++
 board/faraday/a369evb/Makefile            |    9 +
 board/faraday/a369evb/board.c             |  122 +++++++++
 board/faraday/a369evb/clock.c             |   68 +++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 boards.cfg                                |    2 +
 include/common.h                          |    5 +
 include/configs/a360.h                    |   58 ++++
 include/configs/a369.h                    |  103 ++++++++
 include/configs/faraday-common.h          |  253 ++++++++++++++++++
 include/faraday/ftpwmtmr010.h             |   41 +++
 include/faraday/ftsmc020.h                |    1 +
 include/faraday/fttmr010.h                |   17 ++
 35 files changed, 2458 insertions(+), 3 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/sysc.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 arch/arm/include/asm/faraday-common.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/faraday/ftpwmtmr010.h

--
1.7.9.5

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

* [U-Boot] [PATCH v8 1/8] arm: global_data: prepare for Faraday SoC support
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 2/8] arm: make mmu_enabled() a global function Kuo-Jung Su
                     ` (6 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Add 'cpu_id' and 'has_mmu' for Faraday SoC platforms

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- Initial commit

 arch/arm/include/asm/global_data.h |    4 ++++
 arch/arm/lib/cache-cp15.c          |    5 +++++
 2 files changed, 9 insertions(+)

diff --git a/arch/arm/include/asm/global_data.h b/arch/arm/include/asm/global_data.h
index e126436..db24a16 100644
--- a/arch/arm/include/asm/global_data.h
+++ b/arch/arm/include/asm/global_data.h
@@ -26,6 +26,10 @@ struct arch_global_data {
 	unsigned long	pllb_rate_hz;
 	unsigned long	at91_pllb_usb_init;
 #endif
+#ifdef CONFIG_SOC_FARADAY
+	unsigned long cpu_id;
+	unsigned long has_mmu;
+#endif
 	/* "static data" needed by most of timer.c on ARM platforms */
 	unsigned long timer_rate_hz;
 	unsigned long tbu;
diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 8642010..550cced 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -90,6 +90,11 @@ static inline void mmu_setup(void)
 	int i;
 	u32 reg;

+#ifdef CONFIG_SOC_FARADAY
+	if (!gd->arch.has_mmu)
+		return;
+#endif
+
 	arm_init_before_mmu();
 	/* Set up an identity-mapping for all 4GB, rw for everyone */
 	for (i = 0; i < 4096; i++)
--
1.7.9.5

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

* [U-Boot] [PATCH v8 2/8] arm: make mmu_enabled() a global function
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 1/8] arm: global_data: prepare for Faraday SoC support Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 3/8] arm: add Faraday ARM cores support Kuo-Jung Su
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

By making mmu_enabled() a global function, we could reuse the code
in other mmu/d-cache related routines.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- Initial commit

 arch/arm/lib/cache-cp15.c |    2 +-
 include/common.h          |    1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/lib/cache-cp15.c b/arch/arm/lib/cache-cp15.c
index 550cced..61264e8 100644
--- a/arch/arm/lib/cache-cp15.c
+++ b/arch/arm/lib/cache-cp15.c
@@ -119,7 +119,7 @@ static inline void mmu_setup(void)
 	set_cr(reg | CR_M);
 }

-static int mmu_enabled(void)
+int mmu_enabled(void)
 {
 	return get_cr() & CR_M;
 }
diff --git a/include/common.h b/include/common.h
index d49c514..44c6bab 100644
--- a/include/common.h
+++ b/include/common.h
@@ -549,6 +549,7 @@ void	icache_disable(void);
 int	dcache_status (void);
 void	dcache_enable (void);
 void	dcache_disable(void);
+int	mmu_enabled(void);
 void	mmu_disable(void);
 #if defined(CONFIG_ARM)
 void	relocate_code(ulong);
--
1.7.9.5

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

* [U-Boot] [PATCH v8 3/8] arm: add Faraday ARM cores support
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 1/8] arm: global_data: prepare for Faraday SoC support Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 2/8] arm: make mmu_enabled() a global function Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 4/8] arm: faraday: revise the DMA API Kuo-Jung Su
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Here is the list of verified cores:

1. FA606TE (ARMv5TE, no mmu)
2. FA626TE (ARMv5TE)

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- add arm_init_before_mmu() & mmu_page_table_flush()

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Initial commit

 arch/arm/cpu/faraday/Makefile  |   10 +
 arch/arm/cpu/faraday/cache.c   |  190 +++++++++++++++++++
 arch/arm/cpu/faraday/config.mk |   15 ++
 arch/arm/cpu/faraday/cpu.c     |  176 +++++++++++++++++
 arch/arm/cpu/faraday/start.S   |  407 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 798 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..c859238
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,10 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+extra-y := start.o
+
+obj-y   += cpu.o cache.o
diff --git a/arch/arm/cpu/faraday/cache.c b/arch/arm/cpu/faraday/cache.c
new file mode 100644
index 0000000..fe74732
--- /dev/null
+++ b/arch/arm/cpu/faraday/cache.c
@@ -0,0 +1,190 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/*
+ * I-Cache
+ */
+
+#ifdef CONFIG_SYS_ICACHE_OFF
+
+void invalidate_icache_all(void)
+{
+}
+
+#else	/* #ifdef CONFIG_SYS_ICACHE_OFF */
+
+void invalidate_icache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n"
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+#endif	/* #ifdef CONFIG_SYS_ICACHE_OFF */
+
+/*
+ * D-Cache
+ */
+
+#ifdef CONFIG_SYS_DCACHE_OFF
+
+void flush_dcache_all(void)
+{
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+}
+
+void invalidate_dcache_all(void)
+{
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+}
+
+void arm_init_before_mmu(void)
+{
+}
+
+void mmu_page_table_flush(unsigned long start, unsigned long stop)
+{
+}
+
+#else	/* #ifdef CONFIG_SYS_DCACHE_OFF */
+
+void flush_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c14,0\n" /* clean & invalidate d-cache all */
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c14,1\n" /* clean & invalidate d-cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c10,4\n" /* drain write buffer */
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+	unsigned long align = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask  = ~(align - 1);
+
+	/* aligned to cache line */
+	stop  = (stop + (align - 1)) & mask;
+	start = start & mask;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15,0,%0,c7,c6,1\n" /* invalidate cache line */
+		"add %0,%0,%2\n"
+		"cmp %0,%1\n"
+		"blo 1b\n"
+		: "+r"(start) /* output */
+		: "r"(stop), "r"(align) /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+void invalidate_dcache_all(void)
+{
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15,0,r0,c7,c6,0\n" /* invalidate d-cache all */
+		: /* output */
+		: /* input */
+		: "r0"/* clobber list */
+	);
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+static void invalidate_utlb_all(void)
+{
+	/* invalidate U-TLB all */
+	__asm__ __volatile__ (
+		"mov r0,#0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n"
+		: /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+}
+
+static void invalidate_utlb_range(unsigned long start, unsigned long stop)
+{
+	/* make it page aligned */
+	start &= 0xfffff000;
+	stop = (stop + 4095) & 0xfffff000;
+
+	/* invalidate U-TLB entry */
+	__asm__ __volatile__ (
+		"1:\n"
+		"mcr p15, 0, %0, c8, c7, 1\n"
+		"add %0, %0, #4096\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(stop)
+		: "r0"
+	);
+}
+
+void arm_init_before_mmu(void)
+{
+	invalidate_dcache_all();
+	invalidate_utlb_all();
+}
+
+void mmu_page_table_flush(unsigned long start, unsigned long stop)
+{
+	flush_dcache_range(start, stop);
+	invalidate_utlb_range(start, stop);
+}
+
+#endif    /* !defined(CONFIG_SYS_DCACHE_OFF) */
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f39e70b
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+PLATFORM_CPPFLAGS += -march=armv5te
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..d3c8a9e
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,176 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* Vendor ID */
+#define ARM_CPU_VID(x)      (((x) >> 24) & 0xff)
+#define ARM_CPU_ARM         0x41
+#define ARM_CPU_FARADAY     0x66
+
+/* Product ID */
+#define ARM_CPU_PID(x)      (((x) >>  4) & 0x0fff)
+
+/* Instruction Set Architecture */
+#define ARM_CPU_ISA(x)      (((x) >> 16) & 0xff)
+#define ARM_CPU_ARMV4       0x01
+#define ARM_CPU_ARMV5TE     0x05
+
+/* ARM Core ID (no rev.) */
+#define ARM_CPU_CID(x)      (((x) >>  4) & 0x0fffffff)
+#define ARM_CPU_FA526       0x6601526 /* ARMv4 */
+#define ARM_CPU_FA626       0x6601626 /* ARMv4 */
+#define ARM_CPU_FA606TE     0x6605606 /* ARMv5TE, no MMU */
+#define ARM_CPU_FA616TE     0x6605616 /* ARMv5TE */
+#define ARM_CPU_FA626TE     0x6605626 /* ARMv5TE */
+#define ARM_CPU_FA726TE     0x6605726 /* ARMv5TE */
+
+#ifdef CONFIG_ARCH_CPU_INIT
+int arch_cpu_init(void)
+{
+	unsigned int id;
+
+	__asm__ __volatile__ (
+		"mrc p15, 0, %0, c0, c0, 0\n"
+		: "=r"(id) /* output */
+		: /* input */
+		: "r0" /* clobber list */
+	);
+
+	switch (ARM_CPU_CID(id)) {
+	case ARM_CPU_FA606TE: /* FA606TE */
+		gd->arch.has_mmu = 0;
+		break;
+	default:
+		gd->arch.has_mmu = 1;
+		break;
+	}
+
+	gd->arch.cpu_id = id;
+
+	return 0;
+}
+#endif    /* #ifdef CONFIG_ARCH_CPU_INIT */
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	char cpu_name[32];
+	uint vid = ARM_CPU_VID(gd->arch.cpu_id);
+	uint pid = ARM_CPU_PID(gd->arch.cpu_id);
+
+	switch (vid) {
+	case ARM_CPU_FARADAY: /* Faraday */
+		switch (ARM_CPU_ISA(gd->arch.cpu_id)) {
+		case ARM_CPU_ARMV5TE:
+			sprintf(cpu_name, "FA%xTE", pid);
+			break;
+		default:
+			sprintf(cpu_name, "FA%x", pid);
+			break;
+		}
+		break;
+	case ARM_CPU_ARM: /* ARM */
+		if ((pid & 0xff0) == 0xc00)
+			sprintf(cpu_name, "Cortex-A%u", (pid & 0x00f));
+		else if (pid >= 0xa00)
+			sprintf(cpu_name, "ARM%x", 0x1000 + (pid - 0xa00));
+		else
+			sprintf(cpu_name, "ARM%x", pid);
+		break;
+	default:
+		sprintf(cpu_name, "Unknown");
+		break;
+	}
+
+	printf("CPU:   %s\n", cpu_name);
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+#ifndef CONFIG_SPL_BUILD
+	disable_interrupts();
+#endif
+
+	/*
+	 * Turn off I-cache and invalidate it
+	 */
+	icache_disable();
+	invalidate_icache_all();
+
+	/*
+	 * Turn off D-cache
+	 * dcache_disable() in turn flushes the d-cache and disables MMU
+	 */
+	dcache_disable();
+
+	/*
+	 * After D-cache is flushed and before it is disabled there may
+	 * be some new valid entries brought into the cache. We are sure
+	 * that these lines are not dirty and will not affect our execution.
+	 * So just invalidate the entire d-cache again to avoid coherency
+	 * problems for kernel
+	 */
+	invalidate_dcache_all();
+
+	return 0;
+}
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt *regs = (void __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with system reset */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+#endif
+}
+
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+
+/*
+ * This enable_caches() overrides the weak function
+ * in "arch/arm/lib/cache.c".
+ */
+void enable_caches(void)
+{
+	icache_enable();
+	dcache_enable();
+
+	if (mmu_enabled())
+		puts("MMU:   on\n");
+	else
+		puts("MMU:   off\n");
+}
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..32ce92e
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,407 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * With the following bootstrap relocation, we could flawless
+	 * boot from either ROM or NOR flash.
+	 */
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq _main
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+reloc_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo reloc_loop
+
+	ldr pc, =_main
+
+/*----------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+	mov pc, lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
--
1.7.9.5

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

* [U-Boot] [PATCH v8 4/8] arm: faraday: revise the DMA API
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 3/8] arm: add Faraday ARM cores support Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 5/8] arm: faraday: add FTPWMTMR010 timer support Kuo-Jung Su
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The DMA API is revised as follow:

1. Create an un-cached shadow memory for malloc(),
   the un-cached shadow memory is controlled by
   CONFIG_CONSISTENT_DMA_START and CONFIG_CONSISTENT_DMA_END,
   and initialized inside arch_early_init_r().

2. The virtual address returned by dma_alloc_coherent()
   always points to the corresponding uncached shadow memory
   initialized at step 1.

3. The dma_map_single() will now invalidate/flush caches.

4. The virt_to_phys() will now calculate the physical address
   from the section tables.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- Revised to use a shadow uncached region for malloc().

Changes for v6, v7:
	- Nothing updates

Changes for v5:
	- Add void dram_bank_mmu_setup() into 'arch/arm/cpu/faraday/cpu.c'
	  to override the weak function in "cache-cp15.c".
	- Use small page (4KB) to map relocated exception table to 0x0000

Changes for v4:
	- Coding Style cleanup.

Changes for v3:
	- Coding Style cleanup.
	- Always insert a blank line between declarations and code.
	- dma-mapping.h: Have the global data ptr declared outside functions.
	- dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
	- Drop static non-cached region, now we use map_physmem()/unmap_physmem()
	  for dynamic mappings.

Changes for v2:
	- Coding Style cleanup.
	- cache-cp15: Enable write buffer in write-through mode.

 arch/arm/cpu/faraday/cpu.c         |   30 +++++++++++++++++++++++++++++
 arch/arm/include/asm/config.h      |   12 ++++++++++++
 arch/arm/include/asm/dma-mapping.h |   37 ++++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/io.h          |   19 ++++++++++++++++--
 4 files changed, 96 insertions(+), 2 deletions(-)

diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
index d3c8a9e..83bc7f7 100644
--- a/arch/arm/cpu/faraday/cpu.c
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -101,6 +101,36 @@ int print_cpuinfo(void)
 }
 #endif /* CONFIG_DISPLAY_CPUINFO */

+#ifdef CONFIG_ARCH_EARLY_INIT_R
+int	arch_early_init_r(void)
+{
+#ifndef CONFIG_SYS_DCACHE_OFF
+	uint32_t mask = ~(SZ_1M - 1);
+	uint32_t phys = mem_malloc_start & mask;
+	uint32_t stop = (mem_malloc_end + (SZ_1M - 1)) & mask;
+	uint32_t size = stop - phys;
+	uint32_t virt = CONFIG_CONSISTENT_DMA_START & mask;
+	uint32_t *sect_table = (uint32_t *)gd->arch.tlb_addr;
+
+	if (!mmu_enabled())
+		return 0;
+
+	if (size > (CONFIG_CONSISTENT_DMA_END - virt))
+		panic("malloc size is too large for dma buffer\n");
+
+	while (size > 0) {
+		sect_table[virt >> 20] = phys | (3 << 10) | DCACHE_OFF;
+		virt += SZ_1M;
+		phys += SZ_1M;
+		size -= SZ_1M;
+	}
+
+	mmu_page_table_flush(mem_malloc_start & mask, stop);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+	return 0;
+}
+#endif /* CONFIG_ARCH_EARLY_INIT_R */
+
 int cleanup_before_linux(void)
 {
 	/*
diff --git a/arch/arm/include/asm/config.h b/arch/arm/include/asm/config.h
index 99b703e..295907c 100644
--- a/arch/arm/include/asm/config.h
+++ b/arch/arm/include/asm/config.h
@@ -7,6 +7,18 @@
 #ifndef _ASM_CONFIG_H_
 #define _ASM_CONFIG_H_

+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#ifndef CONFIG_ARCH_EARLY_INIT_R
+#define CONFIG_ARCH_EARLY_INIT_R
+#endif
+#ifndef CONFIG_CONSISTENT_DMA_START
+#define CONFIG_CONSISTENT_DMA_START   0xff000000
+#endif
+#ifndef CONFIG_CONSISTENT_DMA_END
+#define CONFIG_CONSISTENT_DMA_END     0xfff00000
+#endif
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 #define CONFIG_LMB
 #define CONFIG_SYS_BOOT_RAMDISK_HIGH
 #endif
diff --git a/arch/arm/include/asm/dma-mapping.h b/arch/arm/include/asm/dma-mapping.h
index 55a4e26..3b76046 100644
--- a/arch/arm/include/asm/dma-mapping.h
+++ b/arch/arm/include/asm/dma-mapping.h
@@ -8,6 +8,10 @@
 #ifndef __ASM_ARM_DMA_MAPPING_H
 #define __ASM_ARM_DMA_MAPPING_H

+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <malloc.h>
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+
 enum dma_data_direction {
 	DMA_BIDIRECTIONAL	= 0,
 	DMA_TO_DEVICE		= 1,
@@ -16,13 +20,46 @@ enum dma_data_direction {

 static void *dma_alloc_coherent(size_t len, unsigned long *handle)
 {
+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	uint32_t ofs;
+	void *mem = memalign(ARCH_DMA_MINALIGN, len);
+
+	if (handle)
+		*handle = (unsigned long)mem;
+
+	if (mem && mmu_enabled()) {
+		invalidate_dcache_range((ulong)mem, (ulong)mem + len);
+		ofs = (uint32_t)mem - (mem_malloc_start & 0xfff00000);
+		mem = (void *)(CONFIG_CONSISTENT_DMA_START + ofs);
+	}
+
+	return mem;
+#else  /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	*handle = (unsigned long)memalign(ARCH_DMA_MINALIGN, len);
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (void *)*handle;
 }

 static inline unsigned long dma_map_single(volatile void *vaddr, size_t len,
 					   enum dma_data_direction dir)
 {
+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	if (mmu_enabled()) {
+		switch (dir) {
+		case DMA_BIDIRECTIONAL:
+		case DMA_TO_DEVICE:
+			flush_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+
+		case DMA_FROM_DEVICE:
+			invalidate_dcache_range((ulong)vaddr,
+				(ulong)vaddr + len);
+			break;
+		}
+		return virt_to_phys((void *)vaddr);
+	}
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 	return (unsigned long)vaddr;
 }

diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1fbc531..b55d9e1 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -28,6 +28,9 @@
 #if 0	/* XXX###XXX */
 #include <asm/arch/hardware.h>
 #endif	/* XXX###XXX */
+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+#include <common.h>
+#endif

 static inline void sync(void)
 {
@@ -57,9 +60,21 @@ static inline void unmap_physmem(void *vaddr, unsigned long flags)

 }

-static inline phys_addr_t virt_to_phys(void * vaddr)
+static inline phys_addr_t virt_to_phys(void *vaddr)
 {
-	return (phys_addr_t)(vaddr);
+#if defined(CONFIG_SOC_FARADAY) && !defined(CONFIG_SYS_DCACHE_OFF)
+	DECLARE_GLOBAL_DATA_PTR;
+	u32 *sect_table = (u32 *)gd->arch.tlb_addr;
+	phys_addr_t phys = (phys_addr_t)vaddr;
+
+	if (!vaddr || !mmu_enabled())
+		return phys;
+
+	phys = sect_table[(u32)vaddr >> 20] & 0xfff00000;
+	return phys + ((phys_addr_t)vaddr & 0x000fffff);
+#else  /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
+	return (phys_addr_t)vaddr;
+#endif /* CONFIG_SOC_FARADAY && !CONFIG_SYS_DCACHE_OFF */
 }

 /*
--
1.7.9.5

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

* [U-Boot] [PATCH v8 5/8] arm: faraday: add FTPWMTMR010 timer support
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 4/8] arm: faraday: revise the DMA API Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 6/8] arm: faraday: add FTTMR010 " Kuo-Jung Su
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTPWMTMR010 is a simple APB device which supports
both timer and pwm functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    2 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  112 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 +++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index c859238..9bcdeba 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -8,3 +8,5 @@
 extra-y := start.o

 obj-y   += cpu.o cache.o
+
+obj-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..1032e44
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TIMER_ID    0
+
+static struct ftpwmtmr010_regs *regs =
+	(void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..29f4f05
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v8 6/8] arm: faraday: add FTTMR010 timer support
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 5/8] arm: faraday: add FTPWMTMR010 timer support Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 7/8] arm: faraday: add A360 SoC support Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 8/8] arm: faraday: add A369 " Kuo-Jung Su
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTTMR010 is a simple APB device which supports
generic timer functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    1 +
 arch/arm/cpu/faraday/fttmr010.c |  123 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 ++++++
 3 files changed, 141 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 9bcdeba..19c5796 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -9,4 +9,5 @@ extra-y := start.o

 obj-y   += cpu.o cache.o

+obj-$(CONFIG_FTTMR010)    += fttmr010.o
 obj-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..28b0086
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 2ab68d1..21ab113 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -45,6 +45,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -58,4 +68,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v8 7/8] arm: faraday: add A360 SoC support
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                     ` (5 preceding siblings ...)
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 6/8] arm: faraday: add FTTMR010 " Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 8/8] arm: faraday: add A369 " Kuo-Jung Su
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds board support for the Faraday A360 SoC platform.

Working functions:
- MMU/D-cache
- SD Host controller
- USB EHCI controller
- Network
- I2C EEPROM
- UART

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- Make A360 a standalong changeset.

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- arch/arm/cpu/faraday/cpu.c:
	  struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
	- Coding Style cleanup:
	  1. struct chip_regs __iomem *regs -> struct chip_regs *regs
	  2. Move Faraday specific APIs into asm/arch-faraday/*.h
	- Fix Copyright notices (dates) throughout the patch
	- Define Faraday machine type in board's config header file
	- Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
	- Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
	  would restart after this patch series have been accepted.
	- Revise clock management system

Changes for v4:
	- Coding Style cleanup.
	- Break-down the interrupt, timers and common utilties.

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.
	- a36x_config: No more static global network configurations.
	- a36x_config: Add a common file for the redundant configurations.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/a360/Makefile        |    8 +
 arch/arm/include/asm/arch-a360/hardware.h |   70 ++++++++
 arch/arm/include/asm/arch-a360/sysc.h     |   68 ++++++++
 arch/arm/include/asm/faraday-common.h     |   13 ++
 board/faraday/a360evb/Makefile            |    9 +
 board/faraday/a360evb/board.c             |   70 ++++++++
 board/faraday/a360evb/clock.c             |   62 +++++++
 board/faraday/a360evb/lowlevel_init.S     |   15 ++
 boards.cfg                                |    1 +
 include/common.h                          |    4 +
 include/configs/a360.h                    |   58 +++++++
 include/configs/faraday-common.h          |  253 +++++++++++++++++++++++++++++
 12 files changed, 631 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a360/Makefile
 create mode 100644 arch/arm/include/asm/arch-a360/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a360/sysc.h
 create mode 100644 arch/arm/include/asm/faraday-common.h
 create mode 100644 board/faraday/a360evb/Makefile
 create mode 100644 board/faraday/a360evb/board.c
 create mode 100644 board/faraday/a360evb/clock.c
 create mode 100644 board/faraday/a360evb/lowlevel_init.S
 create mode 100644 include/configs/a360.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/arch/arm/cpu/faraday/a360/Makefile b/arch/arm/cpu/faraday/a360/Makefile
new file mode 100644
index 0000000..b244f22
--- /dev/null
+++ b/arch/arm/cpu/faraday/a360/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y   :=
diff --git a/arch/arm/include/asm/arch-a360/hardware.h b/arch/arm/include/asm/arch-a360/hardware.h
new file mode 100644
index 0000000..7b97a44
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/hardware.h
@@ -0,0 +1,70 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_SCU_BASE				0x99900000
+#define CONFIG_PMU_BASE				0x98100000
+#define CONFIG_PMU_IRQ				8
+
+/*
+ * Timer
+ */
+#define CONFIG_FTTMR010_BASE		0x98400000
+#define CONFIG_FTTMR010_IRQ			19
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE		0x98200000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE		0x98800000
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE		0x98500000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTMAC110_BASE		0x90900000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC020_BASE		0x91000000
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE		0x98A00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE		0x98B00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90700000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90A00000
+#define CONFIG_FOTG210_BASE         0x90B00000
+
+#endif
diff --git a/arch/arm/include/asm/arch-a360/sysc.h b/arch/arm/include/asm/arch-a360/sysc.h
new file mode 100644
index 0000000..40d4ccf
--- /dev/null
+++ b/arch/arm/include/asm/arch-a360/sysc.h
@@ -0,0 +1,68 @@
+/*
+ * arch/arm/include/asm/arch-a360/sysc.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_SYSC_H
+#define __ASM_ARCH_SYSC_H
+
+struct sysc_regs {
+	uint32_t idr;      /* 0x00: ID Register */
+	uint32_t gcr;      /* 0x04: General Control Register */
+	uint32_t ccr;      /* 0x08: Clock Configuration Register */
+	uint32_t hcer;     /* 0x0C: AHB Clock Enable Register */
+	uint32_t pcer;     /* 0x10: APB Clock Enable Register */
+	uint32_t csr;      /* 0x14: Configuration Strap Register */
+	uint32_t iomcr[4]; /* IO Mux Control Register */
+	uint32_t iopcr[2]; /* IO Parameter Control Register */
+	uint32_t cescr;    /* CPU Edge Sync Control Register */
+	uint32_t expcr[3]; /* PCI-Express Control Register */
+};
+
+#define GCR_LVBC_IRQ3       (1 << 25) /* LVBC interrupt 3 propagation */
+#define GCR_LVBC_IRQ2       (1 << 24) /* LVBC interrupt 2 propagation */
+#define GCR_LVTX_RATE(x)    (((x) & 0x1f) << 16) /* LVTX clock rate */
+#define GCR_LVTX_CLK_OUT    (1 << 13) /* Enable LVTX clock out */
+#define GCR_USBH1_PLL_ALIVE (1 << 11) /* USB Host PLL alive */
+#define GCR_USBH0_PLL_ALIVE (1 << 10) /* USB Host PLL alive */
+#define GCR_USBH1_CLK_OUT   (1 << 9) /* Enable USB Host clock out */
+#define GCR_USBH0_CLK_OUT   (1 << 8) /* Enable USB Host clock out */
+#define GCR_DEBUG           (1 << 7) /* Enable debug mode */
+#define GCR_DEBUG_SW        (1 << 6) /* Enable software debug mode */
+#define GCR_IM              (1 << 5) /* Interrupt mask */
+#define GCR_RESET           (1 << 4) /* Software reset */
+
+#define CCR_LVDSTX_DSEL(x)  (((x) >> 21) & 0x1f) /* LVDS Tx Clock Select */
+#define CCR_LVDSRX_DSEL(x)  (((x) >> 16) & 0x1f) /* LVDS Rx Clock Select */
+#define CCR_SSP1_CKFQ(x)    (((x) >> 12) & 0xf) /* SSP1 Clock Freq. */
+#define CCR_SSP0_CKFQ(x)    (((x) >> 8) & 0xf) /* SSP0 Clock Freq. */
+#define CCR_SSP1_EXTCLK     (1 << 7) /* SSP1 use external clock */
+#define CCR_SSP1_PCLK       (0 << 7) /* SSP1 use APB clock */
+#define CCR_SSP0_EXTCLK     (1 << 6) /* SSP0 use external clock */
+#define CCR_SSP0_PCLK       (0 << 6) /* SSP0 use APB clock */
+#define CCR_LVDSTX_HCLK     (0 << 4) /* LVDS Tx clock select */
+#define CCR_LVDSTX_PCLK     (1 << 4)
+#define CCR_LVDSTX_EXTCLK   (2 << 4)
+#define CCR_SDC_HCLK        (2 << 2) /* SD/MMC clock select */
+#define CCR_SDC_MCLK        (1 << 2)
+#define CCR_SDC_DCLK        (0 << 2)
+#define CCR_LCD_EXTCLK      (2 << 0) /* LCD clock select */
+#define CCR_LCD_MCLK        (1 << 0)
+#define CCR_LCD_HCLK        (0 << 0)
+
+#define CSR_PLL_PRESCALE    (1 << 9)
+#define CSR_PCIE_MODE1      (1 << 8)
+#define CSR_PCIE_MODE0      (1 << 7)
+#define CSR_DBG_SW          (1 << 6)
+#define CSR_DBG_EN          (1 << 5)
+#define CSR_NAND_LP         (1 << 4)         /* NAND: Large Page */
+#define CSR_NAND_AL(x)      (((x) >> 2) & 3) /* NAND: Address Length */
+#define CSR_NAND_16X        (1 << 1)         /* NAND: 16-bits */
+#define CSR_SPIBOOT         (1 << 0)         /* Boot from SPI(1)/NAND(0) */
+
+#endif
diff --git a/arch/arm/include/asm/faraday-common.h b/arch/arm/include/asm/faraday-common.h
new file mode 100644
index 0000000..e8c4c83
--- /dev/null
+++ b/arch/arm/include/asm/faraday-common.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ASM_FARADAY_COMMON_H
+#define _ASM_FARADAY_COMMON_H
+
+ulong clk_get_rate(const char *id);
+
+#endif	/* _ASM_FARADAY_COMMON_H */
diff --git a/board/faraday/a360evb/Makefile b/board/faraday/a360evb/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/a360evb/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/a360evb/board.c b/board/faraday/a360evb/board.c
new file mode 100644
index 0000000..a2df48d
--- /dev/null
+++ b/board/faraday/a360evb/board.c
@@ -0,0 +1,70 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <asm/arch/sysc.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SCU_BASE;
+
+/*
+ * pinmux
+ */
+static void pinmux_init(void)
+{
+	writel(0x00555500, &sysc->iomcr[3]);
+	setbits_le32(&sysc->iomcr[0], 0x800002AA);
+	setbits_le32(&sysc->iomcr[1], 0x82AAAAAA);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	pinmux_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	return ftmac110_initialize(bd);
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a360evb/clock.c b/board/faraday/a360evb/clock.c
new file mode 100644
index 0000000..2bdba52
--- /dev/null
+++ b/board/faraday/a360evb/clock.c
@@ -0,0 +1,62 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysc.h>
+#include <faraday/ftpmu010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SCU_BASE;
+static struct ftpmu010 *pmu = (void __iomem *)CONFIG_PMU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 40000000; /* 40 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return clk_get_rate_sys() * ((readl(&pmu->PDLLCR0) >> 3) & 0x3f) / 8;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	uint32_t s = readl(&sysc->csr);
+	uint32_t p = readl(&pmu->PMODE);
+	ulong clk = clk_get_rate_ahb();
+	ulong mul = (s & CSR_PLL_PRESCALE) ? 2 : 4;
+
+	return (p & FTPMU010_PMODE_TURBO) ? (clk * mul) : clk;
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+
+	return ret;
+}
diff --git a/board/faraday/a360evb/lowlevel_init.S b/board/faraday/a360evb/lowlevel_init.S
new file mode 100644
index 0000000..cbc006d
--- /dev/null
+++ b/board/faraday/a360evb/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index c602a16..304417d 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -59,6 +59,7 @@ Active  arm         arm720t        -           armltd          integrator
 Active  arm         arm920t        -           armltd          integrator          integratorap_cm920t                  integratorap:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        -           armltd          integrator          integratorcp_cm920t                  integratorcp:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        a320        faraday         -                   a320evb                              -                                                                                                                                 Po-Yu Chuang <ratbert@faraday-tech.com>
+Active  arm         faraday        a360        faraday         a360evb             a360evb                              a360                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek                         at91rm9200ek                                                                                                                      Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek_ram                     at91rm9200ek:RAMBOOT                                                                                                              Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        BuS             eb_cpux9k2          eb_cpux9k2                           eb_cpux9k2                                                                                                                        Jens Scharsig <esw@bus-elektronik.de>
diff --git a/include/common.h b/include/common.h
index 44c6bab..5dd1ea1 100644
--- a/include/common.h
+++ b/include/common.h
@@ -94,6 +94,10 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_SOC_FARADAY
+#include <asm/arch/hardware.h>
+#include <asm/faraday-common.h>
+#endif

 #include <part.h>
 #include <flash.h>
diff --git a/include/configs/a360.h b/include/configs/a360.h
new file mode 100644
index 0000000..91bb62a
--- /dev/null
+++ b/include/configs/a360.h
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x00000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x00800000
+
+/* Timer */
+#define CONFIG_FTTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTMAC110
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC010
+
+/* USB */
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 2
+#define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+
+/* Environment */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+#endif	/* EOF */
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..caa6a1e
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,253 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+/* Faraday SoC Platform */
+#define CONFIG_SOC_FARADAY
+#define CONFIG_MACH_TYPE            758 /* Faraday */
+
+/* Faraday ARMv5TE common configuration */
+#define CONFIG_SYS_CACHELINE_SIZE   32
+
+#define CONFIG_SYS_HZ               1000
+
+#ifdef CONFIG_SPL_BUILD
+# undef CONFIG_USE_IRQ
+# ifndef CONFIG_SYS_DCACHE_OFF
+#  define CONFIG_SYS_DCACHE_OFF
+# endif
+#endif
+
+#define CONFIG_ARCH_CPU_INIT
+
+#define CONFIG_DISPLAY_CPUINFO
+
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+#ifdef CONFIG_USE_IRQ
+# define CONFIG_STACKSIZE_IRQ       SZ_32K
+# define CONFIG_STACKSIZE_FIQ       SZ_32K
+#endif
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MONITOR_BASE     CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+/* Default entry point */
+#ifndef CONFIG_SYS_UBOOT_START
+# define CONFIG_SYS_UBOOT_START     CONFIG_SYS_TEXT_BASE
+#endif
+
+/* Default load address */
+#ifndef CONFIG_SYS_LOAD_ADDR
+# define CONFIG_SYS_LOAD_ADDR       (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+/* U-Boot's built-in memory test */
+#ifndef CONFIG_SYS_MEMTEST_START
+# define CONFIG_SYS_MEMTEST_START   (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+#ifndef CONFIG_SYS_MEMTEST_END
+# define CONFIG_SYS_MEMTEST_END     (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+#endif
+
+/*
+ * Serial driver
+ */
+#ifdef CONFIG_FTUART010
+# undef  CONFIG_HWFLOW
+# undef  CONFIG_MODEM_SUPPORT
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# ifdef CONFIG_FTUART010_CLK
+#  define CONFIG_SYS_NS16550_CLK    CONFIG_FTUART010_CLK
+# else
+#  define CONFIG_SYS_NS16550_CLK    18432000
+# endif
+# define CONFIG_SYS_NS16550_COM1    CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE    (-4)
+# define CONFIG_CONS_INDEX          1
+# ifndef CONFIG_BAUDRATE
+#  define CONFIG_BAUDRATE           38400
+# endif
+#endif /* #ifdef CONFIG_FTUART010 */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR        32
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT     20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif /* CONFIG_FTMAC110 || CONFIG_FTGMAC100 */
+
+/*
+ * I2C bus driver
+ */
+#ifdef CONFIG_FTI2C010
+# define CONFIG_SYS_I2C_FTI2C010
+#endif
+#ifdef CONFIG_SYS_I2C_FTI2C010
+# define CONFIG_SYS_I2C
+# define CONFIG_SYS_I2C_SPEED       5000
+# define CONFIG_SYS_I2C_SLAVE       0
+# define CONFIG_CMD_I2C
+# define CONFIG_I2C_CMD_TREE
+#endif /* CONFIG_FTI2C010 */
+
+/*
+ * I2C-EEPROM
+ */
+#ifdef CONFIG_ENV_EEPROM_IS_ON_I2C
+# define CONFIG_CMD_EEPROM
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      3
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  10
+# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN         1
+# define CONFIG_SYS_I2C_MULTI_EEPROMS
+#endif
+
+/*
+ * NOR flash driver
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* HW is configured with SDIO support */
+#endif
+
+#ifdef CONFIG_FTSDC021
+# define CONFIG_SDHCI
+#endif
+
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC021)
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 0
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# define CONFIG_USB_HUB_MIN_POWER_ON_DELAY  500
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#ifdef CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux Kernel Command Line Options
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG      /* support ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#define CONFIG_CMD_LOADB        /* xyzModem */
+
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v8 8/8] arm: faraday: add A369 SoC support
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                     ` (6 preceding siblings ...)
  2013-12-30  9:23   ` [U-Boot] [PATCH v8 7/8] arm: faraday: add A360 SoC support Kuo-Jung Su
@ 2013-12-30  9:23   ` Kuo-Jung Su
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2013-12-30  9:23 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This adds board support for the Faraday A369 SoC platform.

Working functions:
- MMU/D-cache
- SD Host controller
- USB EHCI controller
- Network
- I2C EEPROM
- UART

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8:
	- Make A369 a standalong changeset.

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- arch/arm/cpu/faraday/cpu.c:
	  struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
	- Coding Style cleanup:
	  1. struct chip_regs __iomem *regs -> struct chip_regs *regs
	  2. Move Faraday specific APIs into asm/arch-faraday/*.h
	- Fix Copyright notices (dates) throughout the patch
	- Define Faraday machine type in board's config header file
	- Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
	- Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
	  would restart after this patch series have been accepted.
	- Revise clock management system

Changes for v4:
	- Coding Style cleanup.
	- Break-down the interrupt, timers and common utilties.

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.
	- a36x_config: No more static global network configurations.
	- a36x_config: Add a common file for the redundant configurations.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/a369/Makefile        |    8 ++
 arch/arm/include/asm/arch-a369/hardware.h |   88 ++++++++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++++++++++++++++
 board/faraday/a369evb/Makefile            |    9 ++
 board/faraday/a369evb/board.c             |  122 +++++++++++++++++
 board/faraday/a369evb/clock.c             |   68 ++++++++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 boards.cfg                                |    1 +
 include/configs/a369.h                    |  103 ++++++++++++++
 include/faraday/ftsmc020.h                |    1 +
 10 files changed, 626 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a369.h

diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..1081c06
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y :=
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..8501d35
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SCU_BASE             0x92000000
+#define CONFIG_DDRC_BASE            0x93100000
+#define CONFIG_AHBC_BASE            0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/sysc.h b/arch/arm/include/asm/arch-a369/sysc.h
new file mode 100644
index 0000000..ddf3e70
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/sysc.h
@@ -0,0 +1,211 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_A369_SYSC_H
+#define _ASM_ARCH_A369_SYSC_H
+
+struct sysc_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)    (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x)  ((((x) >> 3) & 3) > 2 ? 2 : (((x) >> 3) & 3))
+#define HWCFG_DLL_OFF      (1 << 2)
+#define HWCFG_PLL_OFF      (1 << 1)
+#define HWCFG_OSCHCNT_OFF  (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif	/* EOF */
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..44395de
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/sysc.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SCU_BASE;
+
+static void pinmux_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&sysc->hclkgr);
+		setbits_le32(&sysc->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_SUPP_EXT_AHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &sysc->hclkgr);
+		writel(GPMUX_DEFAULT, &sysc->gpmux);
+		clrbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &sysc->mfpmux[0]);
+#endif
+	}
+
+	/* Clock Setup: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &sysc->sccfg[1]);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	uint32_t nor_base;
+
+	/* Bank 0: NOR flash */
+	if ((readl(&sysc->ehwcfg) & 3) != EHWCFG_BOOT_NOR)
+		nor_base = 0x20000000;
+	else
+		nor_base = 0;
+	writel(FTSMC020_BANK_ENABLE
+		| FTSMC020_BANK_BASE(nor_base) /* base address */
+		| FTSMC020_BANK_SIZE_64M /* window size */
+		| FTSMC020_BANK_MBW_16, /* data width */
+		&smc->bank[0].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[0].tpr);
+
+	/* Bank 1 ~ 3: nothing attached */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	pinmux_init();
+	smc_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#else
+	return 0;
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a369evb/clock.c b/board/faraday/a369evb/clock.c
new file mode 100644
index 0000000..9246846
--- /dev/null
+++ b/board/faraday/a369evb/clock.c
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SCU_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 33000000; /* 33 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return (clk_get_rate_sys() * PLLCR_NS(readl(&sysc->pllcr))) >> 3;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+	/* If it's an internal CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after kicking
+	 * off slave cpu, so if GPMUX_CPUS_START is set,
+	 * it must be a slave cpu.
+	 */
+	if (!(readl(&sysc->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&sysc->hwcfg));
+
+	return clk;
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+
+	return ret;
+}
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..cbc006d
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index 304417d..53a0133 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -60,6 +60,7 @@ Active  arm         arm920t        -           armltd          integrator
 Active  arm         arm920t        -           armltd          integrator          integratorcp_cm920t                  integratorcp:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        a320        faraday         -                   a320evb                              -                                                                                                                                 Po-Yu Chuang <ratbert@faraday-tech.com>
 Active  arm         faraday        a360        faraday         a360evb             a360evb                              a360                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
+Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek                         at91rm9200ek                                                                                                                      Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek_ram                     at91rm9200ek:RAMBOOT                                                                                                              Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        BuS             eb_cpux9k2          eb_cpux9k2                           eb_cpux9k2                                                                                                                        Jens Scharsig <esw@bus-elektronik.de>
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..b3cdba6
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,103 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support NOR flash */
+/* #define CONFIG_SUPP_NOR_FLASH */
+
+/* Support NOR flash */
+/* #define CONFIG_SUPP_NOR_FLASH */
+
+#if defined(CONFIG_SUPP_NAND_FLASH) && defined(CONFIG_SUPP_NOR_FLASH)
+# error "The NAND flash and NOR flash use shared pins,"
+# error "please don't enable both of them at the same time."
+#endif
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_SUPP_USB_RNDIS */
+
+/* Support External AHB (pinmux) */
+/* #define CONFIG_SUPP_EXT_AHB */
+
+/* Disable MMU/D-CACHE */
+/* #define CONFIG_SYS_DCACHE_OFF */
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Timer */
+#define CONFIG_FTPWMTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTGMAC100
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC010
+
+/* NOR flash */
+#ifdef CONFIG_SUPP_NOR_FLASH
+# define PHYS_FLASH_SIZE                SZ_64M
+# define CONFIG_SYS_FLASH_BASE          0x20000000
+# define CONFIG_SYS_FLASH_CFI_WIDTH     FLASH_CFI_16BIT
+# define CONFIG_SYS_MAX_FLASH_BANKS     1
+# define CONFIG_SYS_MAX_FLASH_SECT      1024
+#endif
+
+/* USB */
+#ifdef CONFIG_SUPP_USB_RNDIS
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+# define CONFIG_USB_EHCI_BASE               CONFIG_FUSBH200_BASE
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST  \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+/* Environment */
+#if defined(CONFIG_SUPP_NAND_FLASH)
+# define CONFIG_ENV_IS_IN_NAND
+# define CONFIG_ENV_OFFSET          0x07fc0000
+# define CONFIG_ENV_OFFSET_REDUND   0x07fe0000
+#elif defined(CONFIG_SUPP_NOR_FLASH)
+# define CONFIG_ENV_IS_IN_FLASH /* NOR flash */
+# define CONFIG_ENV_OFFSET          0x3f0000
+#else
+# define CONFIG_ENV_IS_NOWHERE
+#endif
+
+#define CONFIG_ENV_SIZE             SZ_64K
+
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Default network configuration */ \
+	"ethaddr=00:41:71:00:00:50\0" \
+	"serverip=10.0.0.128\0" \
+	"ipaddr=10.0.0.192\0"
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+#endif	/* EOF */
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 54120ab..485d7c2 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -70,5 +70,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_FAILSAFE	0x0f1ff3ff /* fail-safe timing */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (14 preceding siblings ...)
  2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
@ 2014-01-16  8:31 ` Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 1/7] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
                     ` (6 more replies)
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
                   ` (2 subsequent siblings)
  18 siblings, 7 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A369 & Virtual SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm
   http://www.faraday-tech.com/html/documentation/index.html

There is also a QEMU based A369 emulator available at my github account:

   https://github.com/dantesu1218/qemu.git

Here is quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.5.1 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2014.01/u-boot

Changes for v9:
   - Shrink the patch by dropping MMU/D-cache support, and see if we could get
     this patch accepted ASAP.
   - Replace the out-of-date A360 EVB with Faraday Virtual Machine (FVM).
   - Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
   - Add do_go_exec() to override the default behavior of 'go' command.
   - Make Faraday SoC helper files & ftsmc020 standalone changesets.
   - Coding style cleanup.

Changes for v8:
   - Revise MMU/D-cache support
   - Revise Faraday SoC common configurations.
   - Drop FTINTC020 interrupt controller support.
   - Drop FTLCDC200 LCD controller support.
   - Drop FTNANDC021 NAND flash controller support, it would be latter submitted
     as a standalone patch set.
   - Drop proprietary Faraday SPL support, the u-boot-spl would be adapted instead.
     However because it depends on the FTNANDC021 patch set, so it would be submitted
     after the FTNANDC021 patch set get committed.

Changes for v7:
   - Update license to use SPDX identifiers.
   - cfi_flash: drop the patch to unmap_physmem(),
     because it's already applied.
   - ftnandc021: put_unaligned() -> memcpy()
   - ftnandc021: update ecc relatived function prototypes to fix
     compile warnnings.

Changes for v6:
   - Drop ethernet driver updates for ftmac110&ftgmac100,
     because they are already commited.
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs
   - arch/arm/cpu/faraday/cmd_bootfa.c: fix compiler warnning
   - arch/arm/cpu/faraday/cmd_bootfa.c: use shorter paragraph
     in commit message, and move the original statement into the
     top of source file.
   - ftnandc021: update README for CONFIG_SYS_FTNANDC021_TIMING
   - ftnandc021: remove illegal type-punning

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (7):
  arm: add Faraday ARMv5TE cores support
  arm: add Faraday SoC helper files
  arm: faraday: add FTTMR010 timer support
  arm: faraday: add FTPWMTMR010 timer support
  arm: faraday: ftsmc020: add a fail-safe macro constant
  arm: faraday: add A369 evaluation board support
  arm: faraday: add Faraday Virtual Machine support

 arch/arm/cpu/faraday/Makefile             |   13 +
 arch/arm/cpu/faraday/a369/Makefile        |    8 +
 arch/arm/cpu/faraday/cache.c              |  164 ++++++++++++
 arch/arm/cpu/faraday/config.mk            |   15 ++
 arch/arm/cpu/faraday/cpu.c                |  115 ++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  112 ++++++++
 arch/arm/cpu/faraday/fttmr010.c           |  123 +++++++++
 arch/arm/cpu/faraday/fvm/Makefile         |    8 +
 arch/arm/cpu/faraday/start.S              |  407 +++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++
 arch/arm/include/asm/arch-fvm/hardware.h  |   76 ++++++
 arch/arm/include/asm/faraday.h            |   13 +
 board/faraday/a369evb/Makefile            |    9 +
 board/faraday/a369evb/board.c             |  122 +++++++++
 board/faraday/a369evb/clock.c             |   68 +++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 board/faraday/fvm/Makefile                |    9 +
 board/faraday/fvm/board.c                 |   60 +++++
 board/faraday/fvm/clock.c                 |   49 ++++
 board/faraday/fvm/lowlevel_init.S         |   15 ++
 boards.cfg                                |    2 +
 include/common.h                          |    3 +
 include/configs/a369.h                    |  111 ++++++++
 include/configs/faraday-common.h          |  314 ++++++++++++++++++++++
 include/configs/fvm.h                     |   61 +++++
 include/faraday/ftpwmtmr010.h             |   41 +++
 include/faraday/ftsmc020.h                |    1 +
 include/faraday/fttmr010.h                |   17 ++
 29 files changed, 2250 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 arch/arm/include/asm/faraday.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/clock.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/configs/fvm.h
 create mode 100644 include/faraday/ftpwmtmr010.h

--
1.7.9.5

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

* [U-Boot] [PATCH v9 1/7] arm: add Faraday ARMv5TE cores support
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
@ 2014-01-16  8:31   ` Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 2/7] arm: add Faraday SoC helper files Kuo-Jung Su
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Here is the list of verified cores:

1. FA606TE (ARMv5TE, no mmu)
2. FA626TE (ARMv5TE)

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v9:
	- Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
	- Add do_go_exec() to override the default behavior of 'go' command.

Changes for v8:
	- add arm_init_before_mmu() & mmu_page_table_flush()

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Initial commit

 arch/arm/cpu/faraday/Makefile  |   10 +
 arch/arm/cpu/faraday/cache.c   |  164 ++++++++++++++++
 arch/arm/cpu/faraday/config.mk |   15 ++
 arch/arm/cpu/faraday/cpu.c     |  115 ++++++++++++
 arch/arm/cpu/faraday/start.S   |  407 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 711 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..c859238
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,10 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+extra-y := start.o
+
+obj-y   += cpu.o cache.o
diff --git a/arch/arm/cpu/faraday/cache.c b/arch/arm/cpu/faraday/cache.c
new file mode 100644
index 0000000..2acb954
--- /dev/null
+++ b/arch/arm/cpu/faraday/cache.c
@@ -0,0 +1,164 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/*
+ * I-Cache
+ */
+
+void invalidate_icache_all(void)
+{
+#if !defined(CONFIG_SYS_ICACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_ICACHE_OFF */
+}
+
+/*
+ * D-Cache
+ */
+
+void flush_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c14, 0\n" /* clean & invalidate */
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c14, 1\n" /* clean & invalidate */
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c6, 1\n"
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c6, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+/*
+ * MMU
+ */
+
+static void invalidate_utlb_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+static void invalidate_utlb_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	uint32_t page = 4096;
+	uint32_t mask = ~(page - 1);
+
+	/* aligned to page boundary */
+	stop = (page - 1 + stop) & mask;
+	start = start & mask;
+
+	/* invalidate U-TLB entry */
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c8, c7, 1\n"
+		"add %0, %0, %1\n"
+		"cmp %0, %2\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(page), "r"(stop)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void arm_init_before_mmu(void)
+{
+	invalidate_dcache_all();
+	invalidate_utlb_all();
+}
+
+void mmu_page_table_flush(unsigned long start, unsigned long stop)
+{
+	flush_dcache_range(start, stop);
+	invalidate_utlb_range(start, stop);
+}
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f39e70b
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+PLATFORM_CPPFLAGS += -march=armv5te
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..8eef357
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,115 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This enable_caches() overrides the weak function
+ * in "arch/arm/lib/cache.c".
+ */
+void enable_caches(void)
+{
+	icache_enable();
+	dcache_enable();
+}
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+	disable_interrupts();
+
+	/*
+	 * Turn off I-cache and invalidate it
+	 */
+	icache_disable();
+	invalidate_icache_all();
+
+	/*
+	 * Turn off D-cache
+	 * dcache_disable() in turn flushes the d-cache and disables MMU
+	 */
+	dcache_disable();
+
+	/*
+	 * After D-cache is flushed and before it is disabled there may
+	 * be some new valid entries brought into the cache. We are sure
+	 * that these lines are not dirty and will not affect our execution.
+	 * So just invalidate the entire d-cache again to avoid coherency
+	 * problems for kernel
+	 */
+	invalidate_dcache_all();
+
+	return 0;
+}
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt *regs = (void __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with system reset */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+#endif
+}
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	/* print cpu_info */
+	printf("CPU:   %u MHz\n",
+		(unsigned int)(clk_get_rate("CPU") / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("AHB") / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("APB") / 1000000));
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifdef CONFIG_CMD_GO
+/*
+ * This do_go_exec() overrides the weak function
+ * in "cmd_boot.c".
+ */
+unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
+				 char * const argv[])
+{
+	cleanup_before_linux();
+	return entry(argc, argv);
+}
+#endif /* CONFIG_CMD_GO */
+
+#ifdef CONFIG_CMD_BOOTM
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+#endif /* CONFIG_CMD_BOOTM */
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..32ce92e
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,407 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * With the following bootstrap relocation, we could flawless
+	 * boot from either ROM or NOR flash.
+	 */
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq _main
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+reloc_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo reloc_loop
+
+	ldr pc, =_main
+
+/*----------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+	mov pc, lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
--
1.7.9.5

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

* [U-Boot] [PATCH v9 2/7] arm: add Faraday SoC helper files
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 1/7] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
@ 2014-01-16  8:31   ` Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 3/7] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

1. arch/arm/include/asm/faraday.h:
   Faraday SoC header file

2. include/configs/faraday-common.h:
   Faraday SoC common/default configurations

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v9:
	- Separated as a standalone changeset by first time.

 arch/arm/include/asm/faraday.h   |   13 ++
 include/common.h                 |    3 +
 include/configs/faraday-common.h |  314 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 330 insertions(+)
 create mode 100644 arch/arm/include/asm/faraday.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/arch/arm/include/asm/faraday.h b/arch/arm/include/asm/faraday.h
new file mode 100644
index 0000000..2b59af1
--- /dev/null
+++ b/arch/arm/include/asm/faraday.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ASM_FARADAY_H
+#define _ASM_FARADAY_H
+
+ulong clk_get_rate(const char *id);
+
+#endif	/* EOF */
diff --git a/include/common.h b/include/common.h
index d49c514..eaac828 100644
--- a/include/common.h
+++ b/include/common.h
@@ -94,6 +94,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_SOC_FARADAY
+#include <asm/faraday.h>
+#endif

 #include <part.h>
 #include <flash.h>
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..546c0a9
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,314 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+/* Faraday SoC Platform */
+#define CONFIG_SOC_FARADAY
+#define CONFIG_MACH_TYPE            758 /* Faraday */
+
+/* Faraday ARMv5TE cores are 32 bytes per line */
+#define CONFIG_SYS_CACHELINE_SIZE   32
+
+#ifdef CONFIG_SPL_BUILD
+# undef CONFIG_USE_IRQ
+# ifndef CONFIG_SYS_DCACHE_OFF
+#  define CONFIG_SYS_DCACHE_OFF
+# endif
+# ifndef CONFIG_SYS_THUMB_BUILD
+#  define CONFIG_SYS_THUMB_BUILD
+# endif
+#endif /* CONFIG_SPL_BUILD */
+
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_DISPLAY_CPUINFO
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+#ifdef CONFIG_USE_IRQ
+# define CONFIG_STACKSIZE_IRQ       SZ_32K
+# define CONFIG_STACKSIZE_FIQ       SZ_32K
+#endif
+
+#define CONFIG_SYS_HZ               1000
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MONITOR_BASE     CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+#ifndef CONFIG_CONSISTENT_DMA_START
+#define CONFIG_CONSISTENT_DMA_START 0xff000000
+#endif
+
+#ifndef CONFIG_CONSISTENT_DMA_END
+#define CONFIG_CONSISTENT_DMA_END   0xfff00000
+#endif
+
+/* Default entry point */
+#ifndef CONFIG_SYS_UBOOT_START
+#define CONFIG_SYS_UBOOT_START      CONFIG_SYS_TEXT_BASE
+#endif
+
+/* Default load address */
+#ifndef CONFIG_SYS_LOAD_ADDR
+#define CONFIG_SYS_LOAD_ADDR        (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+/* U-Boot's built-in memory test */
+#ifndef CONFIG_SYS_MEMTEST_START
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+#ifndef CONFIG_SYS_MEMTEST_END
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+#endif
+
+/*
+ * Serial driver
+ */
+#ifdef CONFIG_FTUART010
+# ifndef CONFIG_FTUART010_CLK
+# define CONFIG_FTUART010_CLK       18432000
+# endif
+# ifndef CONFIG_BAUDRATE
+# define CONFIG_BAUDRATE            38400
+# endif
+# undef CONFIG_HWFLOW
+# undef CONFIG_MODEM_SUPPORT
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# define CONFIG_SYS_NS16550_CLK         CONFIG_FTUART010_CLK
+# define CONFIG_SYS_NS16550_COM1        CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE    (-4)
+# define CONFIG_CONS_INDEX              1
+#endif /* CONFIG_FTUART010 */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR        32
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT     20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif /* CONFIG_FTMAC110 || CONFIG_FTGMAC100 */
+
+#ifndef CONFIG_ETHADDR
+#define CONFIG_ETHADDR              00:41:71:00:00:50
+#endif
+
+#ifndef CONFIG_IPADDR
+#define CONFIG_IPADDR               10.0.0.192
+#endif
+
+#ifndef CONFIG_NETMASK
+#define CONFIG_NETMASK              255.255.255.0
+#endif
+
+#ifndef CONFIG_SERVERIP
+#define CONFIG_SERVERIP             10.0.0.128
+#endif
+
+/*
+ * I2C bus driver
+ */
+#ifdef CONFIG_FTI2C010
+# define CONFIG_SYS_I2C_FTI2C010
+#endif
+#ifdef CONFIG_SYS_I2C_FTI2C010
+# define CONFIG_SYS_I2C
+# define CONFIG_SYS_I2C_SPEED       5000
+# define CONFIG_SYS_I2C_SLAVE       0
+# define CONFIG_CMD_I2C
+# define CONFIG_I2C_CMD_TREE
+#endif /* CONFIG_FTI2C010 */
+
+/*
+ * I2C-EEPROM
+ */
+#ifdef CONFIG_ENV_EEPROM_IS_ON_I2C
+# define CONFIG_CMD_EEPROM
+# define CONFIG_SYS_I2C_MULTI_EEPROMS
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      3
+# endif
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  10
+# endif
+# ifndef CONFIG_SYS_I2C_EEPROM_ADDR_LEN
+# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN         1
+# endif
+#endif
+
+/*
+ * NAND flash controller
+ */
+#ifdef CONFIG_FTNANDC021
+# define CONFIG_NAND_FTNANDC021
+#endif
+#ifdef CONFIG_SYS_NAND_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+# define CONFIG_CMD_NAND_YAFFS
+#endif
+
+/*
+ * NOR flash driver
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* HW is configured with SDIO support */
+#endif
+
+#ifdef CONFIG_FTSDC021
+# define CONFIG_SDHCI
+#endif
+
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC021)
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 0
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+# define CONFIG_USB_HUB_MIN_POWER_ON_DELAY  500
+# endif
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#ifdef CONFIG_USB_ETHER
+# ifndef CONFIG_USBNET_DEV_ADDR
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# endif
+# ifndef CONFIG_USBNET_HOST_ADDR
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+# endif
+#endif
+
+#ifdef CONFIG_USBDOWNLOAD_GADGET
+# ifndef CONFIG_G_DNL_MANUFACTURER
+# define CONFIG_G_DNL_MANUFACTURER  "Faraday"
+# endif
+# ifndef CONFIG_G_DNL_VENDOR_NUM
+# define CONFIG_G_DNL_VENDOR_NUM    0x1d50  /* OpenMoko */
+# endif
+# ifndef CONFIG_G_DNL_PRODUCT_NUM
+# define CONFIG_G_DNL_PRODUCT_NUM   0x5119
+# endif
+#endif
+
+#ifdef CONFIG_DFU_FUNCTION
+# ifndef CONFIG_SYS_DFU_DATA_BUF_SIZE
+# define CONFIG_SYS_DFU_DATA_BUF_SIZE   4096
+# endif
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux Kernel Command Line
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG      /* support ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#define CONFIG_CMD_LOADB        /* xyzModem */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v9 3/7] arm: faraday: add FTTMR010 timer support
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 1/7] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 2/7] arm: add Faraday SoC helper files Kuo-Jung Su
@ 2014-01-16  8:31   ` Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 4/7] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTTMR010 is a simple APB device which supports
generic timer functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v9:
	- Nothing updates

Changes for v8:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    2 +
 arch/arm/cpu/faraday/fttmr010.c |  123 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 ++++++
 3 files changed, 142 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index c859238..73f6934 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -8,3 +8,5 @@
 extra-y := start.o

 obj-y   += cpu.o cache.o
+
+obj-$(CONFIG_FTTMR010)    += fttmr010.o
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..28b0086
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 2ab68d1..21ab113 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -45,6 +45,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -58,4 +68,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v9 4/7] arm: faraday: add FTPWMTMR010 timer support
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 3/7] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
@ 2014-01-16  8:31   ` Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 5/7] arm: faraday: ftsmc020: add a fail-safe macro constant Kuo-Jung Su
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTPWMTMR010 is a simple APB device which supports
both timer and pwm functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v9:
	- Nothing updates

Changes for v8:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    1 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  112 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 +++++++++++++
 3 files changed, 154 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 73f6934..19c5796 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -10,3 +10,4 @@ extra-y := start.o
 obj-y   += cpu.o cache.o

 obj-$(CONFIG_FTTMR010)    += fttmr010.o
+obj-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..1032e44
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TIMER_ID    0
+
+static struct ftpwmtmr010_regs *regs =
+	(void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..29f4f05
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v9 5/7] arm: faraday: ftsmc020: add a fail-safe macro constant
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 4/7] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
@ 2014-01-16  8:31   ` Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 6/7] arm: faraday: add A369 evaluation board support Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 7/7] arm: faraday: add Faraday Virtual Machine support Kuo-Jung Su
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Add a macro constant for fail-safe timing value.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v9:
	- Separated as a standalone changeset by first time.

 include/faraday/ftsmc020.h |    1 +
 1 file changed, 1 insertion(+)

diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 54120ab..485d7c2 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -70,5 +70,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_FAILSAFE	0x0f1ff3ff /* fail-safe timing */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v9 6/7] arm: faraday: add A369 evaluation board support
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 5/7] arm: faraday: ftsmc020: add a fail-safe macro constant Kuo-Jung Su
@ 2014-01-16  8:31   ` Kuo-Jung Su
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 7/7] arm: faraday: add Faraday Virtual Machine support Kuo-Jung Su
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The A369 is an ARM CPU-based SoC with rich SoC features and
convenient FPGA link for building fast system prototyping
and volume production.

More information about this hardware can be found at:
http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v9:
	- Revise the commit message.

Changes for v8:
	- Make A369 a standalong changeset.

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- arch/arm/cpu/faraday/cpu.c:
	  struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
	- Coding Style cleanup:
	  1. struct chip_regs __iomem *regs -> struct chip_regs *regs
	  2. Move Faraday specific APIs into asm/arch-faraday/*.h
	- Fix Copyright notices (dates) throughout the patch
	- Define Faraday machine type in board's config header file
	- Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
	- Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
	  would restart after this patch series have been accepted.
	- Revise clock management system

Changes for v4:
	- Coding Style cleanup.
	- Break-down the interrupt, timers and common utilties.

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.
	- a36x_config: No more static global network configurations.
	- a36x_config: Add a common file for the redundant configurations.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/a369/Makefile        |    8 ++
 arch/arm/include/asm/arch-a369/hardware.h |   88 ++++++++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++++++++++++++++
 board/faraday/a369evb/Makefile            |    9 ++
 board/faraday/a369evb/board.c             |  122 +++++++++++++++++
 board/faraday/a369evb/clock.c             |   68 ++++++++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 boards.cfg                                |    1 +
 include/configs/a369.h                    |  111 +++++++++++++++
 9 files changed, 633 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a369.h

diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..1081c06
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y :=
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..55031a4
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SYSC_BASE            0x92000000
+#define CONFIG_DDRC_BASE            0x93100000
+#define CONFIG_AHBC_BASE            0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/sysc.h b/arch/arm/include/asm/arch-a369/sysc.h
new file mode 100644
index 0000000..ddf3e70
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/sysc.h
@@ -0,0 +1,211 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_A369_SYSC_H
+#define _ASM_ARCH_A369_SYSC_H
+
+struct sysc_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)    (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x)  ((((x) >> 3) & 3) > 2 ? 2 : (((x) >> 3) & 3))
+#define HWCFG_DLL_OFF      (1 << 2)
+#define HWCFG_PLL_OFF      (1 << 1)
+#define HWCFG_OSCHCNT_OFF  (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif	/* EOF */
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..cd206bb
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/sysc.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+static void pinmux_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&sysc->hclkgr);
+		setbits_le32(&sysc->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_A369_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &sysc->hclkgr);
+		writel(GPMUX_DEFAULT, &sysc->gpmux);
+		clrbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &sysc->mfpmux[0]);
+#endif
+	}
+
+	/* Clock: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &sysc->sccfg[1]);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	uint32_t nor_base;
+
+	/* Bank 0: NOR flash */
+	if ((readl(&sysc->ehwcfg) & 3) != EHWCFG_BOOT_NOR)
+		nor_base = 0x20000000;
+	else
+		nor_base = 0;
+	writel(FTSMC020_BANK_ENABLE
+		| FTSMC020_BANK_BASE(nor_base) /* base address */
+		| FTSMC020_BANK_SIZE_64M /* window size */
+		| FTSMC020_BANK_MBW_16, /* data width */
+		&smc->bank[0].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[0].tpr);
+
+	/* Bank 1 ~ 3: nothing attached */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	pinmux_init();
+	smc_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#else
+	return 0;
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a369evb/clock.c b/board/faraday/a369evb/clock.c
new file mode 100644
index 0000000..b713b89
--- /dev/null
+++ b/board/faraday/a369evb/clock.c
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 33000000; /* 33 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return (clk_get_rate_sys() * PLLCR_NS(readl(&sysc->pllcr))) >> 3;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+	/* If it's an internal CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after kicking
+	 * off slave cpu, so if GPMUX_CPUS_START is set,
+	 * it must be a slave cpu.
+	 */
+	if (!(readl(&sysc->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&sysc->hwcfg));
+
+	return clk;
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+
+	return ret;
+}
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..2085760
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index a8336cc..a998452 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -59,6 +59,7 @@ Active  arm         arm720t        -           armltd          integrator
 Active  arm         arm920t        -           armltd          integrator          integratorap_cm920t                  integratorap:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        -           armltd          integrator          integratorcp_cm920t                  integratorcp:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        a320        faraday         -                   a320evb                              -                                                                                                                                 Po-Yu Chuang <ratbert@faraday-tech.com>
+Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek                         at91rm9200ek                                                                                                                      Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek_ram                     at91rm9200ek:RAMBOOT                                                                                                              Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        BuS             eb_cpux9k2          eb_cpux9k2                           eb_cpux9k2                                                                                                                        Jens Scharsig <esw@bus-elektronik.de>
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..1cf9230
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,111 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support NOR flash */
+/* #define CONFIG_A369_NOR_FLASH */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_A369_USB_ETHER */
+
+/* Support USB DFU */
+#define CONFIG_A369_USB_DFU
+
+#if defined(CONFIG_A369_USB_ETHER) && defined(CONFIG_A369_USB_DFU)
+# error "USB-ETHER and USB-DFU can't be enabled at the same time."
+#endif
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Timer */
+#define CONFIG_FTPWMTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTGMAC100
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC010
+
+/* NOR flash */
+#ifdef CONFIG_A369_NOR_FLASH
+# define PHYS_FLASH_SIZE                SZ_64M
+# define CONFIG_SYS_FLASH_BASE          0x20000000
+# define CONFIG_SYS_FLASH_CFI_WIDTH     FLASH_CFI_16BIT
+# define CONFIG_SYS_MAX_FLASH_BANKS     1
+# define CONFIG_SYS_MAX_FLASH_SECT      1024
+#endif
+
+/* USB */
+#if defined(CONFIG_A369_USB_DFU) || defined(CONFIG_A369_USB_ETHER)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_GADGET_VBUS_DRAW        200
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+# define CONFIG_USB_EHCI_BASE               CONFIG_FUSBH200_BASE
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+#ifdef CONFIG_A369_USB_DFU
+# define CONFIG_USBDOWNLOAD_GADGET
+# define CONFIG_DFU_FUNCTION
+# define CONFIG_DFU_RAM
+# define CONFIG_CMD_DFU
+#endif
+
+#ifdef CONFIG_A369_USB_ETHER
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+#endif
+
+/* Environment */
+#if defined(CONFIG_A369_NOR_FLASH)
+# define CONFIG_ENV_IS_IN_FLASH /* NOR flash */
+# define CONFIG_ENV_OFFSET          0x3f0000
+#else
+# define CONFIG_ENV_IS_NOWHERE
+#endif
+
+#define CONFIG_ENV_SIZE             SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+/* Platform specific environment variables */
+#ifdef CONFIG_A369_USB_DFU
+# define CONFIG_EXTRA_ENV_SETTINGS \
+	/* USB-DFU: [name] [interface] [start] [end] */ \
+	"dfu_alt_info=ram at 0x10800000 ram 0x10800000 0x11800000\0"
+#endif
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v9 7/7] arm: faraday: add Faraday Virtual Machine support
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (5 preceding siblings ...)
  2014-01-16  8:31   ` [U-Boot] [PATCH v9 6/7] arm: faraday: add A369 evaluation board support Kuo-Jung Su
@ 2014-01-16  8:31   ` Kuo-Jung Su
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-01-16  8:31 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday Virtual Machine (FVM) is a QEMU based emulator
which is designed for early stage software development
(e.g., IPL, SPL).

Please check the link bellow for details:
https://github.com/dantesu1218/qemu/blob/qemu-1.5.1/hw/arm/faraday_fvm.c

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v9:
	- Initial commit

 arch/arm/cpu/faraday/fvm/Makefile        |    8 ++++
 arch/arm/include/asm/arch-fvm/hardware.h |   76 ++++++++++++++++++++++++++++++
 board/faraday/fvm/Makefile               |    9 ++++
 board/faraday/fvm/board.c                |   60 +++++++++++++++++++++++
 board/faraday/fvm/clock.c                |   49 +++++++++++++++++++
 board/faraday/fvm/lowlevel_init.S        |   15 ++++++
 boards.cfg                               |    1 +
 include/configs/fvm.h                    |   61 ++++++++++++++++++++++++
 8 files changed, 279 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/clock.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 include/configs/fvm.h

diff --git a/arch/arm/cpu/faraday/fvm/Makefile b/arch/arm/cpu/faraday/fvm/Makefile
new file mode 100644
index 0000000..1081c06
--- /dev/null
+++ b/arch/arm/cpu/faraday/fvm/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y :=
diff --git a/arch/arm/include/asm/arch-fvm/hardware.h b/arch/arm/include/asm/arch-fvm/hardware.h
new file mode 100644
index 0000000..e362984
--- /dev/null
+++ b/arch/arm/include/asm/arch-fvm/hardware.h
@@ -0,0 +1,76 @@
+/*
+ * arch/arm/include/asm/arch-fvm/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00020000
+
+#define CONFIG_SYSC_BASE            0x90f00000
+#define CONFIG_SYSC_IRQ             15
+
+#define CONFIG_FTINTC030_BASE       0x91000000
+
+#define CONFIG_FTTMR010_BASE        0x90200000
+#define CONFIG_FTTMR010_IRQ         1
+
+#define CONFIG_FTUART010_BASE0      0x90000000
+#define CONFIG_FTUART010_IRQ0       2
+#define CONFIG_FTUART010_BASE1      0x90100000
+#define CONFIG_FTUART010_IRQ1       3
+#define CONFIG_FTUART010_BASE       CONFIG_FTUART010_BASE0
+
+#define CONFIG_DDRC_BASE            0x90300000
+
+#define CONFIG_FTI2C010_BASE        0x90400000
+#define CONFIG_FTI2C010_IRQ         4
+
+#define CONFIG_FTSSP010_BASE        0x90500000
+#define CONFIG_FTSSP010_IRQ         5
+
+#define CONFIG_FTWDT010_BASE        0x90600000
+#define CONFIG_FTWDT010_IRQ         6
+
+#define CONFIG_FTRTC011_BASE        0x90700000
+#define CONFIG_FTRTC011_IRQ         7
+
+#define CONFIG_FTTSC010_BASE        0x90800000
+#define CONFIG_FTTSC010_IRQ         8
+
+#define CONFIG_FTAPBBRG020_BASE     0x91100000
+#define CONFIG_FTAPBBRG020_IRQ      16
+
+#define CONFIG_FTDMAC020_BASE       0x91200000
+#define CONFIG_FTDMAC020_IRQ        17
+
+#define CONFIG_FTMAC110_BASE        0x91300000
+#define CONFIG_FTMAC110_IRQ         18
+
+#define CONFIG_FTSPI020_BASE        0x91400000
+#define CONFIG_FTSPI020_IRQ         19
+
+#define CONFIG_FTNANDC021_BASE      0x91500000
+#define CONFIG_FTNANDC021_IRQ       20
+
+#define CONFIG_FTSDC021_BASE        0x91600000
+#define CONFIG_FTSDC021_IRQ         21
+
+#define CONFIG_FOTG210_BASE         0x91700000
+#define CONFIG_FOTG210_IRQ          22
+
+#define CONFIG_FTLCDC200_BASE       0x91800000
+#define CONFIG_FTLCDC200_IRQ        23
+
+#endif /* EOF */
diff --git a/board/faraday/fvm/Makefile b/board/faraday/fvm/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/fvm/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/fvm/board.c b/board/faraday/fvm/board.c
new file mode 100644
index 0000000..6c2b03a
--- /dev/null
+++ b/board/faraday/fvm/board.c
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <faraday/ftsdc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_FTMAC110
+	return ftmac110_initialize(bd);
+#else
+	return 0;
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC021
+	return ftsdc021_sdhci_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/fvm/clock.c b/board/faraday/fvm/clock.c
new file mode 100644
index 0000000..f5a759d
--- /dev/null
+++ b/board/faraday/fvm/clock.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+
+	return ret;
+}
diff --git a/board/faraday/fvm/lowlevel_init.S b/board/faraday/fvm/lowlevel_init.S
new file mode 100644
index 0000000..cbc006d
--- /dev/null
+++ b/board/faraday/fvm/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index a998452..089f539 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -60,6 +60,7 @@ Active  arm         arm920t        -           armltd          integrator
 Active  arm         arm920t        -           armltd          integrator          integratorcp_cm920t                  integratorcp:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        a320        faraday         -                   a320evb                              -                                                                                                                                 Po-Yu Chuang <ratbert@faraday-tech.com>
 Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
+Active  arm         faraday        fvm         faraday         -                   fvm                                  -                                                                                                                                 Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek                         at91rm9200ek                                                                                                                      Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek_ram                     at91rm9200ek:RAMBOOT                                                                                                              Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        BuS             eb_cpux9k2          eb_cpux9k2                           eb_cpux9k2                                                                                                                        Jens Scharsig <esw@bus-elektronik.de>
diff --git a/include/configs/fvm.h b/include/configs/fvm.h
new file mode 100644
index 0000000..10522b2
--- /dev/null
+++ b/include/configs/fvm.h
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Timer */
+#define CONFIG_FTTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTMAC110
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC021
+
+/* NOR flash */
+#define PHYS_FLASH_SIZE                 SZ_64M
+#define CONFIG_SYS_FLASH_BASE           0x80000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH      FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS      1
+#define CONFIG_SYS_MAX_FLASH_SECT       1024
+
+/* USB */
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#define CONFIG_USB_EHCI_BASE_LIST       { CONFIG_FOTG210_BASE }
+
+/* Environment */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE                 SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (15 preceding siblings ...)
  2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
@ 2014-02-20  3:40 ` Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
                     ` (6 more replies)
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
  18 siblings, 7 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-02-20  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A369 & Virtual SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm
   http://www.faraday-tech.com/html/documentation/index.html

There is also a QEMU based A369 emulator available at my github:

   https://github.com/dantesu1218/qemu.git

Here is a quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.5.1 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2014.01/u-boot

Changes for v10:
   - As per Albert's request, merge patch 1, 2 and patch 5, 6
   - Add missing header file for FTSDC021

Changes for v9:
   - Shrink the patch by dropping MMU/D-cache support, and see if we could get
     this patch accepted ASAP.
   - Replace the out-of-date A360 EVB with Faraday Virtual Machine (FVM).
   - Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
   - Add do_go_exec() to override the default behavior of 'go' command.
   - Make Faraday SoC helper files & ftsmc020 standalone changesets.
   - Coding style cleanup.

Changes for v8:
   - Revise MMU/D-cache support
   - Revise Faraday SoC common configurations.
   - Drop FTINTC020 interrupt controller support.
   - Drop FTLCDC200 LCD controller support.
   - Drop FTNANDC021 NAND flash controller support, it would be latter submitted
     as a standalone patch set.
   - Drop proprietary Faraday SPL support, the u-boot-spl would be adapted instead.
     However because it depends on the FTNANDC021 patch set, so it would be submitted
     after the FTNANDC021 patch set get committed.

Changes for v7:
   - Update license to use SPDX identifiers.
   - cfi_flash: drop the patch to unmap_physmem(),
     because it's already applied.
   - ftnandc021: put_unaligned() -> memcpy()
   - ftnandc021: update ecc relatived function prototypes to fix
     compile warnnings.

Changes for v6:
   - Drop ethernet driver updates for ftmac110&ftgmac100,
     because they are already commited.
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs
   - arch/arm/cpu/faraday/cmd_bootfa.c: fix compiler warnning
   - arch/arm/cpu/faraday/cmd_bootfa.c: use shorter paragraph
     in commit message, and move the original statement into the
     top of source file.
   - ftnandc021: update README for CONFIG_SYS_FTNANDC021_TIMING
   - ftnandc021: remove illegal type-punning

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (6):
  arm: add Faraday ARMv5TE cores support
  arm: faraday: add FTTMR010 timer support
  arm: faraday: add FTPWMTMR010 timer support
  arm: faraday: add A369 evaluation board support
  arm: faraday: add missing header file for FTSDC021
  arm: faraday: add virtual machine support

 arch/arm/cpu/faraday/Makefile             |   13 +
 arch/arm/cpu/faraday/a369/Makefile        |    8 +
 arch/arm/cpu/faraday/cache.c              |  164 ++++++++++++
 arch/arm/cpu/faraday/config.mk            |   15 ++
 arch/arm/cpu/faraday/cpu.c                |  115 ++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  112 ++++++++
 arch/arm/cpu/faraday/fttmr010.c           |  123 +++++++++
 arch/arm/cpu/faraday/fvm/Makefile         |    8 +
 arch/arm/cpu/faraday/start.S              |  407 +++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++
 arch/arm/include/asm/arch-fvm/hardware.h  |   76 ++++++
 arch/arm/include/asm/faraday.h            |   13 +
 board/faraday/a369evb/Makefile            |    9 +
 board/faraday/a369evb/board.c             |  122 +++++++++
 board/faraday/a369evb/clock.c             |   68 +++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 board/faraday/fvm/Makefile                |    9 +
 board/faraday/fvm/board.c                 |   60 +++++
 board/faraday/fvm/clock.c                 |   49 ++++
 board/faraday/fvm/lowlevel_init.S         |   15 ++
 boards.cfg                                |    2 +
 include/common.h                          |    3 +
 include/configs/a369.h                    |  111 ++++++++
 include/configs/faraday-common.h          |  314 ++++++++++++++++++++++
 include/configs/fvm.h                     |   61 +++++
 include/faraday/ftpwmtmr010.h             |   41 +++
 include/faraday/ftsdc021.h                |   13 +
 include/faraday/ftsmc020.h                |    1 +
 include/faraday/fttmr010.h                |   17 ++
 30 files changed, 2263 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 arch/arm/include/asm/faraday.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/clock.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/configs/fvm.h
 create mode 100644 include/faraday/ftpwmtmr010.h
 create mode 100644 include/faraday/ftsdc021.h

--
1.7.9.5

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

* [U-Boot] [PATCH v10 1/6] arm: add Faraday ARMv5TE cores support
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
@ 2014-02-20  3:40   ` Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 2/6] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
                     ` (5 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-02-20  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Here is the list of verified cores:

1. FA606TE (ARMv5TE, no mmu)
2. FA626TE (ARMv5TE)

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v10:
	- Merge [arm: add Faraday SoC helper files]

Changes for v9:
	- Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
	- Add do_go_exec() to override the default behavior of 'go' command.

Changes for v8:
	- add arm_init_before_mmu() & mmu_page_table_flush()

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Initial commit

 arch/arm/cpu/faraday/Makefile    |   10 +
 arch/arm/cpu/faraday/cache.c     |  164 +++++++++++++++
 arch/arm/cpu/faraday/config.mk   |   15 ++
 arch/arm/cpu/faraday/cpu.c       |  115 +++++++++++
 arch/arm/cpu/faraday/start.S     |  407 ++++++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/faraday.h   |   13 ++
 include/common.h                 |    3 +
 include/configs/faraday-common.h |  314 +++++++++++++++++++++++++++++
 8 files changed, 1041 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/faraday.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..c859238
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,10 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+extra-y := start.o
+
+obj-y   += cpu.o cache.o
diff --git a/arch/arm/cpu/faraday/cache.c b/arch/arm/cpu/faraday/cache.c
new file mode 100644
index 0000000..2acb954
--- /dev/null
+++ b/arch/arm/cpu/faraday/cache.c
@@ -0,0 +1,164 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/*
+ * I-Cache
+ */
+
+void invalidate_icache_all(void)
+{
+#if !defined(CONFIG_SYS_ICACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_ICACHE_OFF */
+}
+
+/*
+ * D-Cache
+ */
+
+void flush_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c14, 0\n" /* clean & invalidate */
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c14, 1\n" /* clean & invalidate */
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c6, 1\n"
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c6, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+/*
+ * MMU
+ */
+
+static void invalidate_utlb_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+static void invalidate_utlb_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	uint32_t page = 4096;
+	uint32_t mask = ~(page - 1);
+
+	/* aligned to page boundary */
+	stop = (page - 1 + stop) & mask;
+	start = start & mask;
+
+	/* invalidate U-TLB entry */
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c8, c7, 1\n"
+		"add %0, %0, %1\n"
+		"cmp %0, %2\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(page), "r"(stop)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void arm_init_before_mmu(void)
+{
+	invalidate_dcache_all();
+	invalidate_utlb_all();
+}
+
+void mmu_page_table_flush(unsigned long start, unsigned long stop)
+{
+	flush_dcache_range(start, stop);
+	invalidate_utlb_range(start, stop);
+}
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f39e70b
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+PLATFORM_CPPFLAGS += -march=armv5te
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..8eef357
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,115 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This enable_caches() overrides the weak function
+ * in "arch/arm/lib/cache.c".
+ */
+void enable_caches(void)
+{
+	icache_enable();
+	dcache_enable();
+}
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+	disable_interrupts();
+
+	/*
+	 * Turn off I-cache and invalidate it
+	 */
+	icache_disable();
+	invalidate_icache_all();
+
+	/*
+	 * Turn off D-cache
+	 * dcache_disable() in turn flushes the d-cache and disables MMU
+	 */
+	dcache_disable();
+
+	/*
+	 * After D-cache is flushed and before it is disabled there may
+	 * be some new valid entries brought into the cache. We are sure
+	 * that these lines are not dirty and will not affect our execution.
+	 * So just invalidate the entire d-cache again to avoid coherency
+	 * problems for kernel
+	 */
+	invalidate_dcache_all();
+
+	return 0;
+}
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt *regs = (void __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with system reset */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+#endif
+}
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	/* print cpu_info */
+	printf("CPU:   %u MHz\n",
+		(unsigned int)(clk_get_rate("CPU") / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("AHB") / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("APB") / 1000000));
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifdef CONFIG_CMD_GO
+/*
+ * This do_go_exec() overrides the weak function
+ * in "cmd_boot.c".
+ */
+unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
+				 char * const argv[])
+{
+	cleanup_before_linux();
+	return entry(argc, argv);
+}
+#endif /* CONFIG_CMD_GO */
+
+#ifdef CONFIG_CMD_BOOTM
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+#endif /* CONFIG_CMD_BOOTM */
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..32ce92e
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,407 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * With the following bootstrap relocation, we could flawless
+	 * boot from either ROM or NOR flash.
+	 */
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq _main
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+reloc_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo reloc_loop
+
+	ldr pc, =_main
+
+/*----------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+	mov pc, lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/arch/arm/include/asm/faraday.h b/arch/arm/include/asm/faraday.h
new file mode 100644
index 0000000..2b59af1
--- /dev/null
+++ b/arch/arm/include/asm/faraday.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ASM_FARADAY_H
+#define _ASM_FARADAY_H
+
+ulong clk_get_rate(const char *id);
+
+#endif	/* EOF */
diff --git a/include/common.h b/include/common.h
index ea3e5ed..faae212 100644
--- a/include/common.h
+++ b/include/common.h
@@ -91,6 +91,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_SOC_FARADAY
+#include <asm/faraday.h>
+#endif

 #include <part.h>
 #include <flash.h>
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..546c0a9
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,314 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+/* Faraday SoC Platform */
+#define CONFIG_SOC_FARADAY
+#define CONFIG_MACH_TYPE            758 /* Faraday */
+
+/* Faraday ARMv5TE cores are 32 bytes per line */
+#define CONFIG_SYS_CACHELINE_SIZE   32
+
+#ifdef CONFIG_SPL_BUILD
+# undef CONFIG_USE_IRQ
+# ifndef CONFIG_SYS_DCACHE_OFF
+#  define CONFIG_SYS_DCACHE_OFF
+# endif
+# ifndef CONFIG_SYS_THUMB_BUILD
+#  define CONFIG_SYS_THUMB_BUILD
+# endif
+#endif /* CONFIG_SPL_BUILD */
+
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_DISPLAY_CPUINFO
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+#ifdef CONFIG_USE_IRQ
+# define CONFIG_STACKSIZE_IRQ       SZ_32K
+# define CONFIG_STACKSIZE_FIQ       SZ_32K
+#endif
+
+#define CONFIG_SYS_HZ               1000
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MONITOR_BASE     CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+#ifndef CONFIG_CONSISTENT_DMA_START
+#define CONFIG_CONSISTENT_DMA_START 0xff000000
+#endif
+
+#ifndef CONFIG_CONSISTENT_DMA_END
+#define CONFIG_CONSISTENT_DMA_END   0xfff00000
+#endif
+
+/* Default entry point */
+#ifndef CONFIG_SYS_UBOOT_START
+#define CONFIG_SYS_UBOOT_START      CONFIG_SYS_TEXT_BASE
+#endif
+
+/* Default load address */
+#ifndef CONFIG_SYS_LOAD_ADDR
+#define CONFIG_SYS_LOAD_ADDR        (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+/* U-Boot's built-in memory test */
+#ifndef CONFIG_SYS_MEMTEST_START
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+#ifndef CONFIG_SYS_MEMTEST_END
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+#endif
+
+/*
+ * Serial driver
+ */
+#ifdef CONFIG_FTUART010
+# ifndef CONFIG_FTUART010_CLK
+# define CONFIG_FTUART010_CLK       18432000
+# endif
+# ifndef CONFIG_BAUDRATE
+# define CONFIG_BAUDRATE            38400
+# endif
+# undef CONFIG_HWFLOW
+# undef CONFIG_MODEM_SUPPORT
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# define CONFIG_SYS_NS16550_CLK         CONFIG_FTUART010_CLK
+# define CONFIG_SYS_NS16550_COM1        CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE    (-4)
+# define CONFIG_CONS_INDEX              1
+#endif /* CONFIG_FTUART010 */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR        32
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT     20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif /* CONFIG_FTMAC110 || CONFIG_FTGMAC100 */
+
+#ifndef CONFIG_ETHADDR
+#define CONFIG_ETHADDR              00:41:71:00:00:50
+#endif
+
+#ifndef CONFIG_IPADDR
+#define CONFIG_IPADDR               10.0.0.192
+#endif
+
+#ifndef CONFIG_NETMASK
+#define CONFIG_NETMASK              255.255.255.0
+#endif
+
+#ifndef CONFIG_SERVERIP
+#define CONFIG_SERVERIP             10.0.0.128
+#endif
+
+/*
+ * I2C bus driver
+ */
+#ifdef CONFIG_FTI2C010
+# define CONFIG_SYS_I2C_FTI2C010
+#endif
+#ifdef CONFIG_SYS_I2C_FTI2C010
+# define CONFIG_SYS_I2C
+# define CONFIG_SYS_I2C_SPEED       5000
+# define CONFIG_SYS_I2C_SLAVE       0
+# define CONFIG_CMD_I2C
+# define CONFIG_I2C_CMD_TREE
+#endif /* CONFIG_FTI2C010 */
+
+/*
+ * I2C-EEPROM
+ */
+#ifdef CONFIG_ENV_EEPROM_IS_ON_I2C
+# define CONFIG_CMD_EEPROM
+# define CONFIG_SYS_I2C_MULTI_EEPROMS
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      3
+# endif
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  10
+# endif
+# ifndef CONFIG_SYS_I2C_EEPROM_ADDR_LEN
+# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN         1
+# endif
+#endif
+
+/*
+ * NAND flash controller
+ */
+#ifdef CONFIG_FTNANDC021
+# define CONFIG_NAND_FTNANDC021
+#endif
+#ifdef CONFIG_SYS_NAND_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+# define CONFIG_CMD_NAND_YAFFS
+#endif
+
+/*
+ * NOR flash driver
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* HW is configured with SDIO support */
+#endif
+
+#ifdef CONFIG_FTSDC021
+# define CONFIG_SDHCI
+#endif
+
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC021)
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 0
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+# define CONFIG_USB_HUB_MIN_POWER_ON_DELAY  500
+# endif
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#ifdef CONFIG_USB_ETHER
+# ifndef CONFIG_USBNET_DEV_ADDR
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# endif
+# ifndef CONFIG_USBNET_HOST_ADDR
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+# endif
+#endif
+
+#ifdef CONFIG_USBDOWNLOAD_GADGET
+# ifndef CONFIG_G_DNL_MANUFACTURER
+# define CONFIG_G_DNL_MANUFACTURER  "Faraday"
+# endif
+# ifndef CONFIG_G_DNL_VENDOR_NUM
+# define CONFIG_G_DNL_VENDOR_NUM    0x1d50  /* OpenMoko */
+# endif
+# ifndef CONFIG_G_DNL_PRODUCT_NUM
+# define CONFIG_G_DNL_PRODUCT_NUM   0x5119
+# endif
+#endif
+
+#ifdef CONFIG_DFU_FUNCTION
+# ifndef CONFIG_SYS_DFU_DATA_BUF_SIZE
+# define CONFIG_SYS_DFU_DATA_BUF_SIZE   4096
+# endif
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux Kernel Command Line
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG      /* support ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#define CONFIG_CMD_LOADB        /* xyzModem */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v10 2/6] arm: faraday: add FTTMR010 timer support
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
@ 2014-02-20  3:40   ` Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 3/6] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
                     ` (4 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-02-20  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTTMR010 is a simple APB device which supports
generic timer functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8, v9, v10:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    2 +
 arch/arm/cpu/faraday/fttmr010.c |  123 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 ++++++
 3 files changed, 142 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index c859238..73f6934 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -8,3 +8,5 @@
 extra-y := start.o

 obj-y   += cpu.o cache.o
+
+obj-$(CONFIG_FTTMR010)    += fttmr010.o
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..28b0086
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 2ab68d1..21ab113 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -45,6 +45,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -58,4 +68,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v10 3/6] arm: faraday: add FTPWMTMR010 timer support
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 2/6] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
@ 2014-02-20  3:40   ` Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 4/6] arm: faraday: add A369 evaluation board support Kuo-Jung Su
                     ` (3 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-02-20  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTPWMTMR010 is a simple APB device which supports
both timer and pwm functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v8, v9, v10:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    1 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  112 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 +++++++++++++
 3 files changed, 154 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 73f6934..19c5796 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -10,3 +10,4 @@ extra-y := start.o
 obj-y   += cpu.o cache.o

 obj-$(CONFIG_FTTMR010)    += fttmr010.o
+obj-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..1032e44
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TIMER_ID    0
+
+static struct ftpwmtmr010_regs *regs =
+	(void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..29f4f05
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v10 4/6] arm: faraday: add A369 evaluation board support
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 3/6] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
@ 2014-02-20  3:40   ` Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 5/6] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
                     ` (2 subsequent siblings)
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-02-20  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The A369 is an ARM CPU-based SoC with rich SoC features and
convenient FPGA link for building fast system prototyping
and mass production.

More information about this hardware can be found at:
http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v10:
	- Merge [arm: faraday: ftsmc020: add a fail-safe macro constant]

Changes for v9:
	- Revise the commit message.

Changes for v8:
	- Make A369 a standalong changeset.

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- arch/arm/cpu/faraday/cpu.c:
	  struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
	- Coding Style cleanup:
	  1. struct chip_regs __iomem *regs -> struct chip_regs *regs
	  2. Move Faraday specific APIs into asm/arch-faraday/*.h
	- Fix Copyright notices (dates) throughout the patch
	- Define Faraday machine type in board's config header file
	- Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
	- Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
	  would restart after this patch series have been accepted.
	- Revise clock management system

Changes for v4:
	- Coding Style cleanup.
	- Break-down the interrupt, timers and common utilties.

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.
	- a36x_config: No more static global network configurations.
	- a36x_config: Add a common file for the redundant configurations.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/a369/Makefile        |    8 ++
 arch/arm/include/asm/arch-a369/hardware.h |   88 ++++++++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++++++++++++++++
 board/faraday/a369evb/Makefile            |    9 ++
 board/faraday/a369evb/board.c             |  122 +++++++++++++++++
 board/faraday/a369evb/clock.c             |   68 ++++++++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 boards.cfg                                |    1 +
 include/configs/a369.h                    |  111 +++++++++++++++
 include/faraday/ftsmc020.h                |    1 +
 10 files changed, 634 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a369.h

diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..1081c06
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y :=
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..55031a4
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SYSC_BASE            0x92000000
+#define CONFIG_DDRC_BASE            0x93100000
+#define CONFIG_AHBC_BASE            0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/sysc.h b/arch/arm/include/asm/arch-a369/sysc.h
new file mode 100644
index 0000000..ddf3e70
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/sysc.h
@@ -0,0 +1,211 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_A369_SYSC_H
+#define _ASM_ARCH_A369_SYSC_H
+
+struct sysc_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)    (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x)  ((((x) >> 3) & 3) > 2 ? 2 : (((x) >> 3) & 3))
+#define HWCFG_DLL_OFF      (1 << 2)
+#define HWCFG_PLL_OFF      (1 << 1)
+#define HWCFG_OSCHCNT_OFF  (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif	/* EOF */
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..cd206bb
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/sysc.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+static void pinmux_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&sysc->hclkgr);
+		setbits_le32(&sysc->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_A369_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &sysc->hclkgr);
+		writel(GPMUX_DEFAULT, &sysc->gpmux);
+		clrbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &sysc->mfpmux[0]);
+#endif
+	}
+
+	/* Clock: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &sysc->sccfg[1]);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	uint32_t nor_base;
+
+	/* Bank 0: NOR flash */
+	if ((readl(&sysc->ehwcfg) & 3) != EHWCFG_BOOT_NOR)
+		nor_base = 0x20000000;
+	else
+		nor_base = 0;
+	writel(FTSMC020_BANK_ENABLE
+		| FTSMC020_BANK_BASE(nor_base) /* base address */
+		| FTSMC020_BANK_SIZE_64M /* window size */
+		| FTSMC020_BANK_MBW_16, /* data width */
+		&smc->bank[0].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[0].tpr);
+
+	/* Bank 1 ~ 3: nothing attached */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	pinmux_init();
+	smc_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#else
+	return 0;
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a369evb/clock.c b/board/faraday/a369evb/clock.c
new file mode 100644
index 0000000..b713b89
--- /dev/null
+++ b/board/faraday/a369evb/clock.c
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 33000000; /* 33 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return (clk_get_rate_sys() * PLLCR_NS(readl(&sysc->pllcr))) >> 3;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+	/* If it's an internal CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after kicking
+	 * off slave cpu, so if GPMUX_CPUS_START is set,
+	 * it must be a slave cpu.
+	 */
+	if (!(readl(&sysc->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&sysc->hwcfg));
+
+	return clk;
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+
+	return ret;
+}
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..2085760
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index 0e663d9..194dffe 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -60,6 +60,7 @@ Active  arm         arm720t        -           armltd          integrator
 Active  arm         arm920t        -           armltd          integrator          integratorap_cm920t                  integratorap:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        -           armltd          integrator          integratorcp_cm920t                  integratorcp:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        a320        faraday         -                   a320evb                              -                                                                                                                                 Po-Yu Chuang <ratbert@faraday-tech.com>
+Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek                         at91rm9200ek                                                                                                                      Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek_ram                     at91rm9200ek:RAMBOOT                                                                                                              Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        BuS             eb_cpux9k2          eb_cpux9k2                           eb_cpux9k2                                                                                                                        Jens Scharsig <esw@bus-elektronik.de>
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..1cf9230
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,111 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support NOR flash */
+/* #define CONFIG_A369_NOR_FLASH */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_A369_USB_ETHER */
+
+/* Support USB DFU */
+#define CONFIG_A369_USB_DFU
+
+#if defined(CONFIG_A369_USB_ETHER) && defined(CONFIG_A369_USB_DFU)
+# error "USB-ETHER and USB-DFU can't be enabled at the same time."
+#endif
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Timer */
+#define CONFIG_FTPWMTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTGMAC100
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC010
+
+/* NOR flash */
+#ifdef CONFIG_A369_NOR_FLASH
+# define PHYS_FLASH_SIZE                SZ_64M
+# define CONFIG_SYS_FLASH_BASE          0x20000000
+# define CONFIG_SYS_FLASH_CFI_WIDTH     FLASH_CFI_16BIT
+# define CONFIG_SYS_MAX_FLASH_BANKS     1
+# define CONFIG_SYS_MAX_FLASH_SECT      1024
+#endif
+
+/* USB */
+#if defined(CONFIG_A369_USB_DFU) || defined(CONFIG_A369_USB_ETHER)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_GADGET_VBUS_DRAW        200
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+# define CONFIG_USB_EHCI_BASE               CONFIG_FUSBH200_BASE
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+#ifdef CONFIG_A369_USB_DFU
+# define CONFIG_USBDOWNLOAD_GADGET
+# define CONFIG_DFU_FUNCTION
+# define CONFIG_DFU_RAM
+# define CONFIG_CMD_DFU
+#endif
+
+#ifdef CONFIG_A369_USB_ETHER
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+#endif
+
+/* Environment */
+#if defined(CONFIG_A369_NOR_FLASH)
+# define CONFIG_ENV_IS_IN_FLASH /* NOR flash */
+# define CONFIG_ENV_OFFSET          0x3f0000
+#else
+# define CONFIG_ENV_IS_NOWHERE
+#endif
+
+#define CONFIG_ENV_SIZE             SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+/* Platform specific environment variables */
+#ifdef CONFIG_A369_USB_DFU
+# define CONFIG_EXTRA_ENV_SETTINGS \
+	/* USB-DFU: [name] [interface] [start] [end] */ \
+	"dfu_alt_info=ram at 0x10800000 ram 0x10800000 0x11800000\0"
+#endif
+
+#endif	/* EOF */
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 54120ab..485d7c2 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -70,5 +70,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_FAILSAFE	0x0f1ff3ff /* fail-safe timing */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v10 5/6] arm: faraday: add missing header file for FTSDC021
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 4/6] arm: faraday: add A369 evaluation board support Kuo-Jung Su
@ 2014-02-20  3:40   ` Kuo-Jung Su
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 6/6] arm: faraday: add virtual machine support Kuo-Jung Su
  2014-03-25 12:41   ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Albert ARIBAUD
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-02-20  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

For the Faraday FTSDC021 (SDHCI) controller driver source is
sent out before the patches for Faraday Virtual Machine (FVM)
which actually uses this chip.

The header file (ftsdc021.h) has been accidentally removed
by commit: 3b98b57fa - include: delete unused header files

This patch simply rollback this removal.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v10:
	- Initial commit

 include/faraday/ftsdc021.h |   13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 include/faraday/ftsdc021.h

diff --git a/include/faraday/ftsdc021.h b/include/faraday/ftsdc021.h
new file mode 100644
index 0000000..de8e250
--- /dev/null
+++ b/include/faraday/ftsdc021.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __FTSDC021_H
+#define __FTSDC021_H
+
+int ftsdc021_sdhci_init(u32 regbase);
+
+#endif /* __FTSDC021_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v10 6/6] arm: faraday: add virtual machine support
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 5/6] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
@ 2014-02-20  3:40   ` Kuo-Jung Su
  2014-03-25 12:41   ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Albert ARIBAUD
  6 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-02-20  3:40 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday Virtual Machine (FVM) is a QEMU based emulator
which is designed for early stage software development
(i.e., IPL, SPL development).

Please check the link bellow for details:
https://github.com/dantesu1218/qemu/blob/qemu-1.5.1/hw/arm/faraday_fvm.c

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v10:
	- Nothing updates

Changes for v9:
	- Initial commit

 arch/arm/cpu/faraday/fvm/Makefile        |    8 ++++
 arch/arm/include/asm/arch-fvm/hardware.h |   76 ++++++++++++++++++++++++++++++
 board/faraday/fvm/Makefile               |    9 ++++
 board/faraday/fvm/board.c                |   60 +++++++++++++++++++++++
 board/faraday/fvm/clock.c                |   49 +++++++++++++++++++
 board/faraday/fvm/lowlevel_init.S        |   15 ++++++
 boards.cfg                               |    1 +
 include/configs/fvm.h                    |   61 ++++++++++++++++++++++++
 8 files changed, 279 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/clock.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 include/configs/fvm.h

diff --git a/arch/arm/cpu/faraday/fvm/Makefile b/arch/arm/cpu/faraday/fvm/Makefile
new file mode 100644
index 0000000..1081c06
--- /dev/null
+++ b/arch/arm/cpu/faraday/fvm/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y :=
diff --git a/arch/arm/include/asm/arch-fvm/hardware.h b/arch/arm/include/asm/arch-fvm/hardware.h
new file mode 100644
index 0000000..e362984
--- /dev/null
+++ b/arch/arm/include/asm/arch-fvm/hardware.h
@@ -0,0 +1,76 @@
+/*
+ * arch/arm/include/asm/arch-fvm/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <asm/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00020000
+
+#define CONFIG_SYSC_BASE            0x90f00000
+#define CONFIG_SYSC_IRQ             15
+
+#define CONFIG_FTINTC030_BASE       0x91000000
+
+#define CONFIG_FTTMR010_BASE        0x90200000
+#define CONFIG_FTTMR010_IRQ         1
+
+#define CONFIG_FTUART010_BASE0      0x90000000
+#define CONFIG_FTUART010_IRQ0       2
+#define CONFIG_FTUART010_BASE1      0x90100000
+#define CONFIG_FTUART010_IRQ1       3
+#define CONFIG_FTUART010_BASE       CONFIG_FTUART010_BASE0
+
+#define CONFIG_DDRC_BASE            0x90300000
+
+#define CONFIG_FTI2C010_BASE        0x90400000
+#define CONFIG_FTI2C010_IRQ         4
+
+#define CONFIG_FTSSP010_BASE        0x90500000
+#define CONFIG_FTSSP010_IRQ         5
+
+#define CONFIG_FTWDT010_BASE        0x90600000
+#define CONFIG_FTWDT010_IRQ         6
+
+#define CONFIG_FTRTC011_BASE        0x90700000
+#define CONFIG_FTRTC011_IRQ         7
+
+#define CONFIG_FTTSC010_BASE        0x90800000
+#define CONFIG_FTTSC010_IRQ         8
+
+#define CONFIG_FTAPBBRG020_BASE     0x91100000
+#define CONFIG_FTAPBBRG020_IRQ      16
+
+#define CONFIG_FTDMAC020_BASE       0x91200000
+#define CONFIG_FTDMAC020_IRQ        17
+
+#define CONFIG_FTMAC110_BASE        0x91300000
+#define CONFIG_FTMAC110_IRQ         18
+
+#define CONFIG_FTSPI020_BASE        0x91400000
+#define CONFIG_FTSPI020_IRQ         19
+
+#define CONFIG_FTNANDC021_BASE      0x91500000
+#define CONFIG_FTNANDC021_IRQ       20
+
+#define CONFIG_FTSDC021_BASE        0x91600000
+#define CONFIG_FTSDC021_IRQ         21
+
+#define CONFIG_FOTG210_BASE         0x91700000
+#define CONFIG_FOTG210_IRQ          22
+
+#define CONFIG_FTLCDC200_BASE       0x91800000
+#define CONFIG_FTLCDC200_IRQ        23
+
+#endif /* EOF */
diff --git a/board/faraday/fvm/Makefile b/board/faraday/fvm/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/fvm/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/fvm/board.c b/board/faraday/fvm/board.c
new file mode 100644
index 0000000..6c2b03a
--- /dev/null
+++ b/board/faraday/fvm/board.c
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <faraday/ftsdc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_FTMAC110
+	return ftmac110_initialize(bd);
+#else
+	return 0;
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC021
+	return ftsdc021_sdhci_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/fvm/clock.c b/board/faraday/fvm/clock.c
new file mode 100644
index 0000000..f5a759d
--- /dev/null
+++ b/board/faraday/fvm/clock.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+
+	return ret;
+}
diff --git a/board/faraday/fvm/lowlevel_init.S b/board/faraday/fvm/lowlevel_init.S
new file mode 100644
index 0000000..cbc006d
--- /dev/null
+++ b/board/faraday/fvm/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index 194dffe..e783231 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -61,6 +61,7 @@ Active  arm         arm920t        -           armltd          integrator
 Active  arm         arm920t        -           armltd          integrator          integratorcp_cm920t                  integratorcp:CM920T                                                                                                               Linus Walleij <linus.walleij@linaro.org>
 Active  arm         arm920t        a320        faraday         -                   a320evb                              -                                                                                                                                 Po-Yu Chuang <ratbert@faraday-tech.com>
 Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
+Active  arm         faraday        fvm         faraday         -                   fvm                                  -                                                                                                                                 Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek                         at91rm9200ek                                                                                                                      Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        atmel           at91rm9200ek        at91rm9200ek_ram                     at91rm9200ek:RAMBOOT                                                                                                              Andreas Bie?mann <andreas.devel@gmail.com>
 Active  arm         arm920t        at91        BuS             eb_cpux9k2          eb_cpux9k2                           eb_cpux9k2                                                                                                                        Jens Scharsig <esw@bus-elektronik.de>
diff --git a/include/configs/fvm.h b/include/configs/fvm.h
new file mode 100644
index 0000000..10522b2
--- /dev/null
+++ b/include/configs/fvm.h
@@ -0,0 +1,61 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Timer */
+#define CONFIG_FTTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTMAC110
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC021
+
+/* NOR flash */
+#define PHYS_FLASH_SIZE                 SZ_64M
+#define CONFIG_SYS_FLASH_BASE           0x80000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH      FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS      1
+#define CONFIG_SYS_MAX_FLASH_SECT       1024
+
+/* USB */
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#define CONFIG_USB_EHCI_BASE_LIST       { CONFIG_FOTG210_BASE }
+
+/* Environment */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE                 SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [U-Boot, v8] nand: add Faraday FTNANDC021 NAND controller support
  2013-11-28  2:48   ` [U-Boot] [PATCH v8] nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
@ 2014-03-04  2:17     ` Scott Wood
  2014-03-04  3:58       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Scott Wood @ 2014-03-04  2:17 UTC (permalink / raw)
  To: u-boot

On Thu, Nov 28, 2013 at 10:48:51AM +0800, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday FTNANDC021 is an integrated NAND flash controller.
> It use a build-in command table to abstract the underlying
> NAND flash control logic.
> 
> For example:
> 
> Issuing a command 0x10 to FTNANDC021 would result in
> a page write + a read status operation.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
> CC: Scott Wood <scottwood@freescale.com>
> 
> ---
> Changes for v8:
>    - Add ftnandc021 spl driver
>    - Drop '#include <asm/unaligned.h>'
>    - Coding style cleanup
>    - Update NAND flash ecc layout
>    - Split from Faraday A36x patch series

Acked-by: Scott Wood <scottwood@freescale.com>

Please unsplit (or just have the custodian that takes the other Faraday
patches take this with the ack).  My understanding is that U-Boot's dead
code rules prevent me from applying this separately from a board that
uses it (it also makes it hard for me to verify that it builds).

-Scott

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

* [U-Boot] [U-Boot, v8] nand: add Faraday FTNANDC021 NAND controller support
  2014-03-04  2:17     ` [U-Boot] [U-Boot, " Scott Wood
@ 2014-03-04  3:58       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-04  3:58 UTC (permalink / raw)
  To: u-boot

Got it, thanks, and sorry for the mess I made.

I'll send out the unsplit patch after the Faraday platform patches got commited.

2014-03-04 10:17 GMT+08:00 Scott Wood <scottwood@freescale.com>:
> On Thu, Nov 28, 2013 at 10:48:51AM +0800, Kuo-Jung Su wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday FTNANDC021 is an integrated NAND flash controller.
>> It use a build-in command table to abstract the underlying
>> NAND flash control logic.
>>
>> For example:
>>
>> Issuing a command 0x10 to FTNANDC021 would result in
>> a page write + a read status operation.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Albert ARIBAUD <albert.u.boot@aribaud.net>
>> CC: Scott Wood <scottwood@freescale.com>
>>
>> ---
>> Changes for v8:
>>    - Add ftnandc021 spl driver
>>    - Drop '#include <asm/unaligned.h>'
>>    - Coding style cleanup
>>    - Update NAND flash ecc layout
>>    - Split from Faraday A36x patch series
>
> Acked-by: Scott Wood <scottwood@freescale.com>
>
> Please unsplit (or just have the custodian that takes the other Faraday
> patches take this with the ack).  My understanding is that U-Boot's dead
> code rules prevent me from applying this separately from a board that
> uses it (it also makes it hard for me to verify that it builds).
>
> -Scott



-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (5 preceding siblings ...)
  2014-02-20  3:40   ` [U-Boot] [PATCH v10 6/6] arm: faraday: add virtual machine support Kuo-Jung Su
@ 2014-03-25 12:41   ` Albert ARIBAUD
  2014-03-26  6:08     ` Kuo-Jung Su
  6 siblings, 1 reply; 311+ messages in thread
From: Albert ARIBAUD @ 2014-03-25 12:41 UTC (permalink / raw)
  To: u-boot

Hi Kuo-Jung,

On Thu, 20 Feb 2014 11:40:32 +0800, Kuo-Jung Su <dantesu@gmail.com>
wrote:

> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> These patches introduce Faraday A369 & Virtual SoC platform support.

Except for patches 4/6 and 6/6 in which boards.cfg needed manual
fixing (due to commit 3fa67050), the series applies to current
u-boot-arm/master, but building fails for both a369evb and fvm with
multiple instances of this error:

include/asm/arch/hardware.h:14:23: fatal error: asm/sizes.h: No such
file or directory

Can you please rebase (for boards.cfg) and diagnose?

Amicalement,
-- 
Albert.

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

* [U-Boot] [PATCH v11 0/6] arm: add Faraday SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (16 preceding siblings ...)
  2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
@ 2014-03-26  6:03 ` Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
                     ` (5 more replies)
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
  18 siblings, 6 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:03 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A369 & Virtual SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm
   http://www.faraday-tech.com/html/documentation/index.html

There is also a QEMU based A369 emulator available at my github:

   https://github.com/dantesu1218/qemu.git

Here is a quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.5.1 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2014.01/u-boot

Changes for v11:
   - Fix boards.cfg (due to commit 3fa67050)
   - Rename <asm/sizes.h> to <linux/sizes.h> (due to commit 1ace4022)
   - Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
     instead of using CONFIG_FTTMR010 in 'arch/arm/cpu/faraday/Makefile'
   - Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
     instead of using CONFIG_FTPWMTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v10:
   - As per Albert's request, merge patch 1, 2 and patch 5, 6
   - Add missing header file for FTSDC021

Changes for v9:
   - Shrink the patch by dropping MMU/D-cache support, and see if we could get
     this patch accepted ASAP.
   - Replace the out-of-date A360 EVB with Faraday Virtual Machine (FVM).
   - Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
   - Add do_go_exec() to override the default behavior of 'go' command.
   - Make Faraday SoC helper files & ftsmc020 standalone changesets.
   - Coding style cleanup.

Changes for v8:
   - Revise MMU/D-cache support
   - Revise Faraday SoC common configurations.
   - Drop FTINTC020 interrupt controller support.
   - Drop FTLCDC200 LCD controller support.
   - Drop FTNANDC021 NAND flash controller support, it would be latter submitted
     as a standalone patch set.
   - Drop proprietary Faraday SPL support, the u-boot-spl would be adapted instead.
     However because it depends on the FTNANDC021 patch set, so it would be submitted
     after the FTNANDC021 patch set get committed.

Changes for v7:
   - Update license to use SPDX identifiers.
   - cfi_flash: drop the patch to unmap_physmem(),
     because it's already applied.
   - ftnandc021: put_unaligned() -> memcpy()
   - ftnandc021: update ecc relatived function prototypes to fix
     compile warnnings.

Changes for v6:
   - Drop ethernet driver updates for ftmac110&ftgmac100,
     because they are already commited.
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs
   - arch/arm/cpu/faraday/cmd_bootfa.c: fix compiler warnning
   - arch/arm/cpu/faraday/cmd_bootfa.c: use shorter paragraph
     in commit message, and move the original statement into the
     top of source file.
   - ftnandc021: update README for CONFIG_SYS_FTNANDC021_TIMING
   - ftnandc021: remove illegal type-punning

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.


Kuo-Jung Su (6):
  arm: add Faraday ARMv5TE cores support
  arm: faraday: add FTTMR010 timer support
  arm: faraday: add FTPWMTMR010 timer support
  arm: faraday: add A369 evaluation board support
  arm: faraday: add missing header file for FTSDC021
  arm: faraday: add virtual machine support

 arch/arm/cpu/faraday/Makefile             |   10 +
 arch/arm/cpu/faraday/a369/Makefile        |    8 +
 arch/arm/cpu/faraday/cache.c              |  164 ++++++++++++
 arch/arm/cpu/faraday/config.mk            |   15 ++
 arch/arm/cpu/faraday/cpu.c                |  115 ++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  112 ++++++++
 arch/arm/cpu/faraday/fttmr010.c           |  123 +++++++++
 arch/arm/cpu/faraday/fvm/Makefile         |    8 +
 arch/arm/cpu/faraday/start.S              |  407 +++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++
 arch/arm/include/asm/arch-fvm/hardware.h  |   76 ++++++
 arch/arm/include/asm/faraday.h            |   13 +
 board/faraday/a369evb/Makefile            |    9 +
 board/faraday/a369evb/board.c             |  122 +++++++++
 board/faraday/a369evb/clock.c             |   68 +++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 board/faraday/fvm/Makefile                |    9 +
 board/faraday/fvm/board.c                 |   60 +++++
 board/faraday/fvm/clock.c                 |   49 ++++
 board/faraday/fvm/lowlevel_init.S         |   15 ++
 boards.cfg                                |    2 +
 include/common.h                          |    3 +
 include/configs/a369.h                    |  108 ++++++++
 include/configs/faraday-common.h          |  314 ++++++++++++++++++++++
 include/configs/fvm.h                     |   58 ++++
 include/faraday/ftpwmtmr010.h             |   41 +++
 include/faraday/ftsdc021.h                |   13 +
 include/faraday/ftsmc020.h                |    1 +
 include/faraday/fttmr010.h                |   17 ++
 30 files changed, 2254 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 arch/arm/include/asm/faraday.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/clock.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/configs/fvm.h
 create mode 100644 include/faraday/ftpwmtmr010.h
 create mode 100644 include/faraday/ftsdc021.h

--
1.7.9.5

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

* [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
@ 2014-03-26  6:03   ` Kuo-Jung Su
  2014-03-26  6:47     ` Wolfgang Denk
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 2/6] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:03 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Here is the list of verified cores:

1. FA606TE (ARMv5TE, no mmu)
2. FA626TE (ARMv5TE)

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v11:
	- Nothing updates

Changes for v10:
	- Merge [arm: add Faraday SoC helper files]

Changes for v9:
	- Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
	- Add do_go_exec() to override the default behavior of 'go' command.

Changes for v8:
	- add arm_init_before_mmu() & mmu_page_table_flush()

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Initial commit

 arch/arm/cpu/faraday/Makefile    |   10 +
 arch/arm/cpu/faraday/cache.c     |  164 +++++++++++++++
 arch/arm/cpu/faraday/config.mk   |   15 ++
 arch/arm/cpu/faraday/cpu.c       |  115 +++++++++++
 arch/arm/cpu/faraday/start.S     |  407 ++++++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/faraday.h   |   13 ++
 include/common.h                 |    3 +
 include/configs/faraday-common.h |  314 +++++++++++++++++++++++++++++
 8 files changed, 1041 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/faraday.h
 create mode 100644 include/configs/faraday-common.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..c859238
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,10 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+extra-y := start.o
+
+obj-y   += cpu.o cache.o
diff --git a/arch/arm/cpu/faraday/cache.c b/arch/arm/cpu/faraday/cache.c
new file mode 100644
index 0000000..2acb954
--- /dev/null
+++ b/arch/arm/cpu/faraday/cache.c
@@ -0,0 +1,164 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/*
+ * I-Cache
+ */
+
+void invalidate_icache_all(void)
+{
+#if !defined(CONFIG_SYS_ICACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_ICACHE_OFF */
+}
+
+/*
+ * D-Cache
+ */
+
+void flush_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c14, 0\n" /* clean & invalidate */
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c14, 1\n" /* clean & invalidate */
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c6, 1\n"
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c6, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+/*
+ * MMU
+ */
+
+static void invalidate_utlb_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+static void invalidate_utlb_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	uint32_t page = 4096;
+	uint32_t mask = ~(page - 1);
+
+	/* aligned to page boundary */
+	stop = (page - 1 + stop) & mask;
+	start = start & mask;
+
+	/* invalidate U-TLB entry */
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c8, c7, 1\n"
+		"add %0, %0, %1\n"
+		"cmp %0, %2\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(page), "r"(stop)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void arm_init_before_mmu(void)
+{
+	invalidate_dcache_all();
+	invalidate_utlb_all();
+}
+
+void mmu_page_table_flush(unsigned long start, unsigned long stop)
+{
+	flush_dcache_range(start, stop);
+	invalidate_utlb_range(start, stop);
+}
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f39e70b
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+PLATFORM_CPPFLAGS += -march=armv5te
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..8eef357
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,115 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This enable_caches() overrides the weak function
+ * in "arch/arm/lib/cache.c".
+ */
+void enable_caches(void)
+{
+	icache_enable();
+	dcache_enable();
+}
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+	disable_interrupts();
+
+	/*
+	 * Turn off I-cache and invalidate it
+	 */
+	icache_disable();
+	invalidate_icache_all();
+
+	/*
+	 * Turn off D-cache
+	 * dcache_disable() in turn flushes the d-cache and disables MMU
+	 */
+	dcache_disable();
+
+	/*
+	 * After D-cache is flushed and before it is disabled there may
+	 * be some new valid entries brought into the cache. We are sure
+	 * that these lines are not dirty and will not affect our execution.
+	 * So just invalidate the entire d-cache again to avoid coherency
+	 * problems for kernel
+	 */
+	invalidate_dcache_all();
+
+	return 0;
+}
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt *regs = (void __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with system reset */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+#endif
+}
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	/* print cpu_info */
+	printf("CPU:   %u MHz\n",
+		(unsigned int)(clk_get_rate("CPU") / 1000000));
+
+	printf("AHB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("AHB") / 1000000));
+
+	printf("APB:   %u MHz\n",
+		(unsigned int)(clk_get_rate("APB") / 1000000));
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifdef CONFIG_CMD_GO
+/*
+ * This do_go_exec() overrides the weak function
+ * in "cmd_boot.c".
+ */
+unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
+				 char * const argv[])
+{
+	cleanup_before_linux();
+	return entry(argc, argv);
+}
+#endif /* CONFIG_CMD_GO */
+
+#ifdef CONFIG_CMD_BOOTM
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+#endif /* CONFIG_CMD_BOOTM */
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..32ce92e
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,407 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * With the following bootstrap relocation, we could flawless
+	 * boot from either ROM or NOR flash.
+	 */
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq _main
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+reloc_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo reloc_loop
+
+	ldr pc, =_main
+
+/*----------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+	mov pc, lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/arch/arm/include/asm/faraday.h b/arch/arm/include/asm/faraday.h
new file mode 100644
index 0000000..2b59af1
--- /dev/null
+++ b/arch/arm/include/asm/faraday.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef _ASM_FARADAY_H
+#define _ASM_FARADAY_H
+
+ulong clk_get_rate(const char *id);
+
+#endif	/* EOF */
diff --git a/include/common.h b/include/common.h
index 5c9bd08..de3120c 100644
--- a/include/common.h
+++ b/include/common.h
@@ -88,6 +88,9 @@ typedef volatile unsigned char	vu_char;
 #ifdef CONFIG_SOC_DA8XX
 #include <asm/arch/hardware.h>
 #endif
+#ifdef CONFIG_SOC_FARADAY
+#include <asm/faraday.h>
+#endif

 #include <part.h>
 #include <flash.h>
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..546c0a9
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,314 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+/* Faraday SoC Platform */
+#define CONFIG_SOC_FARADAY
+#define CONFIG_MACH_TYPE            758 /* Faraday */
+
+/* Faraday ARMv5TE cores are 32 bytes per line */
+#define CONFIG_SYS_CACHELINE_SIZE   32
+
+#ifdef CONFIG_SPL_BUILD
+# undef CONFIG_USE_IRQ
+# ifndef CONFIG_SYS_DCACHE_OFF
+#  define CONFIG_SYS_DCACHE_OFF
+# endif
+# ifndef CONFIG_SYS_THUMB_BUILD
+#  define CONFIG_SYS_THUMB_BUILD
+# endif
+#endif /* CONFIG_SPL_BUILD */
+
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_DISPLAY_CPUINFO
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+#ifdef CONFIG_USE_IRQ
+# define CONFIG_STACKSIZE_IRQ       SZ_32K
+# define CONFIG_STACKSIZE_FIQ       SZ_32K
+#endif
+
+#define CONFIG_SYS_HZ               1000
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MONITOR_BASE     CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+#ifndef CONFIG_CONSISTENT_DMA_START
+#define CONFIG_CONSISTENT_DMA_START 0xff000000
+#endif
+
+#ifndef CONFIG_CONSISTENT_DMA_END
+#define CONFIG_CONSISTENT_DMA_END   0xfff00000
+#endif
+
+/* Default entry point */
+#ifndef CONFIG_SYS_UBOOT_START
+#define CONFIG_SYS_UBOOT_START      CONFIG_SYS_TEXT_BASE
+#endif
+
+/* Default load address */
+#ifndef CONFIG_SYS_LOAD_ADDR
+#define CONFIG_SYS_LOAD_ADDR        (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+/* U-Boot's built-in memory test */
+#ifndef CONFIG_SYS_MEMTEST_START
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+#ifndef CONFIG_SYS_MEMTEST_END
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+#endif
+
+/*
+ * Serial driver
+ */
+#ifdef CONFIG_FTUART010
+# ifndef CONFIG_FTUART010_CLK
+# define CONFIG_FTUART010_CLK       18432000
+# endif
+# ifndef CONFIG_BAUDRATE
+# define CONFIG_BAUDRATE            38400
+# endif
+# undef CONFIG_HWFLOW
+# undef CONFIG_MODEM_SUPPORT
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# define CONFIG_SYS_NS16550_CLK         CONFIG_FTUART010_CLK
+# define CONFIG_SYS_NS16550_COM1        CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE    (-4)
+# define CONFIG_CONS_INDEX              1
+#endif /* CONFIG_FTUART010 */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR        32
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT     20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif /* CONFIG_FTMAC110 || CONFIG_FTGMAC100 */
+
+#ifndef CONFIG_ETHADDR
+#define CONFIG_ETHADDR              00:41:71:00:00:50
+#endif
+
+#ifndef CONFIG_IPADDR
+#define CONFIG_IPADDR               10.0.0.192
+#endif
+
+#ifndef CONFIG_NETMASK
+#define CONFIG_NETMASK              255.255.255.0
+#endif
+
+#ifndef CONFIG_SERVERIP
+#define CONFIG_SERVERIP             10.0.0.128
+#endif
+
+/*
+ * I2C bus driver
+ */
+#ifdef CONFIG_FTI2C010
+# define CONFIG_SYS_I2C_FTI2C010
+#endif
+#ifdef CONFIG_SYS_I2C_FTI2C010
+# define CONFIG_SYS_I2C
+# define CONFIG_SYS_I2C_SPEED       5000
+# define CONFIG_SYS_I2C_SLAVE       0
+# define CONFIG_CMD_I2C
+# define CONFIG_I2C_CMD_TREE
+#endif /* CONFIG_FTI2C010 */
+
+/*
+ * I2C-EEPROM
+ */
+#ifdef CONFIG_ENV_EEPROM_IS_ON_I2C
+# define CONFIG_CMD_EEPROM
+# define CONFIG_SYS_I2C_MULTI_EEPROMS
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      3
+# endif
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  10
+# endif
+# ifndef CONFIG_SYS_I2C_EEPROM_ADDR_LEN
+# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN         1
+# endif
+#endif
+
+/*
+ * NAND flash controller
+ */
+#ifdef CONFIG_FTNANDC021
+# define CONFIG_NAND_FTNANDC021
+#endif
+#ifdef CONFIG_SYS_NAND_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+# define CONFIG_CMD_NAND_YAFFS
+#endif
+
+/*
+ * NOR flash driver
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* HW is configured with SDIO support */
+#endif
+
+#ifdef CONFIG_FTSDC021
+# define CONFIG_SDHCI
+#endif
+
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC021)
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 0
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+# define CONFIG_USB_HUB_MIN_POWER_ON_DELAY  500
+# endif
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * USB Gadget
+ */
+#ifdef CONFIG_USB_ETHER
+# ifndef CONFIG_USBNET_DEV_ADDR
+# define CONFIG_USBNET_DEV_ADDR     "00:41:71:00:00:55" /* U-Boot */
+# endif
+# ifndef CONFIG_USBNET_HOST_ADDR
+# define CONFIG_USBNET_HOST_ADDR    "00:41:71:00:00:54" /* Host PC */
+# endif
+#endif
+
+#ifdef CONFIG_USBDOWNLOAD_GADGET
+# ifndef CONFIG_G_DNL_MANUFACTURER
+# define CONFIG_G_DNL_MANUFACTURER  "Faraday"
+# endif
+# ifndef CONFIG_G_DNL_VENDOR_NUM
+# define CONFIG_G_DNL_VENDOR_NUM    0x1d50  /* OpenMoko */
+# endif
+# ifndef CONFIG_G_DNL_PRODUCT_NUM
+# define CONFIG_G_DNL_PRODUCT_NUM   0x5119
+# endif
+#endif
+
+#ifdef CONFIG_DFU_FUNCTION
+# ifndef CONFIG_SYS_DFU_DATA_BUF_SIZE
+# define CONFIG_SYS_DFU_DATA_BUF_SIZE   4096
+# endif
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LZMA                 /* Support LZMA */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          32
+
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2  "$ "
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux Kernel Command Line
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG      /* support ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#define CONFIG_CMD_LOADB        /* xyzModem */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v11 2/6] arm: faraday: add FTTMR010 timer support
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
@ 2014-03-26  6:03   ` Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 3/6] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:03 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTTMR010 is a simple APB device which supports
generic timer functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v11:
	- Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
	  instead of using CONFIG_FTTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v8, v9, v10:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/fttmr010.c |  123 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 ++++++
 2 files changed, 140 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..28b0086
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+		&regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 2ab68d1..21ab113 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -45,6 +45,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -58,4 +68,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v11 3/6] arm: faraday: add FTPWMTMR010 timer support
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 2/6] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
@ 2014-03-26  6:03   ` Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 4/6] arm: faraday: add A369 evaluation board support Kuo-Jung Su
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:03 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTPWMTMR010 is a simple APB device which supports
both timer and pwm functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v11:
	- Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
	  instead of using CONFIG_FTPWMTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v8, v9, v10:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/ftpwmtmr010.c |  112 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 +++++++++++++
 2 files changed, 153 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..1032e44
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TIMER_ID    0
+
+static struct ftpwmtmr010_regs *regs =
+	(void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+		&regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..29f4f05
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v11 4/6] arm: faraday: add A369 evaluation board support
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 3/6] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
@ 2014-03-26  6:03   ` Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 5/6] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 6/6] arm: faraday: add virtual machine support Kuo-Jung Su
  5 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:03 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The A369 is an ARM CPU-based SoC with rich SoC features and
convenient FPGA link for building fast system prototyping
and mass production.

More information about this hardware can be found at:
http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v11:
	- Fix boards.cfg (due to commit 3fa67050)
	- Rename <asm/sizes.h> to <linux/sizes.h> (due to commit 1ace4022)
	- Directly specify the timer object in 'arch/arm/cpu/faraday/a369/Makefile'
	  instead of using CONFIG_FTPWMTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v10:
	- Merge [arm: faraday: ftsmc020: add a fail-safe macro constant]

Changes for v9:
	- Revise the commit message.

Changes for v8:
	- Make A369 a standalong changeset.

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- arch/arm/cpu/faraday/cpu.c:
	  struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
	- Coding Style cleanup:
	  1. struct chip_regs __iomem *regs -> struct chip_regs *regs
	  2. Move Faraday specific APIs into asm/arch-faraday/*.h
	- Fix Copyright notices (dates) throughout the patch
	- Define Faraday machine type in board's config header file
	- Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
	- Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
	  would restart after this patch series have been accepted.
	- Revise clock management system

Changes for v4:
	- Coding Style cleanup.
	- Break-down the interrupt, timers and common utilties.

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.
	- a36x_config: No more static global network configurations.
	- a36x_config: Add a common file for the redundant configurations.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/a369/Makefile        |    8 ++
 arch/arm/include/asm/arch-a369/hardware.h |   88 ++++++++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++++++++++++++++
 board/faraday/a369evb/Makefile            |    9 ++
 board/faraday/a369evb/board.c             |  122 +++++++++++++++++
 board/faraday/a369evb/clock.c             |   68 ++++++++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 boards.cfg                                |    1 +
 include/configs/a369.h                    |  108 +++++++++++++++
 include/faraday/ftsmc020.h                |    1 +
 10 files changed, 631 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/clock.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a369.h

diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..8a7c979
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y := ../ftpwmtmr010.o
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..9c824ad
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <linux/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SYSC_BASE            0x92000000
+#define CONFIG_DDRC_BASE            0x93100000
+#define CONFIG_AHBC_BASE            0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/sysc.h b/arch/arm/include/asm/arch-a369/sysc.h
new file mode 100644
index 0000000..ddf3e70
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/sysc.h
@@ -0,0 +1,211 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_A369_SYSC_H
+#define _ASM_ARCH_A369_SYSC_H
+
+struct sysc_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)    (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x)  ((((x) >> 3) & 3) > 2 ? 2 : (((x) >> 3) & 3))
+#define HWCFG_DLL_OFF      (1 << 2)
+#define HWCFG_PLL_OFF      (1 << 1)
+#define HWCFG_OSCHCNT_OFF  (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif	/* EOF */
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..cd206bb
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,122 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/sysc.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+static void pinmux_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+			&sysc->hclkgr);
+		setbits_le32(&sysc->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_A369_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &sysc->hclkgr);
+		writel(GPMUX_DEFAULT, &sysc->gpmux);
+		clrbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &sysc->mfpmux[0]);
+#endif
+	}
+
+	/* Clock: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &sysc->sccfg[1]);
+}
+
+/*
+ * Static Memory Controller (NOR Flash)
+ */
+static void smc_init(void)
+{
+	uint32_t nor_base;
+
+	/* Bank 0: NOR flash */
+	if ((readl(&sysc->ehwcfg) & 3) != EHWCFG_BOOT_NOR)
+		nor_base = 0x20000000;
+	else
+		nor_base = 0;
+	writel(FTSMC020_BANK_ENABLE
+		| FTSMC020_BANK_BASE(nor_base) /* base address */
+		| FTSMC020_BANK_SIZE_64M /* window size */
+		| FTSMC020_BANK_MBW_16, /* data width */
+		&smc->bank[0].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[0].tpr);
+
+	/* Bank 1 ~ 3: nothing attached */
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[1].tpr);
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[2].tpr);
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[3].tpr);
+}
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	pinmux_init();
+	smc_init();
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_USB_ETHER
+	return usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	return ftgmac100_initialize(bd);
+#else
+	return 0;
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC010
+	return ftsdc010_mmc_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/a369evb/clock.c b/board/faraday/a369evb/clock.c
new file mode 100644
index 0000000..b713b89
--- /dev/null
+++ b/board/faraday/a369evb/clock.c
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysc.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+static inline ulong clk_get_rate_sys(void)
+{
+	return 33000000; /* 33 MHz */
+}
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return (clk_get_rate_sys() * PLLCR_NS(readl(&sysc->pllcr))) >> 3;
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return clk_get_rate_ahb() >> 1;
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	ulong clk = clk_get_rate_ahb();
+
+	/* If it's an internal CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after kicking
+	 * off slave cpu, so if GPMUX_CPUS_START is set,
+	 * it must be a slave cpu.
+	 */
+	if (!(readl(&sysc->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&sysc->hwcfg));
+
+	return clk;
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "SPI") || !strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+
+	return ret;
+}
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..2085760
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index 69c8936..49c4f85 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -390,6 +390,7 @@ Active  arm         armv7:arm720t  tegra20     toradex         colibri_t20_iris
 Active  arm         armv7:arm720t  tegra30     avionic-design  tec-ng              tec-ng                               -                                                                                                                                 Alban Bedel <alban.bedel@avionic-design.de>
 Active  arm         armv7:arm720t  tegra30     nvidia          beaver              beaver                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>:Stephen Warren <swarren@nvidia.com>
 Active  arm         armv7:arm720t  tegra30     nvidia          cardhu              cardhu                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>
+Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         pxa            -           -               -                   balloon3                             -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
 Active  arm         pxa            -           -               -                   h2200                                -                                                                                                                                 Lukasz Dalek <luk0104@gmail.com>
 Active  arm         pxa            -           -               -                   palmld                               -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..48c6bfa
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,108 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support NOR flash */
+/* #define CONFIG_A369_NOR_FLASH */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_A369_USB_ETHER */
+
+/* Support USB DFU */
+#define CONFIG_A369_USB_DFU
+
+#if defined(CONFIG_A369_USB_ETHER) && defined(CONFIG_A369_USB_DFU)
+# error "USB-ETHER and USB-DFU can't be enabled at the same time."
+#endif
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTGMAC100
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC010
+
+/* NOR flash */
+#ifdef CONFIG_A369_NOR_FLASH
+# define PHYS_FLASH_SIZE                SZ_64M
+# define CONFIG_SYS_FLASH_BASE          0x20000000
+# define CONFIG_SYS_FLASH_CFI_WIDTH     FLASH_CFI_16BIT
+# define CONFIG_SYS_MAX_FLASH_BANKS     1
+# define CONFIG_SYS_MAX_FLASH_SECT      1024
+#endif
+
+/* USB */
+#if defined(CONFIG_A369_USB_DFU) || defined(CONFIG_A369_USB_ETHER)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_GADGET_VBUS_DRAW        200
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+# define CONFIG_USB_EHCI_BASE               CONFIG_FUSBH200_BASE
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+#ifdef CONFIG_A369_USB_DFU
+# define CONFIG_USBDOWNLOAD_GADGET
+# define CONFIG_DFU_FUNCTION
+# define CONFIG_DFU_RAM
+# define CONFIG_CMD_DFU
+#endif
+
+#ifdef CONFIG_A369_USB_ETHER
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+#endif
+
+/* Environment */
+#if defined(CONFIG_A369_NOR_FLASH)
+# define CONFIG_ENV_IS_IN_FLASH /* NOR flash */
+# define CONFIG_ENV_OFFSET          0x3f0000
+#else
+# define CONFIG_ENV_IS_NOWHERE
+#endif
+
+#define CONFIG_ENV_SIZE             SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+/* Platform specific environment variables */
+#ifdef CONFIG_A369_USB_DFU
+# define CONFIG_EXTRA_ENV_SETTINGS \
+	/* USB-DFU: [name] [interface] [start] [end] */ \
+	"dfu_alt_info=ram at 0x10800000 ram 0x10800000 0x11800000\0"
+#endif
+
+#endif	/* EOF */
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 54120ab..485d7c2 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -70,5 +70,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_FAILSAFE	0x0f1ff3ff /* fail-safe timing */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v11 5/6] arm: faraday: add missing header file for FTSDC021
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 4/6] arm: faraday: add A369 evaluation board support Kuo-Jung Su
@ 2014-03-26  6:03   ` Kuo-Jung Su
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 6/6] arm: faraday: add virtual machine support Kuo-Jung Su
  5 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:03 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

For the Faraday FTSDC021 (SDHCI) controller driver source is
sent out before the patches for Faraday Virtual Machine (FVM)
which actually uses this chip.

The header file (ftsdc021.h) has been accidentally removed
by commit: 3b98b57fa - include: delete unused header files

This patch simply rollback this removal.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v11:
	- Nothing updates

Changes for v10:
	- Initial commit

 include/faraday/ftsdc021.h |   13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 include/faraday/ftsdc021.h

diff --git a/include/faraday/ftsdc021.h b/include/faraday/ftsdc021.h
new file mode 100644
index 0000000..de8e250
--- /dev/null
+++ b/include/faraday/ftsdc021.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __FTSDC021_H
+#define __FTSDC021_H
+
+int ftsdc021_sdhci_init(u32 regbase);
+
+#endif /* __FTSDC021_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v11 6/6] arm: faraday: add virtual machine support
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 5/6] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
@ 2014-03-26  6:03   ` Kuo-Jung Su
  2014-03-26  6:52     ` Wolfgang Denk
  5 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:03 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday Virtual Machine (FVM) is a QEMU based emulator
which is designed for early stage software development
(i.e., IPL, SPL development).

Please check the link bellow for details:
https://github.com/dantesu1218/qemu/blob/qemu-1.5.1/hw/arm/faraday_fvm.c

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v11:
	- Fix boards.cfg (due to commit 3fa67050)
	- Rename <asm/sizes.h> to <linux/sizes.h> (due to commit 1ace4022)
	- Directly specify the timer object in 'arch/arm/cpu/faraday/fvm/Makefile'
	  instead of using CONFIG_FTTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v10:
	- Nothing updates

Changes for v9:
	- Initial commit

 arch/arm/cpu/faraday/fvm/Makefile        |    8 ++++
 arch/arm/include/asm/arch-fvm/hardware.h |   76 ++++++++++++++++++++++++++++++
 board/faraday/fvm/Makefile               |    9 ++++
 board/faraday/fvm/board.c                |   60 +++++++++++++++++++++++
 board/faraday/fvm/clock.c                |   49 +++++++++++++++++++
 board/faraday/fvm/lowlevel_init.S        |   15 ++++++
 boards.cfg                               |    1 +
 include/configs/fvm.h                    |   58 +++++++++++++++++++++++
 8 files changed, 276 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/clock.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 include/configs/fvm.h

diff --git a/arch/arm/cpu/faraday/fvm/Makefile b/arch/arm/cpu/faraday/fvm/Makefile
new file mode 100644
index 0000000..9c1eaa8
--- /dev/null
+++ b/arch/arm/cpu/faraday/fvm/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y := ../fttmr010.o
diff --git a/arch/arm/include/asm/arch-fvm/hardware.h b/arch/arm/include/asm/arch-fvm/hardware.h
new file mode 100644
index 0000000..dd04ced
--- /dev/null
+++ b/arch/arm/include/asm/arch-fvm/hardware.h
@@ -0,0 +1,76 @@
+/*
+ * arch/arm/include/asm/arch-fvm/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <linux/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00020000
+
+#define CONFIG_SYSC_BASE            0x90f00000
+#define CONFIG_SYSC_IRQ             15
+
+#define CONFIG_FTINTC030_BASE       0x91000000
+
+#define CONFIG_FTTMR010_BASE        0x90200000
+#define CONFIG_FTTMR010_IRQ         1
+
+#define CONFIG_FTUART010_BASE0      0x90000000
+#define CONFIG_FTUART010_IRQ0       2
+#define CONFIG_FTUART010_BASE1      0x90100000
+#define CONFIG_FTUART010_IRQ1       3
+#define CONFIG_FTUART010_BASE       CONFIG_FTUART010_BASE0
+
+#define CONFIG_DDRC_BASE            0x90300000
+
+#define CONFIG_FTI2C010_BASE        0x90400000
+#define CONFIG_FTI2C010_IRQ         4
+
+#define CONFIG_FTSSP010_BASE        0x90500000
+#define CONFIG_FTSSP010_IRQ         5
+
+#define CONFIG_FTWDT010_BASE        0x90600000
+#define CONFIG_FTWDT010_IRQ         6
+
+#define CONFIG_FTRTC011_BASE        0x90700000
+#define CONFIG_FTRTC011_IRQ         7
+
+#define CONFIG_FTTSC010_BASE        0x90800000
+#define CONFIG_FTTSC010_IRQ         8
+
+#define CONFIG_FTAPBBRG020_BASE     0x91100000
+#define CONFIG_FTAPBBRG020_IRQ      16
+
+#define CONFIG_FTDMAC020_BASE       0x91200000
+#define CONFIG_FTDMAC020_IRQ        17
+
+#define CONFIG_FTMAC110_BASE        0x91300000
+#define CONFIG_FTMAC110_IRQ         18
+
+#define CONFIG_FTSPI020_BASE        0x91400000
+#define CONFIG_FTSPI020_IRQ         19
+
+#define CONFIG_FTNANDC021_BASE      0x91500000
+#define CONFIG_FTNANDC021_IRQ       20
+
+#define CONFIG_FTSDC021_BASE        0x91600000
+#define CONFIG_FTSDC021_IRQ         21
+
+#define CONFIG_FOTG210_BASE         0x91700000
+#define CONFIG_FOTG210_IRQ          22
+
+#define CONFIG_FTLCDC200_BASE       0x91800000
+#define CONFIG_FTLCDC200_IRQ        23
+
+#endif /* EOF */
diff --git a/board/faraday/fvm/Makefile b/board/faraday/fvm/Makefile
new file mode 100644
index 0000000..42fef70
--- /dev/null
+++ b/board/faraday/fvm/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o clock.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/fvm/board.c b/board/faraday/fvm/board.c
new file mode 100644
index 0000000..6c2b03a
--- /dev/null
+++ b/board/faraday/fvm/board.c
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <faraday/ftsdc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_early_init_f(void)
+{
+	gd->arch.timer_rate_hz = clk_get_rate("APB");
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+#ifdef CONFIG_FTMAC110
+	return ftmac110_initialize(bd);
+#else
+	return 0;
+#endif
+}
+
+int board_mmc_init(bd_t *bis)
+{
+#ifdef CONFIG_FTSDC021
+	return ftsdc021_sdhci_init(0);
+#else
+	return 0;
+#endif
+}
diff --git a/board/faraday/fvm/clock.c b/board/faraday/fvm/clock.c
new file mode 100644
index 0000000..f5a759d
--- /dev/null
+++ b/board/faraday/fvm/clock.c
@@ -0,0 +1,49 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline ulong clk_get_rate_ahb(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+static inline ulong clk_get_rate_apb(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+static inline ulong clk_get_rate_cpu(void)
+{
+	return 50000000; /* 50MHz */
+}
+
+ulong clk_get_rate(const char *id)
+{
+	ulong ret = 0;
+
+	if (!strcmp(id, "AHB"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "APB"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "CPU"))
+		ret = clk_get_rate_cpu();
+	else if (!strcmp(id, "I2C"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "SSP"))
+		ret = clk_get_rate_apb();
+	else if (!strcmp(id, "SPI"))
+		ret = clk_get_rate_ahb();
+	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
+		ret = clk_get_rate_ahb();
+
+	return ret;
+}
diff --git a/board/faraday/fvm/lowlevel_init.S b/board/faraday/fvm/lowlevel_init.S
new file mode 100644
index 0000000..cbc006d
--- /dev/null
+++ b/board/faraday/fvm/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index 49c4f85..824d1d0 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -391,6 +391,7 @@ Active  arm         armv7:arm720t  tegra30     avionic-design  tec-ng
 Active  arm         armv7:arm720t  tegra30     nvidia          beaver              beaver                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>:Stephen Warren <swarren@nvidia.com>
 Active  arm         armv7:arm720t  tegra30     nvidia          cardhu              cardhu                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>
 Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
+Active  arm         faraday        fvm         faraday         -                   fvm                                  -                                                                                                                                 Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         pxa            -           -               -                   balloon3                             -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
 Active  arm         pxa            -           -               -                   h2200                                -                                                                                                                                 Lukasz Dalek <luk0104@gmail.com>
 Active  arm         pxa            -           -               -                   palmld                               -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
diff --git a/include/configs/fvm.h b/include/configs/fvm.h
new file mode 100644
index 0000000..1d65e94
--- /dev/null
+++ b/include/configs/fvm.h
@@ -0,0 +1,58 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTMAC110
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC021
+
+/* NOR flash */
+#define PHYS_FLASH_SIZE                 SZ_64M
+#define CONFIG_SYS_FLASH_BASE           0x80000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH      FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS      1
+#define CONFIG_SYS_MAX_FLASH_SECT       1024
+
+/* USB */
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#define CONFIG_USB_EHCI_BASE_LIST       { CONFIG_FOTG210_BASE }
+
+/* Environment */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE                 SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+#endif	/* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support
  2014-03-25 12:41   ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Albert ARIBAUD
@ 2014-03-26  6:08     ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  6:08 UTC (permalink / raw)
  To: u-boot

2014-03-25 20:41 GMT+08:00 Albert ARIBAUD <albert.u.boot@aribaud.net>:
> Hi Kuo-Jung,
>
> On Thu, 20 Feb 2014 11:40:32 +0800, Kuo-Jung Su <dantesu@gmail.com>
> wrote:
>
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> These patches introduce Faraday A369 & Virtual SoC platform support.
>
> Except for patches 4/6 and 6/6 in which boards.cfg needed manual
> fixing (due to commit 3fa67050), the series applies to current
> u-boot-arm/master, but building fails for both a369evb and fvm with
> multiple instances of this error:
>
> include/asm/arch/hardware.h:14:23: fatal error: asm/sizes.h: No such
> file or directory
>

It's because that the 'asm/sizes.h' has been moved to 'linux/sizes.h'
by commit 1ace4022394.

> Can you please rebase (for boards.cfg) and diagnose?
>

Sure, the updated patches are on the way.

-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
@ 2014-03-26  6:47     ` Wolfgang Denk
  2014-03-26  7:22       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2014-03-26  6:47 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1395813799-3672-2-git-send-email-dantesu@gmail.com> you wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Here is the list of verified cores:
> 
> 1. FA606TE (ARMv5TE, no mmu)
> 2. FA626TE (ARMv5TE)
...
> diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
> new file mode 100644
> index 0000000..546c0a9
> --- /dev/null
> +++ b/include/configs/faraday-common.h
...
> +#ifndef CONFIG_ETHADDR
> +#define CONFIG_ETHADDR              00:41:71:00:00:50
> +#endif
> +
> +#ifndef CONFIG_IPADDR
> +#define CONFIG_IPADDR               10.0.0.192
> +#endif
> +
> +#ifndef CONFIG_NETMASK
> +#define CONFIG_NETMASK              255.255.255.0
> +#endif
> +
> +#ifndef CONFIG_SERVERIP
> +#define CONFIG_SERVERIP             10.0.0.128
> +#endif

We do not allow such static network configuration.  Especially
assigning the same MAC address to all devices is deadly.  Also,
the address is not an officially assigned nor a local one.
Please remove all this code.

> +# endif
> +# ifndef CONFIG_G_DNL_VENDOR_NUM
> +# define CONFIG_G_DNL_VENDOR_NUM    0x1d50  /* OpenMoko */
> +# endif

This looks wrong to me?

> +# ifndef CONFIG_G_DNL_PRODUCT_NUM
> +# define CONFIG_G_DNL_PRODUCT_NUM   0x5119
> +# endif

Is this a valid ID?

> +/* Console I/O Buffer Size */
> +#define CONFIG_SYS_CBSIZE           256
> +
> +/* Max number of command args */
> +#define CONFIG_SYS_MAXARGS          32

You use a large number of args with a tiny console buffer?  This looks
suspicious.  Please check.

> +#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */

This has been removed years ago.  Please use CONFIG_CMD_SOURCE
instead.


Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
To program is to be.

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

* [U-Boot] [PATCH v11 6/6] arm: faraday: add virtual machine support
  2014-03-26  6:03   ` [U-Boot] [PATCH v11 6/6] arm: faraday: add virtual machine support Kuo-Jung Su
@ 2014-03-26  6:52     ` Wolfgang Denk
  2014-03-26  7:24       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Wolfgang Denk @ 2014-03-26  6:52 UTC (permalink / raw)
  To: u-boot

Dear Kuo-Jung Su,

In message <1395813799-3672-7-git-send-email-dantesu@gmail.com> you wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> Faraday Virtual Machine (FVM) is a QEMU based emulator
> which is designed for early stage software development
> (i.e., IPL, SPL development).
...
> +ulong clk_get_rate(const char *id)
> +{
> +	ulong ret = 0;
> +
> +	if (!strcmp(id, "AHB"))
> +		ret = clk_get_rate_ahb();
> +	else if (!strcmp(id, "APB"))
> +		ret = clk_get_rate_apb();
> +	else if (!strcmp(id, "CPU"))
> +		ret = clk_get_rate_cpu();
> +	else if (!strcmp(id, "I2C"))
> +		ret = clk_get_rate_apb();
> +	else if (!strcmp(id, "SSP"))
> +		ret = clk_get_rate_apb();
> +	else if (!strcmp(id, "SPI"))
> +		ret = clk_get_rate_ahb();
> +	else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
> +		ret = clk_get_rate_ahb();
> +
> +	return ret;
> +}

I have seen basically identical code in  [PATCH v11 4/6] arm: faraday:
add A369 evaluation board; please move this (and other common code)
into a common location so we have only one implementation of common
code.

Best regards,

Wolfgang Denk

-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: wd at denx.de
You don't stop doing things because you get old.  You get old because
you stop doing things.                            - Rosamunde Pilcher

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

* [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support
  2014-03-26  6:47     ` Wolfgang Denk
@ 2014-03-26  7:22       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  7:22 UTC (permalink / raw)
  To: u-boot

2014-03-26 14:47 GMT+08:00 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1395813799-3672-2-git-send-email-dantesu@gmail.com> you wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Here is the list of verified cores:
>>
>> 1. FA606TE (ARMv5TE, no mmu)
>> 2. FA626TE (ARMv5TE)
> ...
>> diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
>> new file mode 100644
>> index 0000000..546c0a9
>> --- /dev/null
>> +++ b/include/configs/faraday-common.h
> ...
>> +#ifndef CONFIG_ETHADDR
>> +#define CONFIG_ETHADDR              00:41:71:00:00:50
>> +#endif
>> +
>> +#ifndef CONFIG_IPADDR
>> +#define CONFIG_IPADDR               10.0.0.192
>> +#endif
>> +
>> +#ifndef CONFIG_NETMASK
>> +#define CONFIG_NETMASK              255.255.255.0
>> +#endif
>> +
>> +#ifndef CONFIG_SERVERIP
>> +#define CONFIG_SERVERIP             10.0.0.128
>> +#endif
>
> We do not allow such static network configuration.  Especially
> assigning the same MAC address to all devices is deadly.  Also,
> the address is not an officially assigned nor a local one.
> Please remove all this code.
>

Got it, thanks

>> +# endif
>> +# ifndef CONFIG_G_DNL_VENDOR_NUM
>> +# define CONFIG_G_DNL_VENDOR_NUM    0x1d50  /* OpenMoko */
>> +# endif
>
> This looks wrong to me?
>
>> +# ifndef CONFIG_G_DNL_PRODUCT_NUM
>> +# define CONFIG_G_DNL_PRODUCT_NUM   0x5119
>> +# endif
>
> Is this a valid ID?
>

By stealing the OpenMoko's vendor id & product id, I could directly use the
OpenMoko dfu-util without any modifications.

And unfortunately we don't have a registered OUI for Faraday Technology, so
I'll remove this ID in the next release.

>> +/* Console I/O Buffer Size */
>> +#define CONFIG_SYS_CBSIZE           256
>> +
>> +/* Max number of command args */
>> +#define CONFIG_SYS_MAXARGS          32
>
> You use a large number of args with a tiny console buffer?  This looks
> suspicious.  Please check.
>

Got it, thanks

>> +#define CONFIG_CMD_AUTOSCRIPT   /* support autoscript */
>
> This has been removed years ago.  Please use CONFIG_CMD_SOURCE
> instead.
>

Got it, thanks



-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v11 6/6] arm: faraday: add virtual machine support
  2014-03-26  6:52     ` Wolfgang Denk
@ 2014-03-26  7:24       ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-03-26  7:24 UTC (permalink / raw)
  To: u-boot

2014-03-26 14:52 GMT+08:00 Wolfgang Denk <wd@denx.de>:
> Dear Kuo-Jung Su,
>
> In message <1395813799-3672-7-git-send-email-dantesu@gmail.com> you wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> Faraday Virtual Machine (FVM) is a QEMU based emulator
>> which is designed for early stage software development
>> (i.e., IPL, SPL development).
> ...
>> +ulong clk_get_rate(const char *id)
>> +{
>> +     ulong ret = 0;
>> +
>> +     if (!strcmp(id, "AHB"))
>> +             ret = clk_get_rate_ahb();
>> +     else if (!strcmp(id, "APB"))
>> +             ret = clk_get_rate_apb();
>> +     else if (!strcmp(id, "CPU"))
>> +             ret = clk_get_rate_cpu();
>> +     else if (!strcmp(id, "I2C"))
>> +             ret = clk_get_rate_apb();
>> +     else if (!strcmp(id, "SSP"))
>> +             ret = clk_get_rate_apb();
>> +     else if (!strcmp(id, "SPI"))
>> +             ret = clk_get_rate_ahb();
>> +     else if (!strcmp(id, "MMC") || !strcmp(id, "SDC"))
>> +             ret = clk_get_rate_ahb();
>> +
>> +     return ret;
>> +}
>
> I have seen basically identical code in  [PATCH v11 4/6] arm: faraday:
> add A369 evaluation board; please move this (and other common code)
> into a common location so we have only one implementation of common
> code.
>

Got it, thanks


-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support
  2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
                   ` (17 preceding siblings ...)
  2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
@ 2014-04-01  8:46 ` Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c Kuo-Jung Su
                     ` (7 more replies)
  18 siblings, 8 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

These patches introduce Faraday A369 & Virtual SoC platform support.

Here are some public documents for your reference.

   http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm
   http://www.faraday-tech.com/html/documentation/index.html

There is also a QEMU based A369 emulator available at my github:

   https://github.com/dantesu1218/qemu.git

Here is a quick start for QEMU + U-Boot:

1. Download the QEMU source tree

   $ git clone -b qemu-1.5.1 https://github.com/dantesu1218/qemu.git

2. Build & Install the QEMU:

   $ ./configure --target-list=arm-softmmu
   $ make
   $ make install

3. Launch u-boot with QEMU:

   $ qemu-system-arm -M a369 -m 512M -nographic -kernel ~/u-boot-2014.01/u-boot

Changes for v12:
   - Coding style cleanup.
   - Move strlcpy() from ether.c to string.c
   - Add Linux legacy clock framework support (no common clock).
   - Migrate to generic board model (CONFIG_SYS_GENERIC_BOARD).
   - Drop pre-defined Ethernet MAC for all platforms.
   - Drop USB-DFU support due to lack of registered Vendor ID.
   - CONFIG_SYS_MAXARGS: 32 -> 8
   - CONFIG_CMD_AUTOSCRIPT -> CONFIG_CMD_SOURCE

Changes for v11:
   - Fix boards.cfg (due to commit 3fa67050)
   - Rename <asm/sizes.h> to <linux/sizes.h> (due to commit 1ace4022)
   - Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
     instead of using CONFIG_FTTMR010 in 'arch/arm/cpu/faraday/Makefile'
   - Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
     instead of using CONFIG_FTPWMTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v10:
   - As per Albert's request, merge patch 1, 2 and patch 5, 6
   - Add missing header file for FTSDC021

Changes for v9:
   - Shrink the patch by dropping MMU/D-cache support, and see if we could get
     this patch accepted ASAP.
   - Replace the out-of-date A360 EVB with Faraday Virtual Machine (FVM).
   - Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
   - Add do_go_exec() to override the default behavior of 'go' command.
   - Make Faraday SoC helper files & ftsmc020 standalone changesets.
   - Coding style cleanup.

Changes for v8:
   - Revise MMU/D-cache support
   - Revise Faraday SoC common configurations.
   - Drop FTINTC020 interrupt controller support.
   - Drop FTLCDC200 LCD controller support.
   - Drop FTNANDC021 NAND flash controller support, it would be latter submitted
     as a standalone patch set.
   - Drop proprietary Faraday SPL support, the u-boot-spl would be adapted instead.
     However because it depends on the FTNANDC021 patch set, so it would be submitted
     after the FTNANDC021 patch set get committed.

Changes for v7:
   - Update license to use SPDX identifiers.
   - cfi_flash: drop the patch to unmap_physmem(),
     because it's already applied.
   - ftnandc021: put_unaligned() -> memcpy()
   - ftnandc021: update ecc relatived function prototypes to fix
     compile warnnings.

Changes for v6:
   - Drop ethernet driver updates for ftmac110&ftgmac100,
     because they are already commited.
   - arch/arm/cpu/faraday/cpu.c:
     struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs
   - arch/arm/cpu/faraday/cmd_bootfa.c: fix compiler warnning
   - arch/arm/cpu/faraday/cmd_bootfa.c: use shorter paragraph
     in commit message, and move the original statement into the
     top of source file.
   - ftnandc021: update README for CONFIG_SYS_FTNANDC021_TIMING
   - ftnandc021: remove illegal type-punning

Changes for v5:
   - Coding Style cleanup:
     1. struct chip_regs __iomem *regs -> struct chip_regs *regs
     2. Move Faraday specific APIs into asm/arch-faraday/*.h
   - Fix Copyright notices (dates) throughout the patch
   - Make 'arm: dma_alloc_coherent: malloc() -> memalign()' as a separate patch
   - Make 'cfi_flash: use buffer length in unmap_physmem()' as a separate patch
   - Define Faraday machine type in board's config header file
   - Add the rationale to the command 'bootfa'
   - Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
   - Chain the video:FTLCDC200 back to this patch series.
   - Chain the nand:FTNANDC021 back to this patch series.
   - Chain the net:FTGMAC100 & FTMAC110 back to this patch series.
   - Update Faraday Firmware Image Format:
     1. Drop u-boot image support to simplify the design.
        Since it's not possible for the hard-wired ROM code of A360/A369
        to support U-boot images. And the real bootloader for A360/A369
        is actually Faraday bootcode2, rather than U-Boot.
     2. Add image creation timestamp
   - Update 'arch/arm/cpu/faraday/start.S' with the new design, which move
     relocation into 'arch/arm/lib/relocate.S'
   - Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
     would restart after this patch series have been accepted.
   - Revise IRQ & MMU design: Now the exception table would be mapped to
     0x00000000 as a small page(4KB), rather than runtime adjust after
     relocation finished.
   - Revise irq:FTINTC020 design, now the irq is always enabled inside
     irq_install_handler().
   - Revise clock management system
   - Revise FTPWMTMR010 & FTTMR010 timer design:
     1. Drop IRQ dependant implementation
     2. Use gd->arch.timer_rate_hz for timer clock source
     3. Use gd->arch.tbl for timestamp

Changes for v4:
   - Coding Style cleanup.
   - Break down the patch series:
       - Patches without hard dependency to this series are now
         seperate patches.
       - Split up the patch into more logical changesets
         (i.e. interrupt & timers are now split up)
   - Drop the faraday/nand.h to remove dependency to ftnandc021
   - Drop the faraday/mmc.h to remove dependency to ftsdc010
   - Add change logs to each part of the patch series to make
     patchwork be able to grab comments.

Changes for v3:
   - Coding Style cleanup.
     There is still one warnning reported by checkpatch.pl,
     however it's too deep for me to fix it.
     Here is the shapshot for it:
     -----------------------------------------------------
     WARNING: do not add new typedefs
     #9735: FILE: include/lcd.h:258:
     +typedef struct vidinfo {
     -----------------------------------------------------
   - Drop bit fields from c struct.
   - Drop macros for wirtel()/readl(), call them directly.
   - Always insert a blank line between declarations and code.
   - Replace all the infinite wait loop with a timeout.
   - Add '__iomem' to all the declaration of HW register pointers.
   - cmd_boot.c: Make it a separate stand-alone patch.
   - ftspi020: Make it a separate stand-alone patch.
   - dma-mapping.h: Have the global data ptr declared outside functions.
   - dma-mapping.h: Add #if...#else...#endif to dma_free_coherent().
   - MMU/D-Cache: Drop static non-cached region, now we use
     map_physmem()/unmap_physmem() for dynamic mappings.
   - ftmac110: Make a correction to multi-line comment style
   - ftmac110: Use random MAC address while having trouble
     to get one from environment variables.
   - ftmac110: Add comments to timing control registers.
   - ftnandc021: Re-write this driver with ECC enabled and
     correct column address handling for OOB read/write,
     and fixing issused addressed by Scott.
   - a36x_config: No more static global network configurations.
   - a36x_config: Add a common file for the redundant configurations.

Changes for v2:
   - Coding Style cleanup.
   - Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
   - Use structure based hardware registers to replace the macro constants.
   - Replace BIT() with BIT_MASK().
   - echi-faraday: Remove debug codes.
   - ftmac110: Remove debug codes.
   - cache-cp15: Enable write buffer in write-through mode.

Kuo-Jung Su (8):
  libc: move strlcpy() from ether.c to string.c
  arm: add legacy linux clock framework support
  arm: add Faraday ARMv5TE platform common libraries
  arm: faraday: add FTTMR010 timer suppor
  arm: faraday: add FTPWMTMR010 timer support
  arm: faraday: add A369 evaluation board support
  arm: faraday: add missing header file for FTSDC021
  arm: faraday: add faraday virtual machine support

 arch/arm/cpu/faraday/Makefile             |   13 +
 arch/arm/cpu/faraday/a369/Makefile        |    8 +
 arch/arm/cpu/faraday/a369/clock.c         |   87 ++++++
 arch/arm/cpu/faraday/a369/core.c          |   21 ++
 arch/arm/cpu/faraday/a369/core.h          |   15 ++
 arch/arm/cpu/faraday/a369/pinmux.c        |   37 +++
 arch/arm/cpu/faraday/cache.c              |  164 ++++++++++++
 arch/arm/cpu/faraday/clk.c                |   67 +++++
 arch/arm/cpu/faraday/config.mk            |   15 ++
 arch/arm/cpu/faraday/cpu.c                |  116 ++++++++
 arch/arm/cpu/faraday/ftpwmtmr010.c        |  112 ++++++++
 arch/arm/cpu/faraday/fttmr010.c           |  123 +++++++++
 arch/arm/cpu/faraday/fvm/Makefile         |    8 +
 arch/arm/cpu/faraday/fvm/clock.c          |   70 +++++
 arch/arm/cpu/faraday/fvm/core.c           |   20 ++
 arch/arm/cpu/faraday/fvm/core.h           |   14 +
 arch/arm/cpu/faraday/start.S              |  407 +++++++++++++++++++++++++++++
 arch/arm/include/asm/arch-a369/clkdev.h   |   20 ++
 arch/arm/include/asm/arch-a369/hardware.h |   88 +++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++
 arch/arm/include/asm/arch-fvm/clkdev.h    |   20 ++
 arch/arm/include/asm/arch-fvm/hardware.h  |   76 ++++++
 arch/arm/include/asm/clkdev.h             |   29 ++
 board/faraday/a369evb/Makefile            |    9 +
 board/faraday/a369evb/board.c             |  118 +++++++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 board/faraday/fvm/Makefile                |    9 +
 board/faraday/fvm/board.c                 |   65 +++++
 board/faraday/fvm/lowlevel_init.S         |   15 ++
 boards.cfg                                |    2 +
 drivers/Makefile                          |    1 +
 drivers/clk/Makefile                      |    8 +
 drivers/clk/clkdev.c                      |  207 +++++++++++++++
 drivers/i2c/fti2c010.c                    |    3 +-
 drivers/mmc/ftsdc010_mci.c                |    3 +-
 drivers/mmc/ftsdc021_sdhci.c              |    3 +-
 drivers/spi/ftssp010_spi.c                |    3 +-
 drivers/usb/gadget/ether.c                |   24 --
 include/configs/a369.h                    |  104 ++++++++
 include/configs/faraday-common.h          |  276 +++++++++++++++++++
 include/configs/fvm.h                     |   68 +++++
 include/faraday/clkdev.h                  |   19 ++
 include/faraday/ftpwmtmr010.h             |   41 +++
 include/faraday/ftsdc021.h                |   13 +
 include/faraday/ftsmc020.h                |    1 +
 include/faraday/fttmr010.h                |   17 ++
 include/linux/clk.h                       |  181 +++++++++++++
 include/linux/clkdev.h                    |   45 ++++
 include/linux/string.h                    |    3 +
 lib/string.c                              |   25 ++
 50 files changed, 2991 insertions(+), 28 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/clock.c
 create mode 100644 arch/arm/cpu/faraday/a369/core.c
 create mode 100644 arch/arm/cpu/faraday/a369/core.h
 create mode 100644 arch/arm/cpu/faraday/a369/pinmux.c
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/clk.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/cpu/faraday/fvm/clock.c
 create mode 100644 arch/arm/cpu/faraday/fvm/core.c
 create mode 100644 arch/arm/cpu/faraday/fvm/core.h
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 arch/arm/include/asm/arch-a369/clkdev.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 arch/arm/include/asm/arch-fvm/clkdev.h
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 arch/arm/include/asm/clkdev.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 drivers/clk/Makefile
 create mode 100644 drivers/clk/clkdev.c
 create mode 100644 include/configs/a369.h
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/configs/fvm.h
 create mode 100644 include/faraday/clkdev.h
 create mode 100644 include/faraday/ftpwmtmr010.h
 create mode 100644 include/faraday/ftsdc021.h
 create mode 100644 include/linux/clk.h
 create mode 100644 include/linux/clkdev.h

--
1.7.9.5

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

* [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  2014-04-01  9:16     ` Marek Vasut
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 2/8] arm: add legacy linux clock framework support Kuo-Jung Su
                     ` (6 subsequent siblings)
  7 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

It would be better to have strlcpy() moved to lib/string.c,
so that it could be reused by others without enabling
USB Gadget Ethernet.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Wolfgang Denk <wd@denx.de>
Cc: Marek Vasut <marex@denx.de>
---
Changes for v12:
	- Initial commit

 drivers/usb/gadget/ether.c |   24 ------------------------
 include/linux/string.h     |    3 +++
 lib/string.c               |   25 +++++++++++++++++++++++++
 3 files changed, 28 insertions(+), 24 deletions(-)

diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index cc6cc1f..cabd81f 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -857,30 +857,6 @@ DEFINE_CACHE_ALIGN_BUFFER(u8, control_req, USB_BUFSIZ);
 DEFINE_CACHE_ALIGN_BUFFER(u8, status_req, STATUS_BYTECOUNT);
 #endif

-
-/**
- * strlcpy - Copy a %NUL terminated string into a sized buffer
- * @dest: Where to copy the string to
- * @src: Where to copy the string from
- * @size: size of destination buffer
- *
- * Compatible with *BSD: the result is always a valid
- * NUL-terminated string that fits in the buffer (unless,
- * of course, the buffer size is zero). It does not pad
- * out the result like strncpy() does.
- */
-size_t strlcpy(char *dest, const char *src, size_t size)
-{
-	size_t ret = strlen(src);
-
-	if (size) {
-		size_t len = (ret >= size) ? size - 1 : ret;
-		memcpy(dest, src, len);
-		dest[len] = '\0';
-	}
-	return ret;
-}
-
 /*============================================================================*/

 /*
diff --git a/include/linux/string.h b/include/linux/string.h
index 8e44855..5c9d6c3 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -23,6 +23,9 @@ extern __kernel_size_t strspn(const char *,const char *);
 #ifndef __HAVE_ARCH_STRCPY
 extern char * strcpy(char *,const char *);
 #endif
+#ifndef __HAVE_ARCH_STRLCPY
+extern __kernel_size_t strlcpy(char *, const char *, __kernel_size_t);
+#endif
 #ifndef __HAVE_ARCH_STRNCPY
 extern char * strncpy(char *,const char *, __kernel_size_t);
 #endif
diff --git a/lib/string.c b/lib/string.c
index 29c2ca7..adf718c 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -80,6 +80,31 @@ char * strcpy(char * dest,const char *src)
 }
 #endif

+#ifndef __HAVE_ARCH_STRLCPY
+/**
+ * strlcpy - Copy a %NUL terminated string into a sized buffer
+ * @dest: Where to copy the string to
+ * @src: Where to copy the string from
+ * @size: size of destination buffer
+ *
+ * Compatible with *BSD: the result is always a valid
+ * NUL-terminated string that fits in the buffer (unless,
+ * of course, the buffer size is zero). It does not pad
+ * out the result like strncpy() does.
+ */
+size_t strlcpy(char *dest, const char *src, size_t size)
+{
+	size_t ret = strlen(src);
+
+	if (size) {
+		size_t len = (ret >= size) ? size - 1 : ret;
+		memcpy(dest, src, len);
+		dest[len] = '\0';
+	}
+	return ret;
+}
+#endif
+
 #ifndef __HAVE_ARCH_STRNCPY
 /**
  * strncpy - Copy a length-limited, %NUL-terminated string
--
1.7.9.5

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

* [U-Boot] [PATCH v12 2/8] arm: add legacy linux clock framework support
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 3/8] arm: add Faraday ARMv5TE platform common libraries Kuo-Jung Su
                     ` (5 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This ports the legacy linux clock framework from linux-3.10
(i.e., no common clock support)

Please check the list bellow for details:

1. CONFIG_CLKDEV_LOOKUP
   - Core clock management APIs
   - clk_get_sys(), clk_put(), clkdev_add(), clkdev_add_table()
     clkdev_alloc(), clkdev_drop(), clk_register_clkdev(),
     clk_register_clkdevs()

2. CONFIG_HAVE_MACH_CLKDEV (CONFIG_HAVE_ARCH_CLKDEV in U-Boot)
   - Use this to have machine specific structs & defines
     included in asm/clkdev.h

3. CONFIG_HAVE_CLK_PREPARE
   - This prepares the clock source for use
   - clk_prepare(), clk_unprepare()

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
CC: Wolfgang Denk <wd@denx.de>
---
Changes for v12:
	- Initial commit

 arch/arm/include/asm/clkdev.h |   29 ++++++
 drivers/Makefile              |    1 +
 drivers/clk/Makefile          |    8 ++
 drivers/clk/clkdev.c          |  207 +++++++++++++++++++++++++++++++++++++++++
 include/linux/clk.h           |  181 +++++++++++++++++++++++++++++++++++
 include/linux/clkdev.h        |   45 +++++++++
 6 files changed, 471 insertions(+)
 create mode 100644 arch/arm/include/asm/clkdev.h
 create mode 100644 drivers/clk/Makefile
 create mode 100644 drivers/clk/clkdev.c
 create mode 100644 include/linux/clk.h
 create mode 100644 include/linux/clkdev.h

diff --git a/arch/arm/include/asm/clkdev.h b/arch/arm/include/asm/clkdev.h
new file mode 100644
index 0000000..2b605aa
--- /dev/null
+++ b/arch/arm/include/asm/clkdev.h
@@ -0,0 +1,29 @@
+/*
+ *  arch/arm/include/asm/clkdev.h
+ *
+ *  Copyright (C) 2008 Russell King.
+ *
+ * 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.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+#ifndef __ASM_CLKDEV_H
+#define __ASM_CLKDEV_H
+
+#ifdef CONFIG_HAVE_ARCH_CLKDEV
+#include <asm/arch/clkdev.h>
+#else
+#define __clk_get(clk)	({ 1; })
+#define __clk_put(clk)	do { } while (0)
+#endif
+
+#include <malloc.h>
+
+static inline struct clk_lookup_alloc *__clkdev_alloc(size_t size)
+{
+	return calloc(1, size);
+}
+
+#endif
diff --git a/drivers/Makefile b/drivers/Makefile
index 5d03f37..b1aba5e 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -1,6 +1,7 @@
 obj-$(CONFIG_BIOSEMU) += bios_emulator/
 obj-y += block/
 obj-$(CONFIG_BOOTCOUNT_LIMIT) += bootcount/
+obj-y += clk/
 obj-y += crypto/
 obj-$(CONFIG_FPGA) += fpga/
 obj-y += hwmon/
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
new file mode 100644
index 0000000..d1479d2
--- /dev/null
+++ b/drivers/clk/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2007
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_CLKDEV_LOOKUP) += clkdev.o
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
new file mode 100644
index 0000000..5f2921e
--- /dev/null
+++ b/drivers/clk/clkdev.c
@@ -0,0 +1,207 @@
+/*
+ * drivers/clk/clkdev.c
+ *
+ *  Copyright (C) 2008 Russell King.
+ *
+ * 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.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+#include <common.h>
+#include <linux/compiler.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+static LIST_HEAD(clocks);
+
+/*
+ * Find the correct struct clk for the device and connection ID.
+ * We do slightly fuzzy matching here:
+ *  An entry with a NULL ID is assumed to be a wildcard.
+ *  If an entry has a device ID, it must match
+ *  If an entry has a connection ID, it must match
+ * Then we take the most specific entry - with the following
+ * order of precedence: dev+con > dev only > con only.
+ */
+static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
+{
+	struct clk_lookup *p, *cl = NULL;
+	int match, best_found = 0, best_possible = 0;
+
+	if (dev_id)
+		best_possible += 2;
+	if (con_id)
+		best_possible += 1;
+
+	list_for_each_entry(p, &clocks, node) {
+		match = 0;
+		if (p->dev_id) {
+			if (!dev_id || strcmp(p->dev_id, dev_id))
+				continue;
+			match += 2;
+		}
+		if (p->con_id) {
+			if (!con_id || strcmp(p->con_id, con_id))
+				continue;
+			match += 1;
+		}
+
+		if (match > best_found) {
+			cl = p;
+			if (match != best_possible)
+				best_found = match;
+			else
+				break;
+		}
+	}
+	return cl;
+}
+
+struct clk *clk_get_sys(const char *dev_id, const char *con_id)
+{
+	struct clk_lookup *cl;
+
+	cl = clk_find(dev_id, con_id);
+	if (cl && !__clk_get(cl->clk))
+		cl = NULL;
+
+	return cl ? cl->clk : ERR_PTR(-ENOENT);
+}
+
+void clk_put(struct clk *clk)
+{
+	__clk_put(clk);
+}
+
+void clkdev_add(struct clk_lookup *cl)
+{
+	list_add_tail(&cl->node, &clocks);
+}
+
+void clkdev_add_table(struct clk_lookup *cl, size_t num)
+{
+	while (num--) {
+		list_add_tail(&cl->node, &clocks);
+		cl++;
+	}
+}
+
+#define MAX_DEV_ID	20
+#define MAX_CON_ID	16
+
+struct clk_lookup_alloc {
+	struct clk_lookup cl;
+	char dev_id[MAX_DEV_ID];
+	char con_id[MAX_CON_ID];
+};
+
+static struct clk_lookup *vclkdev_alloc(struct clk *clk, const char *con_id,
+	const char *dev_fmt, va_list ap)
+{
+	struct clk_lookup_alloc *cla;
+
+	cla = __clkdev_alloc(sizeof(*cla));
+	if (!cla)
+		return NULL;
+
+	cla->cl.clk = clk;
+	if (con_id) {
+		strlcpy(cla->con_id, con_id, sizeof(cla->con_id));
+		cla->cl.con_id = cla->con_id;
+	}
+
+	if (dev_fmt) {
+		vscnprintf(cla->dev_id, sizeof(cla->dev_id), dev_fmt, ap);
+		cla->cl.dev_id = cla->dev_id;
+	}
+
+	return &cla->cl;
+}
+
+struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
+	const char *dev_fmt, ...)
+{
+	struct clk_lookup *cl;
+	va_list ap;
+
+	va_start(ap, dev_fmt);
+	cl = vclkdev_alloc(clk, con_id, dev_fmt, ap);
+	va_end(ap);
+
+	return cl;
+}
+
+/*
+ * clkdev_drop - remove a clock dynamically allocated
+ */
+void clkdev_drop(struct clk_lookup *cl)
+{
+	list_del(&cl->node);
+	free(cl);
+}
+
+/**
+ * clk_register_clkdev - register one clock lookup for a struct clk
+ * @clk: struct clk to associate with all clk_lookups
+ * @con_id: connection ID string on device
+ * @dev_id: format string describing device name
+ *
+ * con_id or dev_id may be NULL as a wildcard, just as in the rest of
+ * clkdev.
+ *
+ * To make things easier for mass registration, we detect error clks
+ * from a previous clk_register() call, and return the error code for
+ * those.  This is to permit this function to be called immediately
+ * after clk_register().
+ */
+int clk_register_clkdev(struct clk *clk, const char *con_id,
+	const char *dev_fmt, ...)
+{
+	struct clk_lookup *cl;
+	va_list ap;
+
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	va_start(ap, dev_fmt);
+	cl = vclkdev_alloc(clk, con_id, dev_fmt, ap);
+	va_end(ap);
+
+	if (!cl)
+		return -ENOMEM;
+
+	clkdev_add(cl);
+
+	return 0;
+}
+
+/**
+ * clk_register_clkdevs - register a set of clk_lookup for a struct clk
+ * @clk: struct clk to associate with all clk_lookups
+ * @cl: array of clk_lookup structures with con_id and dev_id pre-initialized
+ * @num: number of clk_lookup structures to register
+ *
+ * To make things easier for mass registration, we detect error clks
+ * from a previous clk_register() call, and return the error code for
+ * those.  This is to permit this function to be called immediately
+ * after clk_register().
+ */
+int clk_register_clkdevs(struct clk *clk, struct clk_lookup *cl, size_t num)
+{
+	unsigned i;
+
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	for (i = 0; i < num; i++, cl++) {
+		cl->clk = clk;
+		clkdev_add(cl);
+	}
+
+	return 0;
+}
diff --git a/include/linux/clk.h b/include/linux/clk.h
new file mode 100644
index 0000000..5f2ccbb
--- /dev/null
+++ b/include/linux/clk.h
@@ -0,0 +1,181 @@
+/*
+ *  linux/include/linux/clk.h
+ *
+ *  Copyright (C) 2004 ARM Limited.
+ *  Written by Deep Blue Solutions Limited.
+ *  Copyright (C) 2011-2012 Linaro Ltd <mturquette@linaro.org>
+ *
+ * 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.
+ */
+#ifndef __LINUX_CLK_H
+#define __LINUX_CLK_H
+
+#include <linux/compiler.h>
+#include <linux/err.h>
+
+struct clk;
+
+/**
+ * clk_prepare - prepare a clock source
+ * @clk: clock source
+ *
+ * This prepares the clock source for use.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+int clk_prepare(struct clk *clk);
+#else
+static inline int clk_prepare(struct clk *clk)
+{
+	return 0;
+}
+#endif
+
+/**
+ * clk_unprepare - undo preparation of a clock source
+ * @clk: clock source
+ *
+ * This undoes a previously prepared clock.  The caller must balance
+ * the number of prepare and unprepare calls.
+ *
+ * Must not be called from within atomic context.
+ */
+#ifdef CONFIG_HAVE_CLK_PREPARE
+void clk_unprepare(struct clk *clk);
+#else
+static inline void clk_unprepare(struct clk *clk)
+{
+}
+#endif
+
+/**
+ * clk_enable - inform the system when the clock source should be running.
+ * @clk: clock source
+ *
+ * If the clock can not be enabled/disabled, this should return success.
+ *
+ * May be called from atomic contexts.
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_enable(struct clk *clk);
+
+/**
+ * clk_disable - inform the system when the clock source is no longer required.
+ * @clk: clock source
+ *
+ * Inform the system that a clock source is no longer required by
+ * a driver and may be shut down.
+ *
+ * May be called from atomic contexts.
+ *
+ * Implementation detail: if the clock source is shared between
+ * multiple drivers, clk_enable() calls must be balanced by the
+ * same number of clk_disable() calls for the clock source to be
+ * disabled.
+ */
+void clk_disable(struct clk *clk);
+
+/**
+ * clk_get_rate - obtain the current clock rate (in Hz) for a clock source.
+ *		  This is only valid once the clock source has been enabled.
+ * @clk: clock source
+ */
+unsigned long clk_get_rate(struct clk *clk);
+
+/**
+ * clk_put	- "free" the clock source
+ * @clk: clock source
+ *
+ * Note: drivers must ensure that all clk_enable calls made on this
+ * clock source are balanced by clk_disable calls prior to calling
+ * this function.
+ *
+ * clk_put should not be called from within interrupt context.
+ */
+void clk_put(struct clk *clk);
+
+/*
+ * The remaining APIs are optional for machine class support.
+ */
+
+
+/**
+ * clk_round_rate - adjust a rate to the exact rate a clock can provide
+ * @clk: clock source
+ * @rate: desired clock rate in Hz
+ *
+ * Returns rounded clock rate in Hz, or negative errno.
+ */
+long clk_round_rate(struct clk *clk, unsigned long rate);
+
+/**
+ * clk_set_rate - set the clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired clock rate in Hz
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate(struct clk *clk, unsigned long rate);
+
+/**
+ * clk_set_parent - set the parent clock source for this clock
+ * @clk: clock source
+ * @parent: parent clock source
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent);
+
+/**
+ * clk_get_parent - get the parent clock source for this clock
+ * @clk: clock source
+ *
+ * Returns struct clk corresponding to parent clock source, or
+ * valid IS_ERR() condition containing errno.
+ */
+struct clk *clk_get_parent(struct clk *clk);
+
+/**
+ * clk_get_sys - get a clock based upon the device name
+ * @dev_id: device name
+ * @con_id: connection ID
+ *
+ * Returns a struct clk corresponding to the clock producer, or
+ * valid IS_ERR() condition containing errno.  The implementation
+ * uses @dev_id and @con_id to determine the clock consumer, and
+ * thereby the clock producer. In contrast to clk_get() this function
+ * takes the device name instead of the device itself for identification.
+ *
+ * Drivers must assume that the clock source is not enabled.
+ *
+ * clk_get_sys should not be called from within interrupt context.
+ */
+struct clk *clk_get_sys(const char *dev_id, const char *con_id);
+
+/* clk_prepare_enable helps cases using clk_enable in non-atomic context. */
+static inline int clk_prepare_enable(struct clk *clk)
+{
+	int ret;
+
+	ret = clk_prepare(clk);
+	if (ret)
+		return ret;
+	ret = clk_enable(clk);
+	if (ret)
+		clk_unprepare(clk);
+
+	return ret;
+}
+
+/* clk_disable_unprepare helps cases using clk_disable in non-atomic context. */
+static inline void clk_disable_unprepare(struct clk *clk)
+{
+	clk_disable(clk);
+	clk_unprepare(clk);
+}
+
+#endif
diff --git a/include/linux/clkdev.h b/include/linux/clkdev.h
new file mode 100644
index 0000000..78f2ff4
--- /dev/null
+++ b/include/linux/clkdev.h
@@ -0,0 +1,45 @@
+/*
+ *  include/linux/clkdev.h
+ *
+ *  Copyright (C) 2008 Russell King.
+ *
+ * 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.
+ *
+ * Helper for the clk API to assist looking up a struct clk.
+ */
+#ifndef __CLKDEV_H
+#define __CLKDEV_H
+
+#include <linux/list.h>
+#include <asm/clkdev.h>
+
+struct clk;
+
+struct clk_lookup {
+	struct list_head node;
+	const char *dev_id;
+	const char *con_id;
+	struct clk *clk;
+};
+
+#define CLKDEV_INIT(d, n, c)	\
+	{			\
+		.dev_id = d,	\
+		.con_id = n,	\
+		.clk = c,	\
+	}
+
+struct clk_lookup *clkdev_alloc(struct clk *clk, const char *con_id,
+	const char *dev_fmt, ...);
+
+void clkdev_add(struct clk_lookup *cl);
+void clkdev_drop(struct clk_lookup *cl);
+
+void clkdev_add_table(struct clk_lookup *, size_t);
+
+int clk_register_clkdev(struct clk *, const char *, const char *, ...);
+int clk_register_clkdevs(struct clk *, struct clk_lookup *, size_t);
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v12 3/8] arm: add Faraday ARMv5TE platform common libraries
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 2/8] arm: add legacy linux clock framework support Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 4/8] arm: faraday: add FTTMR010 timer suppor Kuo-Jung Su
                     ` (4 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

This includes the Faraday ARMv5TE core support and
generic clock framework.

Here is the list of verified Faraday ARM cores:

1. FA606TE (ARMv5TE, no mmu)
2. FA626TE (ARMv5TE)

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v12:
	- Add Linux legacy clock framework support (no common clock).
	- Migrate to generic board model (CONFIG_SYS_GENERIC_BOARD).
	- Drop pre-defined Ethernet MAC for all platforms.
	- Drop USB-DFU support due to lack of registered Vendor ID.
	- CONFIG_SYS_MAXARGS: 32 -> 8
	- CONFIG_CMD_AUTOSCRIPT -> CONFIG_CMD_SOURCE

Changes for v11:
	- Nothing updates

Changes for v10:
	- Merge [arm: add Faraday SoC helper files]

Changes for v9:
	- Build 'arch_preboot_os()' only when CONFIG_CMD_BOOTM is defined.
	- Add do_go_exec() to override the default behavior of 'go' command.

Changes for v8:
	- add arm_init_before_mmu() & mmu_page_table_flush()

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Initial commit

 arch/arm/cpu/faraday/Makefile    |   10 +
 arch/arm/cpu/faraday/cache.c     |  164 +++++++++++++++
 arch/arm/cpu/faraday/clk.c       |   67 +++++++
 arch/arm/cpu/faraday/config.mk   |   15 ++
 arch/arm/cpu/faraday/cpu.c       |  116 +++++++++++
 arch/arm/cpu/faraday/start.S     |  407 ++++++++++++++++++++++++++++++++++++++
 drivers/i2c/fti2c010.c           |    3 +-
 drivers/mmc/ftsdc010_mci.c       |    3 +-
 drivers/mmc/ftsdc021_sdhci.c     |    3 +-
 drivers/spi/ftssp010_spi.c       |    3 +-
 include/configs/faraday-common.h |  276 ++++++++++++++++++++++++++
 include/faraday/clkdev.h         |   19 ++
 12 files changed, 1082 insertions(+), 4 deletions(-)
 create mode 100644 arch/arm/cpu/faraday/Makefile
 create mode 100644 arch/arm/cpu/faraday/cache.c
 create mode 100644 arch/arm/cpu/faraday/clk.c
 create mode 100644 arch/arm/cpu/faraday/config.mk
 create mode 100644 arch/arm/cpu/faraday/cpu.c
 create mode 100644 arch/arm/cpu/faraday/start.S
 create mode 100644 include/configs/faraday-common.h
 create mode 100644 include/faraday/clkdev.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
new file mode 100644
index 0000000..ab8d5f8
--- /dev/null
+++ b/arch/arm/cpu/faraday/Makefile
@@ -0,0 +1,10 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+extra-y := start.o
+
+obj-y   += cpu.o cache.o clk.o
diff --git a/arch/arm/cpu/faraday/cache.c b/arch/arm/cpu/faraday/cache.c
new file mode 100644
index 0000000..2acb954
--- /dev/null
+++ b/arch/arm/cpu/faraday/cache.c
@@ -0,0 +1,164 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+/*
+ * I-Cache
+ */
+
+void invalidate_icache_all(void)
+{
+#if !defined(CONFIG_SYS_ICACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c5, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_ICACHE_OFF */
+}
+
+/*
+ * D-Cache
+ */
+
+void flush_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c14, 0\n" /* clean & invalidate */
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c14, 1\n" /* clean & invalidate */
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c10, 4\n" /* drain write buffer */
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	unsigned long line = CONFIG_SYS_CACHELINE_SIZE;
+	unsigned long mask = ~(line - 1);
+
+	/* aligned to cache line */
+	stop = (line - 1 + stop) & mask;
+	start = start & mask;
+
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c7, c6, 1\n"
+		"add %0, %0, %2\n"
+		"cmp %0, %1\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(stop), "r"(line)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void invalidate_dcache_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c7, c6, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void flush_cache(unsigned long start, unsigned long size)
+{
+	flush_dcache_range(start, start + size);
+}
+
+/*
+ * MMU
+ */
+
+static void invalidate_utlb_all(void)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	asm volatile (
+		"mov r0, #0\n"
+		"mcr p15, 0, r0, c8, c7, 0\n"
+		: /* output */
+		: /* input */
+		: "r0"
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+static void invalidate_utlb_range(unsigned long start, unsigned long stop)
+{
+#if !defined(CONFIG_SYS_DCACHE_OFF)
+	uint32_t page = 4096;
+	uint32_t mask = ~(page - 1);
+
+	/* aligned to page boundary */
+	stop = (page - 1 + stop) & mask;
+	start = start & mask;
+
+	/* invalidate U-TLB entry */
+	asm volatile (
+		"1:\n"
+		"mcr p15, 0, %0, c8, c7, 1\n"
+		"add %0, %0, %1\n"
+		"cmp %0, %2\n"
+		"blo 1b\n"
+		: "+r"(start)
+		: "r"(page), "r"(stop)
+	);
+#endif /* !CONFIG_SYS_DCACHE_OFF */
+}
+
+void arm_init_before_mmu(void)
+{
+	invalidate_dcache_all();
+	invalidate_utlb_all();
+}
+
+void mmu_page_table_flush(unsigned long start, unsigned long stop)
+{
+	flush_dcache_range(start, stop);
+	invalidate_utlb_range(start, stop);
+}
diff --git a/arch/arm/cpu/faraday/clk.c b/arch/arm/cpu/faraday/clk.c
new file mode 100644
index 0000000..acd7127
--- /dev/null
+++ b/arch/arm/cpu/faraday/clk.c
@@ -0,0 +1,67 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+int clk_enable(struct clk *clk)
+{
+	int ret = 0;
+
+	if (!IS_ERR(clk) && clk->ops.enable)
+		ret = clk->ops.enable();
+
+	return ret;
+}
+
+void clk_disable(struct clk *clk)
+{
+	if (!IS_ERR(clk) && clk->ops.disable)
+		clk->ops.disable();
+}
+
+unsigned long clk_get_rate(struct clk *clk)
+{
+	unsigned long ret = 0;
+
+	if (!IS_ERR(clk) && clk->ops.get_rate)
+		ret = clk->ops.get_rate();
+
+	return ret;
+}
+
+long clk_round_rate(struct clk *clk, unsigned long rate)
+{
+	long ret = -EINVAL;
+
+	if (!IS_ERR(clk) && clk->ops.round_rate)
+		ret = clk->ops.round_rate(rate);
+
+	return ret;
+}
+
+int clk_set_rate(struct clk *clk, unsigned long rate)
+{
+	int ret = -EINVAL;
+
+	if (!IS_ERR(clk) && clk->ops.set_rate)
+		ret = clk->ops.set_rate(rate);
+
+	return ret;
+}
+
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+	return -ENOSYS;
+}
+
+struct clk *clk_get_parent(struct clk *clk)
+{
+	return ERR_PTR(-ENOSYS);
+}
diff --git a/arch/arm/cpu/faraday/config.mk b/arch/arm/cpu/faraday/config.mk
new file mode 100644
index 0000000..f39e70b
--- /dev/null
+++ b/arch/arm/cpu/faraday/config.mk
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+PLATFORM_CPPFLAGS += -march=armv5te
+# =========================================================================
+#
+# Supply options according to compiler version
+#
+# =========================================================================
+PF_RELFLAGS_SLB_AT := $(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))
+PLATFORM_RELFLAGS += $(PF_RELFLAGS_SLB_AT)
diff --git a/arch/arm/cpu/faraday/cpu.c b/arch/arm/cpu/faraday/cpu.c
new file mode 100644
index 0000000..4332328
--- /dev/null
+++ b/arch/arm/cpu/faraday/cpu.c
@@ -0,0 +1,116 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <command.h>
+#include <malloc.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <faraday/ftwdt010_wdt.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * This enable_caches() overrides the weak function
+ * in "arch/arm/lib/cache.c".
+ */
+void enable_caches(void)
+{
+	icache_enable();
+	dcache_enable();
+}
+
+int cleanup_before_linux(void)
+{
+	/*
+	 * this function is called just before we call linux
+	 * it prepares the processor for linux
+	 *
+	 * we turn off caches etc ...
+	 */
+	disable_interrupts();
+
+	/*
+	 * Turn off I-cache and invalidate it
+	 */
+	icache_disable();
+	invalidate_icache_all();
+
+	/*
+	 * Turn off D-cache
+	 * dcache_disable() in turn flushes the d-cache and disables MMU
+	 */
+	dcache_disable();
+
+	/*
+	 * After D-cache is flushed and before it is disabled there may
+	 * be some new valid entries brought into the cache. We are sure
+	 * that these lines are not dirty and will not affect our execution.
+	 * So just invalidate the entire d-cache again to avoid coherency
+	 * problems for kernel
+	 */
+	invalidate_dcache_all();
+
+	return 0;
+}
+
+void reset_cpu(unsigned long ignored)
+{
+#ifdef CONFIG_FTWDT010_BASE
+	struct ftwdt010_wdt *regs = (void __iomem *)CONFIG_FTWDT010_BASE;
+
+	/* Disable WDT */
+	writel(0, &regs->wdcr);
+	/* Timeout in 1000 ticks */
+	writel(1000, &regs->wdload);
+	/* Enable WDT with system reset */
+	writel(FTWDT010_WDCR_ENABLE | FTWDT010_WDCR_RST, &regs->wdcr);
+#endif
+}
+
+#ifdef CONFIG_DISPLAY_CPUINFO
+int print_cpuinfo(void)
+{
+	/* print cpu_info */
+	printf("CPU:   %lu MHz\n",
+	       clk_get_rate(clk_get_sys(NULL, "CPU")) / 1000000);
+
+	printf("AHB:   %lu MHz\n",
+	       clk_get_rate(clk_get_sys(NULL, "AHB")) / 1000000);
+
+	printf("APB:   %lu MHz\n",
+	       clk_get_rate(clk_get_sys(NULL, "APB")) / 1000000);
+
+	return 0;
+}
+#endif /* CONFIG_DISPLAY_CPUINFO */
+
+#ifdef CONFIG_CMD_GO
+/*
+ * This do_go_exec() overrides the weak function
+ * in "cmd_boot.c".
+ */
+unsigned long do_go_exec(ulong (*entry)(int, char * const []), int argc,
+				 char * const argv[])
+{
+	cleanup_before_linux();
+	return entry(argc, argv);
+}
+#endif /* CONFIG_CMD_GO */
+
+#ifdef CONFIG_CMD_BOOTM
+/*
+ * This arch_preboot_os() overrides the weak function
+ * in "cmd_bootm.c".
+ */
+void arch_preboot_os(void)
+{
+	cleanup_before_linux();
+}
+#endif /* CONFIG_CMD_BOOTM */
diff --git a/arch/arm/cpu/faraday/start.S b/arch/arm/cpu/faraday/start.S
new file mode 100644
index 0000000..32ce92e
--- /dev/null
+++ b/arch/arm/cpu/faraday/start.S
@@ -0,0 +1,407 @@
+/*
+ * u-boot - Startup Code for Faraday CPU-core
+ *
+ * Base is arch/arm/cpu/arm926ejs/start.S
+ *
+ * (C) Copyright 2013 Faraday Technology
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm-offsets.h>
+#include <config.h>
+#include <common.h>
+#include <version.h>
+
+/*
+ *************************************************************************
+ *
+ * Jump vector table as in table 3.1 in [1]
+ *
+ *************************************************************************
+ */
+
+
+#ifdef CONFIG_SYS_DV_NOR_BOOT_CFG
+.globl _start
+_start:
+.globl _NOR_BOOT_CFG
+_NOR_BOOT_CFG:
+	.word	CONFIG_SYS_DV_NOR_BOOT_CFG
+	b	reset
+#else
+.globl _start
+_start:
+	b	reset
+#endif
+#ifdef CONFIG_SPL_BUILD
+/* No exception handlers in preloader */
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+	ldr	pc, _hang
+
+_hang:
+	.word	do_hang
+/* pad to 64 byte boundary */
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+	.word	0x12345678
+#else
+	ldr	pc, _undefined_instruction
+	ldr	pc, _software_interrupt
+	ldr	pc, _prefetch_abort
+	ldr	pc, _data_abort
+	ldr	pc, _not_used
+	ldr	pc, _irq
+	ldr	pc, _fiq
+
+_undefined_instruction:
+	.word undefined_instruction
+_software_interrupt:
+	.word software_interrupt
+_prefetch_abort:
+	.word prefetch_abort
+_data_abort:
+	.word data_abort
+_not_used:
+	.word not_used
+_irq:
+	.word irq
+_fiq:
+	.word fiq
+
+#endif	/* CONFIG_SPL_BUILD */
+	.balignl 16,0xdeadbeef
+
+
+/*
+ *************************************************************************
+ *
+ * Startup Code (reset vector)
+ *
+ * do important init only if we don't start from memory!
+ * setup Memory and board specific bits prior to relocation.
+ * relocate armboot to ram
+ * setup stack
+ *
+ *************************************************************************
+ */
+
+.globl _TEXT_BASE
+_TEXT_BASE:
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_TEXT_BASE)
+	.word	CONFIG_SPL_TEXT_BASE
+#else
+	.word	CONFIG_SYS_TEXT_BASE
+#endif
+
+/*
+ * These are defined in the board-specific linker script.
+ * Subtracting _start from them lets the linker put their
+ * relative position in the executable instead of leaving
+ * them null.
+ */
+.globl _bss_start_ofs
+_bss_start_ofs:
+	.word __bss_start - _start
+
+.globl _bss_end_ofs
+_bss_end_ofs:
+	.word __bss_end - _start
+
+.globl _end_ofs
+_end_ofs:
+	.word _end - _start
+
+#ifdef CONFIG_USE_IRQ
+/* IRQ stack memory (calculated at run-time) */
+.globl IRQ_STACK_START
+IRQ_STACK_START:
+	.word	0x0badc0de
+
+/* IRQ stack memory (calculated at run-time) */
+.globl FIQ_STACK_START
+FIQ_STACK_START:
+	.word 0x0badc0de
+#endif
+
+/* IRQ stack memory (calculated at run-time) + 8 bytes */
+.globl IRQ_STACK_START_IN
+IRQ_STACK_START_IN:
+	.word	0x0badc0de
+
+/*
+ * the actual reset code
+ */
+
+reset:
+	/*
+	 * set the cpu to SVC32 mode
+	 */
+	mrs	r0,cpsr
+	bic	r0,r0,#0x1f
+	orr	r0,r0,#0xd3
+	msr	cpsr,r0
+
+	/*
+	 * we do sys-critical inits only at reboot,
+	 * not when booting from ram!
+	 */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	bl	cpu_init_crit
+#endif
+
+	/*
+	 * With the following bootstrap relocation, we could flawless
+	 * boot from either ROM or NOR flash.
+	 */
+	adr r0, _start      /* r0 <- current position of code   */
+	ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */
+	teq r0, r1          /* don't reloc during debug         */
+	bleq _main
+	ldr r2, _end_ofs    /* r2 <- size of u-boot             */
+	add r2, r0, r2      /* r2 <- source end address         */
+
+reloc_loop:
+	ldmia r0!, {r3-r10} /* copy from source address [r0]    */
+	stmia r1!, {r3-r10} /* copy to   target address [r1]    */
+	cmp r0, r2          /* until source end addreee [r2]    */
+	blo reloc_loop
+
+	ldr pc, =_main
+
+/*----------------------------------------------------------------------*/
+
+	.globl	c_runtime_cpu_setup
+c_runtime_cpu_setup:
+	mov pc, lr
+
+/*
+ *************************************************************************
+ *
+ * CPU_init_critical registers
+ *
+ * setup important registers
+ * setup memory timing
+ *
+ *************************************************************************
+ */
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+cpu_init_crit:
+	/*
+	 * flush D cache before disabling it
+	 */
+	mov	r0, #0
+	mcr	p15, 0, r0, c7, c14, 0	/* clean & invalidate D cache */
+	mcr	p15, 0, r0, c8, c7, 0	/* invalidate TLB */
+	mcr	p15, 0, r0, c7, c5, 0	/* invalidate I Cache */
+	mcr	p15, 0, r0, c7, c10, 4	/* drain write buffer */
+
+	/*
+	 * disable MMU and D cache
+	 * enable I cache if CONFIG_SYS_ICACHE_OFF is not defined
+	 */
+	mrc	p15, 0, r0, c1, c0, 0
+	bic	r0, r0, #0x00000300	/* clear bits 9:8 (---- --RS) */
+	bic	r0, r0, #0x00000087	/* clear bits 7, 2:0 (B--- -CAM) */
+#ifdef CONFIG_SYS_EXCEPTION_VECTORS_HIGH
+	orr	r0, r0, #0x00002000	/* set bit 13 (--V- ----) */
+#else
+	bic	r0, r0, #0x00002000	/* clear bit 13 (--V- ----) */
+#endif
+	orr	r0, r0, #0x00000002	/* set bit 2 (A) Align */
+#ifndef CONFIG_SYS_ICACHE_OFF
+	orr	r0, r0, #0x00001000	/* set bit 12 (I) I-Cache */
+#endif
+	mcr	p15, 0, r0, c1, c0, 0
+
+	/*
+	 * Go setup Memory and board specific bits prior to relocation.
+	 */
+	mov	ip, lr		/* perserve link reg across call */
+	bl	lowlevel_init	/* go setup pll,mux,memory */
+	mov	lr, ip		/* restore link */
+	mov	pc, lr		/* back to my caller */
+#endif /* CONFIG_SKIP_LOWLEVEL_INIT */
+
+#ifndef CONFIG_SPL_BUILD
+/*
+ *************************************************************************
+ *
+ * Interrupt handling
+ *
+ *************************************************************************
+ */
+
+@
+@ IRQ stack frame.
+@
+#define S_FRAME_SIZE	72
+
+#define S_OLD_R0	68
+#define S_PSR		64
+#define S_PC		60
+#define S_LR		56
+#define S_SP		52
+
+#define S_IP		48
+#define S_FP		44
+#define S_R10		40
+#define S_R9		36
+#define S_R8		32
+#define S_R7		28
+#define S_R6		24
+#define S_R5		20
+#define S_R4		16
+#define S_R3		12
+#define S_R2		8
+#define S_R1		4
+#define S_R0		0
+
+#define MODE_SVC 0x13
+#define I_BIT	 0x80
+
+/*
+ * use bad_save_user_regs for abort/prefetch/undef/swi ...
+ * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
+ */
+
+	.macro	bad_save_user_regs
+	@ carve out a frame on current user stack
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}	@ Save user registers (now in svc mode) r0-r12
+	ldr	r2, IRQ_STACK_START_IN
+	@ get values for "aborted" pc and cpsr (into parm regs)
+	ldmia	r2, {r2 - r3}
+	add	r0, sp, #S_FRAME_SIZE		@ grab pointer to old stack
+	add	r5, sp, #S_SP
+	mov	r1, lr
+	stmia	r5, {r0 - r3}	@ save sp_SVC, lr_SVC, pc, cpsr
+	mov	r0, sp		@ save current stack into r0 (param register)
+	.endm
+
+	.macro	irq_save_user_regs
+	sub	sp, sp, #S_FRAME_SIZE
+	stmia	sp, {r0 - r12}			@ Calling r0-r12
+	@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
+	add	r8, sp, #S_PC
+	stmdb	r8, {sp, lr}^		@ Calling SP, LR
+	str	lr, [r8, #0]		@ Save calling PC
+	mrs	r6, spsr
+	str	r6, [r8, #4]		@ Save CPSR
+	str	r0, [r8, #8]		@ Save OLD_R0
+	mov	r0, sp
+	.endm
+
+	.macro	irq_restore_user_regs
+	ldmia	sp, {r0 - lr}^			@ Calling r0 - lr
+	mov	r0, r0
+	ldr	lr, [sp, #S_PC]			@ Get PC
+	add	sp, sp, #S_FRAME_SIZE
+	subs	pc, lr, #4		@ return & move spsr_svc into cpsr
+	.endm
+
+	.macro get_bad_stack
+	ldr	r13, IRQ_STACK_START_IN		@ setup our mode stack
+
+	str	lr, [r13]	@ save caller lr in position 0 of saved stack
+	mrs	lr, spsr	@ get the spsr
+	str	lr, [r13, #4]	@ save spsr in position 1 of saved stack
+	mov	r13, #MODE_SVC	@ prepare SVC-Mode
+	@ msr	spsr_c, r13
+	msr	spsr, r13	@ switch modes, make sure moves will execute
+	mov	lr, pc		@ capture return pc
+	movs	pc, lr		@ jump to next instruction & switch modes.
+	.endm
+
+	.macro get_irq_stack			@ setup IRQ stack
+	ldr	sp, IRQ_STACK_START
+	.endm
+
+	.macro get_fiq_stack			@ setup FIQ stack
+	ldr	sp, FIQ_STACK_START
+	.endm
+#endif	/* CONFIG_SPL_BUILD */
+
+/*
+ * exception handlers
+ */
+#ifdef CONFIG_SPL_BUILD
+	.align	5
+do_hang:
+	ldr	sp, _TEXT_BASE			/* switch to abort stack */
+1:
+	bl	1b				/* hang and never return */
+#else	/* !CONFIG_SPL_BUILD */
+	.align  5
+undefined_instruction:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_undefined_instruction
+
+	.align	5
+software_interrupt:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_software_interrupt
+
+	.align	5
+prefetch_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_prefetch_abort
+
+	.align	5
+data_abort:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_data_abort
+
+	.align	5
+not_used:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_not_used
+
+#ifdef CONFIG_USE_IRQ
+
+	.align	5
+irq:
+	get_irq_stack
+	irq_save_user_regs
+	bl	do_irq
+	irq_restore_user_regs
+
+	.align	5
+fiq:
+	get_fiq_stack
+	/* someone ought to write a more effiction fiq_save_user_regs */
+	irq_save_user_regs
+	bl	do_fiq
+	irq_restore_user_regs
+
+#else
+
+	.align	5
+irq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_irq
+
+	.align	5
+fiq:
+	get_bad_stack
+	bad_save_user_regs
+	bl	do_fiq
+
+#endif
+#endif	/* CONFIG_SPL_BUILD */
diff --git a/drivers/i2c/fti2c010.c b/drivers/i2c/fti2c010.c
index 68d9a42..a4e7efc 100644
--- a/drivers/i2c/fti2c010.c
+++ b/drivers/i2c/fti2c010.c
@@ -9,6 +9,7 @@

 #include <common.h>
 #include <asm/io.h>
+#include <linux/clk.h>
 #include <i2c.h>

 #include "fti2c010.h"
@@ -22,7 +23,7 @@
 #endif

 #ifndef CONFIG_FTI2C010_CLOCK
-#define CONFIG_FTI2C010_CLOCK   clk_get_rate("I2C")
+#define CONFIG_FTI2C010_CLOCK   clk_get_rate(clk_get_sys(NULL, "I2C"))
 #endif

 #ifndef CONFIG_FTI2C010_TIMEOUT
diff --git a/drivers/mmc/ftsdc010_mci.c b/drivers/mmc/ftsdc010_mci.c
index a620678..f2ab0c5 100644
--- a/drivers/mmc/ftsdc010_mci.c
+++ b/drivers/mmc/ftsdc010_mci.c
@@ -15,6 +15,7 @@
 #include <asm/io.h>
 #include <asm/errno.h>
 #include <asm/byteorder.h>
+#include <linux/clk.h>
 #include <faraday/ftsdc010.h>

 #define CFG_CMD_TIMEOUT (CONFIG_SYS_HZ >> 4) /* 250 ms */
@@ -339,7 +340,7 @@ int ftsdc010_mmc_init(int devid)
 #ifdef CONFIG_SYS_CLK_FREQ
 	chip->sclk = CONFIG_SYS_CLK_FREQ;
 #else
-	chip->sclk = clk_get_rate("SDC");
+	chip->sclk = clk_get_rate(clk_get_sys(NULL, "MMC"));
 #endif

 	chip->cfg.name = "ftsdc010";
diff --git a/drivers/mmc/ftsdc021_sdhci.c b/drivers/mmc/ftsdc021_sdhci.c
index 1f6cdba..6244dac 100644
--- a/drivers/mmc/ftsdc021_sdhci.c
+++ b/drivers/mmc/ftsdc021_sdhci.c
@@ -8,9 +8,10 @@
 #include <common.h>
 #include <malloc.h>
 #include <sdhci.h>
+#include <linux/clk.h>

 #ifndef CONFIG_FTSDC021_CLOCK
-#define CONFIG_FTSDC021_CLOCK   clk_get_rate("MMC")
+#define CONFIG_FTSDC021_CLOCK   clk_get_rate(clk_get_sys(NULL, "MMC"))
 #endif

 int ftsdc021_sdhci_init(u32 regbase)
diff --git a/drivers/spi/ftssp010_spi.c b/drivers/spi/ftssp010_spi.c
index aa3b5a0..c590dd5 100644
--- a/drivers/spi/ftssp010_spi.c
+++ b/drivers/spi/ftssp010_spi.c
@@ -7,6 +7,7 @@
  */

 #include <common.h>
+#include <linux/clk.h>
 #include <linux/compat.h>
 #include <asm/io.h>
 #include <malloc.h>
@@ -25,7 +26,7 @@
 #endif

 #ifndef CONFIG_FTSSP010_CLOCK
-#define CONFIG_FTSSP010_CLOCK       clk_get_rate("SSP");
+#define CONFIG_FTSSP010_CLOCK       clk_get_rate(clk_get_sys(NULL, "SSP"))
 #endif

 #ifndef CONFIG_FTSSP010_TIMEOUT
diff --git a/include/configs/faraday-common.h b/include/configs/faraday-common.h
new file mode 100644
index 0000000..abe2654
--- /dev/null
+++ b/include/configs/faraday-common.h
@@ -0,0 +1,276 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_FARADAY_COMMON_H
+#define __CONFIG_FARADAY_COMMON_H
+
+/* Faraday SoC Platform */
+#define CONFIG_SOC_FARADAY
+#define CONFIG_MACH_TYPE            758 /* Faraday */
+
+/* Faraday ARMv5TE cores are 32 bytes per line */
+#define CONFIG_SYS_CACHELINE_SIZE   32
+
+#ifndef CONFIG_SYS_DCACHE_OFF
+# define CONFIG_SYS_ARM_CACHE_WRITETHROUGH
+#endif
+
+#ifdef CONFIG_USE_IRQ
+# define CONFIG_STACKSIZE_IRQ       SZ_32K
+# define CONFIG_STACKSIZE_FIQ       SZ_32K
+#endif
+
+#define CONFIG_SYS_HZ               1000
+
+#define CONFIG_SYS_GENERIC_BOARD
+
+#define CONFIG_DISPLAY_CPUINFO
+
+#define CONFIG_CLKDEV_LOOKUP
+
+#define CONFIG_HAVE_ARCH_CLKDEV
+
+/*
+ * Initial stack pointer: GENERATED_GBL_DATA_SIZE in internal SRAM.
+ * Inside the board_init_f, the gd is first assigned to
+ * (CONFIG_SYS_INIT_SP_ADDR) & ~0x07) and then relocated to DRAM
+ * while calling relocate_code.
+ */
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_SDRAM_BASE + SZ_4K - GENERATED_GBL_DATA_SIZE)
+
+#define CONFIG_SYS_MONITOR_BASE     CONFIG_SYS_TEXT_BASE
+#define CONFIG_SYS_MONITOR_LEN      SZ_512K
+
+/* Default entry point */
+#ifndef CONFIG_SYS_UBOOT_START
+#define CONFIG_SYS_UBOOT_START      CONFIG_SYS_TEXT_BASE
+#endif
+
+/* Default load address */
+#ifndef CONFIG_SYS_LOAD_ADDR
+#define CONFIG_SYS_LOAD_ADDR        (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+/* U-Boot's built-in memory test */
+#ifndef CONFIG_SYS_MEMTEST_START
+#define CONFIG_SYS_MEMTEST_START    (CONFIG_SYS_SDRAM_BASE + SZ_8M)
+#endif
+
+#ifndef CONFIG_SYS_MEMTEST_END
+#define CONFIG_SYS_MEMTEST_END      (CONFIG_SYS_SDRAM_BASE + SZ_32M)
+#endif
+
+/*
+ * Serial driver
+ */
+#ifdef CONFIG_FTUART010
+# ifndef CONFIG_FTUART010_CLK
+# define CONFIG_FTUART010_CLK       18432000
+# endif
+# ifndef CONFIG_BAUDRATE
+# define CONFIG_BAUDRATE            38400
+# endif
+# undef CONFIG_HWFLOW
+# undef CONFIG_MODEM_SUPPORT
+# define CONFIG_SYS_NS16550
+# define CONFIG_SYS_NS16550_SERIAL
+# define CONFIG_SYS_NS16550_CLK         CONFIG_FTUART010_CLK
+# define CONFIG_SYS_NS16550_COM1        CONFIG_FTUART010_BASE
+# define CONFIG_SYS_NS16550_MEM32
+# define CONFIG_SYS_NS16550_REG_SIZE    (-4)
+# define CONFIG_CONS_INDEX              1
+#endif /* CONFIG_FTUART010 */
+
+/*
+ * NIC driver
+ */
+#ifdef CONFIG_FTGMAC100
+# define CONFIG_FTGMAC100_EGIGA
+# define CONFIG_PHY_GIGE /* Enable giga phy support for miiphyutil.c */
+#endif
+
+#if defined(CONFIG_FTMAC110) || defined(CONFIG_FTGMAC100)
+# define CONFIG_PHY_MAX_ADDR        32
+# define CONFIG_RANDOM_MACADDR
+# define CONFIG_MII
+# define CONFIG_NET_MULTI
+# define CONFIG_NET_RETRY_COUNT     20
+# define CONFIG_DRIVER_ETHER
+# define CONFIG_CMD_MII
+# define CONFIG_CMD_PING
+#endif /* CONFIG_FTMAC110 || CONFIG_FTGMAC100 */
+
+/*
+ * I2C bus driver
+ */
+#ifdef CONFIG_FTI2C010
+# define CONFIG_SYS_I2C_FTI2C010
+#endif
+#ifdef CONFIG_SYS_I2C_FTI2C010
+# define CONFIG_SYS_I2C
+# define CONFIG_SYS_I2C_SPEED       5000
+# define CONFIG_SYS_I2C_SLAVE       0
+# define CONFIG_CMD_I2C
+# define CONFIG_I2C_CMD_TREE
+#endif /* CONFIG_FTI2C010 */
+
+/*
+ * I2C-EEPROM
+ */
+#ifdef CONFIG_ENV_EEPROM_IS_ON_I2C
+# define CONFIG_CMD_EEPROM
+# define CONFIG_SYS_I2C_MULTI_EEPROMS
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_BITS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS      3
+# endif
+# ifndef CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS
+# define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  10
+# endif
+# ifndef CONFIG_SYS_I2C_EEPROM_ADDR_LEN
+# define CONFIG_SYS_I2C_EEPROM_ADDR_LEN         1
+# endif
+#endif
+
+/*
+ * SPI bus driver
+ */
+#ifdef CONFIG_FTSSP010_SPI
+# define CONFIG_SPI
+# define CONFIG_HARD_SPI
+# define CONFIG_CMD_SPI
+# define CONFIG_ENV_SPI_BUS         0
+# define CONFIG_ENV_SPI_CS          0
+# define CONFIG_ENV_SPI_MAX_HZ      25000000
+# define CONFIG_DEFAULT_SPI_MODE    SPI_MODE_0
+#endif
+
+/*
+ * SPI flash controller
+ */
+#if defined(CONFIG_SPI_FLASH)
+# define CONFIG_CMD_SF
+# define CONFIG_SPI_FLASH_MACRONIX
+# define CONFIG_SPI_FLASH_SPANSION
+# define CONFIG_SPI_FLASH_STMICRO
+# define CONFIG_SPI_FLASH_WINBOND
+# define CONFIG_SF_DEFAULT_MODE     SPI_MODE_0
+# define CONFIG_SF_DEFAULT_SPEED    25000000
+#endif
+
+/*
+ * NAND flash controller
+ */
+#ifdef CONFIG_FTNANDC021
+# define CONFIG_NAND_FTNANDC021
+#endif
+#ifdef CONFIG_SYS_NAND_BASE
+# define CONFIG_MTD_NAND_VERIFY_WRITE
+# define CONFIG_CMD_NAND
+# define CONFIG_CMD_NAND_YAFFS
+#endif
+
+/*
+ * NOR flash driver
+ */
+#ifdef CONFIG_SYS_FLASH_BASE
+# define CONFIG_SYS_FLASH_CFI
+# define CONFIG_FLASH_CFI_DRIVER
+# define CFG_FLASH_EMPTY_INFO /* 'E' for empty sector on flinfo */
+# define CONFIG_CMD_IMLS
+# define CONFIG_CMD_FLASH
+#else
+# define CONFIG_SYS_NO_FLASH
+#endif /* !CONFIG_SYS_NO_FLASH */
+
+/*
+ * MMC/SD
+ */
+#ifdef CONFIG_FTSDC010
+# define CONFIG_FTSDC010_SDIO /* HW is configured with SDIO support */
+#endif
+
+#ifdef CONFIG_FTSDC021
+# define CONFIG_SDHCI
+#endif
+
+#if defined(CONFIG_FTSDC010) || defined(CONFIG_FTSDC021)
+# define CONFIG_MMC
+# define CONFIG_CMD_MMC
+# define CONFIG_GENERIC_MMC
+#endif
+
+/*
+ * USB EHCI
+ */
+#if CONFIG_USB_MAX_CONTROLLER_COUNT > 0
+# define CONFIG_SYS_USB_EHCI_MAX_ROOT_PORTS 1
+# ifndef CONFIG_USB_HUB_MIN_POWER_ON_DELAY
+# define CONFIG_USB_HUB_MIN_POWER_ON_DELAY  500
+# endif
+# define CONFIG_USB_EHCI
+# define CONFIG_USB_EHCI_FARADAY
+# define CONFIG_EHCI_IS_TDI
+# define CONFIG_CMD_USB
+# define CONFIG_USB_STORAGE
+#endif
+
+/*
+ * U-Boot General Configurations
+ */
+#define CONFIG_LIB_RAND             /* Support srand() ... */
+#define CONFIG_VERSION_VARIABLE     /* Include version env variable */
+#define CONFIG_SYS_LONGHELP
+
+/*
+ * Shell
+ */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT           "=> "
+#define CONFIG_AUTO_COMPLETE
+#define CONFIG_CMDLINE_EDITING
+/* Console I/O Buffer Size */
+#define CONFIG_SYS_CBSIZE           256
+/* Print Buffer Size */
+#define CONFIG_SYS_PBSIZE \
+	(CONFIG_SYS_CBSIZE + sizeof(CONFIG_SYS_PROMPT) + 16)
+/* Max number of command args */
+#define CONFIG_SYS_MAXARGS          8
+
+/*
+ * FAT Filesystem
+ */
+#if defined(CONFIG_USB_STORAGE) || defined(CONFIG_MMC)
+# define CONFIG_DOS_PARTITION
+# define CONFIG_CMD_FAT
+#endif
+
+/*
+ * Linux Kernel Command Line
+ */
+#define CONFIG_INITRD_TAG
+#define CONFIG_CMDLINE_TAG      /* support ATAGs */
+#define CONFIG_SETUP_MEMORY_TAGS
+
+/*
+ * Default Commands
+ */
+#define CONFIG_CMD_SOURCE       /* 'source' command */
+#define CONFIG_CMD_BDI          /* bdinfo */
+#define CONFIG_CMD_ECHO         /* echo arguments */
+#define CONFIG_CMD_ENV          /* printenv */
+#define CONFIG_CMD_MEMORY       /* md mm nm mw ... */
+#define CONFIG_CMD_NET          /* bootp, tftpboot, rarpboot */
+#define CONFIG_CMD_RUN          /* run command in env variable */
+#define CONFIG_CMD_ELF          /* support ELF files */
+#define CONFIG_CMD_LOADB        /* xyzModem */
+#ifndef CONFIG_ENV_IS_NOWHERE
+# define CONFIG_CMD_SAVEENV     /* saveenv */
+#endif
+
+#endif /* EOF */
diff --git a/include/faraday/clkdev.h b/include/faraday/clkdev.h
new file mode 100644
index 0000000..b879d55
--- /dev/null
+++ b/include/faraday/clkdev.h
@@ -0,0 +1,19 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __FARADAY_CLKDEV_H
+#define __FARADAY_CLKDEV_H
+
+struct faraday_clk_ops {
+	int (*enable)(void);
+	void (*disable)(void);
+	unsigned long (*get_rate)(void);
+	long (*round_rate)(unsigned long rate);
+	int (*set_rate)(unsigned long rate);
+};
+
+#endif /* __FARADAY_CLKDEV_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v12 4/8] arm: faraday: add FTTMR010 timer suppor
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (2 preceding siblings ...)
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 3/8] arm: add Faraday ARMv5TE platform common libraries Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 5/8] arm: faraday: add FTPWMTMR010 timer support Kuo-Jung Su
                     ` (3 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTTMR010 is a simple APB device which supports
generic timer functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v12:
	- Rollback to v10.
	  Because we now always have core.[ch] inside arch/arm/cpu/faraday/<soc>/,
	  so it's no longer necessary to add some object files in
	  'arch/arm/cpu/faraday/<soc>/Makefile' to avoid linking errors.

Changes for v11:
	- Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
	  instead of using CONFIG_FTTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v8, v9, v10:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile   |    2 +
 arch/arm/cpu/faraday/fttmr010.c |  123 +++++++++++++++++++++++++++++++++++++++
 include/faraday/fttmr010.h      |   17 ++++++
 3 files changed, 142 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fttmr010.c

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index ab8d5f8..521147f 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -8,3 +8,5 @@
 extra-y := start.o

 obj-y   += cpu.o cache.o clk.o
+
+obj-$(CONFIG_FTTMR010)    += fttmr010.o
diff --git a/arch/arm/cpu/faraday/fttmr010.c b/arch/arm/cpu/faraday/fttmr010.c
new file mode 100644
index 0000000..1dec044
--- /dev/null
+++ b/arch/arm/cpu/faraday/fttmr010.c
@@ -0,0 +1,123 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <faraday/fttmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct fttmr010 *regs = (void __iomem *)CONFIG_FTTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer2 */
+	clrbits_le32(&regs->cr, FTTMR010_TM2_CRMASK);
+	/* Disable Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_mask);
+	/* Clear Timer2 interrupts */
+	writel(FTTMR010_TM2_ISRMASK, &regs->interrupt_state);
+
+	/* Configure Timer2 */
+	writel((freq / 1000000) * usec, &regs->timer2_counter);
+	writel(0, &regs->timer2_load);
+	writel(0, &regs->timer2_match1);
+	writel(0, &regs->timer2_match2);
+
+	/* Enable Timer2 */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM2_OFENABLE | FTTMR010_TM2_ENABLE);
+
+	/* Wait until timeout */
+	while (!(readl(&regs->interrupt_state) & FTTMR010_TM2_ISRMASK))
+		;
+}
+
+void reset_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* Disable Timer1 */
+	clrbits_le32(&regs->cr, FTTMR010_TM1_CRMASK);
+
+	/* Disable & Clear Timer1 interrupts */
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_mask);
+	writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+
+	/* Setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->timer1_counter);
+	writel((0xffffffff / freq) * freq, &regs->timer1_load);
+
+	writel(0, &regs->timer1_match1);
+	writel(0, &regs->timer1_match2);
+
+	/* Disable match interrupts */
+	writel(FTTMR010_TM1_MATCH1 | FTTMR010_TM1_MATCH2,
+	       &regs->interrupt_mask);
+
+	/* Enable Timer1 with overflow interrupt */
+	setbits_le32(&regs->cr,
+		FTTMR010_TM1_OFENABLE | FTTMR010_TM1_ENABLE);
+}
+
+ulong get_timer_masked(void)
+{
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->interrupt_state) & FTTMR010_TM1_ISRMASK) {
+		writel(FTTMR010_TM1_ISRMASK, &regs->interrupt_state);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq) - readl(&regs->timer1_counter)) / ms;
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/fttmr010.h b/include/faraday/fttmr010.h
index 2ab68d1..21ab113 100644
--- a/include/faraday/fttmr010.h
+++ b/include/faraday/fttmr010.h
@@ -45,6 +45,16 @@ struct fttmr010 {
 #define FTTMR010_TM1_CLOCK	(1 << 1)
 #define FTTMR010_TM1_ENABLE	(1 << 0)

+#define FTTMR010_TM1_CRMASK \
+	(FTTMR010_TM1_UPDOWN | FTTMR010_TM1_OFENABLE \
+	| FTTMR010_TM1_CLOCK | FTTMR010_TM1_ENABLE)
+#define FTTMR010_TM2_CRMASK \
+	(FTTMR010_TM2_UPDOWN | FTTMR010_TM2_OFENABLE \
+	| FTTMR010_TM2_CLOCK | FTTMR010_TM2_ENABLE)
+#define FTTMR010_TM3_CRMASK \
+	(FTTMR010_TM3_UPDOWN | FTTMR010_TM3_OFENABLE \
+	| FTTMR010_TM3_CLOCK | FTTMR010_TM3_ENABLE)
+
 /*
  * Timer Interrupt State & Mask Registers
  */
@@ -58,4 +68,11 @@ struct fttmr010 {
 #define FTTMR010_TM1_MATCH2	(1 << 1)
 #define FTTMR010_TM1_MATCH1	(1 << 0)

+#define FTTMR010_TM1_ISRMASK \
+	(FTTMR010_TM1_OVERFLOW | FTTMR010_TM1_MATCH2 | FTTMR010_TM1_MATCH1)
+#define FTTMR010_TM2_ISRMASK \
+	(FTTMR010_TM2_OVERFLOW | FTTMR010_TM2_MATCH2 | FTTMR010_TM2_MATCH1)
+#define FTTMR010_TM3_ISRMASK \
+	(FTTMR010_TM3_OVERFLOW | FTTMR010_TM3_MATCH2 | FTTMR010_TM3_MATCH1)
+
 #endif	/* __FTTMR010_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v12 5/8] arm: faraday: add FTPWMTMR010 timer support
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (3 preceding siblings ...)
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 4/8] arm: faraday: add FTTMR010 timer suppor Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 6/8] arm: faraday: add A369 evaluation board support Kuo-Jung Su
                     ` (2 subsequent siblings)
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday FTPWMTMR010 is a simple APB device which supports
both timer and pwm functions.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v12:
	- Rollback to v10.
	  Because we now always have core.[ch] inside arch/arm/cpu/faraday/<soc>/,
	  so it's no longer necessary to add some object files in
	  'arch/arm/cpu/faraday/<soc>/Makefile' to avoid linking errors.

Changes for v11:
	- Directly specify the timer object in 'arch/arm/cpu/faraday/<soc>/Makefile'
	  instead of using CONFIG_FTPWMTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v8, v9, v10:
	- Nothing updates

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- Nothing updates

Changes for v5:
	- Drop IRQ dependant implementation
	- Use gd->arch.timer_rate_hz for timer clock source
	- Use gd->arch.tbl for timestamp

Changes for v4:
	- Coding Style cleanup.
	- Break up from [arm: add Faraday A36x SoC platform support]

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/Makefile      |    1 +
 arch/arm/cpu/faraday/ftpwmtmr010.c |  112 ++++++++++++++++++++++++++++++++++++
 include/faraday/ftpwmtmr010.h      |   41 +++++++++++++
 3 files changed, 154 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/ftpwmtmr010.c
 create mode 100644 include/faraday/ftpwmtmr010.h

diff --git a/arch/arm/cpu/faraday/Makefile b/arch/arm/cpu/faraday/Makefile
index 521147f..fe9fb21 100644
--- a/arch/arm/cpu/faraday/Makefile
+++ b/arch/arm/cpu/faraday/Makefile
@@ -10,3 +10,4 @@ extra-y := start.o
 obj-y   += cpu.o cache.o clk.o

 obj-$(CONFIG_FTTMR010)    += fttmr010.o
+obj-$(CONFIG_FTPWMTMR010) += ftpwmtmr010.o
diff --git a/arch/arm/cpu/faraday/ftpwmtmr010.c b/arch/arm/cpu/faraday/ftpwmtmr010.c
new file mode 100644
index 0000000..51b851e
--- /dev/null
+++ b/arch/arm/cpu/faraday/ftpwmtmr010.c
@@ -0,0 +1,112 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <faraday/ftpwmtmr010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define TIMER_ID    0
+
+static struct ftpwmtmr010_regs *regs =
+	(void __iomem *)CONFIG_FTPWMTMR010_BASE;
+
+void udelay_masked(unsigned long usec)
+{
+	int id = TIMER_ID + 1;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	/* timer re-start */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+	writel(0, &regs->t[id].cmpb);
+	writel((freq / 1000000) * usec, &regs->t[id].cntb);
+	writel(CTRL_INTEN | CTRL_START | CTRL_UPDATE, &regs->t[id].ctrl);
+
+	/* wait for timer interrupt */
+	while (!(readl(&regs->isr) & BIT_MASK(id)))
+		;
+
+	/* timer disabled */
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+}
+
+void reset_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+
+	writel(0, &regs->t[id].ctrl);
+	writel(BIT_MASK(id), &regs->isr);
+
+	/* setup a longest periodic timer */
+	writel((0xffffffff / freq) * freq, &regs->t[id].cntb);
+
+	writel(0, &regs->t[id].cmpb);
+	writel(CTRL_AUTORELOAD | CTRL_INTEN | CTRL_START | CTRL_UPDATE,
+	       &regs->t[id].ctrl);
+}
+
+ulong get_timer_masked(void)
+{
+	int id = TIMER_ID;
+	ulong freq = gd->arch.timer_rate_hz;
+	ulong secs = 0xffffffff / freq;
+	ulong ms = freq / CONFIG_SYS_HZ;
+
+	if (readl(&regs->isr) & BIT_MASK(id)) {
+		writel(BIT_MASK(id), &regs->isr);
+		gd->arch.tbl += secs * CONFIG_SYS_HZ;
+	}
+
+	return gd->arch.tbl
+		+ ((secs * freq - readl(&regs->t[id].cnto)) / ms);
+}
+
+int timer_init(void)
+{
+	gd->arch.tbl = 0;
+	reset_timer_masked();
+	return 0;
+}
+
+void reset_timer(void)
+{
+	reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+	return get_timer_masked() - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	udelay_masked(usec);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+	return CONFIG_SYS_HZ;
+}
diff --git a/include/faraday/ftpwmtmr010.h b/include/faraday/ftpwmtmr010.h
new file mode 100644
index 0000000..29f4f05
--- /dev/null
+++ b/include/faraday/ftpwmtmr010.h
@@ -0,0 +1,41 @@
+/*
+ * arch/arm/cpu/faraday/ftpwmtmr010.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+#define ARCH_ARM_CPU_FARADAY_FTPWMTMR010_H
+
+struct ftpwmtmr010_timer {
+	uint32_t ctrl;	/* Control */
+#define CTRL_EXTCLK			(1 << 0) /* use external clock */
+#define CTRL_START			(1 << 1) /* timer start */
+#define CTRL_UPDATE			(1 << 2) /* update timer counter */
+#define CTRL_AUTORELOAD		(1 << 4) /* auto-reload timer counter */
+#define CTRL_INTEN			(1 << 5) /* interrupt enabled */
+
+	uint32_t cntb;	/* Count buffer */
+	uint32_t cmpb;	/* Compare buffer */
+	uint32_t cnto;	/* Count observation */
+};
+
+struct ftpwmtmr010_regs {
+	/* 0x00: Interrupt status register */
+	uint32_t isr;
+
+	/* 0x04 - 0x0C: Reserved */
+	uint32_t rsvd[3];
+
+	/* 0x10 - 0x8C: timer registers */
+	struct ftpwmtmr010_timer t[8];
+
+	/* 0x90: Revision register */
+	uint32_t rev;
+};
+
+#endif
--
1.7.9.5

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

* [U-Boot] [PATCH v12 6/8] arm: faraday: add A369 evaluation board support
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (4 preceding siblings ...)
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 5/8] arm: faraday: add FTPWMTMR010 timer support Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 7/8] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 8/8] arm: faraday: add faraday virtual machine support Kuo-Jung Su
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

The A369 is an ARM CPU-based SoC with rich SoC features and
convenient FPGA link for building fast system prototyping
and mass production.

More information about this hardware can be found at:
http://www.faraday-tech.com/html/Product/SoCPlatform/SoCreativeIII.htm

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v12:
	- Add Linux legacy clock framework support (no common clock).
	- Drop board_early_init_f()
	- Coding style cleanup

Changes for v11:
	- Fix boards.cfg (due to commit 3fa67050)
	- Rename <asm/sizes.h> to <linux/sizes.h> (due to commit 1ace4022)
	- Directly specify the timer object in 'arch/arm/cpu/faraday/a369/Makefile'
	  instead of using CONFIG_FTPWMTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v10:
	- Merge [arm: faraday: ftsmc020: add a fail-safe macro constant]

Changes for v9:
	- Revise the commit message.

Changes for v8:
	- Make A369 a standalong changeset.

Changes for v7:
	- Update license to use SPDX identifiers.

Changes for v6:
	- arch/arm/cpu/faraday/cpu.c:
	  struct ftwdt010_wdt __iomem *regs -> struct ftwdt010_wdt *regs

Changes for v5:
	- Coding Style cleanup:
	  1. struct chip_regs __iomem *regs -> struct chip_regs *regs
	  2. Move Faraday specific APIs into asm/arch-faraday/*.h
	- Fix Copyright notices (dates) throughout the patch
	- Define Faraday machine type in board's config header file
	- Add myself as the maintainer for Faraday A360/A369 in MAINTAINERS.
	- Drop i2c:FTI2C010 & spi:FTSSP010_SPI support. The corresponding patch
	  would restart after this patch series have been accepted.
	- Revise clock management system

Changes for v4:
	- Coding Style cleanup.
	- Break-down the interrupt, timers and common utilties.

Changes for v3:
	- Coding Style cleanup.
	- Drop macros for wirtel()/readl(), call them directly.
	- Always insert a blank line between declarations and code.
	- Add '__iomem' to all the declaration of HW register pointers.
	- a36x_config: No more static global network configurations.
	- a36x_config: Add a common file for the redundant configurations.

Changes for v2:
	- Coding Style cleanup.
	- Use readl(), writel(), clrsetbits_le32() to replace REG() macros.
	- Use structure based hardware registers to replace the macro constants.
	- Replace BIT() with BIT_MASK().

 arch/arm/cpu/faraday/a369/Makefile        |    8 ++
 arch/arm/cpu/faraday/a369/clock.c         |   87 ++++++++++++
 arch/arm/cpu/faraday/a369/core.c          |   21 +++
 arch/arm/cpu/faraday/a369/core.h          |   15 ++
 arch/arm/cpu/faraday/a369/pinmux.c        |   37 +++++
 arch/arm/include/asm/arch-a369/clkdev.h   |   20 +++
 arch/arm/include/asm/arch-a369/hardware.h |   88 ++++++++++++
 arch/arm/include/asm/arch-a369/sysc.h     |  211 +++++++++++++++++++++++++++++
 board/faraday/a369evb/Makefile            |    9 ++
 board/faraday/a369evb/board.c             |  118 ++++++++++++++++
 board/faraday/a369evb/lowlevel_init.S     |   15 ++
 boards.cfg                                |    1 +
 include/configs/a369.h                    |  104 ++++++++++++++
 include/faraday/ftsmc020.h                |    1 +
 14 files changed, 735 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/a369/Makefile
 create mode 100644 arch/arm/cpu/faraday/a369/clock.c
 create mode 100644 arch/arm/cpu/faraday/a369/core.c
 create mode 100644 arch/arm/cpu/faraday/a369/core.h
 create mode 100644 arch/arm/cpu/faraday/a369/pinmux.c
 create mode 100644 arch/arm/include/asm/arch-a369/clkdev.h
 create mode 100644 arch/arm/include/asm/arch-a369/hardware.h
 create mode 100644 arch/arm/include/asm/arch-a369/sysc.h
 create mode 100644 board/faraday/a369evb/Makefile
 create mode 100644 board/faraday/a369evb/board.c
 create mode 100644 board/faraday/a369evb/lowlevel_init.S
 create mode 100644 include/configs/a369.h

diff --git a/arch/arm/cpu/faraday/a369/Makefile b/arch/arm/cpu/faraday/a369/Makefile
new file mode 100644
index 0000000..8f14bfd
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y := core.o clock.o pinmux.o
diff --git a/arch/arm/cpu/faraday/a369/clock.c b/arch/arm/cpu/faraday/a369/clock.c
new file mode 100644
index 0000000..2c08f73
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/clock.c
@@ -0,0 +1,87 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+#include <asm/io.h>
+#include <asm/arch/sysc.h>
+
+#ifndef CONFIG_PLATFORM_SCLK
+#define CONFIG_PLATFORM_SCLK    33000000 /* 33 MHz */
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+static ulong clk_get_hclk(void)
+{
+	return (CONFIG_PLATFORM_SCLK * PLLCR_NS(readl(&sysc->pllcr))) >> 3;
+}
+
+static ulong clk_get_pclk(void)
+{
+	return clk_get_hclk() >> 1;
+}
+
+static ulong clk_get_cpu(void)
+{
+	ulong clk = clk_get_hclk();
+
+	/* If it's an internal CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU)
+		return clk;
+	/*
+	 * Since the master would stop immediately after kicking
+	 * off slave cpu, so if GPMUX_CPUS_START is set,
+	 * it must be a slave cpu.
+	 */
+	if (!(readl(&sysc->gpmux) & GPMUX_CPUS_START))
+		clk = clk << HWCFG_CPUM_MUL(readl(&sysc->hwcfg));
+
+	return clk;
+}
+
+static struct clk clk_ahb = {
+	.ops = {
+		.get_rate = clk_get_hclk,
+	},
+};
+
+static struct clk clk_apb = {
+	.ops = {
+		.get_rate = clk_get_pclk,
+	},
+};
+
+static struct clk clk_cpu = {
+	.ops = {
+		.get_rate = clk_get_cpu,
+	},
+};
+
+static struct clk_lookup clk_table[] = {
+	CLKDEV_INIT(NULL, "AHB", &clk_ahb),
+	CLKDEV_INIT(NULL, "APB", &clk_apb),
+	CLKDEV_INIT(NULL, "CPU", &clk_cpu),
+	CLKDEV_INIT(NULL, "TMR", &clk_apb),
+	CLKDEV_INIT(NULL, "I2C", &clk_apb),
+	CLKDEV_INIT(NULL, "SPI", &clk_apb),
+	CLKDEV_INIT(NULL, "SSP", &clk_apb),
+	CLKDEV_INIT(NULL, "MMC", &clk_ahb),
+	CLKDEV_INIT(NULL, "SDC", &clk_ahb),
+};
+
+void clock_init(void)
+{
+	clkdev_add_table(clk_table, ARRAY_SIZE(clk_table));
+
+	gd->arch.timer_rate_hz = clk_get_rate(clk_get_sys(NULL, "TMR"));
+}
diff --git a/arch/arm/cpu/faraday/a369/core.c b/arch/arm/cpu/faraday/a369/core.c
new file mode 100644
index 0000000..f3eec4a
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/core.c
@@ -0,0 +1,21 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include "core.h"
+
+/*
+ * This arch_cpu_init() overrides the weak function
+ * in "arch/arm/lib/board.c".
+ */
+int arch_cpu_init(void)
+{
+	pinmux_init();
+	clock_init();
+	return 0;
+}
diff --git a/arch/arm/cpu/faraday/a369/core.h b/arch/arm/cpu/faraday/a369/core.h
new file mode 100644
index 0000000..558950e
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/core.h
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __A369_CORE_H
+#define __A369_CORE_H
+
+void clock_init(void);
+void pinmux_init(void);
+
+#endif
diff --git a/arch/arm/cpu/faraday/a369/pinmux.c b/arch/arm/cpu/faraday/a369/pinmux.c
new file mode 100644
index 0000000..41cd83d
--- /dev/null
+++ b/arch/arm/cpu/faraday/a369/pinmux.c
@@ -0,0 +1,37 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/sysc.h>
+
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+void pinmux_init(void)
+{
+	/* If it's an external CPU */
+	if (readl(&sysc->ehwcfg) & EHWCFG_EXTCPU) {
+		writel(HCLKGR_CPUM | HCLKGR_CPUS | HCLKGR_ISP,
+		       &sysc->hclkgr);
+		setbits_le32(&sysc->gpmux, GPMUX_EXTIRQ);
+	} else {
+#ifdef CONFIG_A369_EXTAHB
+		/* Enable external AHB */
+		writel(HCLKGR_CPUS, &sysc->hclkgr);
+		writel(GPMUX_DEFAULT, &sysc->gpmux);
+		clrbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_MASK);
+		setbits_le32(&sysc->sccfg[0], SCCFG0_EXTAHB_FREQ(8));
+#else
+		/* Enable SD1 */
+		writel(MFPMUX0_DEFAULT, &sysc->mfpmux[0]);
+#endif
+	}
+
+	/* Clock: SD = AHB, SSP = APB (SPI mode) */
+	writel(SCCFG1_DEFAULT, &sysc->sccfg[1]);
+}
diff --git a/arch/arm/include/asm/arch-a369/clkdev.h b/arch/arm/include/asm/arch-a369/clkdev.h
new file mode 100644
index 0000000..912b46a
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/clkdev.h
@@ -0,0 +1,20 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_CLKDEV_H
+#define __ASM_ARCH_CLKDEV_H
+
+#include <faraday/clkdev.h>
+
+struct clk {
+	struct faraday_clk_ops ops;
+};
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif /* __ASM_ARCH_CLKDEV_H */
diff --git a/arch/arm/include/asm/arch-a369/hardware.h b/arch/arm/include/asm/arch-a369/hardware.h
new file mode 100644
index 0000000..9c824ad
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/hardware.h
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/include/asm/arch-a369/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <linux/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00008000
+
+#define CONFIG_SYSC_BASE            0x92000000
+#define CONFIG_DDRC_BASE            0x93100000
+#define CONFIG_AHBC_BASE            0x94000000
+#define CONFIG_SMC_BASE             0x94800000
+#define CONFIG_AHBC2_BASE           0x94200000
+
+/*
+ * Timer
+ */
+#define CONFIG_FTPWMTMR010_BASE     0x92300000
+#define CONFIG_FTPWMTMR010_IRQ      8
+
+/*
+ * UART
+ */
+#define CONFIG_FTUART010_BASE       0x92B00000
+
+/*
+ * Interrupt
+ */
+#define CONFIG_FTINTC020_BASE0      0x90100000
+#define CONFIG_FTINTC020_BASE1      0x96000000
+#define CONFIG_FTINTC020_BASE       CONFIG_FTINTC020_BASE0
+
+/*
+ * I2C
+ */
+#define CONFIG_FTI2C010_BASE0       0x92900000
+#define CONFIG_FTI2C010_BASE1       0x92A00000
+#define CONFIG_FTI2C010_BASE        CONFIG_FTI2C010_BASE0
+
+/*
+ * WatchDog
+ */
+#define CONFIG_FTWDT010_BASE        0x92200000
+
+/*
+ * NIC
+ */
+#define CONFIG_FTGMAC100_BASE       0x90C00000
+
+/*
+ * SPI
+ */
+#define CONFIG_FTSSP010_BASE        0x92700000
+
+/*
+ * NAND
+ */
+#define CONFIG_FTNANDC021_BASE      0x90200000
+
+/*
+ * LCD
+ */
+#define CONFIG_FTLCDC200_BASE       0x94A00000
+
+/*
+ * SD/MMC
+ */
+#define CONFIG_FTSDC010_BASE        0x90600000
+
+/*
+ * USB
+ */
+#define CONFIG_FUSBH200_BASE        0x90800000    /* FUSBH200 */
+#define CONFIG_FOTG210_BASE         0x90900000    /* FOTG210 */
+
+#endif
diff --git a/arch/arm/include/asm/arch-a369/sysc.h b/arch/arm/include/asm/arch-a369/sysc.h
new file mode 100644
index 0000000..ddf3e70
--- /dev/null
+++ b/arch/arm/include/asm/arch-a369/sysc.h
@@ -0,0 +1,211 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef _ASM_ARCH_A369_SYSC_H
+#define _ASM_ARCH_A369_SYSC_H
+
+struct sysc_regs {
+	/* 0x000 ~ 0x0ff */
+	uint32_t idr;      /* ID Register */
+	uint32_t revr;     /* SCU revision id */
+	uint32_t hwcfg;    /* HW configuration strap */
+	uint32_t cpumcfr;  /* CPUM (master) freq. control */
+	uint32_t cr;       /* SCU control register */
+	uint32_t sr;       /* SCU status register */
+	uint32_t rsvd0[1];
+	uint32_t osccr;    /* OSC control register */
+	uint32_t pllcr;    /* PLL1 control register */
+	uint32_t dllcr;    /* DLL control register */
+	uint32_t hclkgr;   /* HCLK gating register */
+	uint32_t pclkgr;   /* PCLK gating register */
+	uint32_t rsvd1[52];
+
+	/* 0x100 ~ 0x1ff */
+	uint32_t spr[16];  /* Scratchpad register */
+	uint32_t rsvd2[48];
+
+	/* 0x200 ~ 0x2ff */
+	uint32_t gpmux;    /* General PINMUX */
+	uint32_t ehwcfg;   /* Extended HW configuration strap */
+	uint32_t rsvd3[8];
+	uint32_t sccfg[2]; /* Special clock configuration */
+	uint32_t scer;     /* Special clock enable register */
+	uint32_t rsvd;
+	uint32_t mfpmux[2];/* Multi-function pinmux */
+	uint32_t dcsrcr[2];/* Driving cap. & Slew rate control */
+	uint32_t rsvd4[3];
+	uint32_t dccr;     /* Delay chain control register */
+	uint32_t pcr;      /* Power control register */
+};
+
+/* HW configuration strap */
+#define HWCFG_PLL1NS(x)    (((x) >> 5) & 0x3f)
+#define HWCFG_CPUM_MUL(x)  ((((x) >> 3) & 3) > 2 ? 2 : (((x) >> 3) & 3))
+#define HWCFG_DLL_OFF      (1 << 2)
+#define HWCFG_PLL_OFF      (1 << 1)
+#define HWCFG_OSCHCNT_OFF  (1 << 0)
+
+/* Extended HW configuration strap */
+#define EHWCFG_AST         (1 << 15)
+#define EHWCFG_DBG         (1 << 14)
+#define EHWCFG_DBGBYSW     (1 << 13)
+#define EHWCFG_SATA_HOST   (1 << 12)
+#define EHWCFG_PCIE_RC     (1 << 11)
+#define EHWCFG_NAND_BK(x)  (((x) >> 9) & 3)
+#define EHWCFG_NAND_BK16   (0 << 9) /* 16 page per block */
+#define EHWCFG_NAND_BK32   (1 << 9) /* 32 page per block */
+#define EHWCFG_NAND_BK64   (2 << 9) /* 64 page per block */
+#define EHWCFG_NAND_BK128  (3 << 9) /* 128 page per block */
+#define EHWCFG_NAND_PS(x)  (((x) >> 7) & 3)
+#define EHWCFG_NAND_PS512  (0 << 7) /* 512 bytes per page */
+#define EHWCFG_NAND_PS2K   (1 << 7) /* 2048 bytes per page */
+#define EHWCFG_NAND_PS4K   (2 << 7) /* 4096 bytes per page */
+#define EHWCFG_NAND_AC(x)  (((x) >> 5) & 3)
+#define EHWCFG_NAND_AC3    (0 << 5) /* addr cycle = 3 */
+#define EHWCFG_NAND_AC4    (1 << 5) /* addr cycle = 4 */
+#define EHWCFG_NAND_AC5    (2 << 5) /* addr cycle = 5 */
+#define EHWCFG_NAND_16X    (1 << 4) /* NAND: 16bit mode */
+#define EHWCFG_EXTCPU      (1 << 2) /* external cpu mode */
+#define EHWCFG_BOOT_NAND   (0 << 0) /* boot from nand */
+#define EHWCFG_BOOT_SPI    (1 << 0) /* boot from spi */
+#define EHWCFG_BOOT_NOR    (2 << 0) /* boot from nor */
+
+/* General PINMUX */
+#define GPMUX_PLLGMAC      (1 << 15) /* PLL = GMAC PLL(PLL2) */
+#define GPMUX_EXTIRQ       (1 << 14) /* re-direct irq to external cpu */
+#define GPMUX_CS0REL       (1 << 13) /* release CS0 memory space */
+#define GPMUX_IOEN         (1 << 12) /* IO output enable */
+#define GPMUX_CPUS_START   (1 << 11) /* start slave cpu (fa606te) */
+#define GPMUX_SATA_RESET   (1 << 8)
+#define GPMUX_PDD          (1 << 7)  /* power-down detection enable */
+#define GPMUX_USBH_ALIVE   (1 << 6)
+#define GPMUX_USBH_PHYOSC  (1 << 5)
+#define GPMUX_OTG_ALIVE    (1 << 4)
+#define GPMUX_OTG_PHYOSC   (1 << 3)
+#define GPMUX_IRQMASK1     (1 << 2)
+#define GPMUX_IRQMASK0     (1 << 1)
+#define GPMUX_RESET        (1 << 0)
+
+#define GPMUX_DEFAULT      0x1078 /* USB keep alive + IO output */
+
+/* HCLK gating register */
+#define HCLKGR_CPUM        (1 << 31)
+#define HCLKGR_CPUS        (1 << 30)
+#define HCLKGR_AHBTSIF     (1 << 28)
+#define HCLKGR_AHBC3       (1 << 27)
+#define HCLKGR_AHBC2       (1 << 26)
+#define HCLKGR_AHBC1       (1 << 25)
+#define HCLKGR_APBBRG      (1 << 24)
+#define HCLKGR_NANDC       (1 << 23)
+#define HCLKGR_SMC         (1 << 22)
+#define HCLKGR_DMAC1       (1 << 21)
+#define HCLKGR_DMAC0       (1 << 20)
+#define HCLKGR_H264        (1 << 19)
+#define HCLKGR_MPEG4       (1 << 18)
+#define HCLKGR_2DGRA       (1 << 17)
+#define HCLKGR_LCD         (1 << 16)
+#define HCLKGR_ISP         (1 << 15)
+#define HCLKGR_AES         (1 << 14)
+#define HCLKGR_GMAC        (1 << 13)
+#define HCLKGR_SATAH       (1 << 12)
+#define HCLKGR_SATAD       (1 << 11)
+#define HCLKGR_PCIE        (1 << 10)
+#define HCLKGR_USBH        (1 << 9)
+#define HCLKGR_OTG         (1 << 8)
+#define HCLKGR_SD1         (1 << 7)
+#define HCLKGR_SD0         (1 << 6)
+#define HCLKGR_IDE         (1 << 5)
+#define HCLKGR_EM1         (1 << 4)
+#define HCLKGR_EM0         (1 << 3)
+#define HCLKGR_IRQ1        (1 << 2)
+#define HCLKGR_IRQ0        (1 << 1)
+#define HCLKGR_SCU         (1 << 0)
+
+/* Special clock configuration */
+#define SCCFG0_SATA_25M       (1 << 29)
+#define SCCFG0_SATA_OFF       (1 << 28)
+#define SCCFG0_GMAC_CLK_IO    (1 << 27)
+#define SCCFG0_GMAC_PLL_OFF   (1 << 26)
+#define SCCFG0_GMAC_PLL_NS(x) (((x) & 0x3f) << 20)
+#define SCCFG0_ISP_BFREQ(x)   (((x) & 0xf) << 16)
+#define SCCFG0_ISP_AFREQ(x)   (((x) & 0xf) << 12)
+#define SCCFG0_IDE_FREQ(x)    (((x) & 0xf) << 8)
+#define SCCFG0_EXTAHB_FREQ(x) (((x) & 0xf) << 4)
+#define SCCFG0_EXTAHB_MASK    0xf0
+#define SCCFG0_LCD_SCK_AHB    (0 << 2) /* LCD scalar clock source */
+#define SCCFG0_LCD_SCK_APB    (1 << 2)
+#define SCCFG0_LCD_SCK_EXT    (2 << 2)
+#define SCCFG0_LCD_CK_AHB     (0 << 0) /* LCD clock source */
+#define SCCFG0_LCD_CK_APB     (1 << 0)
+#define SCCFG0_LCD_CK_EXT     (2 << 0)
+
+#define SCCFG0_DEFAULT        0x26877330
+
+#define SCCFG1_SD1_CK_2AHB    (0 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_3APB    (1 << 18) /* SD1 clock source */
+#define SCCFG1_SD1_CK_AHB     (2 << 18) /* SD1 clock source */
+#define SCCFG1_SD0_CK_2AHB    (0 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_3APB    (1 << 16) /* SD0 clock source */
+#define SCCFG1_SD0_CK_AHB     (2 << 16) /* SD0 clock source */
+#define SCCFG1_SSP1_CK_EXT    (1 << 12) /* SSP1 clock source */
+#define SCCFG1_SSP1_FREQ(x)   (((x) & 0xf) << 8)
+#define SCCFG1_SSP0_CK_EXT    (1 << 4)  /* SSP0 clock source */
+#define SCCFG1_SSP0_FREQ(x)   (((x) & 0xf) << 0)
+
+#define SCCFG1_DEFAULT \
+	(SCCFG1_SD1_CK_AHB | SCCFG1_SD0_CK_AHB \
+	| SCCFG1_SSP1_FREQ(0xA) | SCCFG1_SSP0_FREQ(0xA))
+
+/* Special clock enable register */
+#define SCER_GMAC125M  (1 << 13)
+#define SCER_LCDSC     (1 << 12) /* LCD scalar clock */
+#define SCER_LCD       (1 << 11)
+#define SCER_ISPB      (1 << 10)
+#define SCER_ISPA      (1 << 9)
+#define SCER_IDE       (1 << 8)
+#define SCER_EXTAHB    (1 << 7)
+#define SCER_DDRD      (1 << 6)
+#define SCER_DDRF      (1 << 5)
+#define SCER_SD1       (1 << 4)
+#define SCER_SD0       (1 << 3)
+#define SCER_SSP1      (1 << 2)
+#define SCER_SSP0      (1 << 1)
+#define SCER_TSC       (1 << 0)
+
+/* Multi-function pinmux register */
+#define MFPMUX0_EBI(x)    (((x) & 0x3) << 10)
+#define MFPMUX0_LCD(x)    (((x) & 0x3) << 8)
+#define MFPMUX0_TS(x)     (((x) & 0x3) << 6)
+#define MFPMUX0_ISP(x)    (((x) & 0x3) << 4)
+#define MFPMUX0_SATA(x)   (((x) & 0x3) << 2)
+#define MFPMUX0_EXTAHB(x) (((x) & 0x3) << 0)
+
+#define MFPMUX0_DEFAULT   0x241 /* SD0 disabled, SD1 enabled */
+
+#define MFPMUX1_KBC(x)    (((x) & 0x3) << 20)
+#define MFPMUX1_GPIO0(x)  (((x) & 0x3) << 18)
+#define MFPMUX1_I2C1(x)   (((x) & 0x3) << 16)
+#define MFPMUX1_PWM1(x)   (((x) & 0x3) << 14)
+#define MFPMUX1_PWM0(x)   (((x) & 0x3) << 12)
+#define MFPMUX1_GMAC(x)   (((x) & 0x3) << 10)
+#define MFPMUX1_SSP1(x)   (((x) & 0x3) << 8)
+#define MFPMUX1_SSP0(x)   (((x) & 0x3) << 6)
+#define MFPMUX1_UART3(x)  (((x) & 0x3) << 4)
+#define MFPMUX1_UART2(x)  (((x) & 0x3) << 2)
+#define MFPMUX1_UART1(x)  (((x) & 0x3) << 0)
+
+/* PLL1 control register */
+#define PLLCR_NS(x)    (((x) >> 24) & 0x3f)
+#define PLLCR_STABLE   (1 << 1)
+#define PLLCR_OFF      (1 << 0)
+
+/* DLL control register */
+#define DLLCR_STABLE   (1 << 1)
+#define DLLCR_ON       (1 << 0)
+
+#endif	/* EOF */
diff --git a/board/faraday/a369evb/Makefile b/board/faraday/a369evb/Makefile
new file mode 100644
index 0000000..920ce43
--- /dev/null
+++ b/board/faraday/a369evb/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/a369evb/board.c b/board/faraday/a369evb/board.c
new file mode 100644
index 0000000..b1df4c1
--- /dev/null
+++ b/board/faraday/a369evb/board.c
@@ -0,0 +1,118 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <nand.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <asm/arch/sysc.h>
+#include <faraday/ftsmc020.h>
+#include <faraday/ftsdc010.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static struct ftsmc020 *smc = (void __iomem *)CONFIG_SMC_BASE;
+static struct sysc_regs *sysc = (void __iomem *)CONFIG_SYSC_BASE;
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_init(void)
+{
+	uint32_t base;
+
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+
+	/*
+	 * Static Memory Controller
+	 *
+	 * Bank 0: NOR Flash
+	 * Bank 1: N/A
+	 * Bank 2: N/A
+	 * Bank 3: N/A
+	 */
+	if ((readl(&sysc->ehwcfg) & 3) != EHWCFG_BOOT_NOR)
+		base = 0x20000000;
+	else
+		base = 0;
+
+	writel(FTSMC020_BANK_ENABLE
+		| FTSMC020_BANK_BASE(base)
+		| FTSMC020_BANK_SIZE_64M /* Max. 64MBytes */
+		| FTSMC020_BANK_MBW_16,  /* 16 bits */
+		&smc->bank[0].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[0].tpr);
+
+	writel(0, &smc->bank[1].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[1].tpr);
+
+	writel(0, &smc->bank[2].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[2].tpr);
+
+	writel(0, &smc->bank[3].cr);
+	writel(FTSMC020_TPR_FAILSAFE, &smc->bank[3].tpr);
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	int ret = 0;
+#ifdef CONFIG_USB_ETHER
+	uchar eth_addr[6];
+
+	if (!eth_getenv_enetaddr("usbnet_devaddr", eth_addr)) {
+		printf("WARNING: 'usbnet_devaddr' is a random default\n");
+		eth_random_enetaddr(eth_addr);
+		eth_setenv_enetaddr("usbnet_devaddr", eth_addr);
+	}
+	if (!eth_getenv_enetaddr("usbnet_hostaddr", eth_addr)) {
+		printf("WARNING: 'usbnet_hostaddr' is a random default\n");
+		eth_random_enetaddr(eth_addr);
+		eth_setenv_enetaddr("usbnet_hostaddr", eth_addr);
+	}
+
+	ret = usb_eth_initialize(bd);
+#elif defined(CONFIG_FTGMAC100)
+	uchar eth_addr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", eth_addr)) {
+		printf("WARNING: 'ethaddr' is a random default\n");
+		eth_random_enetaddr(eth_addr);
+		eth_setenv_enetaddr("ethaddr", eth_addr);
+	}
+
+	ret = ftgmac100_initialize(bd);
+#endif
+
+	return ret;
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	int ret = 0;
+
+#ifdef CONFIG_FTSDC010
+	ret = ftsdc010_mmc_init(0);
+#endif
+
+	return ret;
+}
diff --git a/board/faraday/a369evb/lowlevel_init.S b/board/faraday/a369evb/lowlevel_init.S
new file mode 100644
index 0000000..2085760
--- /dev/null
+++ b/board/faraday/a369evb/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index 69c8936..49c4f85 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -390,6 +390,7 @@ Active  arm         armv7:arm720t  tegra20     toradex         colibri_t20_iris
 Active  arm         armv7:arm720t  tegra30     avionic-design  tec-ng              tec-ng                               -                                                                                                                                 Alban Bedel <alban.bedel@avionic-design.de>
 Active  arm         armv7:arm720t  tegra30     nvidia          beaver              beaver                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>:Stephen Warren <swarren@nvidia.com>
 Active  arm         armv7:arm720t  tegra30     nvidia          cardhu              cardhu                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>
+Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         pxa            -           -               -                   balloon3                             -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
 Active  arm         pxa            -           -               -                   h2200                                -                                                                                                                                 Lukasz Dalek <luk0104@gmail.com>
 Active  arm         pxa            -           -               -                   palmld                               -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
diff --git a/include/configs/a369.h b/include/configs/a369.h
new file mode 100644
index 0000000..b04967b
--- /dev/null
+++ b/include/configs/a369.h
@@ -0,0 +1,104 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Support NOR flash */
+/* #define CONFIG_A369_NOR_FLASH */
+
+/* Support USB RNDIS Ethernet */
+/* #define CONFIG_A369_USB_ETHER */
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Timer */
+#define CONFIG_FTPWMTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTGMAC100
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* SPI */
+#define CONFIG_FTSSP010_SPI             /* v1.18.0 */
+/* - CS GPIO: base = BIT[31-20], pin = BIT[4-0] */
+#define CONFIG_FTSSP010_GPIO_BASE       (0x92600000 | 27)
+/* - SPI flash support */
+#define CONFIG_SPI_FLASH
+
+/* MMC/SD */
+#define CONFIG_FTSDC010
+
+/* NOR flash */
+#ifdef CONFIG_A369_NOR_FLASH
+# define PHYS_FLASH_SIZE                SZ_64M
+# define CONFIG_SYS_FLASH_BASE          0x20000000
+# define CONFIG_SYS_FLASH_CFI_WIDTH     FLASH_CFI_16BIT
+# define CONFIG_SYS_MAX_FLASH_BANKS     1
+# define CONFIG_SYS_MAX_FLASH_SECT      1024
+#endif
+
+/* USB */
+#if defined(CONFIG_A369_USB_ETHER)
+# define CONFIG_USB_GADGET
+# define CONFIG_USB_GADGET_FOTG210
+# define CONFIG_USB_GADGET_DUALSPEED
+# define CONFIG_USB_GADGET_VBUS_DRAW        200
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    1
+# define CONFIG_USB_EHCI_BASE               CONFIG_FUSBH200_BASE
+#else
+# define CONFIG_USB_MAX_CONTROLLER_COUNT    2
+# define CONFIG_USB_EHCI_BASE_LIST \
+	{ CONFIG_FUSBH200_BASE, CONFIG_FOTG210_BASE }
+#endif
+
+#ifdef CONFIG_A369_USB_ETHER
+# define CONFIG_USB_ETHER
+# define CONFIG_USB_ETH_RNDIS
+#endif
+
+/* Environment */
+#if defined(CONFIG_A369_NOR_FLASH)
+# define CONFIG_ENV_IS_IN_FLASH /* NOR flash */
+# define CONFIG_ENV_OFFSET          0x3f0000
+#else
+# define CONFIG_ENV_IS_NOWHERE
+#endif
+
+#define CONFIG_ENV_SIZE             SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+/* Platform specific extra environment variables */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Ethernet default configuration */ \
+	"ipaddr=10.0.0.199\0" \
+	"serverip=10.0.0.128\0" \
+	"netmask=255.255.255.0\0"
+
+#endif	/* EOF */
diff --git a/include/faraday/ftsmc020.h b/include/faraday/ftsmc020.h
index 54120ab..485d7c2 100644
--- a/include/faraday/ftsmc020.h
+++ b/include/faraday/ftsmc020.h
@@ -70,5 +70,6 @@ void ftsmc020_init(void);
 #define FTSMC020_TPR_WTC(x)	(((x) & 0x3) << 6)
 #define FTSMC020_TPR_AHT(x)	(((x) & 0x3) << 4)
 #define FTSMC020_TPR_TRNA(x)	(((x) & 0xf) << 0)
+#define FTSMC020_TPR_FAILSAFE	0x0f1ff3ff /* fail-safe timing */

 #endif	/* __FTSMC020_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v12 7/8] arm: faraday: add missing header file for FTSDC021
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (5 preceding siblings ...)
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 6/8] arm: faraday: add A369 evaluation board support Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 8/8] arm: faraday: add faraday virtual machine support Kuo-Jung Su
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

For the Faraday FTSDC021 (SDHCI) controller driver source is
sent out before the patches for Faraday Virtual Machine (FVM)
which actually uses this chip.

So its header file (ftsdc021.h) has been accidentally removed
by commit 3b98b57fa.

This patch simply rollback this removal.

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v11, v12:
	- Nothing updates

Changes for v10:
	- Initial commit

 include/faraday/ftsdc021.h |   13 +++++++++++++
 1 file changed, 13 insertions(+)
 create mode 100644 include/faraday/ftsdc021.h

diff --git a/include/faraday/ftsdc021.h b/include/faraday/ftsdc021.h
new file mode 100644
index 0000000..de8e250
--- /dev/null
+++ b/include/faraday/ftsdc021.h
@@ -0,0 +1,13 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __FTSDC021_H
+#define __FTSDC021_H
+
+int ftsdc021_sdhci_init(u32 regbase);
+
+#endif /* __FTSDC021_H */
--
1.7.9.5

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

* [U-Boot] [PATCH v12 8/8] arm: faraday: add faraday virtual machine support
  2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
                     ` (6 preceding siblings ...)
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 7/8] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
@ 2014-04-01  8:46   ` Kuo-Jung Su
  7 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-01  8:46 UTC (permalink / raw)
  To: u-boot

From: Kuo-Jung Su <dantesu@faraday-tech.com>

Faraday Virtual Machine (FVM) is a QEMU based emulator
which is designed for early stage software development
(i.e., IPL, SPL development).

Please check the link bellow for details:
https://github.com/dantesu1218/qemu/blob/qemu-1.5.1/hw/arm/faraday_fvm.c

Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
CC: Albert Aribaud <albert.u.boot@aribaud.net>
---
Changes for v12:
	- Add Linux legacy clock framework support (no common clock).
	- Drop board_early_init_f()
	- Coding style cleanup

Changes for v11:
	- Fix boards.cfg (due to commit 3fa67050)
	- Rename <asm/sizes.h> to <linux/sizes.h> (due to commit 1ace4022)
	- Directly specify the timer object in 'arch/arm/cpu/faraday/fvm/Makefile'
	  instead of using CONFIG_FTTMR010 in 'arch/arm/cpu/faraday/Makefile'

Changes for v10:
	- Nothing updates

Changes for v9:
	- Initial commit

 arch/arm/cpu/faraday/fvm/Makefile        |    8 ++++
 arch/arm/cpu/faraday/fvm/clock.c         |   70 +++++++++++++++++++++++++++
 arch/arm/cpu/faraday/fvm/core.c          |   20 ++++++++
 arch/arm/cpu/faraday/fvm/core.h          |   14 ++++++
 arch/arm/include/asm/arch-fvm/clkdev.h   |   20 ++++++++
 arch/arm/include/asm/arch-fvm/hardware.h |   76 ++++++++++++++++++++++++++++++
 board/faraday/fvm/Makefile               |    9 ++++
 board/faraday/fvm/board.c                |   65 +++++++++++++++++++++++++
 board/faraday/fvm/lowlevel_init.S        |   15 ++++++
 boards.cfg                               |    1 +
 include/configs/fvm.h                    |   68 ++++++++++++++++++++++++++
 11 files changed, 366 insertions(+)
 create mode 100644 arch/arm/cpu/faraday/fvm/Makefile
 create mode 100644 arch/arm/cpu/faraday/fvm/clock.c
 create mode 100644 arch/arm/cpu/faraday/fvm/core.c
 create mode 100644 arch/arm/cpu/faraday/fvm/core.h
 create mode 100644 arch/arm/include/asm/arch-fvm/clkdev.h
 create mode 100644 arch/arm/include/asm/arch-fvm/hardware.h
 create mode 100644 board/faraday/fvm/Makefile
 create mode 100644 board/faraday/fvm/board.c
 create mode 100644 board/faraday/fvm/lowlevel_init.S
 create mode 100644 include/configs/fvm.h

diff --git a/arch/arm/cpu/faraday/fvm/Makefile b/arch/arm/cpu/faraday/fvm/Makefile
new file mode 100644
index 0000000..5836aff
--- /dev/null
+++ b/arch/arm/cpu/faraday/fvm/Makefile
@@ -0,0 +1,8 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y := core.o clock.o
diff --git a/arch/arm/cpu/faraday/fvm/clock.c b/arch/arm/cpu/faraday/fvm/clock.c
new file mode 100644
index 0000000..d90bc57
--- /dev/null
+++ b/arch/arm/cpu/faraday/fvm/clock.c
@@ -0,0 +1,70 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <linux/clk.h>
+#include <linux/clkdev.h>
+
+#ifndef CONFIG_PLATFORM_SCLK
+#define CONFIG_PLATFORM_SCLK    50000000 /* 50 MHz */
+#endif
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static ulong clk_get_hclk(void)
+{
+	return CONFIG_PLATFORM_SCLK;
+}
+
+static ulong clk_get_pclk(void)
+{
+	return CONFIG_PLATFORM_SCLK;
+}
+
+static ulong clk_get_cpu(void)
+{
+	return CONFIG_PLATFORM_SCLK;
+}
+
+static struct clk clk_ahb = {
+	.ops = {
+		.get_rate = clk_get_hclk,
+	},
+};
+
+static struct clk clk_apb = {
+	.ops = {
+		.get_rate = clk_get_pclk,
+	},
+};
+
+static struct clk clk_cpu = {
+	.ops = {
+		.get_rate = clk_get_cpu,
+	},
+};
+
+static struct clk_lookup clk_table[] = {
+	CLKDEV_INIT(NULL, "AHB", &clk_ahb),
+	CLKDEV_INIT(NULL, "APB", &clk_apb),
+	CLKDEV_INIT(NULL, "CPU", &clk_cpu),
+	CLKDEV_INIT(NULL, "TMR", &clk_apb),
+	CLKDEV_INIT(NULL, "I2C", &clk_apb),
+	CLKDEV_INIT(NULL, "SPI", &clk_apb),
+	CLKDEV_INIT(NULL, "SSP", &clk_apb),
+	CLKDEV_INIT(NULL, "MMC", &clk_ahb),
+	CLKDEV_INIT(NULL, "SDC", &clk_ahb),
+};
+
+void clock_init(void)
+{
+	clkdev_add_table(clk_table, ARRAY_SIZE(clk_table));
+
+	gd->arch.timer_rate_hz = clk_get_rate(clk_get_sys(NULL, "TMR"));
+}
diff --git a/arch/arm/cpu/faraday/fvm/core.c b/arch/arm/cpu/faraday/fvm/core.c
new file mode 100644
index 0000000..318fe72
--- /dev/null
+++ b/arch/arm/cpu/faraday/fvm/core.c
@@ -0,0 +1,20 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include "core.h"
+
+/*
+ * This arch_cpu_init() overrides the weak function
+ * in "arch/arm/lib/board.c".
+ */
+int arch_cpu_init(void)
+{
+	clock_init();
+	return 0;
+}
diff --git a/arch/arm/cpu/faraday/fvm/core.h b/arch/arm/cpu/faraday/fvm/core.h
new file mode 100644
index 0000000..937c780
--- /dev/null
+++ b/arch/arm/cpu/faraday/fvm/core.h
@@ -0,0 +1,14 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __FVM_CORE_H
+#define __FVM_CORE_H
+
+void clock_init(void);
+
+#endif
diff --git a/arch/arm/include/asm/arch-fvm/clkdev.h b/arch/arm/include/asm/arch-fvm/clkdev.h
new file mode 100644
index 0000000..912b46a
--- /dev/null
+++ b/arch/arm/include/asm/arch-fvm/clkdev.h
@@ -0,0 +1,20 @@
+/*
+ * (C) Copyright 2013 Faraday Technology
+ * Dante Su <dantesu@faraday-tech.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_CLKDEV_H
+#define __ASM_ARCH_CLKDEV_H
+
+#include <faraday/clkdev.h>
+
+struct clk {
+	struct faraday_clk_ops ops;
+};
+
+#define __clk_get(clk) ({ 1; })
+#define __clk_put(clk) do { } while (0)
+
+#endif /* __ASM_ARCH_CLKDEV_H */
diff --git a/arch/arm/include/asm/arch-fvm/hardware.h b/arch/arm/include/asm/arch-fvm/hardware.h
new file mode 100644
index 0000000..dd04ced
--- /dev/null
+++ b/arch/arm/include/asm/arch-fvm/hardware.h
@@ -0,0 +1,76 @@
+/*
+ * arch/arm/include/asm/arch-fvm/hardware.h
+ *
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_ARCH_HARDWARE_H
+#define __ASM_ARCH_HARDWARE_H
+
+#include <linux/sizes.h>
+
+#define CONFIG_DRAM_BASE            0x10000000
+
+#define CONFIG_SRAM_BASE            0xA0000000
+#define CONFIG_SRAM_SIZE            0x00020000
+
+#define CONFIG_SYSC_BASE            0x90f00000
+#define CONFIG_SYSC_IRQ             15
+
+#define CONFIG_FTINTC030_BASE       0x91000000
+
+#define CONFIG_FTTMR010_BASE        0x90200000
+#define CONFIG_FTTMR010_IRQ         1
+
+#define CONFIG_FTUART010_BASE0      0x90000000
+#define CONFIG_FTUART010_IRQ0       2
+#define CONFIG_FTUART010_BASE1      0x90100000
+#define CONFIG_FTUART010_IRQ1       3
+#define CONFIG_FTUART010_BASE       CONFIG_FTUART010_BASE0
+
+#define CONFIG_DDRC_BASE            0x90300000
+
+#define CONFIG_FTI2C010_BASE        0x90400000
+#define CONFIG_FTI2C010_IRQ         4
+
+#define CONFIG_FTSSP010_BASE        0x90500000
+#define CONFIG_FTSSP010_IRQ         5
+
+#define CONFIG_FTWDT010_BASE        0x90600000
+#define CONFIG_FTWDT010_IRQ         6
+
+#define CONFIG_FTRTC011_BASE        0x90700000
+#define CONFIG_FTRTC011_IRQ         7
+
+#define CONFIG_FTTSC010_BASE        0x90800000
+#define CONFIG_FTTSC010_IRQ         8
+
+#define CONFIG_FTAPBBRG020_BASE     0x91100000
+#define CONFIG_FTAPBBRG020_IRQ      16
+
+#define CONFIG_FTDMAC020_BASE       0x91200000
+#define CONFIG_FTDMAC020_IRQ        17
+
+#define CONFIG_FTMAC110_BASE        0x91300000
+#define CONFIG_FTMAC110_IRQ         18
+
+#define CONFIG_FTSPI020_BASE        0x91400000
+#define CONFIG_FTSPI020_IRQ         19
+
+#define CONFIG_FTNANDC021_BASE      0x91500000
+#define CONFIG_FTNANDC021_IRQ       20
+
+#define CONFIG_FTSDC021_BASE        0x91600000
+#define CONFIG_FTSDC021_IRQ         21
+
+#define CONFIG_FOTG210_BASE         0x91700000
+#define CONFIG_FOTG210_IRQ          22
+
+#define CONFIG_FTLCDC200_BASE       0x91800000
+#define CONFIG_FTLCDC200_IRQ        23
+
+#endif /* EOF */
diff --git a/board/faraday/fvm/Makefile b/board/faraday/fvm/Makefile
new file mode 100644
index 0000000..920ce43
--- /dev/null
+++ b/board/faraday/fvm/Makefile
@@ -0,0 +1,9 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	:= board.o
+obj-y	+= lowlevel_init.o
diff --git a/board/faraday/fvm/board.c b/board/faraday/fvm/board.c
new file mode 100644
index 0000000..6b7f4f4
--- /dev/null
+++ b/board/faraday/fvm/board.c
@@ -0,0 +1,65 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <spi.h>
+#include <netdev.h>
+#include <malloc.h>
+
+#include <faraday/ftsdc021.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * Miscellaneous platform dependent initialisations
+ */
+int board_init(void)
+{
+	gd->bd->bi_arch_number = CONFIG_MACH_TYPE;
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->bd->bi_dram[0].start = CONFIG_SYS_SDRAM_BASE;
+	gd->bd->bi_dram[0].size  = CONFIG_SYS_SDRAM_SIZE;
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
+
+int board_eth_init(bd_t *bd)
+{
+	int ret = 0;
+#ifdef CONFIG_FTMAC110
+	uchar eth_addr[6];
+
+	if (!eth_getenv_enetaddr("ethaddr", eth_addr)) {
+		printf("WARNING: 'ethaddr' is a random default\n");
+		eth_random_enetaddr(eth_addr);
+		eth_setenv_enetaddr("ethaddr", eth_addr);
+	}
+
+	ret = ftmac110_initialize(bd);
+#endif
+
+	return ret;
+}
+
+int board_mmc_init(bd_t *bis)
+{
+	int ret = 0;
+
+#ifdef CONFIG_FTSDC021
+	ret = ftsdc021_sdhci_init(0);
+#endif
+
+	return ret;
+}
diff --git a/board/faraday/fvm/lowlevel_init.S b/board/faraday/fvm/lowlevel_init.S
new file mode 100644
index 0000000..cbc006d
--- /dev/null
+++ b/board/faraday/fvm/lowlevel_init.S
@@ -0,0 +1,15 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/tw/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <config.h>
+#include <version.h>
+
+/* Set up the platform, once the cpu has been initialized */
+.globl lowlevel_init
+lowlevel_init:
+	mov	pc,lr
diff --git a/boards.cfg b/boards.cfg
index 49c4f85..824d1d0 100644
--- a/boards.cfg
+++ b/boards.cfg
@@ -391,6 +391,7 @@ Active  arm         armv7:arm720t  tegra30     avionic-design  tec-ng
 Active  arm         armv7:arm720t  tegra30     nvidia          beaver              beaver                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>:Stephen Warren <swarren@nvidia.com>
 Active  arm         armv7:arm720t  tegra30     nvidia          cardhu              cardhu                               -                                                                                                                                 Tom Warren <twarren@nvidia.com>
 Active  arm         faraday        a369        faraday         a369evb             a369evb                              a369                                                                                                                              Kuo-Jung Su <dantesu@gmail.com>
+Active  arm         faraday        fvm         faraday         -                   fvm                                  -                                                                                                                                 Kuo-Jung Su <dantesu@gmail.com>
 Active  arm         pxa            -           -               -                   balloon3                             -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
 Active  arm         pxa            -           -               -                   h2200                                -                                                                                                                                 Lukasz Dalek <luk0104@gmail.com>
 Active  arm         pxa            -           -               -                   palmld                               -                                                                                                                                 Marek Vasut <marek.vasut@gmail.com>
diff --git a/include/configs/fvm.h b/include/configs/fvm.h
new file mode 100644
index 0000000..ffd44fc
--- /dev/null
+++ b/include/configs/fvm.h
@@ -0,0 +1,68 @@
+/*
+ * (C) Copyright 2013
+ * Faraday Technology Corporation. <http://www.faraday-tech.com/>
+ * Kuo-Jung Su <dantesu@gmail.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <asm/hardware.h>
+
+/* Disable MMU/D-CACHE */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* Memory Configuration */
+#define CONFIG_NR_DRAM_BANKS            1
+#define CONFIG_SYS_SDRAM_BASE           0x10000000
+#define CONFIG_SYS_SDRAM_SIZE           SZ_256M
+
+#define CONFIG_SYS_MALLOC_LEN           SZ_2M
+#define CONFIG_SYS_TEXT_BASE            0x10800000
+
+/* Timer */
+#define CONFIG_FTTMR010
+
+/* Serial (UART) */
+#define CONFIG_FTUART010
+#define CONFIG_FTUART010_CLK            18432000
+#define CONFIG_BAUDRATE                 38400
+
+/* NIC */
+#define CONFIG_FTMAC110
+
+/* I2C */
+#define CONFIG_FTI2C010
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+
+/* MMC/SD */
+#define CONFIG_FTSDC021
+
+/* NOR flash */
+#define PHYS_FLASH_SIZE                 SZ_64M
+#define CONFIG_SYS_FLASH_BASE           0x80000000
+#define CONFIG_SYS_FLASH_CFI_WIDTH      FLASH_CFI_16BIT
+#define CONFIG_SYS_MAX_FLASH_BANKS      1
+#define CONFIG_SYS_MAX_FLASH_SECT       1024
+
+/* USB */
+#define CONFIG_USB_MAX_CONTROLLER_COUNT 1
+#define CONFIG_USB_EHCI_BASE_LIST       { CONFIG_FOTG210_BASE }
+
+/* Environment */
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE                 SZ_64K
+
+/* Faraday common configuration */
+#include "faraday-common.h"
+
+/* Platform specific extra environment variables */
+#define CONFIG_EXTRA_ENV_SETTINGS \
+	/* Ethernet default configuration */ \
+	"ipaddr=10.0.0.199\0" \
+	"serverip=10.0.0.128\0" \
+	"netmask=255.255.255.0\0"
+
+#endif /* EOF */
--
1.7.9.5

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

* [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c
  2014-04-01  8:46   ` [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c Kuo-Jung Su
@ 2014-04-01  9:16     ` Marek Vasut
  2014-04-03  0:58       ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2014-04-01  9:16 UTC (permalink / raw)
  To: u-boot

On Tuesday, April 01, 2014 at 10:46:52 AM, Kuo-Jung Su wrote:
> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> 
> It would be better to have strlcpy() moved to lib/string.c,
> so that it could be reused by others without enabling
> USB Gadget Ethernet.
> 
> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> CC: Wolfgang Denk <wd@denx.de>
> Cc: Marek Vasut <marex@denx.de>

Good article on strlcpy() is here [1]. I suggest we remove strlcpy() altogether 
and use standard posix functions like strncpy() instead. I am on Ulrich Drepper 
side on this, strlcpy() is just hiding bugs.

[1] https://lwn.net/Articles/507319/

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c
  2014-04-01  9:16     ` Marek Vasut
@ 2014-04-03  0:58       ` Kuo-Jung Su
  2014-04-03  8:16         ` Marek Vasut
  0 siblings, 1 reply; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-03  0:58 UTC (permalink / raw)
  To: u-boot

2014-04-01 17:16 GMT+08:00 Marek Vasut <marex@denx.de>:
> On Tuesday, April 01, 2014 at 10:46:52 AM, Kuo-Jung Su wrote:
>> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>>
>> It would be better to have strlcpy() moved to lib/string.c,
>> so that it could be reused by others without enabling
>> USB Gadget Ethernet.
>>
>> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> CC: Albert Aribaud <albert.u.boot@aribaud.net>
>> CC: Wolfgang Denk <wd@denx.de>
>> Cc: Marek Vasut <marex@denx.de>
>
> Good article on strlcpy() is here [1]. I suggest we remove strlcpy() altogether
> and use standard posix functions like strncpy() instead. I am on Ulrich Drepper
> side on this, strlcpy() is just hiding bugs.
>
> [1] https://lwn.net/Articles/507319/
>

Agree, I'll use strncpy instead of strlcpy in drivers/clk/clkdev.c &
drivers/usb/gadget/ether.c

And the patch for drivers/usb/gadget/ether.c would not be bonded to
this patch series.

-- 
Best wishes,
Kuo-Jung Su

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

* [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c
  2014-04-03  0:58       ` Kuo-Jung Su
@ 2014-04-03  8:16         ` Marek Vasut
  2014-04-07  4:07           ` Kuo-Jung Su
  0 siblings, 1 reply; 311+ messages in thread
From: Marek Vasut @ 2014-04-03  8:16 UTC (permalink / raw)
  To: u-boot

On Thursday, April 03, 2014 at 02:58:27 AM, Kuo-Jung Su wrote:
> 2014-04-01 17:16 GMT+08:00 Marek Vasut <marex@denx.de>:
> > On Tuesday, April 01, 2014 at 10:46:52 AM, Kuo-Jung Su wrote:
> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> 
> >> It would be better to have strlcpy() moved to lib/string.c,
> >> so that it could be reused by others without enabling
> >> USB Gadget Ethernet.
> >> 
> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
> >> CC: Albert Aribaud <albert.u.boot@aribaud.net>
> >> CC: Wolfgang Denk <wd@denx.de>
> >> Cc: Marek Vasut <marex@denx.de>
> > 
> > Good article on strlcpy() is here [1]. I suggest we remove strlcpy()
> > altogether and use standard posix functions like strncpy() instead. I am
> > on Ulrich Drepper side on this, strlcpy() is just hiding bugs.
> > 
> > [1] https://lwn.net/Articles/507319/
> 
> Agree, I'll use strncpy instead of strlcpy in drivers/clk/clkdev.c &
> drivers/usb/gadget/ether.c
> 
> And the patch for drivers/usb/gadget/ether.c would not be bonded to
> this patch series.

Can you please remove that strlcpy() implementation while at it ?

Best regards,
Marek Vasut

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

* [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c
  2014-04-03  8:16         ` Marek Vasut
@ 2014-04-07  4:07           ` Kuo-Jung Su
  0 siblings, 0 replies; 311+ messages in thread
From: Kuo-Jung Su @ 2014-04-07  4:07 UTC (permalink / raw)
  To: u-boot

2014-04-03 16:16 GMT+08:00 Marek Vasut <marex@denx.de>:
> On Thursday, April 03, 2014 at 02:58:27 AM, Kuo-Jung Su wrote:
>> 2014-04-01 17:16 GMT+08:00 Marek Vasut <marex@denx.de>:
>> > On Tuesday, April 01, 2014 at 10:46:52 AM, Kuo-Jung Su wrote:
>> >> From: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >>
>> >> It would be better to have strlcpy() moved to lib/string.c,
>> >> so that it could be reused by others without enabling
>> >> USB Gadget Ethernet.
>> >>
>> >> Signed-off-by: Kuo-Jung Su <dantesu@faraday-tech.com>
>> >> CC: Albert Aribaud <albert.u.boot@aribaud.net>
>> >> CC: Wolfgang Denk <wd@denx.de>
>> >> Cc: Marek Vasut <marex@denx.de>
>> >
>> > Good article on strlcpy() is here [1]. I suggest we remove strlcpy()
>> > altogether and use standard posix functions like strncpy() instead. I am
>> > on Ulrich Drepper side on this, strlcpy() is just hiding bugs.
>> >
>> > [1] https://lwn.net/Articles/507319/
>>
>> Agree, I'll use strncpy instead of strlcpy in drivers/clk/clkdev.c &
>> drivers/usb/gadget/ether.c
>>
>> And the patch for drivers/usb/gadget/ether.c would not be bonded to
>> this patch series.
>
> Can you please remove that strlcpy() implementation while at it ?
>
> Best regards,
> Marek Vasut

Sure, but I'm still waiting for more inputs, so it would be delivered
few days later.

-- 
Best wishes,
Kuo-Jung Su

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

end of thread, other threads:[~2014-04-07  4:07 UTC | newest]

Thread overview: 311+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-03-29  7:06 [U-Boot] [PATCH 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 01/11] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
2013-04-18  9:25   ` [U-Boot] [PATCH v2 00/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 01/12] mtd: spi: winbond: add W25PXX support Kuo-Jung Su
2013-04-26  8:02       ` [U-Boot] [PATCH v3 00/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 01/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
2013-05-07  6:25           ` [U-Boot] [PATCH v4 0/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-05-07  6:25             ` [U-Boot] [PATCH v4 1/7] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
2013-06-10 17:59               ` Albert ARIBAUD
2013-06-11  3:09                 ` Kuo-Jung Su
2013-06-11 15:28                   ` Albert ARIBAUD
2013-06-14  5:44                     ` Kuo-Jung Su
2013-05-07  6:25             ` [U-Boot] [PATCH v4 2/7] arm: add Faraday common utilities Kuo-Jung Su
2013-06-10 18:05               ` Albert ARIBAUD
2013-06-11  3:02                 ` Kuo-Jung Su
2013-05-07  6:25             ` [U-Boot] [PATCH v4 3/7] arm: add Faraday interrupt controller support Kuo-Jung Su
2013-05-07  6:25             ` [U-Boot] [PATCH v4 4/7] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
2013-05-07  6:25             ` [U-Boot] [PATCH v4 5/7] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
2013-05-07  6:25             ` [U-Boot] [PATCH v4 6/7] arm: add Faraday firmware image utility Kuo-Jung Su
2013-06-10 18:38               ` Albert ARIBAUD
2013-06-11  3:00                 ` Kuo-Jung Su
2013-05-07  6:25             ` [U-Boot] [PATCH v4 7/7] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-06-10 18:39               ` Albert ARIBAUD
2013-06-11  3:01                 ` Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 02/11] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
2013-05-07  6:33           ` [U-Boot] [PATCH v4] net: update FTGMAC100 for " Kuo-Jung Su
2013-07-08 16:21             ` Joe Hershberger
2013-04-26  8:02         ` [U-Boot] [PATCH v3 03/11] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
2013-05-02 16:03           ` Tom Rini
2013-05-03  6:01             ` Kuo-Jung Su
2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
2013-07-08 16:19             ` Joe Hershberger
2013-04-26  8:02         ` [U-Boot] [PATCH v3 04/11] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
2013-04-29  3:34           ` Heiko Schocher
2013-05-07  6:32           ` [U-Boot] [PATCH v4 03/16] " Kuo-Jung Su
2013-05-07 13:19             ` Heiko Schocher
2013-05-08  1:51               ` Kuo-Jung Su
2013-05-08  4:30                 ` Heiko Schocher
2013-05-08  5:47                   ` Kuo-Jung Su
2013-05-08  7:36             ` [U-Boot] [PATCH v5] " Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 05/11] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
2013-05-07  6:34           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
2013-06-12 18:56             ` [U-Boot] [U-Boot, " Jagan Teki
2013-06-14  6:00               ` Kuo-Jung Su
2013-11-22  7:44             ` [U-Boot] [PATCH v5] spi: ftssp010_spi: add Faraday " Kuo-Jung Su
2013-11-28  2:46             ` [U-Boot] [PATCH v6] " Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 06/11] mmc: update the Faraday FTSDC010 driver to fix performance issue Kuo-Jung Su
2013-05-03 22:35           ` Andy Fleming
2013-05-06  6:44             ` Kuo-Jung Su
2013-05-07  6:32           ` [U-Boot] [PATCH v4] mmc: update Faraday FTSDC010 for rw performance Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 07/11] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
2013-04-26 23:41           ` Scott Wood
2013-04-29  3:28             ` Kuo-Jung Su
2013-04-29 20:46               ` Scott Wood
2013-04-30  1:33                 ` Kuo-Jung Su
2013-05-07  6:33           ` [U-Boot] [PATCH v4] " Kuo-Jung Su
2013-05-09  0:43             ` Scott Wood
2013-05-09  1:45               ` Kuo-Jung Su
2013-05-09  1:51             ` [U-Boot] [PATCH v5] " Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 08/11] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-04-26 12:19           ` Marek Vasut
2013-04-29  3:10             ` Kuo-Jung Su
2013-04-29 22:50               ` Marek Vasut
2013-04-30  1:32                 ` Kuo-Jung Su
2013-05-01 19:34                   ` Marek Vasut
2013-05-02  1:14                     ` Kuo-Jung Su
2013-05-07  6:26           ` [U-Boot] [PATCH v4 0/2] usb: ehci: add Faraday USB EHCI&Gadget support Kuo-Jung Su
2013-05-07  6:26             ` [U-Boot] [PATCH v4 1/2] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-05-07 21:42               ` Marek Vasut
2013-05-08  2:18                 ` Kuo-Jung Su
2013-05-08  3:09                   ` Marek Vasut
2013-05-08  5:41                     ` Kuo-Jung Su
2013-05-08 11:52                       ` Marek Vasut
2013-05-09  1:51                         ` Kuo-Jung Su
2013-05-09  3:20               ` [U-Boot] [PATCH v5 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
2013-05-09  3:20                 ` [U-Boot] [PATCH v5 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
2013-05-10 11:41                   ` Marek Vasut
2013-05-13  1:11                     ` Kuo-Jung Su
2013-05-13  2:07                   ` [U-Boot] [PATCH v6 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
2013-05-13  2:07                     ` [U-Boot] [PATCH v6 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
2013-05-13  2:36                       ` Marek Vasut
2013-05-13  8:12                         ` Kuo-Jung Su
2013-05-13  8:28                       ` [U-Boot] [PATCH v7 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
2013-05-13  8:28                         ` [U-Boot] [PATCH v7 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
2013-05-14  2:29                           ` [U-Boot] [PATCH v8 0/4] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
2013-05-14  2:29                             ` [U-Boot] [PATCH v8 1/4] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
2013-05-15  7:29                               ` [U-Boot] [PATCH v9 0/5] usb: add Faraday EHCI & Gadget support Kuo-Jung Su
2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 1/5] usb: ehci: prevent bad PORTSC register access Kuo-Jung Su
2013-05-21 20:09                                   ` Marek Vasut
2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 2/5] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 3/5] usb: hub: make minimum power-on delay configurable Kuo-Jung Su
2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 4/5] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-05-15  7:29                                 ` [U-Boot] [PATCH v9 5/5] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
2013-05-19 18:37                                   ` Marek Vasut
2013-05-20  0:56                                     ` Kuo-Jung Su
2013-05-14  2:29                             ` [U-Boot] [PATCH v8 2/4] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
2013-05-14  2:29                             ` [U-Boot] [PATCH v8 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-05-14  2:29                             ` [U-Boot] [PATCH v8 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
2013-05-13  8:28                         ` [U-Boot] [PATCH v7 2/4] usb: ehci: add weak-aliased function for PORTSC Kuo-Jung Su
2013-05-13  8:28                         ` [U-Boot] [PATCH v7 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-05-13  8:28                         ` [U-Boot] [PATCH v7 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
2013-05-13  2:07                     ` [U-Boot] [PATCH v6 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
2013-05-13  2:32                       ` Marek Vasut
2013-05-13  8:09                         ` Kuo-Jung Su
2013-05-13 15:10                           ` Marek Vasut
2013-05-14  1:26                             ` Kuo-Jung Su
2013-05-14 13:47                               ` Marek Vasut
2013-05-15  1:03                                 ` Kuo-Jung Su
2013-05-15  2:42                                   ` Kuo-Jung Su
2013-05-15  3:29                                     ` Marek Vasut
2013-05-15  4:07                                       ` Kuo-Jung Su
2013-05-13  2:07                     ` [U-Boot] [PATCH v6 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-05-13  2:07                     ` [U-Boot] [PATCH v6 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
2013-05-09  3:20                 ` [U-Boot] [PATCH v5 2/4] usb: ehci: add weak-aliased functions to portsc & tdi Kuo-Jung Su
2013-05-10 11:44                   ` Marek Vasut
2013-05-13  1:10                     ` Kuo-Jung Su
2013-05-09  3:20                 ` [U-Boot] [PATCH v5 3/4] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-05-09  3:20                 ` [U-Boot] [PATCH v5 4/4] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
2013-05-07  6:26             ` [U-Boot] [PATCH v4 2/2] " Kuo-Jung Su
2013-05-07 21:37               ` Marek Vasut
2013-05-08  2:30                 ` Kuo-Jung Su
2013-05-08  3:07                   ` Marek Vasut
2013-04-26  8:02         ` [U-Boot] [PATCH v3 09/11] " Kuo-Jung Su
2013-04-26 12:21           ` Marek Vasut
2013-04-29  3:11             ` Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 10/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
2013-05-06 20:18           ` Anatolij Gustschin
2013-05-07  6:34           ` [U-Boot] [PATCH v2] " Kuo-Jung Su
2013-04-26  8:02         ` [U-Boot] [PATCH v3 11/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-05-02 22:27         ` [U-Boot] [PATCH v3 00/11] " Tom Rini
2013-05-03  6:02           ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 02/12] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 03/12] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
2013-04-18 10:52       ` Wolfgang Denk
2013-04-22  2:56         ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 04/12] i2c: add Faraday FTI2C010 I2C controller support Kuo-Jung Su
2013-04-18 10:54       ` Wolfgang Denk
2013-04-22  2:52         ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 05/12] spi: add Faraday FTSPI010 SPI " Kuo-Jung Su
2013-04-18 10:56       ` Wolfgang Denk
2013-04-22  2:52         ` Kuo-Jung Su
2013-08-08 13:38       ` Jagan Teki
2013-08-09  0:47         ` Kuo-Jung Su
2013-08-09 11:27           ` Jagan Teki
2013-08-12  0:37             ` Kuo-Jung Su
2013-10-03 19:53               ` Jagan Teki
2013-04-18  9:25     ` [U-Boot] [PATCH v2 06/12] mmc: add an alternative driver to Faraday FTSDC010 Kuo-Jung Su
2013-04-18 10:57       ` Wolfgang Denk
2013-04-22  2:51         ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 07/12] mtd: nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
2013-04-18 11:04       ` Wolfgang Denk
2013-04-22  1:52         ` Kuo-Jung Su
2013-04-18 19:44       ` Scott Wood
2013-04-22  2:45         ` Kuo-Jung Su
2013-04-22 23:11           ` Scott Wood
2013-04-23  1:19             ` Kuo-Jung Su
2013-04-23 22:57               ` Scott Wood
2013-04-24  1:03                 ` Kuo-Jung Su
2013-04-23  1:22             ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 08/12] mtd: spi: add FTSPI020 SPI Flash " Kuo-Jung Su
2013-04-18 11:08       ` Wolfgang Denk
2013-04-22  1:51         ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 09/12] usb: ehci: add Faraday USB 2.0 EHCI support Kuo-Jung Su
2013-04-18 11:09       ` Wolfgang Denk
2013-04-22  1:45         ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 10/12] usb: gadget: add Faraday FOTG210 USB gadget support Kuo-Jung Su
2013-04-18 11:11       ` Wolfgang Denk
2013-04-22  1:45         ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 11/12] arm: add MMU/d-cache support for Faraday cores Kuo-Jung Su
2013-04-18 11:13       ` Wolfgang Denk
2013-04-22  1:23         ` Kuo-Jung Su
2013-04-18 19:09       ` Albert ARIBAUD
2013-04-22  1:27         ` Kuo-Jung Su
2013-04-18  9:25     ` [U-Boot] [PATCH v2 12/12] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-04-18 11:16       ` Wolfgang Denk
2013-04-22  1:30         ` Kuo-Jung Su
2013-04-18 10:43     ` [U-Boot] [PATCH v2 00/12] " Wolfgang Denk
2013-04-22  1:27       ` Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 02/11] net/ftgmac100: add MMU/D-cache support Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 03/11] net: add FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 04/11] usb-ehci: add Faraday USB 2.0 EHCI controller support Kuo-Jung Su
2013-03-30  6:29   ` Marek Vasut
2013-04-01  1:21     ` Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 05/11] usb-gadget: add FOTG210 USB gadget support Kuo-Jung Su
2013-03-30  6:27   ` Marek Vasut
2013-04-01  1:20     ` Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 06/11] i2c: add FTI2C010 I2C controller support Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 07/11] spi: add FTSPI010 SPI " Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 08/11] mtd/nand: add FTNANDC021 NAND flash " Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 09/11] mtd/spi: add FTSPI020 SPI Flash " Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 10/11] mmc: add an alternative FTSDC010 driver support Kuo-Jung Su
2013-03-29  7:06 ` [U-Boot] [PATCH 11/11] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-06-17 12:06 ` [U-Boot] [PATCH v5 00/14] " Kuo-Jung Su
2013-06-17 12:06   ` [U-Boot] [PATCH v5 01/14] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
2013-06-17 12:06   ` [U-Boot] [PATCH v5 02/14] net: ftgmac100: add MMU/D-cache support Kuo-Jung Su
2013-06-23  7:16     ` Albert ARIBAUD
2013-06-24  1:31       ` Kuo-Jung Su
2013-06-17 12:06   ` [U-Boot] [PATCH v5 03/14] net: add Faraday FTMAC110 10/100Mbps ethernet support Kuo-Jung Su
2013-06-23  7:18     ` Albert ARIBAUD
2013-06-23 11:09       ` Tom Rini
2013-06-23 13:18         ` Albert ARIBAUD
2013-06-23 15:17           ` Tom Rini
2013-06-17 12:06   ` [U-Boot] [PATCH v5 04/14] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
2013-06-17 12:06   ` [U-Boot] [PATCH v5 05/14] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
2013-06-18  0:08     ` Scott Wood
2013-06-18  0:51       ` Kuo-Jung Su
2013-06-18  0:56         ` Scott Wood
2013-06-17 12:06   ` [U-Boot] [PATCH v5 06/14] cfi_flash: use buffer length in unmap_physmem() Kuo-Jung Su
2013-06-17 12:06   ` [U-Boot] [PATCH v5 07/14] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
2013-06-17 12:06   ` [U-Boot] [PATCH v5 08/14] arm: add Faraday processor core support Kuo-Jung Su
2013-06-17 12:06   ` [U-Boot] [PATCH v5 09/14] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
2013-06-17 12:07   ` [U-Boot] [PATCH v5 10/14] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
2013-06-17 12:07   ` [U-Boot] [PATCH v5 11/14] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
2013-06-17 12:07   ` [U-Boot] [PATCH v5 12/14] arm: add Faraday specific boot command Kuo-Jung Su
2013-06-23  7:22     ` Albert ARIBAUD
2013-06-24  1:30       ` Kuo-Jung Su
2013-06-17 12:07   ` [U-Boot] [PATCH v5 13/14] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
2013-06-17 18:32     ` Andy Fleming
2013-06-18  0:48       ` Kuo-Jung Su
2013-06-17 12:07   ` [U-Boot] [PATCH v5 14/14] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
2013-07-04  3:40 ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 01/12] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 02/12] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 03/12] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
2013-07-08 23:59     ` Scott Wood
2013-07-09  1:42       ` Kuo-Jung Su
2013-07-09  1:48         ` Scott Wood
2013-07-09  1:57           ` Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 04/12] cfi_flash: use buffer length in unmap_physmem() Kuo-Jung Su
2013-07-25 14:46     ` Stefan Roese
2013-07-04  3:40   ` [U-Boot] [PATCH v6 05/12] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 06/12] arm: add Faraday processor core support Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 07/12] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 08/12] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 09/12] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 10/12] arm: add customized boot command for Faraday Images Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 11/12] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
2013-07-04  3:40   ` [U-Boot] [PATCH v6 12/12] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
2013-07-25  9:07   ` [U-Boot] [PATCH v6 00/12] arm: add Faraday A36x " Albert ARIBAUD
2013-07-26 14:15     ` Kuo-Jung Su
2013-07-29  5:51 ` [U-Boot] [PATCH v7 00/11] " Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 01/11] arm: dma_alloc_coherent: malloc() -> memalign() Kuo-Jung Su
2013-09-14 10:09     ` Albert ARIBAUD
2013-07-29  5:51   ` [U-Boot] [PATCH v7 02/11] video: add Faraday FTLCDC200 LCD controller support Kuo-Jung Su
2013-08-09 19:33     ` Anatolij Gustschin
2013-07-29  5:51   ` [U-Boot] [PATCH v7 03/11] nand: add Faraday FTNANDC021 NAND " Kuo-Jung Su
2013-07-29 22:59     ` Scott Wood
2013-07-30  0:39       ` Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 04/11] arm: add MMU/D-Cache support for Faraday cores Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 05/11] arm: add Faraday processor core support Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 06/11] arm: add Faraday FTINTC020 interrupt controller support Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 07/11] arm: add Faraday FTTMR010 timer support Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 08/11] arm: add Faraday FTPWMTMR010 " Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 09/11] arm: add customized boot command for Faraday Images Kuo-Jung Su
2013-09-14 10:28     ` Albert ARIBAUD
2013-10-02  0:53       ` Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 10/11] mmc: ftsdc010_mci: clk_get_rate() -> clock_get_rate() Kuo-Jung Su
2013-07-29  5:51   ` [U-Boot] [PATCH v7 11/11] arm: add Faraday A360/A369 SoC platform support Kuo-Jung Su
2013-11-28  2:48   ` [U-Boot] [PATCH v8] nand: add Faraday FTNANDC021 NAND controller support Kuo-Jung Su
2014-03-04  2:17     ` [U-Boot] [U-Boot, " Scott Wood
2014-03-04  3:58       ` Kuo-Jung Su
2013-12-30  9:23 ` [U-Boot] [PATCH v8 0/8] arm: add Faraday A36x SoC platform support Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 1/8] arm: global_data: prepare for Faraday SoC support Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 2/8] arm: make mmu_enabled() a global function Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 3/8] arm: add Faraday ARM cores support Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 4/8] arm: faraday: revise the DMA API Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 5/8] arm: faraday: add FTPWMTMR010 timer support Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 6/8] arm: faraday: add FTTMR010 " Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 7/8] arm: faraday: add A360 SoC support Kuo-Jung Su
2013-12-30  9:23   ` [U-Boot] [PATCH v8 8/8] arm: faraday: add A369 " Kuo-Jung Su
2014-01-16  8:31 ` [U-Boot] [PATCH v9 0/7] arm: add Faraday SoC platform support Kuo-Jung Su
2014-01-16  8:31   ` [U-Boot] [PATCH v9 1/7] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
2014-01-16  8:31   ` [U-Boot] [PATCH v9 2/7] arm: add Faraday SoC helper files Kuo-Jung Su
2014-01-16  8:31   ` [U-Boot] [PATCH v9 3/7] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
2014-01-16  8:31   ` [U-Boot] [PATCH v9 4/7] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
2014-01-16  8:31   ` [U-Boot] [PATCH v9 5/7] arm: faraday: ftsmc020: add a fail-safe macro constant Kuo-Jung Su
2014-01-16  8:31   ` [U-Boot] [PATCH v9 6/7] arm: faraday: add A369 evaluation board support Kuo-Jung Su
2014-01-16  8:31   ` [U-Boot] [PATCH v9 7/7] arm: faraday: add Faraday Virtual Machine support Kuo-Jung Su
2014-02-20  3:40 ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Kuo-Jung Su
2014-02-20  3:40   ` [U-Boot] [PATCH v10 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
2014-02-20  3:40   ` [U-Boot] [PATCH v10 2/6] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
2014-02-20  3:40   ` [U-Boot] [PATCH v10 3/6] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
2014-02-20  3:40   ` [U-Boot] [PATCH v10 4/6] arm: faraday: add A369 evaluation board support Kuo-Jung Su
2014-02-20  3:40   ` [U-Boot] [PATCH v10 5/6] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
2014-02-20  3:40   ` [U-Boot] [PATCH v10 6/6] arm: faraday: add virtual machine support Kuo-Jung Su
2014-03-25 12:41   ` [U-Boot] [PATCH v10 0/6] arm: add Faraday SoC platform support Albert ARIBAUD
2014-03-26  6:08     ` Kuo-Jung Su
2014-03-26  6:03 ` [U-Boot] [PATCH v11 " Kuo-Jung Su
2014-03-26  6:03   ` [U-Boot] [PATCH v11 1/6] arm: add Faraday ARMv5TE cores support Kuo-Jung Su
2014-03-26  6:47     ` Wolfgang Denk
2014-03-26  7:22       ` Kuo-Jung Su
2014-03-26  6:03   ` [U-Boot] [PATCH v11 2/6] arm: faraday: add FTTMR010 timer support Kuo-Jung Su
2014-03-26  6:03   ` [U-Boot] [PATCH v11 3/6] arm: faraday: add FTPWMTMR010 " Kuo-Jung Su
2014-03-26  6:03   ` [U-Boot] [PATCH v11 4/6] arm: faraday: add A369 evaluation board support Kuo-Jung Su
2014-03-26  6:03   ` [U-Boot] [PATCH v11 5/6] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
2014-03-26  6:03   ` [U-Boot] [PATCH v11 6/6] arm: faraday: add virtual machine support Kuo-Jung Su
2014-03-26  6:52     ` Wolfgang Denk
2014-03-26  7:24       ` Kuo-Jung Su
2014-04-01  8:46 ` [U-Boot] [PATCH v12 0/8] arm: add Faraday SoC platform support Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 1/8] libc: move strlcpy() from ether.c to string.c Kuo-Jung Su
2014-04-01  9:16     ` Marek Vasut
2014-04-03  0:58       ` Kuo-Jung Su
2014-04-03  8:16         ` Marek Vasut
2014-04-07  4:07           ` Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 2/8] arm: add legacy linux clock framework support Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 3/8] arm: add Faraday ARMv5TE platform common libraries Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 4/8] arm: faraday: add FTTMR010 timer suppor Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 5/8] arm: faraday: add FTPWMTMR010 timer support Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 6/8] arm: faraday: add A369 evaluation board support Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 7/8] arm: faraday: add missing header file for FTSDC021 Kuo-Jung Su
2014-04-01  8:46   ` [U-Boot] [PATCH v12 8/8] arm: faraday: add faraday virtual machine support Kuo-Jung Su

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.