mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* Prepare support for TI AM35xx
@ 2012-09-03 11:45 Jan Luebbe
  2012-09-03 11:45 ` [PATCH 01/10] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash Jan Luebbe
                   ` (9 more replies)
  0 siblings, 10 replies; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:45 UTC (permalink / raw)
  To: barebox

Hi all,

these patches prepare for TI AM35xx support and have have been tested
together with the board code.

Thanks to Jean-Christophe Plagniol-Villard for his review

Best regards,
Jan


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 01/10] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
@ 2012-09-03 11:45 ` Jan Luebbe
  2012-09-03 11:45 ` [PATCH 02/10] drivers/nor/m25p80: add MEMGETINFO ioctl Jan Luebbe
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:45 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 drivers/nor/m25p80.c |    3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/nor/m25p80.c b/drivers/nor/m25p80.c
index 5713ad5..61f2195 100644
--- a/drivers/nor/m25p80.c
+++ b/drivers/nor/m25p80.c
@@ -648,6 +648,9 @@ static const struct spi_device_id m25p_ids[] = {
 	{ "cat25c09", CAT25_INFO( 128, 8, 32, 2) },
 	{ "cat25c17", CAT25_INFO( 256, 8, 32, 2) },
 	{ "cat25128", CAT25_INFO(2048, 8, 64, 2) },
+
+	/* Micron */
+	{ "n25q128", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
 	{ },
 };
 
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 02/10] drivers/nor/m25p80: add MEMGETINFO ioctl
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
  2012-09-03 11:45 ` [PATCH 01/10] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash Jan Luebbe
@ 2012-09-03 11:45 ` Jan Luebbe
  2012-09-04  8:20   ` Sascha Hauer
  2012-09-03 11:45 ` [PATCH 03/10] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:45 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 drivers/nor/m25p80.c |   26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/nor/m25p80.c b/drivers/nor/m25p80.c
index 61f2195..1722e0a 100644
--- a/drivers/nor/m25p80.c
+++ b/drivers/nor/m25p80.c
@@ -20,6 +20,7 @@
 #include <common.h>
 #include <init.h>
 #include <driver.h>
+#include <ioctl.h>
 #include <spi/spi.h>
 #include <spi/flash.h>
 #include <xfuncs.h>
@@ -690,9 +691,34 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)
 	return NULL;
 }
 
+static int m25p80_ioctl(struct cdev *cdev, int request, void *buf)
+{
+	struct m25p *flash = cdev->priv;
+	struct flash_info *info = flash->info;
+	struct mtd_info_user *user = buf;
+
+	switch (request) {
+	case MEMGETINFO:
+		memset(user, 0, sizeof(*user));
+		user->type = MTD_NORFLASH;
+		user->flags = MTD_CAP_NORFLASH;
+		user->size = flash->size;
+		user->erasesize = info->sector_size;
+		user->writesize = 1;
+		user->oobsize = 0;
+		/* The below fields are obsolete */
+		user->ecctype = -1;
+		user->eccsize = 0;
+		return 0;
+	}
+
+	return -EINVAL;
+}
+
 static struct file_operations m25p80_ops = {
 	.read   = m25p80_read,
 	.write  = m25p80_write,
+	.ioctl  = m25p80_ioctl,
 	.erase  = m25p80_erase,
 	.lseek  = dev_lseek_default,
 };
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 03/10] Makefile: add target to produce a SPL compatible uimage
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
  2012-09-03 11:45 ` [PATCH 01/10] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash Jan Luebbe
  2012-09-03 11:45 ` [PATCH 02/10] drivers/nor/m25p80: add MEMGETINFO ioctl Jan Luebbe
@ 2012-09-03 11:45 ` Jan Luebbe
  2012-09-03 16:22   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-03 11:45 ` [PATCH 04/10] scripts: add tool to create image for SPI boot on AM35xx Jan Luebbe
                   ` (6 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:45 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 Makefile |    5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Makefile b/Makefile
index 969afbb..243a689 100644
--- a/Makefile
+++ b/Makefile
@@ -673,6 +673,11 @@ barebox.bin: barebox FORCE
 	$(call if_changed,objcopy)
 	$(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
 
+barebox.img: barebox.bin
+	$(srctree)/scripts/mkimage -A $(ARCH) -T firmware -C none \
+	-O barebox -a $(CONFIG_TEXT_BASE) -e $(CONFIG_TEXT_BASE) \
+	-n "barebox $(KERNELRELEASE)" -d $< $@
+
 ifdef CONFIG_X86
 barebox.S: barebox
 ifdef CONFIG_X86_HDBOOT
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 04/10] scripts: add tool to create image for SPI boot on AM35xx
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
                   ` (2 preceding siblings ...)
  2012-09-03 11:45 ` [PATCH 03/10] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
@ 2012-09-03 11:45 ` Jan Luebbe
  2012-09-04  8:27   ` Sascha Hauer
  2012-09-03 11:46 ` [PATCH 05/10] common: split out meminfo output and make it optional Jan Luebbe
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:45 UTC (permalink / raw)
  To: barebox

Booting from SPI on an AM35xx (and possibly other TI SOCs) requires
a special format:

- 32 bit image size in big-endian
- 32 bit load address in big-endian
- binary image converted from little- to big-endian

The mk-am35xx-spi-image tool converts barebox.bin to
this format.

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 arch/arm/Makefile             |    8 +++
 arch/arm/mach-omap/Kconfig    |    7 +++
 scripts/.gitignore            |    1 +
 scripts/Makefile              |    2 +-
 scripts/mk-am35xx-spi-image.c |  126 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 scripts/mk-am35xx-spi-image.c

diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 1b60261..ff96299 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -199,6 +199,14 @@ endif
 
 all: $(KBUILD_IMAGE)
 
+barebox.spi: barebox.bin
+	@echo "  SPI    " $@
+	$(Q)scripts/mk-am35xx-spi-image barebox.bin > barebox.spi
+
+ifeq ($(CONFIG_OMAP_BUILD_SPI),y)
+all: barebox.spi
+endif
+
 archprepare: maketools
 maketools:
 	$(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h
diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index d735284..a781287 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -91,6 +91,13 @@ config OMAP_BUILD_IFT
 	prompt "build ift binary"
 	bool
 
+config OMAP_BUILD_SPI
+	prompt "build SPI binary"
+	bool
+	help
+	  Say Y here if you want to build an barebox.spi image as used
+	  on the AM35xx chips when booting form SPI NOR flash.
+
 config ARCH_TEXT_BASE
 	hex
 	default 0x80e80000 if MACH_OMAP343xSDP
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 6e63f85..3f1cbdb 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -2,6 +2,7 @@ bareboxenv
 bin2c
 gen_netx_image
 kallsyms
+mk-am35xx-spi-image
 mkimage
 mkublheader
 omap_signGP
diff --git a/scripts/Makefile b/scripts/Makefile
index 7ca5e29..55ccdac 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -9,7 +9,7 @@ hostprogs-y                      += bin2c
 hostprogs-y                      += mkimage
 hostprogs-y                      += bareboxenv
 hostprogs-$(CONFIG_ARCH_NETX)    += gen_netx_image
-hostprogs-$(CONFIG_ARCH_OMAP)    += omap_signGP
+hostprogs-$(CONFIG_ARCH_OMAP)    += omap_signGP mk-am35xx-spi-image
 hostprogs-$(CONFIG_ARCH_S5PCxx)  += s5p_cksum
 hostprogs-$(CONFIG_ARCH_DAVINCI) += mkublheader
 
diff --git a/scripts/mk-am35xx-spi-image.c b/scripts/mk-am35xx-spi-image.c
new file mode 100644
index 0000000..133f2b7
--- /dev/null
+++ b/scripts/mk-am35xx-spi-image.c
@@ -0,0 +1,126 @@
+/*
+ * mkublheader.c - produce the header needed to load barebox on OMAP-L138
+ *
+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <limits.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <endian.h>
+
+void usage(char *prgname)
+{
+	printf("usage: %s [OPTION] FILE > IMAGE\n"
+	       "\n"
+	       "options:\n"
+	       "  -a <address> memory address for the loaded image in SRAM\n",
+	       prgname);
+}
+
+int main(int argc, char *argv[])
+{
+	FILE *input;
+	int opt;
+	off_t pos;
+	size_t size;
+	uint32_t addr = 0x40200000;
+	uint32_t temp;
+
+	while((opt = getopt(argc, argv, "a:")) != -1) {
+		switch (opt) {
+		case 'a':
+			addr = strtoul(optarg, NULL, 0);
+			break;
+		}
+	}
+
+	if (optind >= argc) {
+		usage(argv[0]);
+		exit(1);
+	}
+
+	input = fopen(argv[optind], "r");
+	if (input == NULL) {
+		perror("fopen");
+		exit(EXIT_FAILURE);
+	}
+
+	if (fseeko(input, 0, SEEK_END) == -1) {
+		perror("fseeko");
+		exit(EXIT_FAILURE);
+	}
+
+	pos = ftello(input);
+	if (pos == -1) {
+		perror("ftello");
+		exit(EXIT_FAILURE);
+	}
+	if (pos % 4) {
+		printf("error: image size must be a multiple of 4 bytes\n");
+		exit(EXIT_FAILURE);
+	}
+	if (pos > 0x100000) {
+		printf("error: image should be smaller than 1 MiB\n");
+		exit(EXIT_FAILURE);
+	}
+
+	if (fseeko(input, 0, SEEK_SET) == -1) {
+		perror("fseeko");
+		exit(EXIT_FAILURE);
+	}
+
+	/* image size */
+	temp = htobe32((uint32_t)pos);
+	fwrite(&temp, sizeof(uint32_t), 1, stdout);
+
+	/* memory address */
+	temp = htobe32(addr);
+	fwrite(&temp, sizeof(uint32_t), 1, stdout);
+
+	for (;;) {
+		size = fread(&temp, 1, sizeof(uint32_t), input);
+		if (!size)
+			break;
+		if (size != 4) {
+			perror("fread");
+			exit(EXIT_FAILURE);
+		}
+		temp = htobe32(le32toh(temp));
+		if (fwrite(&temp, 1, sizeof(uint32_t), stdout) != 4) {
+			perror("fwrite");
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	if (fclose(input) != 0) {
+		perror("fclose");
+		exit(EXIT_FAILURE);
+	}
+
+	exit(EXIT_SUCCESS);
+}
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 05/10] common: split out meminfo output and make it optional
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
                   ` (3 preceding siblings ...)
  2012-09-03 11:45 ` [PATCH 04/10] scripts: add tool to create image for SPI boot on AM35xx Jan Luebbe
@ 2012-09-03 11:46 ` Jan Luebbe
  2012-09-03 11:46 ` [PATCH 06/10] omap: add SPI as a boot mode for xload Jan Luebbe
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:46 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 common/Kconfig   |    4 ++++
 common/Makefile  |    1 +
 common/meminfo.c |   23 +++++++++++++++++++++++
 common/startup.c |   21 ---------------------
 include/common.h |    4 ++--
 5 files changed, 30 insertions(+), 23 deletions(-)
 create mode 100644 common/meminfo.c

diff --git a/common/Kconfig b/common/Kconfig
index 7eb5b49..ba8ccf5 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -96,6 +96,10 @@ config BANNER
 	bool "display banner"
 	default y
 
+config MEMINFO
+	bool "display memory info"
+	default y
+
 config ENVIRONMENT_VARIABLES
 	bool "environment variables support"
 
diff --git a/common/Makefile b/common/Makefile
index d74dffb..5d3ef4b 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -19,6 +19,7 @@ obj-$(CONFIG_MALLOC_TLSF) += tlsf.o
 obj-$(CONFIG_MALLOC_DUMMY) += dummy_malloc.o
 obj-y += clock.o
 obj-$(CONFIG_BANNER) += version.o
+obj-$(CONFIG_MEMINFO) += meminfo.o
 obj-$(CONFIG_COMMAND_SUPPORT) += command.o
 obj-$(CONFIG_CONSOLE_FULL) += console.o
 obj-$(CONFIG_CONSOLE_SIMPLE) += console_simple.o
diff --git a/common/meminfo.c b/common/meminfo.c
new file mode 100644
index 0000000..06fce5a
--- /dev/null
+++ b/common/meminfo.c
@@ -0,0 +1,23 @@
+#include <common.h>
+#include <init.h>
+#include <memory.h>
+#include <asm-generic/memory_layout.h>
+
+static int display_meminfo(void)
+{
+	ulong mstart = mem_malloc_start();
+	ulong mend   = mem_malloc_end();
+	ulong msize  = mend - mstart + 1;
+
+	debug("barebox code: 0x%p -> 0x%p\n", _stext, _etext);
+	debug("bss segment:  0x%p -> 0x%p\n", __bss_start, __bss_stop);
+	printf("malloc space: 0x%08lx -> 0x%08lx (size %s)\n",
+		mstart, mend, size_human_readable(msize));
+#ifdef CONFIG_ARM
+	printf("stack space:  0x%08x -> 0x%08x (size %s)\n",
+		STACK_BASE, STACK_BASE + STACK_SIZE,
+		size_human_readable(STACK_SIZE));
+#endif
+	return 0;
+}
+late_initcall(display_meminfo);
diff --git a/common/startup.c b/common/startup.c
index abd1b77..e639d05 100644
--- a/common/startup.c
+++ b/common/startup.c
@@ -33,34 +33,15 @@
 #include <init.h>
 #include <command.h>
 #include <malloc.h>
-#include <memory.h>
 #include <debug_ll.h>
 #include <fs.h>
 #include <linux/stat.h>
 #include <environment.h>
-#include <asm-generic/memory_layout.h>
 #include <asm/sections.h>
 
 extern initcall_t __barebox_initcalls_start[], __barebox_early_initcalls_end[],
 		  __barebox_initcalls_end[];
 
-static void display_meminfo(void)
-{
-	ulong mstart = mem_malloc_start();
-	ulong mend   = mem_malloc_end();
-	ulong msize  = mend - mstart + 1;
-
-	debug("barebox code: 0x%p -> 0x%p\n", _stext, _etext);
-	debug("bss segment:  0x%p -> 0x%p\n", __bss_start, __bss_stop);
-	printf("Malloc space: 0x%08lx -> 0x%08lx (size %s)\n",
-		mstart, mend, size_human_readable(msize));
-#ifdef CONFIG_ARM
-	printf("Stack space : 0x%08x -> 0x%08x (size %s)\n",
-		STACK_BASE, STACK_BASE + STACK_SIZE,
-		size_human_readable(STACK_SIZE));
-#endif
-}
-
 #ifdef CONFIG_DEFAULT_ENVIRONMENT
 #include <generated/barebox_default_env.h>
 
@@ -128,8 +109,6 @@ void start_barebox (void)
 
 	debug("initcalls done\n");
 
-	display_meminfo();
-
 #ifdef CONFIG_ENV_HANDLING
 	if (envfs_load(default_environment_path, "/env")) {
 #ifdef CONFIG_DEFAULT_ENVIRONMENT
diff --git a/include/common.h b/include/common.h
index df12083..30c1dc6 100644
--- a/include/common.h
+++ b/include/common.h
@@ -150,11 +150,11 @@ static inline void dump_stack(void)
 #define MEMAREA_SIZE_SPECIFIED 1
 
 struct memarea_info {
-        struct device_d *device;
+	struct device_d *device;
 	unsigned long start;
 	unsigned long end;
 	unsigned long size;
-        unsigned long flags;
+	unsigned long flags;
 };
 
 int parse_area_spec(const char *str, loff_t *start, loff_t *size);
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 06/10] omap: add SPI as a boot mode for xload
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
                   ` (4 preceding siblings ...)
  2012-09-03 11:46 ` [PATCH 05/10] common: split out meminfo output and make it optional Jan Luebbe
@ 2012-09-03 11:46 ` Jan Luebbe
  2012-09-03 16:24   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-03 11:46 ` [PATCH 07/10] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch Jan Luebbe
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:46 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 arch/arm/mach-omap/include/mach/xload.h |    1 +
 arch/arm/mach-omap/xload.c              |   27 +++++++++++++++++++++++++++
 2 files changed, 28 insertions(+)

diff --git a/arch/arm/mach-omap/include/mach/xload.h b/arch/arm/mach-omap/include/mach/xload.h
index 844b57f..c62912a 100644
--- a/arch/arm/mach-omap/include/mach/xload.h
+++ b/arch/arm/mach-omap/include/mach/xload.h
@@ -8,6 +8,7 @@ enum omap_boot_src {
 	OMAP_BOOTSRC_UNKNOWN,
 	OMAP_BOOTSRC_MMC1,
 	OMAP_BOOTSRC_NAND,
+	OMAP_BOOTSRC_SPI1,
 };
 
 enum omap_boot_src omap3_bootsrc(void);
diff --git a/arch/arm/mach-omap/xload.c b/arch/arm/mach-omap/xload.c
index 13024ab..1daa827 100644
--- a/arch/arm/mach-omap/xload.c
+++ b/arch/arm/mach-omap/xload.c
@@ -54,6 +54,29 @@ void *omap_xload_boot_mmc(void)
 	return buf;
 }
 
+void *omap_xload_boot_spi(int offset, int size)
+{
+	int ret;
+	void *to = xmalloc(size);
+	struct cdev *cdev;
+
+	devfs_add_partition("m25p0", offset, size, DEVFS_PARTITION_FIXED, "x");
+
+	cdev = cdev_open("x", O_RDONLY);
+	if (!cdev) {
+		printf("failed to open spi flash\n");
+		return NULL;
+	}
+
+	ret = cdev_read(cdev, to, size, 0, 0);
+	if (ret != size) {
+		printf("failed to read from spi flash\n");
+		return NULL;
+	}
+
+	return to;
+}
+
 enum omap_boot_src omap_bootsrc(void)
 {
 #if defined(CONFIG_ARCH_OMAP3)
@@ -82,6 +105,10 @@ int run_shell(void)
 		printf("booting from NAND\n");
 		func = omap_xload_boot_nand(SZ_128K, SZ_256K);
 		break;
+	case OMAP_BOOTSRC_SPI1:
+		printf("booting from SPI1\n");
+		func = omap_xload_boot_spi(SZ_128K, SZ_512K);
+		break;
 	}
 
 	if (!func) {
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 07/10] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
                   ` (5 preceding siblings ...)
  2012-09-03 11:46 ` [PATCH 06/10] omap: add SPI as a boot mode for xload Jan Luebbe
@ 2012-09-03 11:46 ` Jan Luebbe
  2012-09-03 11:46 ` [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:46 UTC (permalink / raw)
  To: barebox

It start the switch and provides basic access to the registers.

This driver could also work with some other Micrel switches, possibly
with some small changes.

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 drivers/net/Kconfig      |    7 ++
 drivers/net/Makefile     |    1 +
 drivers/net/ksz8864rmn.c |  233 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 241 insertions(+)
 create mode 100644 drivers/net/ksz8864rmn.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 749ea6a..0fa4f14 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -126,5 +126,12 @@ config DRIVER_NET_DESIGNWARE_ALTDESCRIPTOR
 
 source "drivers/net/usb/Kconfig"
 
+config DRIVER_NET_MICREL
+	depends on SPI
+	bool "Micrel KSZ8864RMN Ethernet Switch driver"
+	help
+	  This option enables support for enabling the Micrel
+	  KSZ8864RMN Ethernet Switch over SPI.
+
 endmenu
 
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 29727b7..b589240 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -14,3 +14,4 @@ obj-$(CONFIG_NET_USB)			+= usb/
 obj-$(CONFIG_DRIVER_NET_TSE)		+= altera_tse.o
 obj-$(CONFIG_DRIVER_NET_KS8851_MLL)	+= ks8851_mll.o
 obj-$(CONFIG_DRIVER_NET_DESIGNWARE)	+= designware.o
+obj-$(CONFIG_DRIVER_NET_MICREL)		+= ksz8864rmn.o
diff --git a/drivers/net/ksz8864rmn.c b/drivers/net/ksz8864rmn.c
new file mode 100644
index 0000000..5851463
--- /dev/null
+++ b/drivers/net/ksz8864rmn.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2012 Jan Luebbe, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * 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 <init.h>
+#include <driver.h>
+#include <spi/spi.h>
+#include <errno.h>
+
+#define REG_ID0			0x00
+#define REG_ID1			0x01
+
+#define REG_GC00		0x02
+#define REG_GC01		0x03
+#define REG_GC02		0x04
+#define REG_GC03		0x05
+#define REG_GC04		0x06
+#define REG_GC05		0x07
+#define REG_GC06		0x08
+#define REG_GC07		0x09
+#define REG_GC08		0x0a
+#define REG_GC09		0x0b
+#define REG_GC10		0x0c
+#define REG_GC11		0x0d
+
+#define REG_PSTAT1(p)		(0x10 * p + 0xe)
+#define REG_PSTAT2(p)		(0x10 * p + 0xf)
+
+#define CMD_WRITE		0x02
+#define CMD_READ		0x03
+
+struct micrel_switch_priv {
+	struct cdev             cdev;
+	struct spi_device       *spi;
+};
+
+static int micrel_switch_read_reg(struct spi_device *spi, uint8_t reg)
+{
+	uint8_t tx[2];
+	uint8_t rx[1];
+	int ret;
+
+	tx[0] = CMD_READ;
+	tx[1] = reg;
+
+	ret = spi_write_then_read(spi, tx, 2, rx, 1);
+	if (ret < 0)
+		return ret;
+
+	return rx[0];
+}
+
+static void micrel_switch_write_reg(struct spi_device *spi, uint8_t reg, uint8_t val)
+{
+	uint8_t tx[3];
+
+	tx[0] = CMD_WRITE;
+	tx[1] = reg;
+	tx[2] = val;
+
+	spi_write_then_read(spi, tx, 3, NULL, 0);
+}
+
+static int micrel_switch_enable_set(struct device_d *dev, struct param_d *param,
+		const char *val)
+{
+	struct spi_device *spi = (struct spi_device *)dev->type_data;
+	int enable;
+	char *new;
+
+	if (!val)
+		return dev_param_set_generic(dev, param, NULL);
+
+	enable = simple_strtoul(val, NULL, 0);
+
+	if (enable) {
+		micrel_switch_write_reg(spi, REG_ID1, 1);
+		new = "1";
+	} else {
+		micrel_switch_write_reg(spi, REG_ID1, 0);
+		new = "0";
+	}
+
+	dev_param_set_generic(dev, param, new);
+
+	return 0;
+}
+
+static void micrel_switch_print_reg(struct spi_device *spi, const char *name, uint8_t reg)
+{
+	uint8_t tx[2];
+	uint8_t rx[1];
+	int ret;
+
+	tx[0] = CMD_READ;
+	tx[1] = reg;
+
+	ret = spi_write_then_read(spi, tx, 2, rx, 1);
+	if (ret < 0)
+		printf("%s@0x%02x: SPI error\n", name, reg);
+
+	printf("%s@0x%02x: 0x%02x\n", name, reg, rx[0]);
+}
+
+static void micrel_switch_info(struct device_d *dev)
+{
+	struct spi_device *spi = (struct spi_device *)dev->type_data;
+
+	printf("Registers:\n");
+	micrel_switch_print_reg(spi, " Chip ID 0", REG_ID0);
+	micrel_switch_print_reg(spi, " Chip ID 1", REG_ID1);
+	micrel_switch_print_reg(spi, " Global Control  0", REG_GC00);
+	micrel_switch_print_reg(spi, " Global Control  1", REG_GC01);
+	micrel_switch_print_reg(spi, " Global Control  2", REG_GC02);
+	micrel_switch_print_reg(spi, " Global Control  3", REG_GC03);
+	micrel_switch_print_reg(spi, " Global Control  4", REG_GC04);
+	micrel_switch_print_reg(spi, " Global Control  5", REG_GC05);
+	micrel_switch_print_reg(spi, " Global Control  6", REG_GC06);
+	micrel_switch_print_reg(spi, " Global Control  7", REG_GC07);
+	micrel_switch_print_reg(spi, " Global Control  8", REG_GC08);
+	micrel_switch_print_reg(spi, " Global Control  9", REG_GC09);
+	micrel_switch_print_reg(spi, " Global Control 10", REG_GC10);
+	micrel_switch_print_reg(spi, " Global Control 11", REG_GC11);
+	micrel_switch_print_reg(spi, " Port 1 Status 1", REG_PSTAT1(1));
+	micrel_switch_print_reg(spi, " Port 1 Status 2", REG_PSTAT2(1));
+	micrel_switch_print_reg(spi, " Port 2 Status 1", REG_PSTAT1(2));
+	micrel_switch_print_reg(spi, " Port 2 Status 2", REG_PSTAT2(2));
+}
+
+static ssize_t micel_switch_read(struct cdev *cdev, void *_buf, size_t count, loff_t offset, ulong flags)
+{
+	int i, ret;
+	uint8_t *buf = _buf;
+	struct micrel_switch_priv *priv = cdev->priv;
+
+	for (i = 0; i < count; i++) {
+		ret = micrel_switch_read_reg(priv->spi, offset);
+		if (ret < 0)
+			return ret;
+		*buf = ret;
+		buf++;
+		offset++;
+	}
+
+	return count;
+}
+
+static ssize_t micel_switch_write(struct cdev *cdev, const void *_buf, size_t count, loff_t offset, ulong flags)
+{
+	int i;
+	const uint8_t *buf = _buf;
+	struct micrel_switch_priv *priv = cdev->priv;
+
+	for (i = 0; i < count; i++) {
+		micrel_switch_write_reg(priv->spi, offset, *buf);
+		buf++;
+		offset++;
+	}
+
+	return count;
+}
+
+static struct file_operations micrel_switch_ops = {
+	.read  = micel_switch_read,
+	.write = micel_switch_write,
+	.lseek = dev_lseek_default,
+};
+
+static int micrel_switch_probe(struct device_d *dev)
+{
+	struct micrel_switch_priv *priv;
+	int ret = 0;
+
+	priv = xzalloc(sizeof(*priv));
+
+	dev->priv = priv;
+
+	priv->spi = (struct spi_device *)dev->type_data;
+	priv->spi->mode = SPI_MODE_0;
+	priv->spi->bits_per_word = 8;
+
+	ret = micrel_switch_read_reg(priv->spi, REG_ID0);
+	if (ret < 0) {
+		dev_err(&priv->spi->dev, "failed to read device id\n");
+		return ret;
+	}
+	if (ret != 0x95) {
+		dev_err(&priv->spi->dev, "unknown device id: %02x\n", ret);
+		return -ENODEV;
+	}
+
+	priv->cdev.name = asprintf("switch%d", dev->id);
+	priv->cdev.size = 256;
+	priv->cdev.ops = &micrel_switch_ops;
+	priv->cdev.priv = priv;
+	priv->cdev.dev = dev;
+	devfs_create(&priv->cdev);
+
+	dev_add_param(dev, "enable", micrel_switch_enable_set, NULL, 0);
+	dev_set_param(dev, "enable", "1");
+
+	return 0;
+}
+
+static struct driver_d micrel_switch_driver = {
+	.name  = "ksz8864rmn",
+	.probe = micrel_switch_probe,
+	.info  = micrel_switch_info,
+};
+
+static int micrel_switch_init(void)
+{
+	register_driver(&micrel_switch_driver);
+	return 0;
+}
+device_initcall(micrel_switch_init);
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
                   ` (6 preceding siblings ...)
  2012-09-03 11:46 ` [PATCH 07/10] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch Jan Luebbe
@ 2012-09-03 11:46 ` Jan Luebbe
  2012-09-03 16:27   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-04  8:42   ` Sascha Hauer
  2012-09-03 11:46 ` [PATCH 09/10] omap3: allow enabling clocks for UART3, MMC1 and SPI Jan Luebbe
  2012-09-03 11:46 ` [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
  9 siblings, 2 replies; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:46 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 arch/arm/mach-omap/include/mach/emac_defs.h |   53 +++
 drivers/net/Kconfig                         |    5 +
 drivers/net/Makefile                        |    1 +
 drivers/net/davinci_emac.c                  |  619 +++++++++++++++++++++++++++
 drivers/net/davinci_emac.h                  |  331 ++++++++++++++
 5 files changed, 1009 insertions(+)
 create mode 100644 arch/arm/mach-omap/include/mach/emac_defs.h
 create mode 100644 drivers/net/davinci_emac.c
 create mode 100644 drivers/net/davinci_emac.h

diff --git a/arch/arm/mach-omap/include/mach/emac_defs.h b/arch/arm/mach-omap/include/mach/emac_defs.h
new file mode 100644
index 0000000..ef930fc
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/emac_defs.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Based on:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.h
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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.
+ * ----------------------------------------------------------------------------
+
+ * Modifications:
+ * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot.
+ *
+ */
+
+#ifndef _AM3517_EMAC_H_
+#define _AM3517_EMAC_H_
+
+#define EMAC_BASE_ADDR                 0x5C010000
+#define EMAC_WRAPPER_BASE_ADDR         0x5C000000
+#define EMAC_WRAPPER_RAM_ADDR          0x5C020000
+#define EMAC_MDIO_BASE_ADDR            0x5C030000
+#define EMAC_HW_RAM_ADDR               0x01E20000
+
+#define EMAC_MDIO_BUS_FREQ             166000000       /* 166 MHZ check */
+#define EMAC_MDIO_CLOCK_FREQ           1000000         /* 2.0 MHz */
+
+/* SOFTRESET macro definition interferes with emac_regs structure definition */
+#undef SOFTRESET
+
+#define DAVINCI_EMAC_VERSION2
+
+#endif  /* _AM3517_EMAC_H_ */
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 0fa4f14..68c11eb 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -49,6 +49,11 @@ config DRIVER_NET_SMC91111
 	  This option enables support for the SMSC LAN91C111
 	  ethernet chip.
 
+config DRIVER_NET_DAVINCI_EMAC
+	bool "TI Davinci/OMAP EMAC ethernet driver"
+	depends on ARCH_DAVINCI || ARCH_OMAP3
+	select MIIDEV
+
 config DRIVER_NET_DM9K
 	bool "Davicom dm9k[E|A|B] ethernet driver"
 	depends on HAS_DM9000
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index b589240..0f1363f 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -1,6 +1,7 @@
 obj-$(CONFIG_DRIVER_NET_CS8900)		+= cs8900.o
 obj-$(CONFIG_DRIVER_NET_SMC911X)	+= smc911x.o
 obj-$(CONFIG_DRIVER_NET_SMC91111)	+= smc91111.o
+obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC)	+= davinci_emac.o
 obj-$(CONFIG_DRIVER_NET_DM9K)		+= dm9k.o
 obj-$(CONFIG_DRIVER_NET_NETX)		+= netx_eth.o
 obj-$(CONFIG_DRIVER_NET_AT91_ETHER)	+= at91_ether.o
diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
new file mode 100644
index 0000000..b9670ca
--- /dev/null
+++ b/drivers/net/davinci_emac.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
+ *
+ * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
+ * follows:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.c
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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.
+ * ----------------------------------------------------------------------------
+
+ * Modifications:
+ * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
+ * ver  1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
+ *
+ */
+
+#include <common.h>
+#include <io.h>
+#include <clock.h>
+#include <net.h>
+#include <miidev.h>
+#include <malloc.h>
+#include <init.h>
+#include <asm/mmu.h>
+#include <asm/system.h>
+#include <mach/emac_defs.h>
+#include "davinci_emac.h"
+
+struct davinci_emac_priv {
+	struct device_d *dev;
+	struct eth_device edev;
+	struct mii_device miidev;
+	void __iomem *regs;
+
+	/* EMAC Addresses */
+	emac_regs	*adap_emac; /* = (emac_regs *)EMAC_BASE_ADDR; */
+	ewrap_regs	*adap_ewrap; /* = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; */
+	mdio_regs	*adap_mdio; /* = (mdio_regs *)EMAC_MDIO_BASE_ADDR; */
+
+	/* EMAC descriptors */
+	emac_desc	*emac_rx_desc; /* = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); */
+	emac_desc	*emac_tx_desc; /* = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); */
+	emac_desc	*emac_rx_active_head; /* = 0; */
+	emac_desc	*emac_rx_active_tail; /* = 0; */
+	int			emac_rx_queue_active; /* = 0; */
+
+	/* Receive packet buffers */
+	unsigned char	*emac_rx_buffers; /* [EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; */
+
+	/* PHY address for a discovered PHY (0xff - not found) */
+	u_int8_t	active_phy_addr; /* = 0xff; */
+};
+
+/* davinci_eth_mac_addr[0] goes out on the wire first */
+
+static u_int8_t davinci_eth_mac_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x00 };
+
+/*
+ * This function must be called before emac_open() if you want to override
+ * the default mac address.
+ */
+void davinci_eth_set_mac_addr(const u_int8_t *addr)
+{
+	int i;
+
+	for (i = 0; i < sizeof(davinci_eth_mac_addr); i++)
+		davinci_eth_mac_addr[i] = addr[i];
+}
+
+#ifdef EMAC_HW_RAM_ADDR
+static inline dv_reg BD_TO_HW(emac_desc *x)
+{
+	if (x == 0)
+		return 0;
+
+	return (dv_reg)(x) - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
+}
+
+static inline emac_desc* HW_TO_BD(dv_reg x)
+{
+	if (x == 0)
+		return 0;
+
+	return (emac_desc*)(x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR);
+}
+#else
+#define BD_TO_HW(x)     (x)
+#define HW_TO_BD(x)     (x)
+#endif
+
+static void davinci_eth_mdio_enable(struct davinci_emac_priv *priv)
+{
+	u_int32_t	clkdiv;
+
+	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+
+	dev_dbg(priv->dev, "mdio_enable + 0x%08x\n", priv->adap_mdio->CONTROL);
+	writel((clkdiv & 0xff) |
+		MDIO_CONTROL_ENABLE |
+		MDIO_CONTROL_FAULT |
+		MDIO_CONTROL_FAULT_ENABLE,
+		&priv->adap_mdio->CONTROL);
+	dev_dbg(priv->dev, "mdio_enable - 0x%08x\n", priv->adap_mdio->CONTROL);
+
+	while (readl(&priv->adap_mdio->CONTROL) & MDIO_CONTROL_IDLE);
+}
+
+/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
+int davinci_eth_phy_read(struct davinci_emac_priv *priv, u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
+{
+	int	tmp;
+
+	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
+
+	writel(MDIO_USERACCESS0_GO |
+		MDIO_USERACCESS0_WRITE_READ |
+		((reg_num & 0x1f) << 21) |
+		((phy_addr & 0x1f) << 16),
+		&priv->adap_mdio->USERACCESS0);
+
+	/* Wait for command to complete */
+	while ((tmp = readl(&priv->adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO);
+
+	if (tmp & MDIO_USERACCESS0_ACK) {
+		*data = tmp & 0xffff;
+		dev_dbg(priv->dev, "emac_phy_read: addr=0x%02x reg=0x%02x data=0x%04x\n",
+			   phy_addr, reg_num, *data);
+		return 1;
+	}
+
+	*data = -1;
+	return 0;
+}
+
+/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
+int davinci_eth_phy_write(struct davinci_emac_priv *priv, u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
+{
+
+	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
+
+	dev_dbg(priv->dev, "emac_phy_write: addr=0x%02x reg=0x%02x data=0x%04x\n",
+		   phy_addr, reg_num, data);
+	writel(MDIO_USERACCESS0_GO |
+				MDIO_USERACCESS0_WRITE_WRITE |
+				((reg_num & 0x1f) << 21) |
+				((phy_addr & 0x1f) << 16) |
+				(data & 0xffff),
+		&priv->adap_mdio->USERACCESS0);
+
+	/* Wait for command to complete */
+	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
+
+	return 1;
+}
+
+static int davinci_miidev_read(struct mii_device *dev, int addr, int reg)
+{
+	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)dev->edev->priv;
+	uint16_t value = 0;
+	return davinci_eth_phy_read(priv, addr, reg, &value) ? value : -1;
+}
+
+static int davinci_miidev_write(struct mii_device *dev, int addr, int reg, int value)
+{
+	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)dev->edev->priv;
+	return davinci_eth_phy_write(priv, addr, reg, value) ? 0 : -1;
+}
+
+static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+	return -1;
+}
+
+static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *adr)
+{
+	davinci_eth_set_mac_addr(adr);
+	return 0;
+}
+
+static int davinci_emac_init(struct eth_device *edev)
+{
+	dev_dbg(&edev->dev, "* emac_init\n");
+	return 0;
+}
+
+static int davinci_emac_open(struct eth_device *edev)
+{
+	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
+
+	dv_reg_p	addr;
+	u_int32_t	clkdiv, cnt;
+	emac_desc	*rx_desc;
+	unsigned long mac_hi, mac_lo;
+	int ret;
+
+	dev_dbg(priv->dev, "+ emac_open\n");
+
+	dev_dbg(priv->dev, "emac->TXIDVER: 0x%08x\n", priv->adap_emac->TXIDVER);
+	dev_dbg(priv->dev, "emac->RXIDVER: 0x%08x\n", priv->adap_emac->RXIDVER);
+
+	/* Reset EMAC module and disable interrupts in wrapper */
+	writel(1, &priv->adap_emac->SOFTRESET);
+	while (readl(&priv->adap_emac->SOFTRESET) != 0);
+	writel(1, &priv->adap_ewrap->softrst);
+	while (readl(&priv->adap_ewrap->softrst) != 0);
+
+	writel(0, &priv->adap_ewrap->c0rxen);
+	writel(0, &priv->adap_ewrap->c1rxen);
+	writel(0, &priv->adap_ewrap->c2rxen);
+	writel(0, &priv->adap_ewrap->c0txen);
+	writel(0, &priv->adap_ewrap->c1txen);
+	writel(0, &priv->adap_ewrap->c2txen);
+	writel(0, &priv->adap_ewrap->c0miscen);
+	writel(0, &priv->adap_ewrap->c1miscen);
+	writel(0, &priv->adap_ewrap->c2miscen);
+
+	rx_desc = priv->emac_rx_desc;
+
+	/*
+	 * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
+	 * receive)
+	 * Use channel 0 only - other channels are disabled
+	 */
+	writel(0, &priv->adap_emac->MACINDEX);
+	mac_hi = (davinci_eth_mac_addr[3] << 24) |
+		 (davinci_eth_mac_addr[2] << 16) |
+		 (davinci_eth_mac_addr[1] << 8)  |
+		 (davinci_eth_mac_addr[0]);
+	mac_lo = (davinci_eth_mac_addr[5] << 8) |
+		 (davinci_eth_mac_addr[4]);
+
+	writel(mac_hi, &priv->adap_emac->MACADDRHI);
+	writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
+	       &priv->adap_emac->MACADDRLO);
+
+	/* Set source MAC address - REQUIRED */
+	writel(mac_hi, &priv->adap_emac->MACSRCADDRHI);
+	writel(mac_lo, &priv->adap_emac->MACSRCADDRLO);
+
+	/* Set DMA 8 TX / 8 RX Head pointers to 0 */
+	addr = &priv->adap_emac->TX0HDP;
+	for(cnt = 0; cnt < 16; cnt++)
+		*addr++ = 0;
+
+	addr = &priv->adap_emac->RX0HDP;
+	for(cnt = 0; cnt < 16; cnt++)
+		*addr++ = 0;
+
+	/* Clear Statistics (do this before setting MacControl register) */
+	addr = &priv->adap_emac->RXGOODFRAMES;
+	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
+		*addr++ = 0;
+
+	/* No multicast addressing */
+	writel(0, &priv->adap_emac->MACHASH1);
+	writel(0, &priv->adap_emac->MACHASH2);
+
+	writel(0x01, &priv->adap_emac->TXCONTROL);
+	writel(0x01, &priv->adap_emac->RXCONTROL);
+
+	/* Create RX queue and set receive process in place */
+	priv->emac_rx_active_head = priv->emac_rx_desc;
+	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
+		rx_desc->next = BD_TO_HW(rx_desc + 1);
+		rx_desc->buffer = &priv->emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
+		rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
+		rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
+		rx_desc++;
+	}
+
+	/* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
+	rx_desc--;
+	rx_desc->next = 0;
+	priv->emac_rx_active_tail = rx_desc;
+	priv->emac_rx_queue_active = 1;
+
+	/* Enable TX/RX */
+	writel(EMAC_MAX_ETHERNET_PKT_SIZE, &priv->adap_emac->RXMAXLEN);
+	writel(0, &priv->adap_emac->RXBUFFEROFFSET);
+
+	/* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
+	writel(EMAC_RXMBPENABLE_RXBROADEN, &priv->adap_emac->RXMBPENABLE);
+
+	/* Enable ch 0 only */
+	writel(0x01, &priv->adap_emac->RXUNICASTSET);
+
+	/* Enable MII interface and full duplex mode (using RMMI) */
+	writel((EMAC_MACCONTROL_MIIEN_ENABLE |
+		EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
+		EMAC_MACCONTROL_RMIISPEED_100),
+	       &priv->adap_emac->MACCONTROL);
+
+	/* Init MDIO & get link state */
+	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+	writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
+		&priv->adap_mdio->CONTROL);
+
+	/* Start receive process */
+	writel(BD_TO_HW(priv->emac_rx_desc), &priv->adap_emac->RX0HDP);
+
+	ret = miidev_wait_aneg(&priv->miidev);
+	if (ret)
+		return ret;
+
+	ret = miidev_get_status(&priv->miidev);
+	if (ret < 0)
+		return ret;
+
+	miidev_print_status(&priv->miidev);
+
+	dev_dbg(priv->dev, "- emac_open\n");
+
+	return 0;
+}
+
+/* EMAC Channel Teardown */
+static void davinci_eth_ch_teardown(struct davinci_emac_priv *priv, int ch)
+{
+	dv_reg		dly = 0xff;
+	dv_reg		cnt;
+
+	dev_dbg(priv->dev, "+ emac_ch_teardown\n");
+
+	if (ch == EMAC_CH_TX) {
+		/* Init TX channel teardown */
+		writel(0, &priv->adap_emac->TXTEARDOWN);
+		for(cnt = 0; cnt != 0xfffffffc; cnt = readl(&priv->adap_emac->TX0CP)) {
+			/* Wait here for Tx teardown completion interrupt to occur
+			 * Note: A task delay can be called here to pend rather than
+			 * occupying CPU cycles - anyway it has been found that teardown
+			 * takes very few cpu cycles and does not affect functionality */
+			 dly--;
+			 udelay(1);
+			 if (dly == 0)
+				break;
+		}
+		writel(cnt, &priv->adap_emac->TX0CP);
+		writel(0, &priv->adap_emac->TX0HDP);
+	} else {
+		/* Init RX channel teardown */
+		writel(0, &priv->adap_emac->RXTEARDOWN);
+		for(cnt = 0; cnt != 0xfffffffc; cnt = readl(&priv->adap_emac->RX0CP)) {
+			/* Wait here for Rx teardown completion interrupt to occur
+			 * Note: A task delay can be called here to pend rather than
+			 * occupying CPU cycles - anyway it has been found that teardown
+			 * takes very few cpu cycles and does not affect functionality */
+			 dly--;
+			 udelay(1);
+			 if (dly == 0)
+				break;
+		}
+		writel(cnt, &priv->adap_emac->RX0CP);
+		writel(0, &priv->adap_emac->RX0HDP);
+	}
+
+	dev_dbg(priv->dev, "- emac_ch_teardown\n");
+}
+
+static void davinci_emac_halt(struct eth_device *edev)
+{
+	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
+
+	dev_dbg(priv->dev, "+ emac_halt\n");
+
+	davinci_eth_ch_teardown(priv, EMAC_CH_TX);	/* TX Channel teardown */
+	davinci_eth_ch_teardown(priv, EMAC_CH_RX);	/* RX Channel teardown */
+
+	/* Reset EMAC module and disable interrupts in wrapper */
+	writel(1, &priv->adap_emac->SOFTRESET);
+	writel(1, &priv->adap_ewrap->softrst);
+
+	writel(0, &priv->adap_ewrap->c0rxen);
+	writel(0, &priv->adap_ewrap->c1rxen);
+	writel(0, &priv->adap_ewrap->c2rxen);
+	writel(0, &priv->adap_ewrap->c0txen);
+	writel(0, &priv->adap_ewrap->c1txen);
+	writel(0, &priv->adap_ewrap->c2txen);
+	writel(0, &priv->adap_ewrap->c0miscen);
+	writel(0, &priv->adap_ewrap->c1miscen);
+	writel(0, &priv->adap_ewrap->c2miscen);
+
+	dev_dbg(priv->dev, "- emac_halt\n");
+}
+
+/*
+ * This function sends a single packet on the network and returns
+ * positive number (number of bytes transmitted) or negative for error
+ */
+static int davinci_emac_send(struct eth_device *edev, void *packet, int length)
+{
+	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
+	uint64_t start = 0;
+	int ret_status = -1;
+
+	dev_dbg(priv->dev, "+ emac_send (length %d)\n", length);
+
+	/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
+	if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
+		length = EMAC_MIN_ETHERNET_PKT_SIZE;
+	}
+
+	/* Populate the TX descriptor */
+	writel(0, &priv->emac_tx_desc->next);
+	writel((u_int8_t *) packet, &priv->emac_tx_desc->buffer);
+	writel((length & 0xffff), &priv->emac_tx_desc->buff_off_len);
+	writel(((length & 0xffff) | EMAC_CPPI_SOP_BIT |
+				    EMAC_CPPI_OWNERSHIP_BIT |
+				    EMAC_CPPI_EOP_BIT),
+		&priv->emac_tx_desc->pkt_flag_len);
+	dma_flush_range((ulong) packet, (ulong)packet + length);
+	/* Send the packet */
+	writel(BD_TO_HW(priv->emac_tx_desc), &priv->adap_emac->TX0HDP);
+
+	/* Wait for packet to complete or link down */
+	start = get_time_ns();
+	while (1) {
+		if (readl(&priv->adap_emac->TXINTSTATRAW) & 0x01) {
+			/* Acknowledge the TX descriptor */
+			writel(BD_TO_HW(priv->emac_tx_desc), &priv->adap_emac->TX0CP);
+			ret_status = length;
+			break;
+		}
+	}
+
+	dev_dbg(priv->dev, "- emac_send (ret_status %i)\n", ret_status);
+	return ret_status;
+}
+
+/*
+ * This function handles receipt of a packet from the network
+ */
+static int davinci_emac_recv(struct eth_device *edev)
+{
+	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
+	emac_desc *rx_curr_desc;
+	emac_desc *curr_desc;
+	emac_desc *tail_desc;
+	unsigned char *pkt;
+	int status, len, ret = -1;
+
+	dev_dbg(priv->dev, "+ emac_recv\n");
+
+	rx_curr_desc = priv->emac_rx_active_head;
+	status = readl(&rx_curr_desc->pkt_flag_len);
+	if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
+		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
+			/* Error in packet - discard it and requeue desc */
+			dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n");
+		} else {
+			pkt = (unsigned char *)readl(&rx_curr_desc->buffer);
+			len = readl(&rx_curr_desc->buff_off_len) & 0xffff;
+			dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len);
+			dma_inv_range((ulong)pkt,
+					(ulong)rx_curr_desc->buffer + len);
+			net_receive(pkt, len);
+			ret = len;
+		}
+
+		/* Ack received packet descriptor */
+		writel(BD_TO_HW(rx_curr_desc), &priv->adap_emac->RX0CP);
+		curr_desc = rx_curr_desc;
+		priv->emac_rx_active_head = HW_TO_BD(readl(&rx_curr_desc->next));
+
+		if (status & EMAC_CPPI_EOQ_BIT) {
+			if (priv->emac_rx_active_head) {
+				writel(BD_TO_HW(priv->emac_rx_active_head),
+					&priv->adap_emac->RX0HDP);
+			} else {
+				priv->emac_rx_queue_active = 0;
+				dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n");
+			}
+		}
+
+		/* Recycle RX descriptor */
+		writel(EMAC_MAX_ETHERNET_PKT_SIZE, &rx_curr_desc->buff_off_len);
+		writel(EMAC_CPPI_OWNERSHIP_BIT, &rx_curr_desc->pkt_flag_len);
+		writel(0, &rx_curr_desc->next);
+
+		if (priv->emac_rx_active_head == 0) {
+			dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n");
+			priv->emac_rx_active_head = curr_desc;
+			priv->emac_rx_active_tail = curr_desc;
+			if (priv->emac_rx_queue_active != 0) {
+				writel(BD_TO_HW(priv->emac_rx_active_head), &priv->adap_emac->RX0HDP);
+				dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
+				priv->emac_rx_queue_active = 1;
+			}
+		} else {
+			tail_desc = priv->emac_rx_active_tail;
+			priv->emac_rx_active_tail = curr_desc;
+			writel(BD_TO_HW(curr_desc), &tail_desc->next);
+			status = readl(&tail_desc->pkt_flag_len);
+			if (status & EMAC_CPPI_EOQ_BIT) {
+				writel(BD_TO_HW(curr_desc), &priv->adap_emac->RX0HDP);
+				status &= ~EMAC_CPPI_EOQ_BIT;
+				writel(status, &tail_desc->pkt_flag_len);
+			}
+		}
+		return ret;
+	}
+
+	dev_dbg(priv->dev, "- emac_recv\n");
+
+	return 0;
+}
+
+static int davinci_emac_probe(struct device_d *dev)
+{
+	struct davinci_emac_priv *priv;
+	int		i;
+
+	dev_dbg(dev, "+ emac_probe\n");
+
+	priv = xzalloc(sizeof(*priv));
+	dev->priv = priv;
+
+	priv->dev = dev;
+
+	priv->adap_emac = (emac_regs *)EMAC_BASE_ADDR;
+	priv->adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
+	priv->adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
+
+	/* EMAC descriptors */
+	priv->emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
+	priv->emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
+	priv->emac_rx_active_head = 0;
+	priv->emac_rx_active_tail = 0;
+	priv->emac_rx_queue_active = 0;
+
+	/* Receive packet buffers */
+	priv->emac_rx_buffers = xmemalign(4096, EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN));
+
+	/* PHY address for a discovered PHY (0xff - not found) */
+	priv->active_phy_addr = 0xff;
+
+	priv->edev.priv = priv;
+	priv->edev.init = davinci_emac_init;
+	priv->edev.open = davinci_emac_open;
+	priv->edev.halt = davinci_emac_halt;
+	priv->edev.send = davinci_emac_send;
+	priv->edev.recv = davinci_emac_recv;
+	priv->edev.get_ethaddr = davinci_emac_get_ethaddr;
+	priv->edev.set_ethaddr = davinci_emac_set_ethaddr;
+	priv->edev.parent = dev;
+
+	priv->regs = dev_request_mem_region(dev, 0);
+
+	davinci_eth_mdio_enable(priv);
+
+	for (i = 0; i < 256; i++) {
+		if (priv->adap_mdio->ALIVE)
+			break;
+		udelay(1000);
+	}
+
+	if (i >= 256) {
+		dev_err(dev, "No ETH PHY detected!\n");
+	}
+
+	priv->miidev.read = davinci_miidev_read;
+	priv->miidev.write = davinci_miidev_write;
+	priv->miidev.address = 0x01;
+	priv->miidev.flags = MIIDEV_FORCE_LINK;
+	priv->miidev.edev = &priv->edev;
+	priv->miidev.parent = dev;
+
+	mii_register(&priv->miidev);
+
+	eth_register(&priv->edev);
+
+	dev_dbg(dev, "- emac_probe\n");
+	return 0;
+}
+
+static void davinci_emac_remove(struct device_d *dev)
+{
+	struct davinci_emac_priv *priv = dev->priv;
+
+	davinci_emac_halt(&priv->edev);
+}
+
+static struct driver_d davinci_emac_driver = {
+	.name   = "davinci_emac",
+	.probe  = davinci_emac_probe,
+	.remove = davinci_emac_remove,
+};
+
+static int davinci_emac_register(void)
+{
+	register_driver(&davinci_emac_driver);
+	return 0;
+}
+
+device_initcall(davinci_emac_register);
diff --git a/drivers/net/davinci_emac.h b/drivers/net/davinci_emac.h
new file mode 100644
index 0000000..4e97ce5
--- /dev/null
+++ b/drivers/net/davinci_emac.h
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Based on:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * dm644x_emac.h
+ *
+ * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
+ *
+ * Copyright (C) 2005 Texas Instruments.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * 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.
+ * ----------------------------------------------------------------------------
+
+ * Modifications:
+ * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot.
+ *
+ */
+
+#ifndef _DAVINCI_EMAC_H_
+#define _DAVINCI_EMAC_H_
+
+/* PHY mask - set only those phy number bits where phy is/can be connected */
+#define EMAC_MDIO_PHY_NUM           1
+#define EMAC_MDIO_PHY_MASK          (1 << EMAC_MDIO_PHY_NUM)
+
+/* Ethernet Min/Max packet size */
+#define EMAC_MIN_ETHERNET_PKT_SIZE	60
+#define EMAC_MAX_ETHERNET_PKT_SIZE	1518
+#define EMAC_PKT_ALIGN			18	/* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */
+
+/* Number of RX packet buffers
+ * NOTE: Only 1 buffer supported as of now
+ */
+#define EMAC_MAX_RX_BUFFERS		10
+
+typedef unsigned int	dv_reg;
+typedef unsigned int	*dv_reg_p;
+
+/***********************************************
+ ******** Internally used macros ***************
+ ***********************************************/
+
+#define EMAC_CH_TX			1
+#define EMAC_CH_RX			0
+
+/* Each descriptor occupies 4 words, lets start RX desc's at 0 and
+ * reserve space for 64 descriptors max
+ */
+#define EMAC_RX_DESC_BASE		0x0
+#define EMAC_TX_DESC_BASE		0x1000
+
+/* EMAC Teardown value */
+#define EMAC_TEARDOWN_VALUE		0xfffffffc
+
+/* MII Status Register */
+#define MII_STATUS_REG			1
+
+/* Number of statistics registers */
+#define EMAC_NUM_STATS			36
+
+
+/* EMAC Descriptor */
+typedef struct
+{
+	u_int32_t	next;		/* Pointer to next descriptor in chain */
+	u_int8_t	*buffer;	/* Pointer to data buffer */
+	u_int32_t	buff_off_len;	/* Buffer Offset(MSW) and Length(LSW) */
+	u_int32_t	pkt_flag_len;	/* Packet Flags(MSW) and Length(LSW) */
+} emac_desc;
+
+/* CPPI bit positions */
+#define EMAC_CPPI_SOP_BIT		(0x80000000)
+#define EMAC_CPPI_EOP_BIT		(0x40000000)
+#define EMAC_CPPI_OWNERSHIP_BIT		(0x20000000)
+#define EMAC_CPPI_EOQ_BIT		(0x10000000)
+#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT	(0x08000000)
+#define EMAC_CPPI_PASS_CRC_BIT		(0x04000000)
+
+#define EMAC_CPPI_RX_ERROR_FRAME	(0x03fc0000)
+
+#define EMAC_MACCONTROL_MIIEN_ENABLE		(0x20)
+#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE	(0x1)
+#define EMAC_MACCONTROL_GIGABIT_ENABLE		(1 << 7)
+#define EMAC_MACCONTROL_GIGFORCE		(1 << 17)
+#define EMAC_MACCONTROL_RMIISPEED_100		(1 << 15)
+
+#define EMAC_MAC_ADDR_MATCH		(1 << 19)
+#define EMAC_MAC_ADDR_IS_VALID		(1 << 20)
+
+#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE	(0x200000)
+#define EMAC_RXMBPENABLE_RXBROADEN	(0x2000)
+
+
+#define MDIO_CONTROL_IDLE		(0x80000000)
+#define MDIO_CONTROL_ENABLE		(0x40000000)
+#define MDIO_CONTROL_FAULT_ENABLE	(0x40000)
+#define MDIO_CONTROL_FAULT		(0x80000)
+#define MDIO_USERACCESS0_GO		(0x80000000)
+#define MDIO_USERACCESS0_WRITE_READ	(0x0)
+#define MDIO_USERACCESS0_WRITE_WRITE	(0x40000000)
+#define MDIO_USERACCESS0_ACK		(0x20000000)
+
+/* Ethernet MAC Registers Structure */
+typedef struct  {
+	dv_reg		TXIDVER;
+	dv_reg		TXCONTROL;
+	dv_reg		TXTEARDOWN;
+	u_int8_t	RSVD0[4];
+	dv_reg		RXIDVER;
+	dv_reg		RXCONTROL;
+	dv_reg		RXTEARDOWN;
+	u_int8_t	RSVD1[100];
+	dv_reg		TXINTSTATRAW;
+	dv_reg		TXINTSTATMASKED;
+	dv_reg		TXINTMASKSET;
+	dv_reg		TXINTMASKCLEAR;
+	dv_reg		MACINVECTOR;
+	u_int8_t	RSVD2[12];
+	dv_reg		RXINTSTATRAW;
+	dv_reg		RXINTSTATMASKED;
+	dv_reg		RXINTMASKSET;
+	dv_reg		RXINTMASKCLEAR;
+	dv_reg		MACINTSTATRAW;
+	dv_reg		MACINTSTATMASKED;
+	dv_reg		MACINTMASKSET;
+	dv_reg		MACINTMASKCLEAR;
+	u_int8_t	RSVD3[64];
+	dv_reg		RXMBPENABLE;
+	dv_reg		RXUNICASTSET;
+	dv_reg		RXUNICASTCLEAR;
+	dv_reg		RXMAXLEN;
+	dv_reg		RXBUFFEROFFSET;
+	dv_reg		RXFILTERLOWTHRESH;
+	u_int8_t	RSVD4[8];
+	dv_reg		RX0FLOWTHRESH;
+	dv_reg		RX1FLOWTHRESH;
+	dv_reg		RX2FLOWTHRESH;
+	dv_reg		RX3FLOWTHRESH;
+	dv_reg		RX4FLOWTHRESH;
+	dv_reg		RX5FLOWTHRESH;
+	dv_reg		RX6FLOWTHRESH;
+	dv_reg		RX7FLOWTHRESH;
+	dv_reg		RX0FREEBUFFER;
+	dv_reg		RX1FREEBUFFER;
+	dv_reg		RX2FREEBUFFER;
+	dv_reg		RX3FREEBUFFER;
+	dv_reg		RX4FREEBUFFER;
+	dv_reg		RX5FREEBUFFER;
+	dv_reg		RX6FREEBUFFER;
+	dv_reg		RX7FREEBUFFER;
+	dv_reg		MACCONTROL;
+	dv_reg		MACSTATUS;
+	dv_reg		EMCONTROL;
+	dv_reg		FIFOCONTROL;
+	dv_reg		MACCONFIG;
+	dv_reg		SOFTRESET;
+	u_int8_t	RSVD5[88];
+	dv_reg		MACSRCADDRLO;
+	dv_reg		MACSRCADDRHI;
+	dv_reg		MACHASH1;
+	dv_reg		MACHASH2;
+	dv_reg		BOFFTEST;
+	dv_reg		TPACETEST;
+	dv_reg		RXPAUSE;
+	dv_reg		TXPAUSE;
+	u_int8_t	RSVD6[16];
+	dv_reg		RXGOODFRAMES;
+	dv_reg		RXBCASTFRAMES;
+	dv_reg		RXMCASTFRAMES;
+	dv_reg		RXPAUSEFRAMES;
+	dv_reg		RXCRCERRORS;
+	dv_reg		RXALIGNCODEERRORS;
+	dv_reg		RXOVERSIZED;
+	dv_reg		RXJABBER;
+	dv_reg		RXUNDERSIZED;
+	dv_reg		RXFRAGMENTS;
+	dv_reg		RXFILTERED;
+	dv_reg		RXQOSFILTERED;
+	dv_reg		RXOCTETS;
+	dv_reg		TXGOODFRAMES;
+	dv_reg		TXBCASTFRAMES;
+	dv_reg		TXMCASTFRAMES;
+	dv_reg		TXPAUSEFRAMES;
+	dv_reg		TXDEFERRED;
+	dv_reg		TXCOLLISION;
+	dv_reg		TXSINGLECOLL;
+	dv_reg		TXMULTICOLL;
+	dv_reg		TXEXCESSIVECOLL;
+	dv_reg		TXLATECOLL;
+	dv_reg		TXUNDERRUN;
+	dv_reg		TXCARRIERSENSE;
+	dv_reg		TXOCTETS;
+	dv_reg		FRAME64;
+	dv_reg		FRAME65T127;
+	dv_reg		FRAME128T255;
+	dv_reg		FRAME256T511;
+	dv_reg		FRAME512T1023;
+	dv_reg		FRAME1024TUP;
+	dv_reg		NETOCTETS;
+	dv_reg		RXSOFOVERRUNS;
+	dv_reg		RXMOFOVERRUNS;
+	dv_reg		RXDMAOVERRUNS;
+	u_int8_t	RSVD7[624];
+	dv_reg		MACADDRLO;
+	dv_reg		MACADDRHI;
+	dv_reg		MACINDEX;
+	u_int8_t	RSVD8[244];
+	dv_reg		TX0HDP;
+	dv_reg		TX1HDP;
+	dv_reg		TX2HDP;
+	dv_reg		TX3HDP;
+	dv_reg		TX4HDP;
+	dv_reg		TX5HDP;
+	dv_reg		TX6HDP;
+	dv_reg		TX7HDP;
+	dv_reg		RX0HDP;
+	dv_reg		RX1HDP;
+	dv_reg		RX2HDP;
+	dv_reg		RX3HDP;
+	dv_reg		RX4HDP;
+	dv_reg		RX5HDP;
+	dv_reg		RX6HDP;
+	dv_reg		RX7HDP;
+	dv_reg		TX0CP;
+	dv_reg		TX1CP;
+	dv_reg		TX2CP;
+	dv_reg		TX3CP;
+	dv_reg		TX4CP;
+	dv_reg		TX5CP;
+	dv_reg		TX6CP;
+	dv_reg		TX7CP;
+	dv_reg		RX0CP;
+	dv_reg		RX1CP;
+	dv_reg		RX2CP;
+	dv_reg		RX3CP;
+	dv_reg		RX4CP;
+	dv_reg		RX5CP;
+	dv_reg		RX6CP;
+	dv_reg		RX7CP;
+} emac_regs;
+
+/* EMAC Wrapper Registers Structure */
+typedef struct  {
+#ifdef DAVINCI_EMAC_VERSION2
+	dv_reg		idver;
+	dv_reg		softrst;
+	dv_reg		emctrl;
+	dv_reg		c0rxthreshen;
+	dv_reg		c0rxen;
+	dv_reg		c0txen;
+	dv_reg		c0miscen;
+	dv_reg		c1rxthreshen;
+	dv_reg		c1rxen;
+	dv_reg		c1txen;
+	dv_reg		c1miscen;
+	dv_reg		c2rxthreshen;
+	dv_reg		c2rxen;
+	dv_reg		c2txen;
+	dv_reg		c2miscen;
+	dv_reg		c0rxthreshstat;
+	dv_reg		c0rxstat;
+	dv_reg		c0txstat;
+	dv_reg		c0miscstat;
+	dv_reg		c1rxthreshstat;
+	dv_reg		c1rxstat;
+	dv_reg		c1txstat;
+	dv_reg		c1miscstat;
+	dv_reg		c2rxthreshstat;
+	dv_reg		c2rxstat;
+	dv_reg		c2txstat;
+	dv_reg		c2miscstat;
+	dv_reg		c0rximax;
+	dv_reg		c0tximax;
+	dv_reg		c1rximax;
+	dv_reg		c1tximax;
+	dv_reg		c2rximax;
+	dv_reg		c2tximax;
+#else
+	u_int8_t	RSVD0[4100];
+	dv_reg		EWCTL;
+	dv_reg		EWINTTCNT;
+#endif
+} ewrap_regs;
+
+/* EMAC MDIO Registers Structure */
+typedef struct  {
+	dv_reg		VERSION;
+	dv_reg		CONTROL;
+	dv_reg		ALIVE;
+	dv_reg		LINK;
+	dv_reg		LINKINTRAW;
+	dv_reg		LINKINTMASKED;
+	u_int8_t	RSVD0[8];
+	dv_reg		USERINTRAW;
+	dv_reg		USERINTMASKED;
+	dv_reg		USERINTMASKSET;
+	dv_reg		USERINTMASKCLEAR;
+	u_int8_t	RSVD1[80];
+	dv_reg		USERACCESS0;
+	dv_reg		USERPHYSEL0;
+	dv_reg		USERACCESS1;
+	dv_reg		USERPHYSEL1;
+} mdio_regs;
+
+typedef struct
+{
+	char	name[64];
+	int	(*init)(int phy_addr);
+	int	(*is_phy_connected)(int phy_addr);
+	int	(*get_link_speed)(int phy_addr);
+	int	(*auto_negotiate)(int phy_addr);
+} phy_t;
+
+#endif  /* _DAVINCI_EMAC_H_ */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 09/10] omap3: allow enabling clocks for UART3, MMC1 and SPI
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
                   ` (7 preceding siblings ...)
  2012-09-03 11:46 ` [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
@ 2012-09-03 11:46 ` Jan Luebbe
  2012-09-04  8:48   ` Sascha Hauer
  2012-09-03 11:46 ` [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
  9 siblings, 1 reply; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:46 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 arch/arm/mach-omap/Kconfig       |    4 ++++
 arch/arm/mach-omap/omap3_clock.c |   35 +++++++++++++++++++++++++----------
 2 files changed, 29 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index a781287..82fa46b 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -61,6 +61,10 @@ config OMAP_CLOCK_UART3
 	bool
 config OMAP_CLOCK_I2C
 	bool
+config OMAP_CLOCK_MMC1
+	bool
+config OMAP_CLOCK_SPI
+	bool
 
 # Blind enable all possible clocks.. think twice before you do this.
 config OMAP_CLOCK_ALL
diff --git a/arch/arm/mach-omap/omap3_clock.c b/arch/arm/mach-omap/omap3_clock.c
index 646235e..bfaa1cf 100644
--- a/arch/arm/mach-omap/omap3_clock.c
+++ b/arch/arm/mach-omap/omap3_clock.c
@@ -674,16 +674,31 @@ static void per_clocks_enable(void)
 	/* Enable the ICLK for 32K Sync Timer as its used in udelay */
 	sr32(CM_REG(ICLKEN_WKUP), 2, 1, 0x1);
 
-#ifdef CONFIG_OMAP_CLOCK_UART
-	/* Enable UART1 clocks */
-	sr32(CM_REG(FCLKEN1_CORE), 13, 1, 0x1);
-	sr32(CM_REG(ICLKEN1_CORE), 13, 1, 0x1);
-#endif
-#ifdef CONFIG_OMAP_CLOCK_I2C
-	/* Turn on all 3 I2C clocks */
-	sr32(CM_REG(FCLKEN1_CORE), 15, 3, 0x7);
-	sr32(CM_REG(ICLKEN1_CORE), 15, 3, 0x7);	/* I2C1,2,3 = on */
-#endif
+	if (IS_ENABLED(CONFIG_OMAP_CLOCK_UART)) {
+		/* Enable UART1 clocks */
+		sr32(CM_REG(FCLKEN1_CORE), 13, 1, 0x1);
+		sr32(CM_REG(ICLKEN1_CORE), 13, 1, 0x1);
+	}
+	if (IS_ENABLED(CONFIG_OMAP_CLOCK_UART3)) {
+		/* Enable UART3 clocks */
+		sr32(CM_REG(FCLKEN_PER), 11, 1, 0x1);
+		sr32(CM_REG(ICLKEN_PER), 11, 1, 0x1);
+	}
+	if (IS_ENABLED(CONFIG_OMAP_CLOCK_I2C)) {
+		/* Turn on all 3 I2C clocks */
+		sr32(CM_REG(FCLKEN1_CORE), 15, 3, 0x7);
+		sr32(CM_REG(ICLKEN1_CORE), 15, 3, 0x7);	/* I2C1,2,3 = on */
+	}
+	if (IS_ENABLED(CONFIG_OMAP_CLOCK_MMC1)) {
+		/* Enable MMC1 clocks */
+		sr32(CM_REG(FCLKEN1_CORE), 24, 1, 0x1);
+		sr32(CM_REG(ICLKEN1_CORE), 24, 1, 0x1);
+	}
+	if (IS_ENABLED(CONFIG_OMAP_CLOCK_SPI)) {
+		/* Enable SPI clocks */
+		sr32(CM_REG(FCLKEN1_CORE), 18, 4, 0xf);
+		sr32(CM_REG(ICLKEN1_CORE), 18, 4, 0xf);
+	}
 
 #ifdef CONFIG_OMAP_CLOCK_ALL
 #define FCK_IVA2_ON	0x00000001
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs
  2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
                   ` (8 preceding siblings ...)
  2012-09-03 11:46 ` [PATCH 09/10] omap3: allow enabling clocks for UART3, MMC1 and SPI Jan Luebbe
@ 2012-09-03 11:46 ` Jan Luebbe
  2012-09-03 16:32   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-04  8:58   ` Sascha Hauer
  9 siblings, 2 replies; 23+ messages in thread
From: Jan Luebbe @ 2012-09-03 11:46 UTC (permalink / raw)
  To: barebox

Also create devices for OMAP3.

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 arch/arm/mach-omap/include/mach/mcspi.h         |   11 +
 arch/arm/mach-omap/include/mach/omap3-devices.h |   34 ++
 drivers/spi/Kconfig                             |    6 +
 drivers/spi/Makefile                            |    1 +
 drivers/spi/omap3_spi.c                         |  403 +++++++++++++++++++++++
 drivers/spi/omap3_spi.h                         |  100 ++++++
 6 files changed, 555 insertions(+)
 create mode 100644 arch/arm/mach-omap/include/mach/mcspi.h
 create mode 100644 arch/arm/mach-omap/include/mach/omap3-devices.h
 create mode 100644 drivers/spi/omap3_spi.c
 create mode 100644 drivers/spi/omap3_spi.h

diff --git a/arch/arm/mach-omap/include/mach/mcspi.h b/arch/arm/mach-omap/include/mach/mcspi.h
new file mode 100644
index 0000000..dbde67a
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/mcspi.h
@@ -0,0 +1,11 @@
+#ifndef __OMAP_MCSPI_H
+#define  __OMAP_MCSPI_H
+
+#define OMAP3_MCSPI1_BASE	0x48098000
+#define OMAP3_MCSPI2_BASE	0x4809A000
+#define OMAP3_MCSPI3_BASE	0x480B8000
+#define OMAP3_MCSPI4_BASE	0x480BA000
+
+int mcspi_devices_init(void);
+
+#endif /* __OMAP_MCSPI_H */
diff --git a/arch/arm/mach-omap/include/mach/omap3-devices.h b/arch/arm/mach-omap/include/mach/omap3-devices.h
new file mode 100644
index 0000000..2db8583
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/omap3-devices.h
@@ -0,0 +1,34 @@
+#include <driver.h>
+#include <sizes.h>
+
+#include <mach/mcspi.h>
+
+/* the device numbering is the same as in the device tree */
+
+static inline struct device_d *omap3_add_spi1(void)
+{
+	return add_generic_device("omap3_spi", 1, NULL,
+				   OMAP3_MCSPI1_BASE, SZ_4K,
+				   IORESOURCE_MEM, NULL);
+}
+
+static inline struct device_d *omap3_add_spi2(void)
+{
+	return add_generic_device("omap3_spi", 2, NULL,
+				   OMAP3_MCSPI2_BASE, SZ_4K,
+				   IORESOURCE_MEM, NULL);
+}
+
+static inline struct device_d *omap3_add_spi3(void)
+{
+	return add_generic_device("omap3_spi", 3, NULL,
+				   OMAP3_MCSPI3_BASE, SZ_4K,
+				   IORESOURCE_MEM, NULL);
+}
+
+static inline struct device_d *omap3_add_spi4(void)
+{
+	return add_generic_device("omap3_spi", 4, NULL,
+				   OMAP3_MCSPI4_BASE, SZ_4K,
+				   IORESOURCE_MEM, NULL);
+}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index a249b81..ba1b948 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -34,4 +34,10 @@ config DRIVER_SPI_ATMEL
 	depends on ARCH_AT91
 	depends on SPI
 
+
+config DRIVER_SPI_OMAP3
+	bool "OMAP3 McSPI Master driver"
+	depends on ARCH_OMAP3
+	depends on SPI
+
 endmenu
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 101652f..b53061e 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_SPI) += spi.o
 obj-$(CONFIG_DRIVER_SPI_IMX) += imx_spi.o
 obj-$(CONFIG_DRIVER_SPI_ALTERA) += altera_spi.o
 obj-$(CONFIG_DRIVER_SPI_ATMEL) += atmel_spi.o
+obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
new file mode 100644
index 0000000..eadb78d
--- /dev/null
+++ b/drivers/spi/omap3_spi.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
+ *
+ * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
+ *
+ * Driver for McSPI controller on OMAP3. Based on davinci_spi.c
+ * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * Parts taken from linux/drivers/spi/omap2_mcspi.c
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ *
+ * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.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 <common.h>
+#include <init.h>
+#include <driver.h>
+#include <errno.h>
+#include <spi/spi.h>
+#include <malloc.h>
+#include <io.h>
+#include "omap3_spi.h"
+
+#define WORD_LEN	8
+#define SPI_WAIT_TIMEOUT 30000000
+
+#define SPI_XFER_BEGIN  0x01                    /* Assert CS before transfer */
+#define SPI_XFER_END    0x02                    /* Deassert CS after transfer */
+
+static void spi_reset(struct spi_master *master)
+{
+	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
+	struct mcspi __iomem *regs = omap3_master->regs;
+	unsigned int tmp;
+
+	writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &regs->sysconfig);
+	do {
+		tmp = readl(&regs->sysstatus);
+	} while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
+
+	writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
+				 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
+				 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE,
+				 &regs->sysconfig);
+
+	writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &regs->wakeupenable);
+}
+
+int spi_claim_bus(struct spi_device *spi)
+{
+	struct spi_master *master = spi->master;
+	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
+	struct mcspi __iomem *regs = omap3_master->regs;
+	unsigned int conf, div = 0;
+
+	/* McSPI global module configuration */
+
+	/*
+	 * setup when switching from (reset default) slave mode
+	 * to single-channel master mode
+	 */
+	conf = readl(&regs->modulctrl);
+	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
+	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
+	writel(conf, &regs->modulctrl);
+
+	/* McSPI individual channel configuration */
+
+	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
+	if (spi->max_speed_hz) {
+		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
+					 > spi->max_speed_hz)
+			div++;
+	} else
+		div = 0xC;
+
+	conf = readl(&regs->channel[spi->chip_select].chconf);
+
+	/* standard 4-wire master mode:	SCK, MOSI/out, MISO/in, nCS
+	 * REVISIT: this controller could support SPI_3WIRE mode.
+	 */
+	conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
+	conf |= OMAP3_MCSPI_CHCONF_DPE0;
+
+	/* wordlength */
+	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
+	conf |= (WORD_LEN - 1) << 7;
+
+	/* set chipselect polarity; manage with FORCE */
+	if (!(spi->mode & SPI_CS_HIGH))
+		conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
+	else
+		conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
+
+	/* set clock divisor */
+	conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
+	conf |= div << 2;
+
+	/* set SPI mode 0..3 */
+	if (spi->mode & SPI_CPOL)
+		conf |= OMAP3_MCSPI_CHCONF_POL;
+	else
+		conf &= ~OMAP3_MCSPI_CHCONF_POL;
+	if (spi->mode & SPI_CPHA)
+		conf |= OMAP3_MCSPI_CHCONF_PHA;
+	else
+		conf &= ~OMAP3_MCSPI_CHCONF_PHA;
+
+	/* Transmit & receive mode */
+	conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
+
+	writel(conf, &regs->channel[spi->chip_select].chconf);
+	readl(&regs->channel[spi->chip_select].chconf);
+
+	return 0;
+}
+
+int omap3_spi_write(struct spi_device *spi, unsigned int len, const u8 *txp,
+		    unsigned long flags)
+{
+	struct spi_master *master = spi->master;
+	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
+	struct mcspi __iomem *regs = omap3_master->regs;
+	int i;
+	int timeout = SPI_WAIT_TIMEOUT;
+	int chconf = readl(&regs->channel[spi->chip_select].chconf);
+
+	if (flags & SPI_XFER_BEGIN)
+		writel(OMAP3_MCSPI_CHCTRL_EN,
+		       &regs->channel[spi->chip_select].chctrl);
+
+	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
+	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
+	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
+	writel(chconf, &regs->channel[spi->chip_select].chconf);
+	readl(&regs->channel[spi->chip_select].chconf);
+
+	for (i = 0; i < len; i++) {
+		/* wait till TX register is empty (TXS == 1) */
+		while (!(readl(&regs->channel[spi->chip_select].chstat) &
+			 OMAP3_MCSPI_CHSTAT_TXS)) {
+			if (--timeout <= 0) {
+				printf("SPI TXS timed out, status=0x%08x\n",
+				       readl(&regs->channel[spi->chip_select].chstat));
+				return -1;
+			}
+		}
+		/* Write the data */
+		writel(txp[i], &regs->channel[spi->chip_select].tx);
+	}
+
+	if (flags & SPI_XFER_END) {
+		/* wait to finish of transfer */
+		while (!(readl(&regs->channel[spi->chip_select].chstat) &
+			 OMAP3_MCSPI_CHSTAT_EOT));
+
+		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
+		writel(chconf, &regs->channel[spi->chip_select].chconf);
+
+		writel(0, &regs->channel[spi->chip_select].chctrl);
+	}
+
+	while (!(readl(&regs->channel[spi->chip_select].chstat) &
+			 OMAP3_MCSPI_CHSTAT_TXS));
+	while (!(readl(&regs->channel[spi->chip_select].chstat) &
+			 OMAP3_MCSPI_CHSTAT_EOT));
+
+	return 0;
+}
+
+int omap3_spi_read(struct spi_device *spi, unsigned int len, u8 *rxp,
+		   unsigned long flags)
+{
+	struct spi_master *master = spi->master;
+	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
+	struct mcspi __iomem *regs = omap3_master->regs;
+	int i;
+	int timeout = SPI_WAIT_TIMEOUT;
+	int chconf = readl(&regs->channel[spi->chip_select].chconf);
+
+	if (flags & SPI_XFER_BEGIN)
+		writel(OMAP3_MCSPI_CHCTRL_EN,
+		       &regs->channel[spi->chip_select].chctrl);
+
+	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
+	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
+	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
+	writel(chconf, &regs->channel[spi->chip_select].chconf);
+	readl(&regs->channel[spi->chip_select].chconf);
+	writel(0, &regs->channel[spi->chip_select].tx);
+
+	for (i = 0; i < len; i++) {
+		/* Wait till RX register contains data (RXS == 1) */
+		while (!(readl(&regs->channel[spi->chip_select].chstat) &
+			 OMAP3_MCSPI_CHSTAT_RXS)) {
+			if (--timeout <= 0) {
+				printf("SPI RXS timed out, status=0x%08x\n",
+				       readl(&regs->channel[spi->chip_select].chstat));
+				return -1;
+			}
+		}
+		/* Read the data */
+		rxp[i] = readl(&regs->channel[spi->chip_select].rx);
+	}
+
+	if (flags & SPI_XFER_END) {
+		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
+		writel(chconf, &regs->channel[spi->chip_select].chconf);
+		readl(&regs->channel[spi->chip_select].chconf);
+
+		writel(0, &regs->channel[spi->chip_select].chctrl);
+	}
+
+	return 0;
+}
+
+int spi_xfer(struct spi_device *spi, struct spi_transfer *t, unsigned long flags)
+{
+	struct spi_master *master = spi->master;
+	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
+	struct mcspi __iomem *regs = omap3_master->regs;
+	unsigned int    len = t->len;
+	int             ret = -1;
+	const u8        *txp = t->tx_buf; /* can be NULL for read operation */
+	u8              *rxp = t->rx_buf; /* can be NULL for write operation */
+
+	if (len == 0) {	 /* only change CS */
+		int chconf = readl(&regs->channel[spi->chip_select].chconf);
+
+		if (flags & SPI_XFER_BEGIN) {
+			writel(OMAP3_MCSPI_CHCTRL_EN,
+			       &regs->channel[spi->chip_select].chctrl);
+			chconf |= OMAP3_MCSPI_CHCONF_FORCE;
+			writel(chconf,
+			       &regs->channel[spi->chip_select].chconf);
+			readl(&regs->channel[spi->chip_select].chconf);
+		}
+
+		if (flags & SPI_XFER_END) {
+			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
+			writel(chconf,
+			       &regs->channel[spi->chip_select].chconf);
+			writel(0, &regs->channel[spi->chip_select].chctrl);
+			readl(&regs->channel[spi->chip_select].chconf);
+		}
+
+		ret = 0;
+	} else {
+		if (t->tx_buf != NULL)
+			ret = omap3_spi_write(spi, len, txp, flags);
+
+		if (t->rx_buf != NULL)
+			ret = omap3_spi_read(spi, len, rxp, flags);
+	}
+	return ret;
+}
+
+static int omap3_spi_transfer(struct spi_device *spi, struct spi_message *mesg)
+{
+	struct spi_master *master = spi->master;
+	struct spi_transfer *t, *t_first, *t_last = NULL;
+	unsigned long flags;
+	int ret = 0;
+
+	ret = spi_claim_bus(spi);
+	if (ret)
+		return ret;
+
+	if (list_empty(&mesg->transfers))
+		return 0;
+
+	t_first = list_first_entry(&mesg->transfers, struct spi_transfer, transfer_list);
+	t_last = list_last_entry(&mesg->transfers, struct spi_transfer, transfer_list);
+
+	mesg->actual_length = 0;
+
+	dev_dbg(master->dev, "transfer start actual_length=%i\n", mesg->actual_length);
+	list_for_each_entry(t, &mesg->transfers, transfer_list) {
+		dev_dbg(master->dev,
+			"  xfer %p: len %u tx %p rx %p\n",
+			t, t->len, t->tx_buf, t->rx_buf);
+		flags = 0;
+		if (t == t_first)
+			flags |= SPI_XFER_BEGIN;
+		if (t == t_last)
+			flags |= SPI_XFER_END;
+		spi_xfer(spi, t, flags);
+		mesg->actual_length += t->len;
+	}
+	dev_dbg(master->dev, "transfer done actual_length=%i\n", mesg->actual_length);
+
+	return ret;
+}
+
+static int omap3_spi_setup(struct spi_device *spi)
+{
+	struct spi_master *master = spi->master;
+
+	if (((master->bus_num == 0) && (spi->chip_select > 3)) ||
+			((master->bus_num == 1) && (spi->chip_select > 1)) ||
+			((master->bus_num == 2) && (spi->chip_select > 1)) ||
+			((master->bus_num == 3) && (spi->chip_select > 0))) {
+		printf("SPI error: unsupported chip select %i \
+			on bus %i\n", spi->chip_select, master->bus_num);
+		return -1;
+	}
+
+	if (spi->max_speed_hz > OMAP3_MCSPI_MAX_FREQ) {
+		printf("SPI error: unsupported frequency %i Hz. \
+			Max frequency is 48 Mhz\n", spi->max_speed_hz);
+		return -1;
+	}
+
+	if (spi->mode > SPI_MODE_3) {
+		printf("SPI error: unsupported SPI mode %i\n", spi->mode);
+		return -1;
+	}
+
+	return 0;
+}
+
+static int omap3_spi_probe(struct device_d *dev)
+{
+	struct spi_master *master;
+	struct omap3_spi_master *omap3_master;
+
+	omap3_master = xzalloc(sizeof(*omap3_master));
+
+	master = &omap3_master->master;
+	master->dev = dev;
+
+	/*
+	 * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
+	 * with different number of chip selects (CS, channels):
+	 * McSPI1 has 4 CS (bus 0, cs 0 - 3)
+	 * McSPI2 has 2 CS (bus 1, cs 0 - 1)
+	 * McSPI3 has 2 CS (bus 2, cs 0 - 1)
+	 * McSPI4 has 1 CS (bus 3, cs 0)
+	 */
+
+	master->bus_num = dev->id;
+	switch (master->bus_num) {
+	case 1:
+		master->num_chipselect = 4;
+		break;
+	case 2:
+		master->num_chipselect = 2;
+		break;
+	case 3:
+		master->num_chipselect = 2;
+		break;
+	case 4:
+		master->num_chipselect = 1;
+		break;
+	default:
+		printf("SPI error: unsupported bus %i. \
+			Supported busses 1 - 4\n", master->bus_num);
+		return -ENODEV;
+	}
+	master->setup = omap3_spi_setup;
+	master->transfer = omap3_spi_transfer;
+
+	omap3_master->regs = (struct mcspi *)dev_request_mem_region(dev, 0);;
+
+	spi_reset(master);
+
+	spi_register_master(master);
+
+	return 0;
+}
+
+static struct driver_d omap3_spi_driver = {
+	.name = "omap3_spi",
+	.probe = omap3_spi_probe,
+};
+
+static int omap3_spi_init(void)
+{
+	return register_driver(&omap3_spi_driver);
+}
+
+device_initcall(omap3_spi_init);
diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h
new file mode 100644
index 0000000..2ad8ef7
--- /dev/null
+++ b/drivers/spi/omap3_spi.h
@@ -0,0 +1,100 @@
+/*
+ * Register definitions for the OMAP3 McSPI Controller
+ *
+ * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
+ *
+ * Parts taken from linux/drivers/spi/omap2_mcspi.c
+ * Copyright (C) 2005, 2006 Nokia Corporation
+ *
+ * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.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
+ */
+
+#ifndef _OMAP3_SPI_H_
+#define _OMAP3_SPI_H_
+
+#define OMAP3_MCSPI_MAX_FREQ	48000000
+
+/* OMAP3 McSPI registers */
+struct mcspi_channel {
+	unsigned int chconf;		/* 0x2C, 0x40, 0x54, 0x68 */
+	unsigned int chstat;		/* 0x30, 0x44, 0x58, 0x6C */
+	unsigned int chctrl;		/* 0x34, 0x48, 0x5C, 0x70 */
+	unsigned int tx;		/* 0x38, 0x4C, 0x60, 0x74 */
+	unsigned int rx;		/* 0x3C, 0x50, 0x64, 0x78 */
+};
+
+struct mcspi {
+	unsigned char res1[0x10];
+	unsigned int sysconfig;		/* 0x10 */
+	unsigned int sysstatus;		/* 0x14 */
+	unsigned int irqstatus;		/* 0x18 */
+	unsigned int irqenable;		/* 0x1C */
+	unsigned int wakeupenable;	/* 0x20 */
+	unsigned int syst;		/* 0x24 */
+	unsigned int modulctrl;		/* 0x28 */
+	struct mcspi_channel channel[4]; /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */
+					/* channel1: 0x40 - 0x50, bus 0 & 1 */
+					/* channel2: 0x54 - 0x64, bus 0 & 1 */
+					/* channel3: 0x68 - 0x78, bus 0 */
+};
+
+/* per-register bitmasks */
+#define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3)
+#define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP (1 << 2)
+#define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE	(1 << 0)
+#define OMAP3_MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
+
+#define OMAP3_MCSPI_SYSSTATUS_RESETDONE (1 << 0)
+
+#define OMAP3_MCSPI_MODULCTRL_SINGLE	(1 << 0)
+#define OMAP3_MCSPI_MODULCTRL_MS	(1 << 2)
+#define OMAP3_MCSPI_MODULCTRL_STEST	(1 << 3)
+
+#define OMAP3_MCSPI_CHCONF_PHA		(1 << 0)
+#define OMAP3_MCSPI_CHCONF_POL		(1 << 1)
+#define OMAP3_MCSPI_CHCONF_CLKD_MASK	(0x0f << 2)
+#define OMAP3_MCSPI_CHCONF_EPOL		(1 << 6)
+#define OMAP3_MCSPI_CHCONF_WL_MASK	(0x1f << 7)
+#define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY	(0x01 << 12)
+#define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY	(0x02 << 12)
+#define OMAP3_MCSPI_CHCONF_TRM_MASK	(0x03 << 12)
+#define OMAP3_MCSPI_CHCONF_DMAW		(1 << 14)
+#define OMAP3_MCSPI_CHCONF_DMAR		(1 << 15)
+#define OMAP3_MCSPI_CHCONF_DPE0		(1 << 16)
+#define OMAP3_MCSPI_CHCONF_DPE1		(1 << 17)
+#define OMAP3_MCSPI_CHCONF_IS		(1 << 18)
+#define OMAP3_MCSPI_CHCONF_TURBO	(1 << 19)
+#define OMAP3_MCSPI_CHCONF_FORCE	(1 << 20)
+
+#define OMAP3_MCSPI_CHSTAT_RXS		(1 << 0)
+#define OMAP3_MCSPI_CHSTAT_TXS		(1 << 1)
+#define OMAP3_MCSPI_CHSTAT_EOT		(1 << 2)
+
+#define OMAP3_MCSPI_CHCTRL_EN		(1 << 0)
+
+#define OMAP3_MCSPI_WAKEUPENABLE_WKEN	(1 << 0)
+
+struct omap3_spi_master {
+	struct spi_master master;
+	struct mcspi __iomem *regs;
+};
+
+#endif /* _OMAP3_SPI_H_ */
-- 
1.7.10.4


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 03/10] Makefile: add target to produce a SPL compatible uimage
  2012-09-03 11:45 ` [PATCH 03/10] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
@ 2012-09-03 16:22   ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 23+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-03 16:22 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On 13:45 Mon 03 Sep     , Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  Makefile |    5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/Makefile b/Makefile
> index 969afbb..243a689 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -673,6 +673,11 @@ barebox.bin: barebox FORCE
>  	$(call if_changed,objcopy)
>  	$(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
>  
> +barebox.img: barebox.bin
> +	$(srctree)/scripts/mkimage -A $(ARCH) -T firmware -C none \
> +	-O barebox -a $(CONFIG_TEXT_BASE) -e $(CONFIG_TEXT_BASE) \
> +	-n "barebox $(KERNELRELEASE)" -d $< $@
> +
you must us this kbuild style

quiet_cmd_xxx
      cmd_xxx

and you need to use the $(KBUILD_IMAGE) present in the next

Best Regards,
J.

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 06/10] omap: add SPI as a boot mode for xload
  2012-09-03 11:46 ` [PATCH 06/10] omap: add SPI as a boot mode for xload Jan Luebbe
@ 2012-09-03 16:24   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-04  7:41     ` Jan Weitzel
  0 siblings, 1 reply; 23+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-03 16:24 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On 13:46 Mon 03 Sep     , Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
you need to sync with 

257     Aug27 Jan Weitzel     [RFC] xload: get barebox size from barebox_arm_head

Best Regards,
J.

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs
  2012-09-03 11:46 ` [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
@ 2012-09-03 16:27   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-04  8:42   ` Sascha Hauer
  1 sibling, 0 replies; 23+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-03 16:27 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On 13:46 Mon 03 Sep     , Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  arch/arm/mach-omap/include/mach/emac_defs.h |   53 +++
>  drivers/net/Kconfig                         |    5 +
>  drivers/net/Makefile                        |    1 +
>  drivers/net/davinci_emac.c                  |  619 +++++++++++++++++++++++++++
>  drivers/net/davinci_emac.h                  |  331 ++++++++++++++
>  5 files changed, 1009 insertions(+)
>  create mode 100644 arch/arm/mach-omap/include/mach/emac_defs.h
>  create mode 100644 drivers/net/davinci_emac.c
>  create mode 100644 drivers/net/davinci_emac.h
> 
> diff --git a/arch/arm/mach-omap/include/mach/emac_defs.h b/arch/arm/mach-omap/include/mach/emac_defs.h
> new file mode 100644
> index 0000000..ef930fc
> --- /dev/null
> +++ b/arch/arm/mach-omap/include/mach/emac_defs.h
> @@ -0,0 +1,53 @@
> +/*
> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
> + *
> + * Based on:
this drivers is really not clean ad very difficult to read

no please re-write it clean

no UPERCASE and no struct for the regs it's horrible

Best Regards,
J.
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * dm644x_emac.h
> + *
> + * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
> + *
> + * Copyright (C) 2005 Texas Instruments.
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * 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.
> + * ----------------------------------------------------------------------------
> +
> + * Modifications:
> + * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot.
> + *
> + */
> +
> +#ifndef _AM3517_EMAC_H_
> +#define _AM3517_EMAC_H_
> +
> +#define EMAC_BASE_ADDR                 0x5C010000
> +#define EMAC_WRAPPER_BASE_ADDR         0x5C000000
> +#define EMAC_WRAPPER_RAM_ADDR          0x5C020000
> +#define EMAC_MDIO_BASE_ADDR            0x5C030000
> +#define EMAC_HW_RAM_ADDR               0x01E20000
> +
> +#define EMAC_MDIO_BUS_FREQ             166000000       /* 166 MHZ check */
> +#define EMAC_MDIO_CLOCK_FREQ           1000000         /* 2.0 MHz */
> +
> +/* SOFTRESET macro definition interferes with emac_regs structure definition */
> +#undef SOFTRESET
> +
> +#define DAVINCI_EMAC_VERSION2
> +
> +#endif  /* _AM3517_EMAC_H_ */
> diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
> index 0fa4f14..68c11eb 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -49,6 +49,11 @@ config DRIVER_NET_SMC91111
>  	  This option enables support for the SMSC LAN91C111
>  	  ethernet chip.
>  
> +config DRIVER_NET_DAVINCI_EMAC
> +	bool "TI Davinci/OMAP EMAC ethernet driver"
> +	depends on ARCH_DAVINCI || ARCH_OMAP3
> +	select MIIDEV
> +
>  config DRIVER_NET_DM9K
>  	bool "Davicom dm9k[E|A|B] ethernet driver"
>  	depends on HAS_DM9000
> diff --git a/drivers/net/Makefile b/drivers/net/Makefile
> index b589240..0f1363f 100644
> --- a/drivers/net/Makefile
> +++ b/drivers/net/Makefile
> @@ -1,6 +1,7 @@
>  obj-$(CONFIG_DRIVER_NET_CS8900)		+= cs8900.o
>  obj-$(CONFIG_DRIVER_NET_SMC911X)	+= smc911x.o
>  obj-$(CONFIG_DRIVER_NET_SMC91111)	+= smc91111.o
> +obj-$(CONFIG_DRIVER_NET_DAVINCI_EMAC)	+= davinci_emac.o
>  obj-$(CONFIG_DRIVER_NET_DM9K)		+= dm9k.o
>  obj-$(CONFIG_DRIVER_NET_NETX)		+= netx_eth.o
>  obj-$(CONFIG_DRIVER_NET_AT91_ETHER)	+= at91_ether.o
> diff --git a/drivers/net/davinci_emac.c b/drivers/net/davinci_emac.c
> new file mode 100644
> index 0000000..b9670ca
> --- /dev/null
> +++ b/drivers/net/davinci_emac.c
> @@ -0,0 +1,619 @@
> +/*
> + * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
> + *
> + * Ethernet driver for TI TMS320DM644x (DaVinci) chips.
> + *
> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
> + *
> + * Parts shamelessly stolen from TI's dm644x_emac.c. Original copyright
> + * follows:
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * dm644x_emac.c
> + *
> + * TI DaVinci (DM644X) EMAC peripheral driver source for DV-EVM
> + *
> + * Copyright (C) 2005 Texas Instruments.
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * 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.
> + * ----------------------------------------------------------------------------
> +
> + * Modifications:
> + * ver. 1.0: Sep 2005, Anant Gole - Created EMAC version for uBoot.
> + * ver  1.1: Nov 2005, Anant Gole - Extended the RX logic for multiple descriptors
> + *
> + */
> +
> +#include <common.h>
> +#include <io.h>
> +#include <clock.h>
> +#include <net.h>
> +#include <miidev.h>
> +#include <malloc.h>
> +#include <init.h>
> +#include <asm/mmu.h>
> +#include <asm/system.h>
> +#include <mach/emac_defs.h>
> +#include "davinci_emac.h"
> +
> +struct davinci_emac_priv {
> +	struct device_d *dev;
> +	struct eth_device edev;
> +	struct mii_device miidev;
> +	void __iomem *regs;
> +
> +	/* EMAC Addresses */
> +	emac_regs	*adap_emac; /* = (emac_regs *)EMAC_BASE_ADDR; */
> +	ewrap_regs	*adap_ewrap; /* = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; */
> +	mdio_regs	*adap_mdio; /* = (mdio_regs *)EMAC_MDIO_BASE_ADDR; */
> +
> +	/* EMAC descriptors */
> +	emac_desc	*emac_rx_desc; /* = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE); */
> +	emac_desc	*emac_tx_desc; /* = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE); */
> +	emac_desc	*emac_rx_active_head; /* = 0; */
> +	emac_desc	*emac_rx_active_tail; /* = 0; */
> +	int			emac_rx_queue_active; /* = 0; */
> +
> +	/* Receive packet buffers */
> +	unsigned char	*emac_rx_buffers; /* [EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)]; */
> +
> +	/* PHY address for a discovered PHY (0xff - not found) */
> +	u_int8_t	active_phy_addr; /* = 0xff; */
> +};
> +
> +/* davinci_eth_mac_addr[0] goes out on the wire first */
> +
> +static u_int8_t davinci_eth_mac_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x00 };
> +
> +/*
> + * This function must be called before emac_open() if you want to override
> + * the default mac address.
> + */
> +void davinci_eth_set_mac_addr(const u_int8_t *addr)
> +{
> +	int i;
> +
> +	for (i = 0; i < sizeof(davinci_eth_mac_addr); i++)
> +		davinci_eth_mac_addr[i] = addr[i];
> +}
> +
> +#ifdef EMAC_HW_RAM_ADDR
> +static inline dv_reg BD_TO_HW(emac_desc *x)
> +{
> +	if (x == 0)
> +		return 0;
> +
> +	return (dv_reg)(x) - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
> +}
> +
> +static inline emac_desc* HW_TO_BD(dv_reg x)
> +{
> +	if (x == 0)
> +		return 0;
> +
> +	return (emac_desc*)(x - EMAC_HW_RAM_ADDR + EMAC_WRAPPER_RAM_ADDR);
> +}
> +#else
> +#define BD_TO_HW(x)     (x)
> +#define HW_TO_BD(x)     (x)
> +#endif
> +
> +static void davinci_eth_mdio_enable(struct davinci_emac_priv *priv)
> +{
> +	u_int32_t	clkdiv;
> +
> +	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
> +
> +	dev_dbg(priv->dev, "mdio_enable + 0x%08x\n", priv->adap_mdio->CONTROL);
> +	writel((clkdiv & 0xff) |
> +		MDIO_CONTROL_ENABLE |
> +		MDIO_CONTROL_FAULT |
> +		MDIO_CONTROL_FAULT_ENABLE,
> +		&priv->adap_mdio->CONTROL);
> +	dev_dbg(priv->dev, "mdio_enable - 0x%08x\n", priv->adap_mdio->CONTROL);
> +
> +	while (readl(&priv->adap_mdio->CONTROL) & MDIO_CONTROL_IDLE);
> +}
> +
> +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
> +int davinci_eth_phy_read(struct davinci_emac_priv *priv, u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
> +{
> +	int	tmp;
> +
> +	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
> +
> +	writel(MDIO_USERACCESS0_GO |
> +		MDIO_USERACCESS0_WRITE_READ |
> +		((reg_num & 0x1f) << 21) |
> +		((phy_addr & 0x1f) << 16),
> +		&priv->adap_mdio->USERACCESS0);
> +
> +	/* Wait for command to complete */
> +	while ((tmp = readl(&priv->adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO);
> +
> +	if (tmp & MDIO_USERACCESS0_ACK) {
> +		*data = tmp & 0xffff;
> +		dev_dbg(priv->dev, "emac_phy_read: addr=0x%02x reg=0x%02x data=0x%04x\n",
> +			   phy_addr, reg_num, *data);
> +		return 1;
> +	}
> +
> +	*data = -1;
> +	return 0;
> +}
> +
> +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
> +int davinci_eth_phy_write(struct davinci_emac_priv *priv, u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
> +{
> +
> +	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
> +
> +	dev_dbg(priv->dev, "emac_phy_write: addr=0x%02x reg=0x%02x data=0x%04x\n",
> +		   phy_addr, reg_num, data);
> +	writel(MDIO_USERACCESS0_GO |
> +				MDIO_USERACCESS0_WRITE_WRITE |
> +				((reg_num & 0x1f) << 21) |
> +				((phy_addr & 0x1f) << 16) |
> +				(data & 0xffff),
> +		&priv->adap_mdio->USERACCESS0);
> +
> +	/* Wait for command to complete */
> +	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
> +
> +	return 1;
> +}
> +
> +static int davinci_miidev_read(struct mii_device *dev, int addr, int reg)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)dev->edev->priv;
> +	uint16_t value = 0;
> +	return davinci_eth_phy_read(priv, addr, reg, &value) ? value : -1;
> +}
> +
> +static int davinci_miidev_write(struct mii_device *dev, int addr, int reg, int value)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)dev->edev->priv;
> +	return davinci_eth_phy_write(priv, addr, reg, value) ? 0 : -1;
> +}
> +
> +static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr)
> +{
> +	return -1;
> +}
> +
> +static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *adr)
> +{
> +	davinci_eth_set_mac_addr(adr);
> +	return 0;
> +}
> +
> +static int davinci_emac_init(struct eth_device *edev)
> +{
> +	dev_dbg(&edev->dev, "* emac_init\n");
> +	return 0;
> +}
> +
> +static int davinci_emac_open(struct eth_device *edev)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +
> +	dv_reg_p	addr;
> +	u_int32_t	clkdiv, cnt;
> +	emac_desc	*rx_desc;
> +	unsigned long mac_hi, mac_lo;
> +	int ret;
> +
> +	dev_dbg(priv->dev, "+ emac_open\n");
> +
> +	dev_dbg(priv->dev, "emac->TXIDVER: 0x%08x\n", priv->adap_emac->TXIDVER);
> +	dev_dbg(priv->dev, "emac->RXIDVER: 0x%08x\n", priv->adap_emac->RXIDVER);
> +
> +	/* Reset EMAC module and disable interrupts in wrapper */
> +	writel(1, &priv->adap_emac->SOFTRESET);
> +	while (readl(&priv->adap_emac->SOFTRESET) != 0);
> +	writel(1, &priv->adap_ewrap->softrst);
> +	while (readl(&priv->adap_ewrap->softrst) != 0);
> +
> +	writel(0, &priv->adap_ewrap->c0rxen);
> +	writel(0, &priv->adap_ewrap->c1rxen);
> +	writel(0, &priv->adap_ewrap->c2rxen);
> +	writel(0, &priv->adap_ewrap->c0txen);
> +	writel(0, &priv->adap_ewrap->c1txen);
> +	writel(0, &priv->adap_ewrap->c2txen);
> +	writel(0, &priv->adap_ewrap->c0miscen);
> +	writel(0, &priv->adap_ewrap->c1miscen);
> +	writel(0, &priv->adap_ewrap->c2miscen);
> +
> +	rx_desc = priv->emac_rx_desc;
> +
> +	/*
> +	 * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
> +	 * receive)
> +	 * Use channel 0 only - other channels are disabled
> +	 */
> +	writel(0, &priv->adap_emac->MACINDEX);
> +	mac_hi = (davinci_eth_mac_addr[3] << 24) |
> +		 (davinci_eth_mac_addr[2] << 16) |
> +		 (davinci_eth_mac_addr[1] << 8)  |
> +		 (davinci_eth_mac_addr[0]);
> +	mac_lo = (davinci_eth_mac_addr[5] << 8) |
> +		 (davinci_eth_mac_addr[4]);
> +
> +	writel(mac_hi, &priv->adap_emac->MACADDRHI);
> +	writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
> +	       &priv->adap_emac->MACADDRLO);
> +
> +	/* Set source MAC address - REQUIRED */
> +	writel(mac_hi, &priv->adap_emac->MACSRCADDRHI);
> +	writel(mac_lo, &priv->adap_emac->MACSRCADDRLO);
> +
> +	/* Set DMA 8 TX / 8 RX Head pointers to 0 */
> +	addr = &priv->adap_emac->TX0HDP;
> +	for(cnt = 0; cnt < 16; cnt++)
> +		*addr++ = 0;
> +
> +	addr = &priv->adap_emac->RX0HDP;
> +	for(cnt = 0; cnt < 16; cnt++)
> +		*addr++ = 0;
> +
> +	/* Clear Statistics (do this before setting MacControl register) */
> +	addr = &priv->adap_emac->RXGOODFRAMES;
> +	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
> +		*addr++ = 0;
> +
> +	/* No multicast addressing */
> +	writel(0, &priv->adap_emac->MACHASH1);
> +	writel(0, &priv->adap_emac->MACHASH2);
> +
> +	writel(0x01, &priv->adap_emac->TXCONTROL);
> +	writel(0x01, &priv->adap_emac->RXCONTROL);
> +
> +	/* Create RX queue and set receive process in place */
> +	priv->emac_rx_active_head = priv->emac_rx_desc;
> +	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
> +		rx_desc->next = BD_TO_HW(rx_desc + 1);
> +		rx_desc->buffer = &priv->emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
> +		rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
> +		rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
> +		rx_desc++;
> +	}
> +
> +	/* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
> +	rx_desc--;
> +	rx_desc->next = 0;
> +	priv->emac_rx_active_tail = rx_desc;
> +	priv->emac_rx_queue_active = 1;
> +
> +	/* Enable TX/RX */
> +	writel(EMAC_MAX_ETHERNET_PKT_SIZE, &priv->adap_emac->RXMAXLEN);
> +	writel(0, &priv->adap_emac->RXBUFFEROFFSET);
> +
> +	/* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
> +	writel(EMAC_RXMBPENABLE_RXBROADEN, &priv->adap_emac->RXMBPENABLE);
> +
> +	/* Enable ch 0 only */
> +	writel(0x01, &priv->adap_emac->RXUNICASTSET);
> +
> +	/* Enable MII interface and full duplex mode (using RMMI) */
> +	writel((EMAC_MACCONTROL_MIIEN_ENABLE |
> +		EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
> +		EMAC_MACCONTROL_RMIISPEED_100),
> +	       &priv->adap_emac->MACCONTROL);
> +
> +	/* Init MDIO & get link state */
> +	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
> +	writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
> +		&priv->adap_mdio->CONTROL);
> +
> +	/* Start receive process */
> +	writel(BD_TO_HW(priv->emac_rx_desc), &priv->adap_emac->RX0HDP);
> +
> +	ret = miidev_wait_aneg(&priv->miidev);
> +	if (ret)
> +		return ret;
> +
> +	ret = miidev_get_status(&priv->miidev);
> +	if (ret < 0)
> +		return ret;
> +
> +	miidev_print_status(&priv->miidev);
> +
> +	dev_dbg(priv->dev, "- emac_open\n");
> +
> +	return 0;
> +}
> +
> +/* EMAC Channel Teardown */
> +static void davinci_eth_ch_teardown(struct davinci_emac_priv *priv, int ch)
> +{
> +	dv_reg		dly = 0xff;
> +	dv_reg		cnt;
> +
> +	dev_dbg(priv->dev, "+ emac_ch_teardown\n");
> +
> +	if (ch == EMAC_CH_TX) {
> +		/* Init TX channel teardown */
> +		writel(0, &priv->adap_emac->TXTEARDOWN);
> +		for(cnt = 0; cnt != 0xfffffffc; cnt = readl(&priv->adap_emac->TX0CP)) {
> +			/* Wait here for Tx teardown completion interrupt to occur
> +			 * Note: A task delay can be called here to pend rather than
> +			 * occupying CPU cycles - anyway it has been found that teardown
> +			 * takes very few cpu cycles and does not affect functionality */
> +			 dly--;
> +			 udelay(1);
> +			 if (dly == 0)
> +				break;
> +		}
> +		writel(cnt, &priv->adap_emac->TX0CP);
> +		writel(0, &priv->adap_emac->TX0HDP);
> +	} else {
> +		/* Init RX channel teardown */
> +		writel(0, &priv->adap_emac->RXTEARDOWN);
> +		for(cnt = 0; cnt != 0xfffffffc; cnt = readl(&priv->adap_emac->RX0CP)) {
> +			/* Wait here for Rx teardown completion interrupt to occur
> +			 * Note: A task delay can be called here to pend rather than
> +			 * occupying CPU cycles - anyway it has been found that teardown
> +			 * takes very few cpu cycles and does not affect functionality */
> +			 dly--;
> +			 udelay(1);
> +			 if (dly == 0)
> +				break;
> +		}
> +		writel(cnt, &priv->adap_emac->RX0CP);
> +		writel(0, &priv->adap_emac->RX0HDP);
> +	}
> +
> +	dev_dbg(priv->dev, "- emac_ch_teardown\n");
> +}
> +
> +static void davinci_emac_halt(struct eth_device *edev)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +
> +	dev_dbg(priv->dev, "+ emac_halt\n");
> +
> +	davinci_eth_ch_teardown(priv, EMAC_CH_TX);	/* TX Channel teardown */
> +	davinci_eth_ch_teardown(priv, EMAC_CH_RX);	/* RX Channel teardown */
> +
> +	/* Reset EMAC module and disable interrupts in wrapper */
> +	writel(1, &priv->adap_emac->SOFTRESET);
> +	writel(1, &priv->adap_ewrap->softrst);
> +
> +	writel(0, &priv->adap_ewrap->c0rxen);
> +	writel(0, &priv->adap_ewrap->c1rxen);
> +	writel(0, &priv->adap_ewrap->c2rxen);
> +	writel(0, &priv->adap_ewrap->c0txen);
> +	writel(0, &priv->adap_ewrap->c1txen);
> +	writel(0, &priv->adap_ewrap->c2txen);
> +	writel(0, &priv->adap_ewrap->c0miscen);
> +	writel(0, &priv->adap_ewrap->c1miscen);
> +	writel(0, &priv->adap_ewrap->c2miscen);
> +
> +	dev_dbg(priv->dev, "- emac_halt\n");
> +}
> +
> +/*
> + * This function sends a single packet on the network and returns
> + * positive number (number of bytes transmitted) or negative for error
> + */
> +static int davinci_emac_send(struct eth_device *edev, void *packet, int length)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +	uint64_t start = 0;
> +	int ret_status = -1;
> +
> +	dev_dbg(priv->dev, "+ emac_send (length %d)\n", length);
> +
> +	/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
> +	if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
> +		length = EMAC_MIN_ETHERNET_PKT_SIZE;
> +	}
> +
> +	/* Populate the TX descriptor */
> +	writel(0, &priv->emac_tx_desc->next);
> +	writel((u_int8_t *) packet, &priv->emac_tx_desc->buffer);
> +	writel((length & 0xffff), &priv->emac_tx_desc->buff_off_len);
> +	writel(((length & 0xffff) | EMAC_CPPI_SOP_BIT |
> +				    EMAC_CPPI_OWNERSHIP_BIT |
> +				    EMAC_CPPI_EOP_BIT),
> +		&priv->emac_tx_desc->pkt_flag_len);
> +	dma_flush_range((ulong) packet, (ulong)packet + length);
> +	/* Send the packet */
> +	writel(BD_TO_HW(priv->emac_tx_desc), &priv->adap_emac->TX0HDP);
> +
> +	/* Wait for packet to complete or link down */
> +	start = get_time_ns();
> +	while (1) {
> +		if (readl(&priv->adap_emac->TXINTSTATRAW) & 0x01) {
> +			/* Acknowledge the TX descriptor */
> +			writel(BD_TO_HW(priv->emac_tx_desc), &priv->adap_emac->TX0CP);
> +			ret_status = length;
> +			break;
> +		}
> +	}
> +
> +	dev_dbg(priv->dev, "- emac_send (ret_status %i)\n", ret_status);
> +	return ret_status;
> +}
> +
> +/*
> + * This function handles receipt of a packet from the network
> + */
> +static int davinci_emac_recv(struct eth_device *edev)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +	emac_desc *rx_curr_desc;
> +	emac_desc *curr_desc;
> +	emac_desc *tail_desc;
> +	unsigned char *pkt;
> +	int status, len, ret = -1;
> +
> +	dev_dbg(priv->dev, "+ emac_recv\n");
> +
> +	rx_curr_desc = priv->emac_rx_active_head;
> +	status = readl(&rx_curr_desc->pkt_flag_len);
> +	if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
> +		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
> +			/* Error in packet - discard it and requeue desc */
> +			dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n");
> +		} else {
> +			pkt = (unsigned char *)readl(&rx_curr_desc->buffer);
> +			len = readl(&rx_curr_desc->buff_off_len) & 0xffff;
> +			dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len);
> +			dma_inv_range((ulong)pkt,
> +					(ulong)rx_curr_desc->buffer + len);
> +			net_receive(pkt, len);
> +			ret = len;
> +		}
> +
> +		/* Ack received packet descriptor */
> +		writel(BD_TO_HW(rx_curr_desc), &priv->adap_emac->RX0CP);
> +		curr_desc = rx_curr_desc;
> +		priv->emac_rx_active_head = HW_TO_BD(readl(&rx_curr_desc->next));
> +
> +		if (status & EMAC_CPPI_EOQ_BIT) {
> +			if (priv->emac_rx_active_head) {
> +				writel(BD_TO_HW(priv->emac_rx_active_head),
> +					&priv->adap_emac->RX0HDP);
> +			} else {
> +				priv->emac_rx_queue_active = 0;
> +				dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n");
> +			}
> +		}
> +
> +		/* Recycle RX descriptor */
> +		writel(EMAC_MAX_ETHERNET_PKT_SIZE, &rx_curr_desc->buff_off_len);
> +		writel(EMAC_CPPI_OWNERSHIP_BIT, &rx_curr_desc->pkt_flag_len);
> +		writel(0, &rx_curr_desc->next);
> +
> +		if (priv->emac_rx_active_head == 0) {
> +			dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n");
> +			priv->emac_rx_active_head = curr_desc;
> +			priv->emac_rx_active_tail = curr_desc;
> +			if (priv->emac_rx_queue_active != 0) {
> +				writel(BD_TO_HW(priv->emac_rx_active_head), &priv->adap_emac->RX0HDP);
> +				dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
> +				priv->emac_rx_queue_active = 1;
> +			}
> +		} else {
> +			tail_desc = priv->emac_rx_active_tail;
> +			priv->emac_rx_active_tail = curr_desc;
> +			writel(BD_TO_HW(curr_desc), &tail_desc->next);
> +			status = readl(&tail_desc->pkt_flag_len);
> +			if (status & EMAC_CPPI_EOQ_BIT) {
> +				writel(BD_TO_HW(curr_desc), &priv->adap_emac->RX0HDP);
> +				status &= ~EMAC_CPPI_EOQ_BIT;
> +				writel(status, &tail_desc->pkt_flag_len);
> +			}
> +		}
> +		return ret;
> +	}
> +
> +	dev_dbg(priv->dev, "- emac_recv\n");
> +
> +	return 0;
> +}
> +
> +static int davinci_emac_probe(struct device_d *dev)
> +{
> +	struct davinci_emac_priv *priv;
> +	int		i;
> +
> +	dev_dbg(dev, "+ emac_probe\n");
> +
> +	priv = xzalloc(sizeof(*priv));
> +	dev->priv = priv;
> +
> +	priv->dev = dev;
> +
> +	priv->adap_emac = (emac_regs *)EMAC_BASE_ADDR;
> +	priv->adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
> +	priv->adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
> +
> +	/* EMAC descriptors */
> +	priv->emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
> +	priv->emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
> +	priv->emac_rx_active_head = 0;
> +	priv->emac_rx_active_tail = 0;
> +	priv->emac_rx_queue_active = 0;
> +
> +	/* Receive packet buffers */
> +	priv->emac_rx_buffers = xmemalign(4096, EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN));
> +
> +	/* PHY address for a discovered PHY (0xff - not found) */
> +	priv->active_phy_addr = 0xff;
> +
> +	priv->edev.priv = priv;
> +	priv->edev.init = davinci_emac_init;
> +	priv->edev.open = davinci_emac_open;
> +	priv->edev.halt = davinci_emac_halt;
> +	priv->edev.send = davinci_emac_send;
> +	priv->edev.recv = davinci_emac_recv;
> +	priv->edev.get_ethaddr = davinci_emac_get_ethaddr;
> +	priv->edev.set_ethaddr = davinci_emac_set_ethaddr;
> +	priv->edev.parent = dev;
> +
> +	priv->regs = dev_request_mem_region(dev, 0);
> +
> +	davinci_eth_mdio_enable(priv);
> +
> +	for (i = 0; i < 256; i++) {
> +		if (priv->adap_mdio->ALIVE)
> +			break;
> +		udelay(1000);
> +	}
> +
> +	if (i >= 256) {
> +		dev_err(dev, "No ETH PHY detected!\n");
> +	}
> +
> +	priv->miidev.read = davinci_miidev_read;
> +	priv->miidev.write = davinci_miidev_write;
> +	priv->miidev.address = 0x01;
> +	priv->miidev.flags = MIIDEV_FORCE_LINK;
> +	priv->miidev.edev = &priv->edev;
> +	priv->miidev.parent = dev;
> +
> +	mii_register(&priv->miidev);
> +
> +	eth_register(&priv->edev);
> +
> +	dev_dbg(dev, "- emac_probe\n");
> +	return 0;
> +}
> +
> +static void davinci_emac_remove(struct device_d *dev)
> +{
> +	struct davinci_emac_priv *priv = dev->priv;
> +
> +	davinci_emac_halt(&priv->edev);
> +}
> +
> +static struct driver_d davinci_emac_driver = {
> +	.name   = "davinci_emac",
> +	.probe  = davinci_emac_probe,
> +	.remove = davinci_emac_remove,
> +};
> +
> +static int davinci_emac_register(void)
> +{
> +	register_driver(&davinci_emac_driver);
> +	return 0;
> +}
> +
> +device_initcall(davinci_emac_register);
> diff --git a/drivers/net/davinci_emac.h b/drivers/net/davinci_emac.h
> new file mode 100644
> index 0000000..4e97ce5
> --- /dev/null
> +++ b/drivers/net/davinci_emac.h
> @@ -0,0 +1,331 @@
> +/*
> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
> + *
> + * Based on:
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * dm644x_emac.h
> + *
> + * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
> + *
> + * Copyright (C) 2005 Texas Instruments.
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * 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.
> + * ----------------------------------------------------------------------------
> +
> + * Modifications:
> + * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot.
> + *
> + */
> +
> +#ifndef _DAVINCI_EMAC_H_
> +#define _DAVINCI_EMAC_H_
> +
> +/* PHY mask - set only those phy number bits where phy is/can be connected */
> +#define EMAC_MDIO_PHY_NUM           1
> +#define EMAC_MDIO_PHY_MASK          (1 << EMAC_MDIO_PHY_NUM)
> +
> +/* Ethernet Min/Max packet size */
> +#define EMAC_MIN_ETHERNET_PKT_SIZE	60
> +#define EMAC_MAX_ETHERNET_PKT_SIZE	1518
> +#define EMAC_PKT_ALIGN			18	/* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */
> +
> +/* Number of RX packet buffers
> + * NOTE: Only 1 buffer supported as of now
> + */
> +#define EMAC_MAX_RX_BUFFERS		10
> +
> +typedef unsigned int	dv_reg;
> +typedef unsigned int	*dv_reg_p;
> +
> +/***********************************************
> + ******** Internally used macros ***************
> + ***********************************************/
> +
> +#define EMAC_CH_TX			1
> +#define EMAC_CH_RX			0
> +
> +/* Each descriptor occupies 4 words, lets start RX desc's at 0 and
> + * reserve space for 64 descriptors max
> + */
> +#define EMAC_RX_DESC_BASE		0x0
> +#define EMAC_TX_DESC_BASE		0x1000
> +
> +/* EMAC Teardown value */
> +#define EMAC_TEARDOWN_VALUE		0xfffffffc
> +
> +/* MII Status Register */
> +#define MII_STATUS_REG			1
> +
> +/* Number of statistics registers */
> +#define EMAC_NUM_STATS			36
> +
> +
> +/* EMAC Descriptor */
> +typedef struct
> +{
> +	u_int32_t	next;		/* Pointer to next descriptor in chain */
> +	u_int8_t	*buffer;	/* Pointer to data buffer */
> +	u_int32_t	buff_off_len;	/* Buffer Offset(MSW) and Length(LSW) */
> +	u_int32_t	pkt_flag_len;	/* Packet Flags(MSW) and Length(LSW) */
> +} emac_desc;
> +
> +/* CPPI bit positions */
> +#define EMAC_CPPI_SOP_BIT		(0x80000000)
> +#define EMAC_CPPI_EOP_BIT		(0x40000000)
> +#define EMAC_CPPI_OWNERSHIP_BIT		(0x20000000)
> +#define EMAC_CPPI_EOQ_BIT		(0x10000000)
> +#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT	(0x08000000)
> +#define EMAC_CPPI_PASS_CRC_BIT		(0x04000000)
> +
> +#define EMAC_CPPI_RX_ERROR_FRAME	(0x03fc0000)
> +
> +#define EMAC_MACCONTROL_MIIEN_ENABLE		(0x20)
> +#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE	(0x1)
> +#define EMAC_MACCONTROL_GIGABIT_ENABLE		(1 << 7)
> +#define EMAC_MACCONTROL_GIGFORCE		(1 << 17)
> +#define EMAC_MACCONTROL_RMIISPEED_100		(1 << 15)
> +
> +#define EMAC_MAC_ADDR_MATCH		(1 << 19)
> +#define EMAC_MAC_ADDR_IS_VALID		(1 << 20)
> +
> +#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE	(0x200000)
> +#define EMAC_RXMBPENABLE_RXBROADEN	(0x2000)
> +
> +
> +#define MDIO_CONTROL_IDLE		(0x80000000)
> +#define MDIO_CONTROL_ENABLE		(0x40000000)
> +#define MDIO_CONTROL_FAULT_ENABLE	(0x40000)
> +#define MDIO_CONTROL_FAULT		(0x80000)
> +#define MDIO_USERACCESS0_GO		(0x80000000)
> +#define MDIO_USERACCESS0_WRITE_READ	(0x0)
> +#define MDIO_USERACCESS0_WRITE_WRITE	(0x40000000)
> +#define MDIO_USERACCESS0_ACK		(0x20000000)
> +
> +/* Ethernet MAC Registers Structure */
> +typedef struct  {
> +	dv_reg		TXIDVER;
> +	dv_reg		TXCONTROL;
> +	dv_reg		TXTEARDOWN;
> +	u_int8_t	RSVD0[4];
> +	dv_reg		RXIDVER;
> +	dv_reg		RXCONTROL;
> +	dv_reg		RXTEARDOWN;
> +	u_int8_t	RSVD1[100];
> +	dv_reg		TXINTSTATRAW;
> +	dv_reg		TXINTSTATMASKED;
> +	dv_reg		TXINTMASKSET;
> +	dv_reg		TXINTMASKCLEAR;
> +	dv_reg		MACINVECTOR;
> +	u_int8_t	RSVD2[12];
> +	dv_reg		RXINTSTATRAW;
> +	dv_reg		RXINTSTATMASKED;
> +	dv_reg		RXINTMASKSET;
> +	dv_reg		RXINTMASKCLEAR;
> +	dv_reg		MACINTSTATRAW;
> +	dv_reg		MACINTSTATMASKED;
> +	dv_reg		MACINTMASKSET;
> +	dv_reg		MACINTMASKCLEAR;
> +	u_int8_t	RSVD3[64];
> +	dv_reg		RXMBPENABLE;
> +	dv_reg		RXUNICASTSET;
> +	dv_reg		RXUNICASTCLEAR;
> +	dv_reg		RXMAXLEN;
> +	dv_reg		RXBUFFEROFFSET;
> +	dv_reg		RXFILTERLOWTHRESH;
> +	u_int8_t	RSVD4[8];
> +	dv_reg		RX0FLOWTHRESH;
> +	dv_reg		RX1FLOWTHRESH;
> +	dv_reg		RX2FLOWTHRESH;
> +	dv_reg		RX3FLOWTHRESH;
> +	dv_reg		RX4FLOWTHRESH;
> +	dv_reg		RX5FLOWTHRESH;
> +	dv_reg		RX6FLOWTHRESH;
> +	dv_reg		RX7FLOWTHRESH;
> +	dv_reg		RX0FREEBUFFER;
> +	dv_reg		RX1FREEBUFFER;
> +	dv_reg		RX2FREEBUFFER;
> +	dv_reg		RX3FREEBUFFER;
> +	dv_reg		RX4FREEBUFFER;
> +	dv_reg		RX5FREEBUFFER;
> +	dv_reg		RX6FREEBUFFER;
> +	dv_reg		RX7FREEBUFFER;
> +	dv_reg		MACCONTROL;
> +	dv_reg		MACSTATUS;
> +	dv_reg		EMCONTROL;
> +	dv_reg		FIFOCONTROL;
> +	dv_reg		MACCONFIG;
> +	dv_reg		SOFTRESET;
> +	u_int8_t	RSVD5[88];
> +	dv_reg		MACSRCADDRLO;
> +	dv_reg		MACSRCADDRHI;
> +	dv_reg		MACHASH1;
> +	dv_reg		MACHASH2;
> +	dv_reg		BOFFTEST;
> +	dv_reg		TPACETEST;
> +	dv_reg		RXPAUSE;
> +	dv_reg		TXPAUSE;
> +	u_int8_t	RSVD6[16];
> +	dv_reg		RXGOODFRAMES;
> +	dv_reg		RXBCASTFRAMES;
> +	dv_reg		RXMCASTFRAMES;
> +	dv_reg		RXPAUSEFRAMES;
> +	dv_reg		RXCRCERRORS;
> +	dv_reg		RXALIGNCODEERRORS;
> +	dv_reg		RXOVERSIZED;
> +	dv_reg		RXJABBER;
> +	dv_reg		RXUNDERSIZED;
> +	dv_reg		RXFRAGMENTS;
> +	dv_reg		RXFILTERED;
> +	dv_reg		RXQOSFILTERED;
> +	dv_reg		RXOCTETS;
> +	dv_reg		TXGOODFRAMES;
> +	dv_reg		TXBCASTFRAMES;
> +	dv_reg		TXMCASTFRAMES;
> +	dv_reg		TXPAUSEFRAMES;
> +	dv_reg		TXDEFERRED;
> +	dv_reg		TXCOLLISION;
> +	dv_reg		TXSINGLECOLL;
> +	dv_reg		TXMULTICOLL;
> +	dv_reg		TXEXCESSIVECOLL;
> +	dv_reg		TXLATECOLL;
> +	dv_reg		TXUNDERRUN;
> +	dv_reg		TXCARRIERSENSE;
> +	dv_reg		TXOCTETS;
> +	dv_reg		FRAME64;
> +	dv_reg		FRAME65T127;
> +	dv_reg		FRAME128T255;
> +	dv_reg		FRAME256T511;
> +	dv_reg		FRAME512T1023;
> +	dv_reg		FRAME1024TUP;
> +	dv_reg		NETOCTETS;
> +	dv_reg		RXSOFOVERRUNS;
> +	dv_reg		RXMOFOVERRUNS;
> +	dv_reg		RXDMAOVERRUNS;
> +	u_int8_t	RSVD7[624];
> +	dv_reg		MACADDRLO;
> +	dv_reg		MACADDRHI;
> +	dv_reg		MACINDEX;
> +	u_int8_t	RSVD8[244];
> +	dv_reg		TX0HDP;
> +	dv_reg		TX1HDP;
> +	dv_reg		TX2HDP;
> +	dv_reg		TX3HDP;
> +	dv_reg		TX4HDP;
> +	dv_reg		TX5HDP;
> +	dv_reg		TX6HDP;
> +	dv_reg		TX7HDP;
> +	dv_reg		RX0HDP;
> +	dv_reg		RX1HDP;
> +	dv_reg		RX2HDP;
> +	dv_reg		RX3HDP;
> +	dv_reg		RX4HDP;
> +	dv_reg		RX5HDP;
> +	dv_reg		RX6HDP;
> +	dv_reg		RX7HDP;
> +	dv_reg		TX0CP;
> +	dv_reg		TX1CP;
> +	dv_reg		TX2CP;
> +	dv_reg		TX3CP;
> +	dv_reg		TX4CP;
> +	dv_reg		TX5CP;
> +	dv_reg		TX6CP;
> +	dv_reg		TX7CP;
> +	dv_reg		RX0CP;
> +	dv_reg		RX1CP;
> +	dv_reg		RX2CP;
> +	dv_reg		RX3CP;
> +	dv_reg		RX4CP;
> +	dv_reg		RX5CP;
> +	dv_reg		RX6CP;
> +	dv_reg		RX7CP;
> +} emac_regs;
> +
> +/* EMAC Wrapper Registers Structure */
> +typedef struct  {
> +#ifdef DAVINCI_EMAC_VERSION2
> +	dv_reg		idver;
> +	dv_reg		softrst;
> +	dv_reg		emctrl;
> +	dv_reg		c0rxthreshen;
> +	dv_reg		c0rxen;
> +	dv_reg		c0txen;
> +	dv_reg		c0miscen;
> +	dv_reg		c1rxthreshen;
> +	dv_reg		c1rxen;
> +	dv_reg		c1txen;
> +	dv_reg		c1miscen;
> +	dv_reg		c2rxthreshen;
> +	dv_reg		c2rxen;
> +	dv_reg		c2txen;
> +	dv_reg		c2miscen;
> +	dv_reg		c0rxthreshstat;
> +	dv_reg		c0rxstat;
> +	dv_reg		c0txstat;
> +	dv_reg		c0miscstat;
> +	dv_reg		c1rxthreshstat;
> +	dv_reg		c1rxstat;
> +	dv_reg		c1txstat;
> +	dv_reg		c1miscstat;
> +	dv_reg		c2rxthreshstat;
> +	dv_reg		c2rxstat;
> +	dv_reg		c2txstat;
> +	dv_reg		c2miscstat;
> +	dv_reg		c0rximax;
> +	dv_reg		c0tximax;
> +	dv_reg		c1rximax;
> +	dv_reg		c1tximax;
> +	dv_reg		c2rximax;
> +	dv_reg		c2tximax;
> +#else
> +	u_int8_t	RSVD0[4100];
> +	dv_reg		EWCTL;
> +	dv_reg		EWINTTCNT;
> +#endif
> +} ewrap_regs;
> +
> +/* EMAC MDIO Registers Structure */
> +typedef struct  {
> +	dv_reg		VERSION;
> +	dv_reg		CONTROL;
> +	dv_reg		ALIVE;
> +	dv_reg		LINK;
> +	dv_reg		LINKINTRAW;
> +	dv_reg		LINKINTMASKED;
> +	u_int8_t	RSVD0[8];
> +	dv_reg		USERINTRAW;
> +	dv_reg		USERINTMASKED;
> +	dv_reg		USERINTMASKSET;
> +	dv_reg		USERINTMASKCLEAR;
> +	u_int8_t	RSVD1[80];
> +	dv_reg		USERACCESS0;
> +	dv_reg		USERPHYSEL0;
> +	dv_reg		USERACCESS1;
> +	dv_reg		USERPHYSEL1;
> +} mdio_regs;
> +
> +typedef struct
> +{
> +	char	name[64];
> +	int	(*init)(int phy_addr);
> +	int	(*is_phy_connected)(int phy_addr);
> +	int	(*get_link_speed)(int phy_addr);
> +	int	(*auto_negotiate)(int phy_addr);
> +} phy_t;
> +
> +#endif  /* _DAVINCI_EMAC_H_ */
> -- 
> 1.7.10.4
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs
  2012-09-03 11:46 ` [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
@ 2012-09-03 16:32   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-04  8:58   ` Sascha Hauer
  1 sibling, 0 replies; 23+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-03 16:32 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On 13:46 Mon 03 Sep     , Jan Luebbe wrote:
> Also create devices for OMAP3.
> 
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  arch/arm/mach-omap/include/mach/mcspi.h         |   11 +
>  arch/arm/mach-omap/include/mach/omap3-devices.h |   34 ++
>  drivers/spi/Kconfig                             |    6 +
>  drivers/spi/Makefile                            |    1 +
>  drivers/spi/omap3_spi.c                         |  403 +++++++++++++++++++++++
>  drivers/spi/omap3_spi.h                         |  100 ++++++
>  6 files changed, 555 insertions(+)
>  create mode 100644 arch/arm/mach-omap/include/mach/mcspi.h
>  create mode 100644 arch/arm/mach-omap/include/mach/omap3-devices.h
>  create mode 100644 drivers/spi/omap3_spi.c
>  create mode 100644 drivers/spi/omap3_spi.h
> 
> diff --git a/arch/arm/mach-omap/include/mach/mcspi.h b/arch/arm/mach-omap/include/mach/mcspi.h
> new file mode 100644
> index 0000000..dbde67a
> --- /dev/null
> +++ b/arch/arm/mach-omap/include/mach/mcspi.h
> @@ -0,0 +1,11 @@
> +#ifndef __OMAP_MCSPI_H
> +#define  __OMAP_MCSPI_H
> +
> +#define OMAP3_MCSPI1_BASE	0x48098000
> +#define OMAP3_MCSPI2_BASE	0x4809A000
> +#define OMAP3_MCSPI3_BASE	0x480B8000
> +#define OMAP3_MCSPI4_BASE	0x480BA000
> +
> +int mcspi_devices_init(void);
> +
> +#endif /* __OMAP_MCSPI_H */
> diff --git a/arch/arm/mach-omap/include/mach/omap3-devices.h b/arch/arm/mach-omap/include/mach/omap3-devices.h
> new file mode 100644
> index 0000000..2db8583
> --- /dev/null
> +++ b/arch/arm/mach-omap/include/mach/omap3-devices.h
> @@ -0,0 +1,34 @@
> +#include <driver.h>
> +#include <sizes.h>
> +
> +#include <mach/mcspi.h>
> +
> +/* the device numbering is the same as in the device tree */
> +
this avoid duplicaation

static inline struct device_d *omap3_add_spi(int id, resource_t start)
{
	return add_generic_device("omap3_spi", id, NULL, start, SZ_4K,
				   IORESOURCE_MEM, NULL);
}

static inline struct device_d *omap3_add_spi1(void)
{
	return omap3_add_spi(1, OMAP3_MCSPI1_BASE);
}

static inline struct device_d *omap3_add_spi2(void)
{
	return omap3_add_spi(2, OMAP3_MCSPI2_BASE);
}
...


really DROP this struct way to describe the register it's too much dangerous
to modiffy and maintian

Best Regards,
J.
> +static inline struct device_d *omap3_add_spi1(void)
> +{
> +	return add_generic_device("omap3_spi", 1, NULL,
> +				   OMAP3_MCSPI1_BASE, SZ_4K,
> +				   IORESOURCE_MEM, NULL);
> +}
> +
> +static inline struct device_d *omap3_add_spi2(void)
> +{
> +	return add_generic_device("omap3_spi", 2, NULL,
> +				   OMAP3_MCSPI2_BASE, SZ_4K,
> +				   IORESOURCE_MEM, NULL);
> +}
> +
> +static inline struct device_d *omap3_add_spi3(void)
> +{
> +	return add_generic_device("omap3_spi", 3, NULL,
> +				   OMAP3_MCSPI3_BASE, SZ_4K,
> +				   IORESOURCE_MEM, NULL);
> +}
> +
> +static inline struct device_d *omap3_add_spi4(void)
> +{
> +	return add_generic_device("omap3_spi", 4, NULL,
> +				   OMAP3_MCSPI4_BASE, SZ_4K,
> +				   IORESOURCE_MEM, NULL);
> +}
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index a249b81..ba1b948 100644
> --- a/drivers/spi/Kconfig
> +++ b/drivers/spi/Kconfig
> @@ -34,4 +34,10 @@ config DRIVER_SPI_ATMEL
>  	depends on ARCH_AT91
>  	depends on SPI
>  
> +
> +config DRIVER_SPI_OMAP3
> +	bool "OMAP3 McSPI Master driver"
> +	depends on ARCH_OMAP3
> +	depends on SPI
> +
>  endmenu
> diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
> index 101652f..b53061e 100644
> --- a/drivers/spi/Makefile
> +++ b/drivers/spi/Makefile
> @@ -2,3 +2,4 @@ obj-$(CONFIG_SPI) += spi.o
>  obj-$(CONFIG_DRIVER_SPI_IMX) += imx_spi.o
>  obj-$(CONFIG_DRIVER_SPI_ALTERA) += altera_spi.o
>  obj-$(CONFIG_DRIVER_SPI_ATMEL) += atmel_spi.o
> +obj-$(CONFIG_DRIVER_SPI_OMAP3) += omap3_spi.o
> diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
> new file mode 100644
> index 0000000..eadb78d
> --- /dev/null
> +++ b/drivers/spi/omap3_spi.c
> @@ -0,0 +1,403 @@
> +/*
> + * Copyright (C) 2012 Jan Luebbe <j.luebbe@pengutronix.de>
> + *
> + * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
> + *
> + * Driver for McSPI controller on OMAP3. Based on davinci_spi.c
> + * Copyright (C) 2009 Texas Instruments Incorporated - http://www.ti.com/
> + *
> + * Copyright (C) 2007 Atmel Corporation
> + *
> + * Parts taken from linux/drivers/spi/omap2_mcspi.c
> + * Copyright (C) 2005, 2006 Nokia Corporation
> + *
> + * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.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 <common.h>
> +#include <init.h>
> +#include <driver.h>
> +#include <errno.h>
> +#include <spi/spi.h>
> +#include <malloc.h>
> +#include <io.h>
> +#include "omap3_spi.h"
> +
> +#define WORD_LEN	8
> +#define SPI_WAIT_TIMEOUT 30000000
> +
> +#define SPI_XFER_BEGIN  0x01                    /* Assert CS before transfer */
> +#define SPI_XFER_END    0x02                    /* Deassert CS after transfer */
> +
> +static void spi_reset(struct spi_master *master)
> +{
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	unsigned int tmp;
> +
> +	writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &regs->sysconfig);
> +	do {
> +		tmp = readl(&regs->sysstatus);
> +	} while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
> +
> +	writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
> +				 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
> +				 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE,
> +				 &regs->sysconfig);
> +
> +	writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &regs->wakeupenable);
> +}
> +
> +int spi_claim_bus(struct spi_device *spi)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	unsigned int conf, div = 0;
> +
> +	/* McSPI global module configuration */
> +
> +	/*
> +	 * setup when switching from (reset default) slave mode
> +	 * to single-channel master mode
> +	 */
> +	conf = readl(&regs->modulctrl);
> +	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
> +	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
> +	writel(conf, &regs->modulctrl);
> +
> +	/* McSPI individual channel configuration */
> +
> +	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
> +	if (spi->max_speed_hz) {
> +		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
> +					 > spi->max_speed_hz)
> +			div++;
> +	} else
> +		div = 0xC;
> +
> +	conf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +	/* standard 4-wire master mode:	SCK, MOSI/out, MISO/in, nCS
> +	 * REVISIT: this controller could support SPI_3WIRE mode.
> +	 */
> +	conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
> +	conf |= OMAP3_MCSPI_CHCONF_DPE0;
> +
> +	/* wordlength */
> +	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
> +	conf |= (WORD_LEN - 1) << 7;
> +
> +	/* set chipselect polarity; manage with FORCE */
> +	if (!(spi->mode & SPI_CS_HIGH))
> +		conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
> +	else
> +		conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
> +
> +	/* set clock divisor */
> +	conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
> +	conf |= div << 2;
> +
> +	/* set SPI mode 0..3 */
> +	if (spi->mode & SPI_CPOL)
> +		conf |= OMAP3_MCSPI_CHCONF_POL;
> +	else
> +		conf &= ~OMAP3_MCSPI_CHCONF_POL;
> +	if (spi->mode & SPI_CPHA)
> +		conf |= OMAP3_MCSPI_CHCONF_PHA;
> +	else
> +		conf &= ~OMAP3_MCSPI_CHCONF_PHA;
> +
> +	/* Transmit & receive mode */
> +	conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
> +
> +	writel(conf, &regs->channel[spi->chip_select].chconf);
> +	readl(&regs->channel[spi->chip_select].chconf);
> +
> +	return 0;
> +}
> +
> +int omap3_spi_write(struct spi_device *spi, unsigned int len, const u8 *txp,
> +		    unsigned long flags)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	int i;
> +	int timeout = SPI_WAIT_TIMEOUT;
> +	int chconf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +	if (flags & SPI_XFER_BEGIN)
> +		writel(OMAP3_MCSPI_CHCTRL_EN,
> +		       &regs->channel[spi->chip_select].chctrl);
> +
> +	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
> +	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
> +	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
> +	writel(chconf, &regs->channel[spi->chip_select].chconf);
> +	readl(&regs->channel[spi->chip_select].chconf);
> +
> +	for (i = 0; i < len; i++) {
> +		/* wait till TX register is empty (TXS == 1) */
> +		while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_TXS)) {
> +			if (--timeout <= 0) {
> +				printf("SPI TXS timed out, status=0x%08x\n",
> +				       readl(&regs->channel[spi->chip_select].chstat));
> +				return -1;
> +			}
> +		}
> +		/* Write the data */
> +		writel(txp[i], &regs->channel[spi->chip_select].tx);
> +	}
> +
> +	if (flags & SPI_XFER_END) {
> +		/* wait to finish of transfer */
> +		while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_EOT));
> +
> +		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
> +		writel(chconf, &regs->channel[spi->chip_select].chconf);
> +
> +		writel(0, &regs->channel[spi->chip_select].chctrl);
> +	}
> +
> +	while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_TXS));
> +	while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_EOT));
> +
> +	return 0;
> +}
> +
> +int omap3_spi_read(struct spi_device *spi, unsigned int len, u8 *rxp,
> +		   unsigned long flags)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	int i;
> +	int timeout = SPI_WAIT_TIMEOUT;
> +	int chconf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +	if (flags & SPI_XFER_BEGIN)
> +		writel(OMAP3_MCSPI_CHCTRL_EN,
> +		       &regs->channel[spi->chip_select].chctrl);
> +
> +	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
> +	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
> +	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
> +	writel(chconf, &regs->channel[spi->chip_select].chconf);
> +	readl(&regs->channel[spi->chip_select].chconf);
> +	writel(0, &regs->channel[spi->chip_select].tx);
> +
> +	for (i = 0; i < len; i++) {
> +		/* Wait till RX register contains data (RXS == 1) */
> +		while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_RXS)) {
> +			if (--timeout <= 0) {
> +				printf("SPI RXS timed out, status=0x%08x\n",
> +				       readl(&regs->channel[spi->chip_select].chstat));
> +				return -1;
> +			}
> +		}
> +		/* Read the data */
> +		rxp[i] = readl(&regs->channel[spi->chip_select].rx);
> +	}
> +
> +	if (flags & SPI_XFER_END) {
> +		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
> +		writel(chconf, &regs->channel[spi->chip_select].chconf);
> +		readl(&regs->channel[spi->chip_select].chconf);
> +
> +		writel(0, &regs->channel[spi->chip_select].chctrl);
> +	}
> +
> +	return 0;
> +}
> +
> +int spi_xfer(struct spi_device *spi, struct spi_transfer *t, unsigned long flags)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	unsigned int    len = t->len;
> +	int             ret = -1;
> +	const u8        *txp = t->tx_buf; /* can be NULL for read operation */
> +	u8              *rxp = t->rx_buf; /* can be NULL for write operation */
> +
> +	if (len == 0) {	 /* only change CS */
> +		int chconf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +		if (flags & SPI_XFER_BEGIN) {
> +			writel(OMAP3_MCSPI_CHCTRL_EN,
> +			       &regs->channel[spi->chip_select].chctrl);
> +			chconf |= OMAP3_MCSPI_CHCONF_FORCE;
> +			writel(chconf,
> +			       &regs->channel[spi->chip_select].chconf);
> +			readl(&regs->channel[spi->chip_select].chconf);
> +		}
> +
> +		if (flags & SPI_XFER_END) {
> +			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
> +			writel(chconf,
> +			       &regs->channel[spi->chip_select].chconf);
> +			writel(0, &regs->channel[spi->chip_select].chctrl);
> +			readl(&regs->channel[spi->chip_select].chconf);
> +		}
> +
> +		ret = 0;
> +	} else {
> +		if (t->tx_buf != NULL)
> +			ret = omap3_spi_write(spi, len, txp, flags);
> +
> +		if (t->rx_buf != NULL)
> +			ret = omap3_spi_read(spi, len, rxp, flags);
> +	}
> +	return ret;
> +}
> +
> +static int omap3_spi_transfer(struct spi_device *spi, struct spi_message *mesg)
> +{
> +	struct spi_master *master = spi->master;
> +	struct spi_transfer *t, *t_first, *t_last = NULL;
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	ret = spi_claim_bus(spi);
> +	if (ret)
> +		return ret;
> +
> +	if (list_empty(&mesg->transfers))
> +		return 0;
> +
> +	t_first = list_first_entry(&mesg->transfers, struct spi_transfer, transfer_list);
> +	t_last = list_last_entry(&mesg->transfers, struct spi_transfer, transfer_list);
> +
> +	mesg->actual_length = 0;
> +
> +	dev_dbg(master->dev, "transfer start actual_length=%i\n", mesg->actual_length);
> +	list_for_each_entry(t, &mesg->transfers, transfer_list) {
> +		dev_dbg(master->dev,
> +			"  xfer %p: len %u tx %p rx %p\n",
> +			t, t->len, t->tx_buf, t->rx_buf);
> +		flags = 0;
> +		if (t == t_first)
> +			flags |= SPI_XFER_BEGIN;
> +		if (t == t_last)
> +			flags |= SPI_XFER_END;
> +		spi_xfer(spi, t, flags);
> +		mesg->actual_length += t->len;
> +	}
> +	dev_dbg(master->dev, "transfer done actual_length=%i\n", mesg->actual_length);
> +
> +	return ret;
> +}
> +
> +static int omap3_spi_setup(struct spi_device *spi)
> +{
> +	struct spi_master *master = spi->master;
> +
> +	if (((master->bus_num == 0) && (spi->chip_select > 3)) ||
> +			((master->bus_num == 1) && (spi->chip_select > 1)) ||
> +			((master->bus_num == 2) && (spi->chip_select > 1)) ||
> +			((master->bus_num == 3) && (spi->chip_select > 0))) {
> +		printf("SPI error: unsupported chip select %i \
> +			on bus %i\n", spi->chip_select, master->bus_num);
> +		return -1;
> +	}
> +
> +	if (spi->max_speed_hz > OMAP3_MCSPI_MAX_FREQ) {
> +		printf("SPI error: unsupported frequency %i Hz. \
> +			Max frequency is 48 Mhz\n", spi->max_speed_hz);
> +		return -1;
> +	}
> +
> +	if (spi->mode > SPI_MODE_3) {
> +		printf("SPI error: unsupported SPI mode %i\n", spi->mode);
> +		return -1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int omap3_spi_probe(struct device_d *dev)
> +{
> +	struct spi_master *master;
> +	struct omap3_spi_master *omap3_master;
> +
> +	omap3_master = xzalloc(sizeof(*omap3_master));
> +
> +	master = &omap3_master->master;
> +	master->dev = dev;
> +
> +	/*
> +	 * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
> +	 * with different number of chip selects (CS, channels):
> +	 * McSPI1 has 4 CS (bus 0, cs 0 - 3)
> +	 * McSPI2 has 2 CS (bus 1, cs 0 - 1)
> +	 * McSPI3 has 2 CS (bus 2, cs 0 - 1)
> +	 * McSPI4 has 1 CS (bus 3, cs 0)
> +	 */
> +
> +	master->bus_num = dev->id;
> +	switch (master->bus_num) {
> +	case 1:
> +		master->num_chipselect = 4;
> +		break;
> +	case 2:
> +		master->num_chipselect = 2;
> +		break;
> +	case 3:
> +		master->num_chipselect = 2;
> +		break;
> +	case 4:
> +		master->num_chipselect = 1;
> +		break;
> +	default:
> +		printf("SPI error: unsupported bus %i. \
> +			Supported busses 1 - 4\n", master->bus_num);
> +		return -ENODEV;
> +	}
> +	master->setup = omap3_spi_setup;
> +	master->transfer = omap3_spi_transfer;
> +
> +	omap3_master->regs = (struct mcspi *)dev_request_mem_region(dev, 0);;
> +
> +	spi_reset(master);
> +
> +	spi_register_master(master);
> +
> +	return 0;
> +}
> +
> +static struct driver_d omap3_spi_driver = {
> +	.name = "omap3_spi",
> +	.probe = omap3_spi_probe,
> +};
> +
> +static int omap3_spi_init(void)
> +{
> +	return register_driver(&omap3_spi_driver);
> +}
> +
> +device_initcall(omap3_spi_init);
> diff --git a/drivers/spi/omap3_spi.h b/drivers/spi/omap3_spi.h
> new file mode 100644
> index 0000000..2ad8ef7
> --- /dev/null
> +++ b/drivers/spi/omap3_spi.h
> @@ -0,0 +1,100 @@
> +/*
> + * Register definitions for the OMAP3 McSPI Controller
> + *
> + * Copyright (C) 2010 Dirk Behme <dirk.behme@googlemail.com>
> + *
> + * Parts taken from linux/drivers/spi/omap2_mcspi.c
> + * Copyright (C) 2005, 2006 Nokia Corporation
> + *
> + * Modified by Ruslan Araslanov <ruslan.araslanov@vitecmm.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
> + */
> +
> +#ifndef _OMAP3_SPI_H_
> +#define _OMAP3_SPI_H_
> +
> +#define OMAP3_MCSPI_MAX_FREQ	48000000
> +
> +/* OMAP3 McSPI registers */
> +struct mcspi_channel {
> +	unsigned int chconf;		/* 0x2C, 0x40, 0x54, 0x68 */
> +	unsigned int chstat;		/* 0x30, 0x44, 0x58, 0x6C */
> +	unsigned int chctrl;		/* 0x34, 0x48, 0x5C, 0x70 */
> +	unsigned int tx;		/* 0x38, 0x4C, 0x60, 0x74 */
> +	unsigned int rx;		/* 0x3C, 0x50, 0x64, 0x78 */
> +};
> +
> +struct mcspi {
> +	unsigned char res1[0x10];
> +	unsigned int sysconfig;		/* 0x10 */
> +	unsigned int sysstatus;		/* 0x14 */
> +	unsigned int irqstatus;		/* 0x18 */
> +	unsigned int irqenable;		/* 0x1C */
> +	unsigned int wakeupenable;	/* 0x20 */
> +	unsigned int syst;		/* 0x24 */
> +	unsigned int modulctrl;		/* 0x28 */
> +	struct mcspi_channel channel[4]; /* channel0: 0x2C - 0x3C, bus 0 & 1 & 2 & 3 */
> +					/* channel1: 0x40 - 0x50, bus 0 & 1 */
> +					/* channel2: 0x54 - 0x64, bus 0 & 1 */
> +					/* channel3: 0x68 - 0x78, bus 0 */
> +};
> +
> +/* per-register bitmasks */
> +#define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3)
> +#define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP (1 << 2)
> +#define OMAP3_MCSPI_SYSCONFIG_AUTOIDLE	(1 << 0)
> +#define OMAP3_MCSPI_SYSCONFIG_SOFTRESET (1 << 1)
> +
> +#define OMAP3_MCSPI_SYSSTATUS_RESETDONE (1 << 0)
> +
> +#define OMAP3_MCSPI_MODULCTRL_SINGLE	(1 << 0)
> +#define OMAP3_MCSPI_MODULCTRL_MS	(1 << 2)
> +#define OMAP3_MCSPI_MODULCTRL_STEST	(1 << 3)
> +
> +#define OMAP3_MCSPI_CHCONF_PHA		(1 << 0)
> +#define OMAP3_MCSPI_CHCONF_POL		(1 << 1)
> +#define OMAP3_MCSPI_CHCONF_CLKD_MASK	(0x0f << 2)
> +#define OMAP3_MCSPI_CHCONF_EPOL		(1 << 6)
> +#define OMAP3_MCSPI_CHCONF_WL_MASK	(0x1f << 7)
> +#define OMAP3_MCSPI_CHCONF_TRM_RX_ONLY	(0x01 << 12)
> +#define OMAP3_MCSPI_CHCONF_TRM_TX_ONLY	(0x02 << 12)
> +#define OMAP3_MCSPI_CHCONF_TRM_MASK	(0x03 << 12)
> +#define OMAP3_MCSPI_CHCONF_DMAW		(1 << 14)
> +#define OMAP3_MCSPI_CHCONF_DMAR		(1 << 15)
> +#define OMAP3_MCSPI_CHCONF_DPE0		(1 << 16)
> +#define OMAP3_MCSPI_CHCONF_DPE1		(1 << 17)
> +#define OMAP3_MCSPI_CHCONF_IS		(1 << 18)
> +#define OMAP3_MCSPI_CHCONF_TURBO	(1 << 19)
> +#define OMAP3_MCSPI_CHCONF_FORCE	(1 << 20)
> +
> +#define OMAP3_MCSPI_CHSTAT_RXS		(1 << 0)
> +#define OMAP3_MCSPI_CHSTAT_TXS		(1 << 1)
> +#define OMAP3_MCSPI_CHSTAT_EOT		(1 << 2)
> +
> +#define OMAP3_MCSPI_CHCTRL_EN		(1 << 0)
> +
> +#define OMAP3_MCSPI_WAKEUPENABLE_WKEN	(1 << 0)
> +
> +struct omap3_spi_master {
> +	struct spi_master master;
> +	struct mcspi __iomem *regs;
> +};
> +
> +#endif /* _OMAP3_SPI_H_ */
> -- 
> 1.7.10.4
> 
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 06/10] omap: add SPI as a boot mode for xload
  2012-09-03 16:24   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-04  7:41     ` Jan Weitzel
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Weitzel @ 2012-09-04  7:41 UTC (permalink / raw)
  To: barebox

Am Montag, den 03.09.2012, 18:24 +0200 schrieb Jean-Christophe
PLAGNIOL-VILLARD:
> On 13:46 Mon 03 Sep     , Jan Luebbe wrote:
> > Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> you need to sync with 
> 
> 257     Aug27 Jan Weitzel     [RFC] xload: get barebox size from barebox_arm_head

read_image_head reads the size from partition. Could you try it?.
[PATCH v3] xload: get barebox size from barebox_arm_head

Jan



> Best Regards,
> J.
> 
> _______________________________________________
> barebox mailing list
> barebox@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/barebox



_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 02/10] drivers/nor/m25p80: add MEMGETINFO ioctl
  2012-09-03 11:45 ` [PATCH 02/10] drivers/nor/m25p80: add MEMGETINFO ioctl Jan Luebbe
@ 2012-09-04  8:20   ` Sascha Hauer
  0 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2012-09-04  8:20 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On Mon, Sep 03, 2012 at 01:45:57PM +0200, Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  drivers/nor/m25p80.c |   26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/nor/m25p80.c b/drivers/nor/m25p80.c
> index 61f2195..1722e0a 100644
> --- a/drivers/nor/m25p80.c
> +++ b/drivers/nor/m25p80.c
> @@ -20,6 +20,7 @@
>  #include <common.h>
>  #include <init.h>
>  #include <driver.h>
> +#include <ioctl.h>
>  #include <spi/spi.h>
>  #include <spi/flash.h>
>  #include <xfuncs.h>
> @@ -690,9 +691,34 @@ static const struct spi_device_id *jedec_probe(struct spi_device *spi)
>  	return NULL;
>  }
>  
> +static int m25p80_ioctl(struct cdev *cdev, int request, void *buf)
> +{
> +	struct m25p *flash = cdev->priv;
> +	struct flash_info *info = flash->info;
> +	struct mtd_info_user *user = buf;
> +
> +	switch (request) {
> +	case MEMGETINFO:
> +		memset(user, 0, sizeof(*user));
> +		user->type = MTD_NORFLASH;
> +		user->flags = MTD_CAP_NORFLASH;
> +		user->size = flash->size;
> +		user->erasesize = info->sector_size;
> +		user->writesize = 1;
> +		user->oobsize = 0;
> +		/* The below fields are obsolete */
> +		user->ecctype = -1;
> +		user->eccsize = 0;
> +		return 0;
> +	}
> +
> +	return -EINVAL;
> +}
> +
>  static struct file_operations m25p80_ops = {
>  	.read   = m25p80_read,
>  	.write  = m25p80_write,
> +	.ioctl  = m25p80_ioctl,

Rather than doing this you should simply fill in cdev->mtd. See how the
cfi flash driver does this. Then it will also work for partitions on a
m25p80.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 04/10] scripts: add tool to create image for SPI boot on AM35xx
  2012-09-03 11:45 ` [PATCH 04/10] scripts: add tool to create image for SPI boot on AM35xx Jan Luebbe
@ 2012-09-04  8:27   ` Sascha Hauer
  0 siblings, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2012-09-04  8:27 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On Mon, Sep 03, 2012 at 01:45:59PM +0200, Jan Luebbe wrote:
> Booting from SPI on an AM35xx (and possibly other TI SOCs) requires
> a special format:
> 
> - 32 bit image size in big-endian
> - 32 bit load address in big-endian
> - binary image converted from little- to big-endian
> 
> The mk-am35xx-spi-image tool converts barebox.bin to
> this format.
> 
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  arch/arm/Makefile             |    8 +++
>  arch/arm/mach-omap/Kconfig    |    7 +++
>  scripts/.gitignore            |    1 +
>  scripts/Makefile              |    2 +-
>  scripts/mk-am35xx-spi-image.c |  126 +++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 143 insertions(+), 1 deletion(-)
>  create mode 100644 scripts/mk-am35xx-spi-image.c
> 
> diff --git a/arch/arm/Makefile b/arch/arm/Makefile
> index 1b60261..ff96299 100644
> --- a/arch/arm/Makefile
> +++ b/arch/arm/Makefile
> @@ -199,6 +199,14 @@ endif
>  
>  all: $(KBUILD_IMAGE)
>  
> +barebox.spi: barebox.bin
> +	@echo "  SPI    " $@
> +	$(Q)scripts/mk-am35xx-spi-image barebox.bin > barebox.spi
> +
> +ifeq ($(CONFIG_OMAP_BUILD_SPI),y)
> +all: barebox.spi
> +endif
> +
>  archprepare: maketools
>  maketools:
>  	$(Q)$(MAKE) $(build)=arch/arm/tools include/generated/mach-types.h
> diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
> index d735284..a781287 100644
> --- a/arch/arm/mach-omap/Kconfig
> +++ b/arch/arm/mach-omap/Kconfig
> @@ -91,6 +91,13 @@ config OMAP_BUILD_IFT
>  	prompt "build ift binary"
>  	bool
>  
> +config OMAP_BUILD_SPI
> +	prompt "build SPI binary"
> +	bool
> +	help
> +	  Say Y here if you want to build an barebox.spi image as used
> +	  on the AM35xx chips when booting form SPI NOR flash.
> +
>  config ARCH_TEXT_BASE
>  	hex
>  	default 0x80e80000 if MACH_OMAP343xSDP
> diff --git a/scripts/.gitignore b/scripts/.gitignore
> index 6e63f85..3f1cbdb 100644
> --- a/scripts/.gitignore
> +++ b/scripts/.gitignore
> @@ -2,6 +2,7 @@ bareboxenv
>  bin2c
>  gen_netx_image
>  kallsyms
> +mk-am35xx-spi-image
>  mkimage
>  mkublheader
>  omap_signGP
> diff --git a/scripts/Makefile b/scripts/Makefile
> index 7ca5e29..55ccdac 100644
> --- a/scripts/Makefile
> +++ b/scripts/Makefile
> @@ -9,7 +9,7 @@ hostprogs-y                      += bin2c
>  hostprogs-y                      += mkimage
>  hostprogs-y                      += bareboxenv
>  hostprogs-$(CONFIG_ARCH_NETX)    += gen_netx_image
> -hostprogs-$(CONFIG_ARCH_OMAP)    += omap_signGP
> +hostprogs-$(CONFIG_ARCH_OMAP)    += omap_signGP mk-am35xx-spi-image
>  hostprogs-$(CONFIG_ARCH_S5PCxx)  += s5p_cksum
>  hostprogs-$(CONFIG_ARCH_DAVINCI) += mkublheader
>  
> diff --git a/scripts/mk-am35xx-spi-image.c b/scripts/mk-am35xx-spi-image.c
> new file mode 100644
> index 0000000..133f2b7
> --- /dev/null
> +++ b/scripts/mk-am35xx-spi-image.c
> @@ -0,0 +1,126 @@
> +/*
> + * mkublheader.c - produce the header needed to load barebox on OMAP-L138

We already have scripts/mkublheader.c:

/*
 * mkublheader.c - produce the header needed to load barebox on OMAP-L138
 */

This indeed seems to be a different tool. Can we clarify this a bit,
maybe by adding the purpose of the different tools to the header?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs
  2012-09-03 11:46 ` [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
  2012-09-03 16:27   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-04  8:42   ` Sascha Hauer
  1 sibling, 0 replies; 23+ messages in thread
From: Sascha Hauer @ 2012-09-04  8:42 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On Mon, Sep 03, 2012 at 01:46:03PM +0200, Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  arch/arm/mach-omap/include/mach/emac_defs.h |   53 +++
>  drivers/net/Kconfig                         |    5 +
>  drivers/net/Makefile                        |    1 +
>  drivers/net/davinci_emac.c                  |  619 +++++++++++++++++++++++++++
>  drivers/net/davinci_emac.h                  |  331 ++++++++++++++
>  5 files changed, 1009 insertions(+)
>  create mode 100644 arch/arm/mach-omap/include/mach/emac_defs.h
>  create mode 100644 drivers/net/davinci_emac.c
>  create mode 100644 drivers/net/davinci_emac.h
> 
> diff --git a/arch/arm/mach-omap/include/mach/emac_defs.h b/arch/arm/mach-omap/include/mach/emac_defs.h
> new file mode 100644
> index 0000000..ef930fc
> --- /dev/null
> +++ b/arch/arm/mach-omap/include/mach/emac_defs.h
> +struct davinci_emac_priv {
> +	struct device_d *dev;
> +	struct eth_device edev;
> +	struct mii_device miidev;
> +	void __iomem *regs;

This seems to be filled in in probe(), but otherwise unused.

> +
> +	/* EMAC Addresses */
> +	emac_regs	*adap_emac; /* = (emac_regs *)EMAC_BASE_ADDR; */
> +	ewrap_regs	*adap_ewrap; /* = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR; */
> +	mdio_regs	*adap_mdio; /* = (mdio_regs *)EMAC_MDIO_BASE_ADDR; */

These should be filled in by resources, not hardcoded addresses.

> +};
> +
> +/* davinci_eth_mac_addr[0] goes out on the wire first */
> +
> +static u_int8_t davinci_eth_mac_addr[] = { 0x00, 0xff, 0xff, 0xff, 0xff, 0x00 };

Add this to struct davinci_emac_priv

> +
> +/*
> + * This function must be called before emac_open() if you want to override
> + * the default mac address.
> + */
> +void davinci_eth_set_mac_addr(const u_int8_t *addr)

static please. If you intend to call this from somewhere else than this
file there is something wrong.

> +}
> +
> +/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
> +int davinci_eth_phy_read(struct davinci_emac_priv *priv, u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)

static

> +{
> +	int	tmp;
> +
> +	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
> +
> +	writel(MDIO_USERACCESS0_GO |
> +		MDIO_USERACCESS0_WRITE_READ |
> +		((reg_num & 0x1f) << 21) |
> +		((phy_addr & 0x1f) << 16),
> +		&priv->adap_mdio->USERACCESS0);
> +
> +	/* Wait for command to complete */
> +	while ((tmp = readl(&priv->adap_mdio->USERACCESS0)) & MDIO_USERACCESS0_GO);
> +
> +	if (tmp & MDIO_USERACCESS0_ACK) {
> +		*data = tmp & 0xffff;
> +		dev_dbg(priv->dev, "emac_phy_read: addr=0x%02x reg=0x%02x data=0x%04x\n",
> +			   phy_addr, reg_num, *data);
> +		return 1;
> +	}
> +
> +	*data = -1;
> +	return 0;
> +}
> +
> +/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
> +int davinci_eth_phy_write(struct davinci_emac_priv *priv, u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)

static

> +{
> +
> +	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
> +
> +	dev_dbg(priv->dev, "emac_phy_write: addr=0x%02x reg=0x%02x data=0x%04x\n",
> +		   phy_addr, reg_num, data);
> +	writel(MDIO_USERACCESS0_GO |
> +				MDIO_USERACCESS0_WRITE_WRITE |
> +				((reg_num & 0x1f) << 21) |
> +				((phy_addr & 0x1f) << 16) |
> +				(data & 0xffff),
> +		&priv->adap_mdio->USERACCESS0);
> +
> +	/* Wait for command to complete */
> +	while (readl(&priv->adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO);
> +
> +	return 1;
> +}
> +
> +static int davinci_miidev_read(struct mii_device *dev, int addr, int reg)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)dev->edev->priv;
> +	uint16_t value = 0;
> +	return davinci_eth_phy_read(priv, addr, reg, &value) ? value : -1;
> +}
> +
> +static int davinci_miidev_write(struct mii_device *dev, int addr, int reg, int value)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)dev->edev->priv;
> +	return davinci_eth_phy_write(priv, addr, reg, value) ? 0 : -1;
> +}
> +
> +static int davinci_emac_get_ethaddr(struct eth_device *edev, unsigned char *adr)
> +{
> +	return -1;
> +}
> +
> +static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *adr)
> +{
> +	davinci_eth_set_mac_addr(adr);
> +	return 0;
> +}
> +
> +static int davinci_emac_init(struct eth_device *edev)
> +{
> +	dev_dbg(&edev->dev, "* emac_init\n");
> +	return 0;
> +}
> +
> +static int davinci_emac_open(struct eth_device *edev)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +
> +	dv_reg_p	addr;
> +	u_int32_t	clkdiv, cnt;
> +	emac_desc	*rx_desc;
> +	unsigned long mac_hi, mac_lo;
> +	int ret;
> +
> +	dev_dbg(priv->dev, "+ emac_open\n");
> +
> +	dev_dbg(priv->dev, "emac->TXIDVER: 0x%08x\n", priv->adap_emac->TXIDVER);
> +	dev_dbg(priv->dev, "emac->RXIDVER: 0x%08x\n", priv->adap_emac->RXIDVER);
> +
> +	/* Reset EMAC module and disable interrupts in wrapper */
> +	writel(1, &priv->adap_emac->SOFTRESET);
> +	while (readl(&priv->adap_emac->SOFTRESET) != 0);
> +	writel(1, &priv->adap_ewrap->softrst);
> +	while (readl(&priv->adap_ewrap->softrst) != 0);
> +
> +	writel(0, &priv->adap_ewrap->c0rxen);
> +	writel(0, &priv->adap_ewrap->c1rxen);
> +	writel(0, &priv->adap_ewrap->c2rxen);
> +	writel(0, &priv->adap_ewrap->c0txen);
> +	writel(0, &priv->adap_ewrap->c1txen);
> +	writel(0, &priv->adap_ewrap->c2txen);
> +	writel(0, &priv->adap_ewrap->c0miscen);
> +	writel(0, &priv->adap_ewrap->c1miscen);
> +	writel(0, &priv->adap_ewrap->c2miscen);
> +
> +	rx_desc = priv->emac_rx_desc;
> +
> +	/*
> +	 * Set MAC Addresses & Init multicast Hash to 0 (disable any multicast
> +	 * receive)
> +	 * Use channel 0 only - other channels are disabled
> +	 */
> +	writel(0, &priv->adap_emac->MACINDEX);
> +	mac_hi = (davinci_eth_mac_addr[3] << 24) |
> +		 (davinci_eth_mac_addr[2] << 16) |
> +		 (davinci_eth_mac_addr[1] << 8)  |
> +		 (davinci_eth_mac_addr[0]);
> +	mac_lo = (davinci_eth_mac_addr[5] << 8) |
> +		 (davinci_eth_mac_addr[4]);
> +
> +	writel(mac_hi, &priv->adap_emac->MACADDRHI);
> +	writel(mac_lo | EMAC_MAC_ADDR_IS_VALID | EMAC_MAC_ADDR_MATCH,
> +	       &priv->adap_emac->MACADDRLO);
> +
> +	/* Set source MAC address - REQUIRED */
> +	writel(mac_hi, &priv->adap_emac->MACSRCADDRHI);
> +	writel(mac_lo, &priv->adap_emac->MACSRCADDRLO);
> +
> +	/* Set DMA 8 TX / 8 RX Head pointers to 0 */
> +	addr = &priv->adap_emac->TX0HDP;
> +	for(cnt = 0; cnt < 16; cnt++)
> +		*addr++ = 0;
> +
> +	addr = &priv->adap_emac->RX0HDP;
> +	for(cnt = 0; cnt < 16; cnt++)
> +		*addr++ = 0;
> +
> +	/* Clear Statistics (do this before setting MacControl register) */
> +	addr = &priv->adap_emac->RXGOODFRAMES;
> +	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
> +		*addr++ = 0;
> +
> +	/* No multicast addressing */
> +	writel(0, &priv->adap_emac->MACHASH1);
> +	writel(0, &priv->adap_emac->MACHASH2);
> +
> +	writel(0x01, &priv->adap_emac->TXCONTROL);
> +	writel(0x01, &priv->adap_emac->RXCONTROL);
> +
> +	/* Create RX queue and set receive process in place */
> +	priv->emac_rx_active_head = priv->emac_rx_desc;
> +	for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
> +		rx_desc->next = BD_TO_HW(rx_desc + 1);
> +		rx_desc->buffer = &priv->emac_rx_buffers[cnt * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN)];
> +		rx_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
> +		rx_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
> +		rx_desc++;
> +	}
> +
> +	/* Set the last descriptor's "next" parameter to 0 to end the RX desc list */
> +	rx_desc--;
> +	rx_desc->next = 0;
> +	priv->emac_rx_active_tail = rx_desc;
> +	priv->emac_rx_queue_active = 1;
> +
> +	/* Enable TX/RX */
> +	writel(EMAC_MAX_ETHERNET_PKT_SIZE, &priv->adap_emac->RXMAXLEN);
> +	writel(0, &priv->adap_emac->RXBUFFEROFFSET);
> +
> +	/* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
> +	writel(EMAC_RXMBPENABLE_RXBROADEN, &priv->adap_emac->RXMBPENABLE);
> +
> +	/* Enable ch 0 only */
> +	writel(0x01, &priv->adap_emac->RXUNICASTSET);
> +
> +	/* Enable MII interface and full duplex mode (using RMMI) */
> +	writel((EMAC_MACCONTROL_MIIEN_ENABLE |
> +		EMAC_MACCONTROL_FULLDUPLEX_ENABLE |
> +		EMAC_MACCONTROL_RMIISPEED_100),
> +	       &priv->adap_emac->MACCONTROL);
> +
> +	/* Init MDIO & get link state */
> +	clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
> +	writel((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT,
> +		&priv->adap_mdio->CONTROL);
> +
> +	/* Start receive process */
> +	writel(BD_TO_HW(priv->emac_rx_desc), &priv->adap_emac->RX0HDP);
> +
> +	ret = miidev_wait_aneg(&priv->miidev);
> +	if (ret)
> +		return ret;
> +
> +	ret = miidev_get_status(&priv->miidev);
> +	if (ret < 0)
> +		return ret;
> +
> +	miidev_print_status(&priv->miidev);
> +
> +	dev_dbg(priv->dev, "- emac_open\n");
> +
> +	return 0;
> +}
> +
> +/* EMAC Channel Teardown */
> +static void davinci_eth_ch_teardown(struct davinci_emac_priv *priv, int ch)
> +{
> +	dv_reg		dly = 0xff;
> +	dv_reg		cnt;
> +
> +	dev_dbg(priv->dev, "+ emac_ch_teardown\n");
> +
> +	if (ch == EMAC_CH_TX) {
> +		/* Init TX channel teardown */
> +		writel(0, &priv->adap_emac->TXTEARDOWN);
> +		for(cnt = 0; cnt != 0xfffffffc; cnt = readl(&priv->adap_emac->TX0CP)) {
> +			/* Wait here for Tx teardown completion interrupt to occur
> +			 * Note: A task delay can be called here to pend rather than
> +			 * occupying CPU cycles - anyway it has been found that teardown
> +			 * takes very few cpu cycles and does not affect functionality */
> +			 dly--;
> +			 udelay(1);
> +			 if (dly == 0)
> +				break;
> +		}
> +		writel(cnt, &priv->adap_emac->TX0CP);
> +		writel(0, &priv->adap_emac->TX0HDP);
> +	} else {
> +		/* Init RX channel teardown */
> +		writel(0, &priv->adap_emac->RXTEARDOWN);
> +		for(cnt = 0; cnt != 0xfffffffc; cnt = readl(&priv->adap_emac->RX0CP)) {
> +			/* Wait here for Rx teardown completion interrupt to occur
> +			 * Note: A task delay can be called here to pend rather than
> +			 * occupying CPU cycles - anyway it has been found that teardown
> +			 * takes very few cpu cycles and does not affect functionality */
> +			 dly--;
> +			 udelay(1);
> +			 if (dly == 0)
> +				break;
> +		}
> +		writel(cnt, &priv->adap_emac->RX0CP);
> +		writel(0, &priv->adap_emac->RX0HDP);
> +	}
> +
> +	dev_dbg(priv->dev, "- emac_ch_teardown\n");
> +}
> +
> +static void davinci_emac_halt(struct eth_device *edev)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +
> +	dev_dbg(priv->dev, "+ emac_halt\n");
> +
> +	davinci_eth_ch_teardown(priv, EMAC_CH_TX);	/* TX Channel teardown */
> +	davinci_eth_ch_teardown(priv, EMAC_CH_RX);	/* RX Channel teardown */
> +
> +	/* Reset EMAC module and disable interrupts in wrapper */
> +	writel(1, &priv->adap_emac->SOFTRESET);
> +	writel(1, &priv->adap_ewrap->softrst);
> +
> +	writel(0, &priv->adap_ewrap->c0rxen);
> +	writel(0, &priv->adap_ewrap->c1rxen);
> +	writel(0, &priv->adap_ewrap->c2rxen);
> +	writel(0, &priv->adap_ewrap->c0txen);
> +	writel(0, &priv->adap_ewrap->c1txen);
> +	writel(0, &priv->adap_ewrap->c2txen);
> +	writel(0, &priv->adap_ewrap->c0miscen);
> +	writel(0, &priv->adap_ewrap->c1miscen);
> +	writel(0, &priv->adap_ewrap->c2miscen);
> +
> +	dev_dbg(priv->dev, "- emac_halt\n");
> +}
> +
> +/*
> + * This function sends a single packet on the network and returns
> + * positive number (number of bytes transmitted) or negative for error
> + */
> +static int davinci_emac_send(struct eth_device *edev, void *packet, int length)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +	uint64_t start = 0;
> +	int ret_status = -1;
> +
> +	dev_dbg(priv->dev, "+ emac_send (length %d)\n", length);
> +
> +	/* Check packet size and if < EMAC_MIN_ETHERNET_PKT_SIZE, pad it up */
> +	if (length < EMAC_MIN_ETHERNET_PKT_SIZE) {
> +		length = EMAC_MIN_ETHERNET_PKT_SIZE;
> +	}
> +
> +	/* Populate the TX descriptor */
> +	writel(0, &priv->emac_tx_desc->next);
> +	writel((u_int8_t *) packet, &priv->emac_tx_desc->buffer);
> +	writel((length & 0xffff), &priv->emac_tx_desc->buff_off_len);
> +	writel(((length & 0xffff) | EMAC_CPPI_SOP_BIT |
> +				    EMAC_CPPI_OWNERSHIP_BIT |
> +				    EMAC_CPPI_EOP_BIT),
> +		&priv->emac_tx_desc->pkt_flag_len);
> +	dma_flush_range((ulong) packet, (ulong)packet + length);
> +	/* Send the packet */
> +	writel(BD_TO_HW(priv->emac_tx_desc), &priv->adap_emac->TX0HDP);
> +
> +	/* Wait for packet to complete or link down */
> +	start = get_time_ns();

You initialize a timeout value. That's good.

> +	while (1) {
> +		if (readl(&priv->adap_emac->TXINTSTATRAW) & 0x01) {
> +			/* Acknowledge the TX descriptor */
> +			writel(BD_TO_HW(priv->emac_tx_desc), &priv->adap_emac->TX0CP);
> +			ret_status = length;
> +			break;
> +		}
> +	}

Unfortunately it's unused.

> +
> +	dev_dbg(priv->dev, "- emac_send (ret_status %i)\n", ret_status);
> +	return ret_status;
> +}
> +
> +/*
> + * This function handles receipt of a packet from the network
> + */
> +static int davinci_emac_recv(struct eth_device *edev)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +	emac_desc *rx_curr_desc;
> +	emac_desc *curr_desc;
> +	emac_desc *tail_desc;
> +	unsigned char *pkt;
> +	int status, len, ret = -1;
> +
> +	dev_dbg(priv->dev, "+ emac_recv\n");
> +
> +	rx_curr_desc = priv->emac_rx_active_head;
> +	status = readl(&rx_curr_desc->pkt_flag_len);
> +	if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {

The code would be easier to read if you just invert the 'if' above and
return here.

> +		if (status & EMAC_CPPI_RX_ERROR_FRAME) {
> +			/* Error in packet - discard it and requeue desc */
> +			dev_warn(priv->dev, "WARN: emac_rcv_pkt: Error in packet\n");
> +		} else {
> +			pkt = (unsigned char *)readl(&rx_curr_desc->buffer);
> +			len = readl(&rx_curr_desc->buff_off_len) & 0xffff;
> +			dev_dbg(priv->dev, "| emac_recv got packet (length %i)\n", len);
> +			dma_inv_range((ulong)pkt,
> +					(ulong)rx_curr_desc->buffer + len);
> +			net_receive(pkt, len);
> +			ret = len;
> +		}
> +
> +		/* Ack received packet descriptor */
> +		writel(BD_TO_HW(rx_curr_desc), &priv->adap_emac->RX0CP);
> +		curr_desc = rx_curr_desc;
> +		priv->emac_rx_active_head = HW_TO_BD(readl(&rx_curr_desc->next));
> +
> +		if (status & EMAC_CPPI_EOQ_BIT) {
> +			if (priv->emac_rx_active_head) {
> +				writel(BD_TO_HW(priv->emac_rx_active_head),
> +					&priv->adap_emac->RX0HDP);
> +			} else {
> +				priv->emac_rx_queue_active = 0;
> +				dev_info(priv->dev, "INFO:emac_rcv_packet: RX Queue not active\n");
> +			}
> +		}
> +
> +		/* Recycle RX descriptor */
> +		writel(EMAC_MAX_ETHERNET_PKT_SIZE, &rx_curr_desc->buff_off_len);
> +		writel(EMAC_CPPI_OWNERSHIP_BIT, &rx_curr_desc->pkt_flag_len);
> +		writel(0, &rx_curr_desc->next);
> +
> +		if (priv->emac_rx_active_head == 0) {
> +			dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0\n");
> +			priv->emac_rx_active_head = curr_desc;
> +			priv->emac_rx_active_tail = curr_desc;
> +			if (priv->emac_rx_queue_active != 0) {
> +				writel(BD_TO_HW(priv->emac_rx_active_head), &priv->adap_emac->RX0HDP);
> +				dev_info(priv->dev, "INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
> +				priv->emac_rx_queue_active = 1;
> +			}
> +		} else {
> +			tail_desc = priv->emac_rx_active_tail;
> +			priv->emac_rx_active_tail = curr_desc;
> +			writel(BD_TO_HW(curr_desc), &tail_desc->next);
> +			status = readl(&tail_desc->pkt_flag_len);
> +			if (status & EMAC_CPPI_EOQ_BIT) {
> +				writel(BD_TO_HW(curr_desc), &priv->adap_emac->RX0HDP);
> +				status &= ~EMAC_CPPI_EOQ_BIT;
> +				writel(status, &tail_desc->pkt_flag_len);
> +			}
> +		}
> +		return ret;
> +	}
> +
> +	dev_dbg(priv->dev, "- emac_recv\n");
> +
> +	return 0;
> +}
> +
> +static int davinci_emac_probe(struct device_d *dev)
> +{
> +	struct davinci_emac_priv *priv;
> +	int		i;
> +
> +	dev_dbg(dev, "+ emac_probe\n");
> +
> +	priv = xzalloc(sizeof(*priv));
> +	dev->priv = priv;
> +
> +	priv->dev = dev;
> +
> +	priv->adap_emac = (emac_regs *)EMAC_BASE_ADDR;
> +	priv->adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
> +	priv->adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
> +
> +	/* EMAC descriptors */
> +	priv->emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
> +	priv->emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
> +	priv->emac_rx_active_head = 0;
> +	priv->emac_rx_active_tail = 0;
> +	priv->emac_rx_queue_active = 0;
> +
> +	/* Receive packet buffers */
> +	priv->emac_rx_buffers = xmemalign(4096, EMAC_MAX_RX_BUFFERS * (EMAC_MAX_ETHERNET_PKT_SIZE + EMAC_PKT_ALIGN));
> +
> +	/* PHY address for a discovered PHY (0xff - not found) */
> +	priv->active_phy_addr = 0xff;
> +
> +	priv->edev.priv = priv;
> +	priv->edev.init = davinci_emac_init;
> +	priv->edev.open = davinci_emac_open;
> +	priv->edev.halt = davinci_emac_halt;
> +	priv->edev.send = davinci_emac_send;
> +	priv->edev.recv = davinci_emac_recv;
> +	priv->edev.get_ethaddr = davinci_emac_get_ethaddr;
> +	priv->edev.set_ethaddr = davinci_emac_set_ethaddr;
> +	priv->edev.parent = dev;
> +
> +	priv->regs = dev_request_mem_region(dev, 0);
> +
> +	davinci_eth_mdio_enable(priv);
> +
> +	for (i = 0; i < 256; i++) {
> +		if (priv->adap_mdio->ALIVE)

readl

Also, use a regular is_timout() loop.

> +			break;
> +		udelay(1000);
> +	}
> +
> +	if (i >= 256) {
> +		dev_err(dev, "No ETH PHY detected!\n");
> +	}
> +
> +	priv->miidev.read = davinci_miidev_read;
> +	priv->miidev.write = davinci_miidev_write;
> +	priv->miidev.address = 0x01;
> +	priv->miidev.flags = MIIDEV_FORCE_LINK;
> +	priv->miidev.edev = &priv->edev;
> +	priv->miidev.parent = dev;
> +
> +	mii_register(&priv->miidev);
> +
> +	eth_register(&priv->edev);
> +
> +	dev_dbg(dev, "- emac_probe\n");
> +	return 0;
> +}
> +
> +static void davinci_emac_remove(struct device_d *dev)
> +{
> +	struct davinci_emac_priv *priv = dev->priv;
> +
> +	davinci_emac_halt(&priv->edev);
> +}
> +
> +static struct driver_d davinci_emac_driver = {
> +	.name   = "davinci_emac",
> +	.probe  = davinci_emac_probe,
> +	.remove = davinci_emac_remove,
> +};
> +
> +static int davinci_emac_register(void)
> +{
> +	register_driver(&davinci_emac_driver);
> +	return 0;
> +}
> +
> +device_initcall(davinci_emac_register);
> diff --git a/drivers/net/davinci_emac.h b/drivers/net/davinci_emac.h
> new file mode 100644
> index 0000000..4e97ce5
> --- /dev/null
> +++ b/drivers/net/davinci_emac.h
> @@ -0,0 +1,331 @@
> +/*
> + * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
> + *
> + * Based on:
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * dm644x_emac.h
> + *
> + * TI DaVinci (DM644X) EMAC peripheral driver header for DV-EVM
> + *
> + * Copyright (C) 2005 Texas Instruments.
> + *
> + * ----------------------------------------------------------------------------
> + *
> + * 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.
> + * ----------------------------------------------------------------------------
> +
> + * Modifications:
> + * ver. 1.0: Sep 2005, TI PSP Team - Created EMAC version for uBoot.
> + *
> + */
> +
> +#ifndef _DAVINCI_EMAC_H_
> +#define _DAVINCI_EMAC_H_
> +
> +/* PHY mask - set only those phy number bits where phy is/can be connected */
> +#define EMAC_MDIO_PHY_NUM           1
> +#define EMAC_MDIO_PHY_MASK          (1 << EMAC_MDIO_PHY_NUM)
> +
> +/* Ethernet Min/Max packet size */
> +#define EMAC_MIN_ETHERNET_PKT_SIZE	60
> +#define EMAC_MAX_ETHERNET_PKT_SIZE	1518
> +#define EMAC_PKT_ALIGN			18	/* 1518 + 18 = 1536 (packet aligned on 32 byte boundry) */
> +
> +/* Number of RX packet buffers
> + * NOTE: Only 1 buffer supported as of now
> + */
> +#define EMAC_MAX_RX_BUFFERS		10
> +
> +typedef unsigned int	dv_reg;
> +typedef unsigned int	*dv_reg_p;
> +
> +/***********************************************
> + ******** Internally used macros ***************
> + ***********************************************/
> +
> +#define EMAC_CH_TX			1
> +#define EMAC_CH_RX			0
> +
> +/* Each descriptor occupies 4 words, lets start RX desc's at 0 and
> + * reserve space for 64 descriptors max
> + */
> +#define EMAC_RX_DESC_BASE		0x0
> +#define EMAC_TX_DESC_BASE		0x1000
> +
> +/* EMAC Teardown value */
> +#define EMAC_TEARDOWN_VALUE		0xfffffffc
> +
> +/* MII Status Register */
> +#define MII_STATUS_REG			1
> +
> +/* Number of statistics registers */
> +#define EMAC_NUM_STATS			36
> +
> +
> +/* EMAC Descriptor */
> +typedef struct
> +{
> +	u_int32_t	next;		/* Pointer to next descriptor in chain */
> +	u_int8_t	*buffer;	/* Pointer to data buffer */
> +	u_int32_t	buff_off_len;	/* Buffer Offset(MSW) and Length(LSW) */
> +	u_int32_t	pkt_flag_len;	/* Packet Flags(MSW) and Length(LSW) */
> +} emac_desc;
> +
> +/* CPPI bit positions */
> +#define EMAC_CPPI_SOP_BIT		(0x80000000)
> +#define EMAC_CPPI_EOP_BIT		(0x40000000)
> +#define EMAC_CPPI_OWNERSHIP_BIT		(0x20000000)
> +#define EMAC_CPPI_EOQ_BIT		(0x10000000)
> +#define EMAC_CPPI_TEARDOWN_COMPLETE_BIT	(0x08000000)
> +#define EMAC_CPPI_PASS_CRC_BIT		(0x04000000)
> +
> +#define EMAC_CPPI_RX_ERROR_FRAME	(0x03fc0000)
> +
> +#define EMAC_MACCONTROL_MIIEN_ENABLE		(0x20)
> +#define EMAC_MACCONTROL_FULLDUPLEX_ENABLE	(0x1)
> +#define EMAC_MACCONTROL_GIGABIT_ENABLE		(1 << 7)
> +#define EMAC_MACCONTROL_GIGFORCE		(1 << 17)
> +#define EMAC_MACCONTROL_RMIISPEED_100		(1 << 15)
> +
> +#define EMAC_MAC_ADDR_MATCH		(1 << 19)
> +#define EMAC_MAC_ADDR_IS_VALID		(1 << 20)
> +
> +#define EMAC_RXMBPENABLE_RXCAFEN_ENABLE	(0x200000)
> +#define EMAC_RXMBPENABLE_RXBROADEN	(0x2000)
> +
> +
> +#define MDIO_CONTROL_IDLE		(0x80000000)
> +#define MDIO_CONTROL_ENABLE		(0x40000000)
> +#define MDIO_CONTROL_FAULT_ENABLE	(0x40000)
> +#define MDIO_CONTROL_FAULT		(0x80000)
> +#define MDIO_USERACCESS0_GO		(0x80000000)
> +#define MDIO_USERACCESS0_WRITE_READ	(0x0)
> +#define MDIO_USERACCESS0_WRITE_WRITE	(0x40000000)
> +#define MDIO_USERACCESS0_ACK		(0x20000000)
> +
> +/* Ethernet MAC Registers Structure */
> +typedef struct  {

No typedef for structs please.

> +	dv_reg		TXIDVER;

Or better, no typedefs at all ;)

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 09/10] omap3: allow enabling clocks for UART3, MMC1 and SPI
  2012-09-03 11:46 ` [PATCH 09/10] omap3: allow enabling clocks for UART3, MMC1 and SPI Jan Luebbe
@ 2012-09-04  8:48   ` Sascha Hauer
  2012-09-05  9:28     ` Jan Lübbe
  0 siblings, 1 reply; 23+ messages in thread
From: Sascha Hauer @ 2012-09-04  8:48 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On Mon, Sep 03, 2012 at 01:46:04PM +0200, Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  arch/arm/mach-omap/Kconfig       |    4 ++++
>  arch/arm/mach-omap/omap3_clock.c |   35 +++++++++++++++++++++++++----------
>  2 files changed, 29 insertions(+), 10 deletions(-)
> 
> diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
> index a781287..82fa46b 100644
> --- a/arch/arm/mach-omap/Kconfig
> +++ b/arch/arm/mach-omap/Kconfig
> @@ -61,6 +61,10 @@ config OMAP_CLOCK_UART3
>  	bool
>  config OMAP_CLOCK_I2C
>  	bool
> +config OMAP_CLOCK_MMC1
> +	bool
> +config OMAP_CLOCK_SPI
> +	bool

A Kconfig entry for enabling a clock is overkill. Please do not continue
this.

Right now we have:

config OMAP_CLOCK_UART
	bool
config OMAP_CLOCK_UART2
	bool
config OMAP_CLOCK_UART3
	bool
config OMAP_CLOCK_I2C
	bool

And it's completely unused, so can be simply removed.

Sascha


-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs
  2012-09-03 11:46 ` [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
  2012-09-03 16:32   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-04  8:58   ` Sascha Hauer
  2012-09-05  9:20     ` Jan Lübbe
  1 sibling, 1 reply; 23+ messages in thread
From: Sascha Hauer @ 2012-09-04  8:58 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On Mon, Sep 03, 2012 at 01:46:05PM +0200, Jan Luebbe wrote:
> Also create devices for OMAP3.
> 
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
> +
> +#define WORD_LEN	8
> +#define SPI_WAIT_TIMEOUT 30000000
> +
> +#define SPI_XFER_BEGIN  0x01                    /* Assert CS before transfer */
> +#define SPI_XFER_END    0x02                    /* Deassert CS after transfer */
> +
> +static void spi_reset(struct spi_master *master)
> +{
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	unsigned int tmp;
> +
> +	writel(OMAP3_MCSPI_SYSCONFIG_SOFTRESET, &regs->sysconfig);
> +	do {
> +		tmp = readl(&regs->sysstatus);
> +	} while (!(tmp & OMAP3_MCSPI_SYSSTATUS_RESETDONE));
> +
> +	writel(OMAP3_MCSPI_SYSCONFIG_AUTOIDLE |
> +				 OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP |
> +				 OMAP3_MCSPI_SYSCONFIG_SMARTIDLE,
> +				 &regs->sysconfig);
> +
> +	writel(OMAP3_MCSPI_WAKEUPENABLE_WKEN, &regs->wakeupenable);
> +}
> +
> +int spi_claim_bus(struct spi_device *spi)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	unsigned int conf, div = 0;
> +
> +	/* McSPI global module configuration */
> +
> +	/*
> +	 * setup when switching from (reset default) slave mode
> +	 * to single-channel master mode
> +	 */
> +	conf = readl(&regs->modulctrl);
> +	conf &= ~(OMAP3_MCSPI_MODULCTRL_STEST | OMAP3_MCSPI_MODULCTRL_MS);
> +	conf |= OMAP3_MCSPI_MODULCTRL_SINGLE;
> +	writel(conf, &regs->modulctrl);
> +
> +	/* McSPI individual channel configuration */
> +
> +	/* Calculate clock divisor. Valid range: 0x0 - 0xC ( /1 - /4096 ) */
> +	if (spi->max_speed_hz) {
> +		while (div <= 0xC && (OMAP3_MCSPI_MAX_FREQ / (1 << div))
> +					 > spi->max_speed_hz)
> +			div++;
> +	} else
> +		div = 0xC;

if an 'if' has braces then add them to the 'else' path aswell.

> +
> +	conf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +	/* standard 4-wire master mode:	SCK, MOSI/out, MISO/in, nCS
> +	 * REVISIT: this controller could support SPI_3WIRE mode.
> +	 */
> +	conf &= ~(OMAP3_MCSPI_CHCONF_IS|OMAP3_MCSPI_CHCONF_DPE1);
> +	conf |= OMAP3_MCSPI_CHCONF_DPE0;
> +
> +	/* wordlength */
> +	conf &= ~OMAP3_MCSPI_CHCONF_WL_MASK;
> +	conf |= (WORD_LEN - 1) << 7;
> +
> +	/* set chipselect polarity; manage with FORCE */
> +	if (!(spi->mode & SPI_CS_HIGH))
> +		conf |= OMAP3_MCSPI_CHCONF_EPOL; /* active-low; normal */
> +	else
> +		conf &= ~OMAP3_MCSPI_CHCONF_EPOL;
> +
> +	/* set clock divisor */
> +	conf &= ~OMAP3_MCSPI_CHCONF_CLKD_MASK;
> +	conf |= div << 2;
> +
> +	/* set SPI mode 0..3 */
> +	if (spi->mode & SPI_CPOL)
> +		conf |= OMAP3_MCSPI_CHCONF_POL;
> +	else
> +		conf &= ~OMAP3_MCSPI_CHCONF_POL;
> +	if (spi->mode & SPI_CPHA)
> +		conf |= OMAP3_MCSPI_CHCONF_PHA;
> +	else
> +		conf &= ~OMAP3_MCSPI_CHCONF_PHA;
> +
> +	/* Transmit & receive mode */
> +	conf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
> +
> +	writel(conf, &regs->channel[spi->chip_select].chconf);
> +	readl(&regs->channel[spi->chip_select].chconf);
> +
> +	return 0;
> +}
> +
> +int omap3_spi_write(struct spi_device *spi, unsigned int len, const u8 *txp,
> +		    unsigned long flags)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	int i;
> +	int timeout = SPI_WAIT_TIMEOUT;
> +	int chconf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +	if (flags & SPI_XFER_BEGIN)
> +		writel(OMAP3_MCSPI_CHCTRL_EN,
> +		       &regs->channel[spi->chip_select].chctrl);
> +
> +	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
> +	chconf |= OMAP3_MCSPI_CHCONF_TRM_TX_ONLY;
> +	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
> +	writel(chconf, &regs->channel[spi->chip_select].chconf);
> +	readl(&regs->channel[spi->chip_select].chconf);
> +
> +	for (i = 0; i < len; i++) {
> +		/* wait till TX register is empty (TXS == 1) */
> +		while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_TXS)) {
> +			if (--timeout <= 0) {
> +				printf("SPI TXS timed out, status=0x%08x\n",
> +				       readl(&regs->channel[spi->chip_select].chstat));
> +				return -1;
> +			}
> +		}

Please use a well defined timeout rather than 'poll a million times'

> +		/* Write the data */
> +		writel(txp[i], &regs->channel[spi->chip_select].tx);
> +	}
> +
> +	if (flags & SPI_XFER_END) {
> +		/* wait to finish of transfer */
> +		while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_EOT));
> +
> +		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
> +		writel(chconf, &regs->channel[spi->chip_select].chconf);
> +
> +		writel(0, &regs->channel[spi->chip_select].chctrl);
> +	}
> +
> +	while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_TXS));
> +	while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_EOT));
> +
> +	return 0;
> +}
> +
> +int omap3_spi_read(struct spi_device *spi, unsigned int len, u8 *rxp,
> +		   unsigned long flags)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	int i;
> +	int timeout = SPI_WAIT_TIMEOUT;
> +	int chconf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +	if (flags & SPI_XFER_BEGIN)
> +		writel(OMAP3_MCSPI_CHCTRL_EN,
> +		       &regs->channel[spi->chip_select].chctrl);
> +
> +	chconf &= ~OMAP3_MCSPI_CHCONF_TRM_MASK;
> +	chconf |= OMAP3_MCSPI_CHCONF_TRM_RX_ONLY;
> +	chconf |= OMAP3_MCSPI_CHCONF_FORCE;
> +	writel(chconf, &regs->channel[spi->chip_select].chconf);
> +	readl(&regs->channel[spi->chip_select].chconf);
> +	writel(0, &regs->channel[spi->chip_select].tx);
> +
> +	for (i = 0; i < len; i++) {
> +		/* Wait till RX register contains data (RXS == 1) */
> +		while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_RXS)) {
> +			if (--timeout <= 0) {
> +				printf("SPI RXS timed out, status=0x%08x\n",
> +				       readl(&regs->channel[spi->chip_select].chstat));
> +				return -1;
> +			}
> +		}

ditto

> +		/* Read the data */
> +		rxp[i] = readl(&regs->channel[spi->chip_select].rx);
> +	}
> +
> +	if (flags & SPI_XFER_END) {
> +		chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
> +		writel(chconf, &regs->channel[spi->chip_select].chconf);
> +		readl(&regs->channel[spi->chip_select].chconf);
> +
> +		writel(0, &regs->channel[spi->chip_select].chctrl);
> +	}
> +
> +	return 0;
> +}
> +
> +int spi_xfer(struct spi_device *spi, struct spi_transfer *t, unsigned long flags)
> +{
> +	struct spi_master *master = spi->master;
> +	struct omap3_spi_master *omap3_master = container_of(master, struct omap3_spi_master, master);
> +	struct mcspi __iomem *regs = omap3_master->regs;
> +	unsigned int    len = t->len;
> +	int             ret = -1;

-1 is no valid error code. Please remove the initialization on ret.

> +	const u8        *txp = t->tx_buf; /* can be NULL for read operation */
> +	u8              *rxp = t->rx_buf; /* can be NULL for write operation */
> +
> +	if (len == 0) {	 /* only change CS */
> +		int chconf = readl(&regs->channel[spi->chip_select].chconf);
> +
> +		if (flags & SPI_XFER_BEGIN) {
> +			writel(OMAP3_MCSPI_CHCTRL_EN,
> +			       &regs->channel[spi->chip_select].chctrl);
> +			chconf |= OMAP3_MCSPI_CHCONF_FORCE;
> +			writel(chconf,
> +			       &regs->channel[spi->chip_select].chconf);
> +			readl(&regs->channel[spi->chip_select].chconf);
> +		}
> +
> +		if (flags & SPI_XFER_END) {
> +			chconf &= ~OMAP3_MCSPI_CHCONF_FORCE;
> +			writel(chconf,
> +			       &regs->channel[spi->chip_select].chconf);
> +			writel(0, &regs->channel[spi->chip_select].chctrl);
> +			readl(&regs->channel[spi->chip_select].chconf);
> +		}
> +
> +		ret = 0;
> +	} else {
> +		if (t->tx_buf != NULL)
> +			ret = omap3_spi_write(spi, len, txp, flags);
> +
> +		if (t->rx_buf != NULL)
> +			ret = omap3_spi_read(spi, len, rxp, flags);
> +	}
> +	return ret;
> +}
> +
> +static int omap3_spi_transfer(struct spi_device *spi, struct spi_message *mesg)
> +{
> +	struct spi_master *master = spi->master;
> +	struct spi_transfer *t, *t_first, *t_last = NULL;
> +	unsigned long flags;
> +	int ret = 0;
> +
> +	ret = spi_claim_bus(spi);
> +	if (ret)
> +		return ret;
> +
> +	if (list_empty(&mesg->transfers))
> +		return 0;
> +
> +	t_first = list_first_entry(&mesg->transfers, struct spi_transfer, transfer_list);
> +	t_last = list_last_entry(&mesg->transfers, struct spi_transfer, transfer_list);
> +
> +	mesg->actual_length = 0;
> +
> +	dev_dbg(master->dev, "transfer start actual_length=%i\n", mesg->actual_length);
> +	list_for_each_entry(t, &mesg->transfers, transfer_list) {
> +		dev_dbg(master->dev,
> +			"  xfer %p: len %u tx %p rx %p\n",
> +			t, t->len, t->tx_buf, t->rx_buf);
> +		flags = 0;
> +		if (t == t_first)
> +			flags |= SPI_XFER_BEGIN;
> +		if (t == t_last)
> +			flags |= SPI_XFER_END;
> +		spi_xfer(spi, t, flags);
> +		mesg->actual_length += t->len;
> +	}
> +	dev_dbg(master->dev, "transfer done actual_length=%i\n", mesg->actual_length);
> +
> +	return ret;
> +}
> +
> +static int omap3_spi_setup(struct spi_device *spi)
> +{
> +	struct spi_master *master = spi->master;
> +
> +	if (((master->bus_num == 0) && (spi->chip_select > 3)) ||
> +			((master->bus_num == 1) && (spi->chip_select > 1)) ||
> +			((master->bus_num == 2) && (spi->chip_select > 1)) ||
> +			((master->bus_num == 3) && (spi->chip_select > 0))) {
> +		printf("SPI error: unsupported chip select %i \
> +			on bus %i\n", spi->chip_select, master->bus_num);
> +		return -1;
> +	}
> +
> +	if (spi->max_speed_hz > OMAP3_MCSPI_MAX_FREQ) {
> +		printf("SPI error: unsupported frequency %i Hz. \
> +			Max frequency is 48 Mhz\n", spi->max_speed_hz);
> +		return -1;
> +	}
> +
> +	if (spi->mode > SPI_MODE_3) {
> +		printf("SPI error: unsupported SPI mode %i\n", spi->mode);
> +		return -1;
> +	}

Please use valid error codes here.

> +
> +	return 0;
> +}
> +
> +static int omap3_spi_probe(struct device_d *dev)
> +{
> +	struct spi_master *master;
> +	struct omap3_spi_master *omap3_master;
> +
> +	omap3_master = xzalloc(sizeof(*omap3_master));
> +
> +	master = &omap3_master->master;
> +	master->dev = dev;
> +
> +	/*
> +	 * OMAP3 McSPI (MultiChannel SPI) has 4 busses (modules)
> +	 * with different number of chip selects (CS, channels):
> +	 * McSPI1 has 4 CS (bus 0, cs 0 - 3)
> +	 * McSPI2 has 2 CS (bus 1, cs 0 - 1)
> +	 * McSPI3 has 2 CS (bus 2, cs 0 - 1)
> +	 * McSPI4 has 1 CS (bus 3, cs 0)
> +	 */
> +
> +	master->bus_num = dev->id;
> +	switch (master->bus_num) {
> +	case 1:
> +		master->num_chipselect = 4;
> +		break;
> +	case 2:
> +		master->num_chipselect = 2;
> +		break;
> +	case 3:
> +		master->num_chipselect = 2;
> +		break;
> +	case 4:
> +		master->num_chipselect = 1;
> +		break;
> +	default:
> +		printf("SPI error: unsupported bus %i. \
> +			Supported busses 1 - 4\n", master->bus_num);
> +		return -ENODEV;
> +	}

This does not scale for different SoCs. Can't you just initialize
num_chipselect to the maximum value of 4?

Sascha

-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |

_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs
  2012-09-04  8:58   ` Sascha Hauer
@ 2012-09-05  9:20     ` Jan Lübbe
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Lübbe @ 2012-09-05  9:20 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox-request

Hi,

On Tue, 2012-09-04 at 10:58 +0200, Sascha Hauer wrote:
> > +     for (i = 0; i < len; i++) {
> > +             /* wait till TX register is empty (TXS == 1) */
> > +             while
> (!(readl(&regs->channel[spi->chip_select].chstat) &
> > +                      OMAP3_MCSPI_CHSTAT_TXS)) {
> > +                     if (--timeout <= 0) {
> > +                             printf("SPI TXS timed out, status=0x%
> 08x\n",
> > +
> readl(&regs->channel[spi->chip_select].chstat));
> > +                             return -1;
> > +                     }
> > +             }
> 
> Please use a well defined timeout rather than 'poll a million times' 

I tried using is_timeout like this:
                timer_start = get_time_ns();
                while (!(readl(&regs->channel[spi->chip_select].chstat) &
                         OMAP3_MCSPI_CHSTAT_TXS)) {
                        if (is_timeout(timer_start, SPI_WAIT_TIMEOUT)) {
                                printf("SPI TXS timed out, status=0x%08x\n",
                                       readl(&regs->channel[spi->chip_select].chstat));
                                return -1;
                        }
                }

With SPI_WAIT_TIMEOUT = MSECOND this results in ~23% more time needed
for reading/writing:

With a simple counter:
barebox@KSP-0500:/ time cp /dev/m25p0.norkernel /dev/null
time: 12639ms
barebox@KSP-0500:/ time cp /dev/m25p0.norkernel /dev/null
time: 12639ms
barebox@KSP-0500:/ time cp /dev/m25p0.norkernel /dev/null
time: 12659ms

With is_timeout():
barebox@KSP-0500:/ time cp /dev/m25p0.norkernel /dev/null
time: 15561ms
barebox@KSP-0500:/ time cp /dev/m25p0.norkernel /dev/null
time: 15564ms
barebox@KSP-0500:/ time cp /dev/m25p0.norkernel /dev/null
time: 15568ms

Is this really acceptable? Is there a way to avoid the overhead of
calling several functions for each loop?

Regards,
Jan
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

* Re: [PATCH 09/10] omap3: allow enabling clocks for UART3, MMC1 and SPI
  2012-09-04  8:48   ` Sascha Hauer
@ 2012-09-05  9:28     ` Jan Lübbe
  0 siblings, 0 replies; 23+ messages in thread
From: Jan Lübbe @ 2012-09-05  9:28 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox-request

On Tue, 2012-09-04 at 10:48 +0200, Sascha Hauer wrote:
> On Mon, Sep 03, 2012 at 01:46:04PM +0200, Jan Luebbe wrote:
> > Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> > ---
> >  arch/arm/mach-omap/Kconfig       |    4 ++++
> >  arch/arm/mach-omap/omap3_clock.c |   35 +++++++++++++++++++++++++----------
> >  2 files changed, 29 insertions(+), 10 deletions(-)
> > 
> > diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
> > index a781287..82fa46b 100644
> > --- a/arch/arm/mach-omap/Kconfig
> > +++ b/arch/arm/mach-omap/Kconfig
> > @@ -61,6 +61,10 @@ config OMAP_CLOCK_UART3
> >  	bool
> >  config OMAP_CLOCK_I2C
> >  	bool
> > +config OMAP_CLOCK_MMC1
> > +	bool
> > +config OMAP_CLOCK_SPI
> > +	bool
> 
> A Kconfig entry for enabling a clock is overkill. Please do not continue
> this.
> 
> Right now we have:
> 
> config OMAP_CLOCK_UART
> 	bool
> config OMAP_CLOCK_UART2
> 	bool
> config OMAP_CLOCK_UART3
> 	bool
> config OMAP_CLOCK_I2C
> 	bool
> 
> And it's completely unused, so can be simply removed.

What should I do instead? Enable all clocks? Or enable just the clocks
for which drivers have been enabled in Kconfig?

Thanks,
Jan
-- 
Pengutronix e.K.                           |                             |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |
Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |


_______________________________________________
barebox mailing list
barebox@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox

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

end of thread, other threads:[~2012-09-05  9:28 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-03 11:45 Prepare support for TI AM35xx Jan Luebbe
2012-09-03 11:45 ` [PATCH 01/10] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash Jan Luebbe
2012-09-03 11:45 ` [PATCH 02/10] drivers/nor/m25p80: add MEMGETINFO ioctl Jan Luebbe
2012-09-04  8:20   ` Sascha Hauer
2012-09-03 11:45 ` [PATCH 03/10] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
2012-09-03 16:22   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-03 11:45 ` [PATCH 04/10] scripts: add tool to create image for SPI boot on AM35xx Jan Luebbe
2012-09-04  8:27   ` Sascha Hauer
2012-09-03 11:46 ` [PATCH 05/10] common: split out meminfo output and make it optional Jan Luebbe
2012-09-03 11:46 ` [PATCH 06/10] omap: add SPI as a boot mode for xload Jan Luebbe
2012-09-03 16:24   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-04  7:41     ` Jan Weitzel
2012-09-03 11:46 ` [PATCH 07/10] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch Jan Luebbe
2012-09-03 11:46 ` [PATCH 08/10] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
2012-09-03 16:27   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-04  8:42   ` Sascha Hauer
2012-09-03 11:46 ` [PATCH 09/10] omap3: allow enabling clocks for UART3, MMC1 and SPI Jan Luebbe
2012-09-04  8:48   ` Sascha Hauer
2012-09-05  9:28     ` Jan Lübbe
2012-09-03 11:46 ` [PATCH 10/10] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
2012-09-03 16:32   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-04  8:58   ` Sascha Hauer
2012-09-05  9:20     ` Jan Lübbe

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox