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

Hi all,

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

The patches should apply individually to the current master (=next).

Thanks again to Jean-Christophe Plagniol-Villard and Sacha Hauer for
their reviews.

Best regards,
Jan


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

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

* [PATCH 1/8] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 15:52 ` [PATCH 2/8] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 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] 16+ messages in thread

* [PATCH 2/8] Makefile: add target to produce a SPL compatible uimage
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
  2012-09-05 15:52 ` [PATCH 1/8] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 18:05   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-05 15:52 ` [PATCH 3/8] scripts: add tool to create image for SPI boot on AM35xx Jan Luebbe
                   ` (5 subsequent siblings)
  7 siblings, 1 reply; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 UTC (permalink / raw)
  To: barebox

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

diff --git a/Makefile b/Makefile
index c6264d3..69e28e3 100644
--- a/Makefile
+++ b/Makefile
@@ -680,6 +680,16 @@ ifndef CONFIG_PBL_IMAGE
 	$(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
 endif
 
+# For development provide a target which makes barebox loadable by an
+# unmodified u-boot
+quiet_cmd_barebox_mkimage = MKIMAGE $@
+      cmd_barebox_mkimage = $(srctree)/scripts/mkimage -A $(ARCH) -T firmware -C none \
+	-O barebox -a $(CONFIG_TEXT_BASE) -e $(CONFIG_TEXT_BASE) \
+	-n "barebox $(KERNELRELEASE)" -d $< $@
+
+barebox.img: barebox.bin FORCE
+	$(call if_changed,barebox_mkimage)
+
 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] 16+ messages in thread

* [PATCH 3/8] scripts: add tool to create image for SPI boot on AM35xx
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
  2012-09-05 15:52 ` [PATCH 1/8] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash Jan Luebbe
  2012-09-05 15:52 ` [PATCH 2/8] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 15:52 ` [PATCH 4/8] common: split out meminfo output and make it optional Jan Luebbe
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 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 |  141 +++++++++++++++++++++++++++++++++++++++++
 5 files changed, 158 insertions(+), 1 deletion(-)
 create mode 100644 scripts/mk-am35xx-spi-image.c

diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 8e660be..e40b67e 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -221,6 +221,14 @@ archclean:
 
 KBUILD_IMAGE := $(KBUILD_BINARY)
 
+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..ec311fd
--- /dev/null
+++ b/scripts/mk-am35xx-spi-image.c
@@ -0,0 +1,141 @@
+/*
+ * mk-am35xx-spi-image.c - convert a barebox image for SPI loading on AM35xx
+ *
+ * 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.
+ */
+/**
+ * @file
+ * @brief convert a barebox image for SPI loading on AM35xx
+ *
+ * FileName: scripts/mk-am35xx-spi-image.c
+ *
+ * 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
+ *
+ * This tool converts barebox.bin to the required format.
+ */
+
+#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] 16+ messages in thread

* [PATCH 4/8] common: split out meminfo output and make it optional
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
                   ` (2 preceding siblings ...)
  2012-09-05 15:52 ` [PATCH 3/8] scripts: add tool to create image for SPI boot on AM35xx Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 15:52 ` [PATCH 5/8] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch Jan Luebbe
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 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 b97392c..c1aaabe 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 df9f301..68582b7 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] 16+ messages in thread

* [PATCH 5/8] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
                   ` (3 preceding siblings ...)
  2012-09-05 15:52 ` [PATCH 4/8] common: split out meminfo output and make it optional Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 15:52 ` [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 UTC (permalink / raw)
  To: barebox

It starts 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 3c5f729..dac1eb9 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -125,5 +125,12 @@ config DRIVER_NET_GIANFAR
 
 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 4d960e8..951a220 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -15,3 +15,4 @@ 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_GIANFAR)	+= gianfar.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] 16+ messages in thread

* [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
                   ` (4 preceding siblings ...)
  2012-09-05 15:52 ` [PATCH 5/8] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 18:03   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-05 15:52 ` [PATCH 7/8] omap3: remove unused coded for clock configuration Jan Luebbe
  2012-09-05 15:52 ` [PATCH 8/8] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
  7 siblings, 1 reply; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 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                  |  615 +++++++++++++++++++++++++++
 drivers/net/davinci_emac.h                  |  318 ++++++++++++++
 5 files changed, 992 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 dac1eb9..bfde54b 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -43,6 +43,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 951a220..52611f8 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..3615f96
--- /dev/null
+++ b/drivers/net/davinci_emac.c
@@ -0,0 +1,615 @@
+/*
+ * 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;
+
+	/* EMAC Addresses */
+	struct emac_regs *adap_emac; /* = EMAC_BASE_ADDR */
+	struct ewrap_regs *adap_ewrap; /* = EMAC_WRAPPER_BASE_ADDR */
+	struct mdio_regs *adap_mdio; /* = EMAC_MDIO_BASE_ADDR */
+
+	/* EMAC descriptors */
+	struct emac_desc *emac_rx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE */
+	struct emac_desc *emac_tx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE */
+	struct emac_desc *emac_rx_active_head; /* = 0 */
+	struct 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) */
+	uint8_t active_phy_addr; /* = 0xff */
+
+	/* mac_addr[0] goes out on the wire first */
+	uint8_t mac_addr[6];
+};
+
+#ifdef EMAC_HW_RAM_ADDR
+static inline uint32_t BD_TO_HW(struct emac_desc *x)
+{
+	if (x == 0)
+		return 0;
+
+	return (uint32_t)(x) - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
+}
+
+static inline struct emac_desc* HW_TO_BD(uint32_t x)
+{
+	if (x == 0)
+		return 0;
+
+	return (struct 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)
+{
+	uint32_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 */
+static int davinci_eth_phy_read(struct davinci_emac_priv *priv, uint8_t phy_addr, uint8_t reg_num, uint16_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. */
+static int davinci_eth_phy_write(struct davinci_emac_priv *priv, uint8_t phy_addr, uint8_t reg_num, uint16_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;
+}
+
+/*
+ * This function must be called before emac_open() if you want to override
+ * the default mac address.
+ */
+static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *addr)
+{
+	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
+	int i;
+
+	for (i = 0; i < sizeof(priv->mac_addr); i++)
+		priv->mac_addr[i] = addr[i];
+	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;
+
+	uint32_t	clkdiv, cnt;
+	struct 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 = (priv->mac_addr[3] << 24) |
+		 (priv->mac_addr[2] << 16) |
+		 (priv->mac_addr[1] << 8)  |
+		 (priv->mac_addr[0]);
+	mac_lo = (priv->mac_addr[5] << 8) |
+		 (priv->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 head and completion pointers to 0 */
+	for(cnt = 0; cnt < 8; cnt++) {
+		writel(0, (void *)&priv->adap_emac->TX0HDP + 4 * cnt);
+		writel(0, (void *)&priv->adap_emac->RX0HDP + 4 * cnt);
+		writel(0, (void *)&priv->adap_emac->TX0CP + 4 * cnt);
+		writel(0, (void *)&priv->adap_emac->RX0CP + 4 * cnt);
+	}
+
+	/* Clear Statistics (do this before setting MacControl register) */
+	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
+		writel(0, (void *)&priv->adap_emac->RXGOODFRAMES + 4 * cnt);
+
+	/* 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)
+{
+	uint32_t dly = 0xff;
+	uint32_t 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;
+	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((uint8_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;
+		}
+		if (is_timeout(start, 100 * MSECOND)) {
+			ret_status = -ETIMEDOUT;
+			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;
+	struct emac_desc *rx_curr_desc;
+	struct emac_desc *curr_desc;
+	struct 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 (status & EMAC_CPPI_OWNERSHIP_BIT) {
+		ret = 0;
+		goto out;
+	}
+
+	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);
+		}
+	}
+
+out:
+	dev_dbg(priv->dev, "- emac_recv\n");
+
+	return ret;
+}
+
+static int davinci_emac_probe(struct device_d *dev)
+{
+	struct davinci_emac_priv *priv;
+	uint64_t start;
+
+	dev_dbg(dev, "+ emac_probe\n");
+
+	priv = xzalloc(sizeof(*priv));
+	dev->priv = priv;
+
+	priv->dev = dev;
+
+	priv->adap_emac = (struct emac_regs *)dev_request_mem_region(dev, 0);
+	priv->adap_ewrap = (struct ewrap_regs *)dev_request_mem_region(dev, 1);
+	priv->adap_mdio = (struct mdio_regs *)dev_request_mem_region(dev, 2);
+
+	/* EMAC descriptors */
+	priv->emac_rx_desc = (struct emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
+	priv->emac_tx_desc = (struct 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;
+
+	davinci_eth_mdio_enable(priv);
+
+	start = get_time_ns();
+	while (1) {
+		if (readl(&priv->adap_mdio->ALIVE))
+			break;
+		if (is_timeout(start, 256 * MSECOND)) {
+			dev_err(dev, "No ETH PHY detected!\n");
+			break;
+		}
+	}
+
+	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..b5d1dfa
--- /dev/null
+++ b/drivers/net/davinci_emac.h
@@ -0,0 +1,318 @@
+/*
+ * 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
+
+/***********************************************
+ ******** 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 */
+struct emac_desc {
+	uint32_t	next;		/* Pointer to next descriptor in chain */
+	uint8_t		*buffer;	/* Pointer to data buffer */
+	uint32_t	buff_off_len;	/* Buffer Offset(MSW) and Length(LSW) */
+	uint32_t	pkt_flag_len;	/* Packet Flags(MSW) and Length(LSW) */
+};
+
+/* 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 */
+struct emac_regs {
+	uint32_t	TXIDVER;
+	uint32_t	TXCONTROL;
+	uint32_t	TXTEARDOWN;
+	uint8_t		RSVD0[4];
+	uint32_t	RXIDVER;
+	uint32_t	RXCONTROL;
+	uint32_t	RXTEARDOWN;
+	uint8_t		RSVD1[100];
+	uint32_t	TXINTSTATRAW;
+	uint32_t	TXINTSTATMASKED;
+	uint32_t	TXINTMASKSET;
+	uint32_t	TXINTMASKCLEAR;
+	uint32_t	MACINVECTOR;
+	uint8_t		RSVD2[12];
+	uint32_t	RXINTSTATRAW;
+	uint32_t	RXINTSTATMASKED;
+	uint32_t	RXINTMASKSET;
+	uint32_t	RXINTMASKCLEAR;
+	uint32_t	MACINTSTATRAW;
+	uint32_t	MACINTSTATMASKED;
+	uint32_t	MACINTMASKSET;
+	uint32_t	MACINTMASKCLEAR;
+	uint8_t		RSVD3[64];
+	uint32_t	RXMBPENABLE;
+	uint32_t	RXUNICASTSET;
+	uint32_t	RXUNICASTCLEAR;
+	uint32_t	RXMAXLEN;
+	uint32_t	RXBUFFEROFFSET;
+	uint32_t	RXFILTERLOWTHRESH;
+	uint8_t		RSVD4[8];
+	uint32_t	RX0FLOWTHRESH;
+	uint32_t	RX1FLOWTHRESH;
+	uint32_t	RX2FLOWTHRESH;
+	uint32_t	RX3FLOWTHRESH;
+	uint32_t	RX4FLOWTHRESH;
+	uint32_t	RX5FLOWTHRESH;
+	uint32_t	RX6FLOWTHRESH;
+	uint32_t	RX7FLOWTHRESH;
+	uint32_t	RX0FREEBUFFER;
+	uint32_t	RX1FREEBUFFER;
+	uint32_t	RX2FREEBUFFER;
+	uint32_t	RX3FREEBUFFER;
+	uint32_t	RX4FREEBUFFER;
+	uint32_t	RX5FREEBUFFER;
+	uint32_t	RX6FREEBUFFER;
+	uint32_t	RX7FREEBUFFER;
+	uint32_t	MACCONTROL;
+	uint32_t	MACSTATUS;
+	uint32_t	EMCONTROL;
+	uint32_t	FIFOCONTROL;
+	uint32_t	MACCONFIG;
+	uint32_t	SOFTRESET;
+	uint8_t		RSVD5[88];
+	uint32_t	MACSRCADDRLO;
+	uint32_t	MACSRCADDRHI;
+	uint32_t	MACHASH1;
+	uint32_t	MACHASH2;
+	uint32_t	BOFFTEST;
+	uint32_t	TPACETEST;
+	uint32_t	RXPAUSE;
+	uint32_t	TXPAUSE;
+	uint8_t		RSVD6[16];
+	uint32_t	RXGOODFRAMES;
+	uint32_t	RXBCASTFRAMES;
+	uint32_t	RXMCASTFRAMES;
+	uint32_t	RXPAUSEFRAMES;
+	uint32_t	RXCRCERRORS;
+	uint32_t	RXALIGNCODEERRORS;
+	uint32_t	RXOVERSIZED;
+	uint32_t	RXJABBER;
+	uint32_t	RXUNDERSIZED;
+	uint32_t	RXFRAGMENTS;
+	uint32_t	RXFILTERED;
+	uint32_t	RXQOSFILTERED;
+	uint32_t	RXOCTETS;
+	uint32_t	TXGOODFRAMES;
+	uint32_t	TXBCASTFRAMES;
+	uint32_t	TXMCASTFRAMES;
+	uint32_t	TXPAUSEFRAMES;
+	uint32_t	TXDEFERRED;
+	uint32_t	TXCOLLISION;
+	uint32_t	TXSINGLECOLL;
+	uint32_t	TXMULTICOLL;
+	uint32_t	TXEXCESSIVECOLL;
+	uint32_t	TXLATECOLL;
+	uint32_t	TXUNDERRUN;
+	uint32_t	TXCARRIERSENSE;
+	uint32_t	TXOCTETS;
+	uint32_t	FRAME64;
+	uint32_t	FRAME65T127;
+	uint32_t	FRAME128T255;
+	uint32_t	FRAME256T511;
+	uint32_t	FRAME512T1023;
+	uint32_t	FRAME1024TUP;
+	uint32_t	NETOCTETS;
+	uint32_t	RXSOFOVERRUNS;
+	uint32_t	RXMOFOVERRUNS;
+	uint32_t	RXDMAOVERRUNS;
+	uint8_t		RSVD7[624];
+	uint32_t	MACADDRLO;
+	uint32_t	MACADDRHI;
+	uint32_t	MACINDEX;
+	uint8_t		RSVD8[244];
+	uint32_t	TX0HDP;
+	uint32_t	TX1HDP;
+	uint32_t	TX2HDP;
+	uint32_t	TX3HDP;
+	uint32_t	TX4HDP;
+	uint32_t	TX5HDP;
+	uint32_t	TX6HDP;
+	uint32_t	TX7HDP;
+	uint32_t	RX0HDP;
+	uint32_t	RX1HDP;
+	uint32_t	RX2HDP;
+	uint32_t	RX3HDP;
+	uint32_t	RX4HDP;
+	uint32_t	RX5HDP;
+	uint32_t	RX6HDP;
+	uint32_t	RX7HDP;
+	uint32_t	TX0CP;
+	uint32_t	TX1CP;
+	uint32_t	TX2CP;
+	uint32_t	TX3CP;
+	uint32_t	TX4CP;
+	uint32_t	TX5CP;
+	uint32_t	TX6CP;
+	uint32_t	TX7CP;
+	uint32_t	RX0CP;
+	uint32_t	RX1CP;
+	uint32_t	RX2CP;
+	uint32_t	RX3CP;
+	uint32_t	RX4CP;
+	uint32_t	RX5CP;
+	uint32_t	RX6CP;
+	uint32_t	RX7CP;
+};
+
+/* EMAC Wrapper Registers Structure */
+struct ewrap_regs {
+#ifdef DAVINCI_EMAC_VERSION2
+	uint32_t	idver;
+	uint32_t	softrst;
+	uint32_t	emctrl;
+	uint32_t	c0rxthreshen;
+	uint32_t	c0rxen;
+	uint32_t	c0txen;
+	uint32_t	c0miscen;
+	uint32_t	c1rxthreshen;
+	uint32_t	c1rxen;
+	uint32_t	c1txen;
+	uint32_t	c1miscen;
+	uint32_t	c2rxthreshen;
+	uint32_t	c2rxen;
+	uint32_t	c2txen;
+	uint32_t	c2miscen;
+	uint32_t	c0rxthreshstat;
+	uint32_t	c0rxstat;
+	uint32_t	c0txstat;
+	uint32_t	c0miscstat;
+	uint32_t	c1rxthreshstat;
+	uint32_t	c1rxstat;
+	uint32_t	c1txstat;
+	uint32_t	c1miscstat;
+	uint32_t	c2rxthreshstat;
+	uint32_t	c2rxstat;
+	uint32_t	c2txstat;
+	uint32_t	c2miscstat;
+	uint32_t	c0rximax;
+	uint32_t	c0tximax;
+	uint32_t	c1rximax;
+	uint32_t	c1tximax;
+	uint32_t	c2rximax;
+	uint32_t	c2tximax;
+#else
+	uint8_t		RSVD0[4100];
+	uint32_t	EWCTL;
+	uint32_t	EWINTTCNT;
+#endif
+};
+
+/* EMAC MDIO Registers Structure */
+struct mdio_regs {
+	uint32_t	VERSION;
+	uint32_t	CONTROL;
+	uint32_t	ALIVE;
+	uint32_t	LINK;
+	uint32_t	LINKINTRAW;
+	uint32_t	LINKINTMASKED;
+	uint8_t	RSVD0[8];
+	uint32_t	USERINTRAW;
+	uint32_t	USERINTMASKED;
+	uint32_t	USERINTMASKSET;
+	uint32_t	USERINTMASKCLEAR;
+	uint8_t	RSVD1[80];
+	uint32_t	USERACCESS0;
+	uint32_t	USERPHYSEL0;
+	uint32_t	USERACCESS1;
+	uint32_t	USERPHYSEL1;
+};
+
+#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] 16+ messages in thread

* [PATCH 7/8] omap3: remove unused coded for clock configuration
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
                   ` (5 preceding siblings ...)
  2012-09-05 15:52 ` [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 15:52 ` [PATCH 8/8] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
  7 siblings, 0 replies; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 UTC (permalink / raw)
  To: barebox

Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
---
 arch/arm/mach-omap/Kconfig       |   17 -----------------
 arch/arm/mach-omap/omap3_clock.c |   14 +-------------
 2 files changed, 1 insertion(+), 30 deletions(-)

diff --git a/arch/arm/mach-omap/Kconfig b/arch/arm/mach-omap/Kconfig
index a781287..98750c4 100644
--- a/arch/arm/mach-omap/Kconfig
+++ b/arch/arm/mach-omap/Kconfig
@@ -52,20 +52,7 @@ config ARCH_OMAP4
 
 endchoice
 
-### Generic Clock configurations to be enabled by Mach - invisible to enable.
-config OMAP_CLOCK_UART
-	bool
-config OMAP_CLOCK_UART2
-	bool
-config OMAP_CLOCK_UART3
-	bool
-config OMAP_CLOCK_I2C
-	bool
-
 # Blind enable all possible clocks.. think twice before you do this.
-config OMAP_CLOCK_ALL
-	bool
-
 config OMAP_CLOCK_SOURCE_S32K
 	bool
 
@@ -117,14 +104,12 @@ choice
 
 config MACH_OMAP343xSDP
 	bool "Texas Instrument's SDP343x"
-	select OMAP_CLOCK_ALL
 	depends on ARCH_OMAP3
 	help
 	  Say Y here if you are using SDP343x platform
 
 config MACH_BEAGLE
 	bool "Texas Instrument's Beagle Board"
-	select OMAP_CLOCK_ALL
 	select HAVE_NOSHELL
 	depends on ARCH_OMAP3
 	  help
@@ -132,7 +117,6 @@ config MACH_BEAGLE
 
 config MACH_OMAP3EVM
 	bool "Texas Instrument's OMAP3 EVM"
-	select OMAP_CLOCK_ALL
 	select HAVE_NOSHELL
 	depends on ARCH_OMAP3
 	  help
@@ -157,7 +141,6 @@ config MACH_PCM049
 
 config MACH_PCAAL1
 	bool "Phytec phyCARD-A-L1"
-	select OMAP_CLOCK_ALL
 	select HAVE_NOSHELL
 	depends on ARCH_OMAP3
 	  help
diff --git a/arch/arm/mach-omap/omap3_clock.c b/arch/arm/mach-omap/omap3_clock.c
index 646235e..463633a 100644
--- a/arch/arm/mach-omap/omap3_clock.c
+++ b/arch/arm/mach-omap/omap3_clock.c
@@ -674,18 +674,6 @@ 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
-
-#ifdef CONFIG_OMAP_CLOCK_ALL
 #define FCK_IVA2_ON	0x00000001
 #define FCK_CORE1_ON	0x03fffe29
 #define ICK_CORE1_ON	0x3ffffffb
@@ -710,7 +698,7 @@ static void per_clocks_enable(void)
 	sr32(CM_REG(ICLKEN_CAM), 0, 32, ICK_CAM_ON);
 	sr32(CM_REG(FCLKEN_PER), 0, 32, FCK_PER_ON);
 	sr32(CM_REG(ICLKEN_PER), 0, 32, ICK_PER_ON);
-#endif
+
 	/* Settle down my friend */
 	sdelay(1000);
 }
-- 
1.7.10.4


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

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

* [PATCH 8/8] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs
  2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
                   ` (6 preceding siblings ...)
  2012-09-05 15:52 ` [PATCH 7/8] omap3: remove unused coded for clock configuration Jan Luebbe
@ 2012-09-05 15:52 ` Jan Luebbe
  2012-09-05 18:04   ` Jean-Christophe PLAGNIOL-VILLARD
  7 siblings, 1 reply; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 15:52 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 |   32 ++
 drivers/spi/Kconfig                             |    6 +
 drivers/spi/Makefile                            |    1 +
 drivers/spi/omap3_spi.c                         |  399 +++++++++++++++++++++++
 drivers/spi/omap3_spi.h                         |  100 ++++++
 6 files changed, 549 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..8a6b324
--- /dev/null
+++ b/arch/arm/mach-omap/include/mach/omap3-devices.h
@@ -0,0 +1,32 @@
+#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_spi(int id, resource_size_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);
+}
+
+static inline struct device_d *omap3_add_spi3(void)
+{
+	return omap3_add_spi(3, OMAP3_MCSPI3_BASE);
+}
+
+static inline struct device_d *omap3_add_spi4(void)
+{
+	return omap3_add_spi(4, OMAP3_MCSPI4_BASE);
+}
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index b5c55a4..dc17ead 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..c789bba
--- /dev/null
+++ b/drivers/spi/omap3_spi.c
@@ -0,0 +1,399 @@
+/*
+ * 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 <clock.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 MSECOND
+
+#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;
+	uint64_t timer_start;
+	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) */
+		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 -ETIMEDOUT;
+			}
+		}
+		/* 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;
+	uint64_t timer_start;
+	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) */
+		timer_start = get_time_ns();
+		while (!(readl(&regs->channel[spi->chip_select].chstat) &
+			 OMAP3_MCSPI_CHSTAT_RXS)) {
+			if (is_timeout(timer_start, SPI_WAIT_TIMEOUT)) {
+				printf("SPI RXS timed out, status=0x%08x\n",
+				       readl(&regs->channel[spi->chip_select].chstat));
+				return -ETIMEDOUT;
+			}
+		}
+		/* 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;
+	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) && (t->rx_buf != NULL)) {
+		printf("SPI error: full duplex unsupported\n");
+		ret = -EINVAL;
+	} else if (t->tx_buf != NULL) {
+		ret = omap3_spi_write(spi, len, txp, flags);
+	} else if (t->rx_buf != NULL) {
+		ret = omap3_spi_read(spi, len, rxp, flags);
+	} else {
+		printf("SPI error: neither tx_buf nor rx_buf set\n");
+		ret = -EINVAL;
+	}
+	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;
+		ret = spi_xfer(spi, t, flags);
+		if (ret < 0)
+			return ret;
+		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 -EINVAL;
+	}
+
+	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 -EINVAL;
+	}
+
+	if (spi->mode > SPI_MODE_3) {
+		printf("SPI error: unsupported SPI mode %i\n", spi->mode);
+		return -EINVAL;
+	}
+
+	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)
+	 *
+	 * The board code has to make sure that it does not use
+	 * invalid buses or chip selects.
+	 */
+
+	master->bus_num = dev->id;
+	master->num_chipselect = 4;
+	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] 16+ messages in thread

* Re: [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs
  2012-09-05 15:52 ` [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
@ 2012-09-05 18:03   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-06  7:20     ` Sascha Hauer
  0 siblings, 1 reply; 16+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-05 18:03 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On 17:52 Wed 05 Sep     , Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Again NACK

drop the struct XXXX on hte reg

Best Regards,
J.
> ---
>  arch/arm/mach-omap/include/mach/emac_defs.h |   53 +++
>  drivers/net/Kconfig                         |    5 +
>  drivers/net/Makefile                        |    1 +
>  drivers/net/davinci_emac.c                  |  615 +++++++++++++++++++++++++++
>  drivers/net/davinci_emac.h                  |  318 ++++++++++++++
>  5 files changed, 992 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 dac1eb9..bfde54b 100644
> --- a/drivers/net/Kconfig
> +++ b/drivers/net/Kconfig
> @@ -43,6 +43,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 951a220..52611f8 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..3615f96
> --- /dev/null
> +++ b/drivers/net/davinci_emac.c
> @@ -0,0 +1,615 @@
> +/*
> + * 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;
> +
> +	/* EMAC Addresses */
> +	struct emac_regs *adap_emac; /* = EMAC_BASE_ADDR */
> +	struct ewrap_regs *adap_ewrap; /* = EMAC_WRAPPER_BASE_ADDR */
> +	struct mdio_regs *adap_mdio; /* = EMAC_MDIO_BASE_ADDR */
> +
> +	/* EMAC descriptors */
> +	struct emac_desc *emac_rx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE */
> +	struct emac_desc *emac_tx_desc; /* = EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE */
> +	struct emac_desc *emac_rx_active_head; /* = 0 */
> +	struct 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) */
> +	uint8_t active_phy_addr; /* = 0xff */
> +
> +	/* mac_addr[0] goes out on the wire first */
> +	uint8_t mac_addr[6];
> +};
> +
> +#ifdef EMAC_HW_RAM_ADDR
> +static inline uint32_t BD_TO_HW(struct emac_desc *x)
> +{
> +	if (x == 0)
> +		return 0;
> +
> +	return (uint32_t)(x) - EMAC_WRAPPER_RAM_ADDR + EMAC_HW_RAM_ADDR;
> +}
> +
> +static inline struct emac_desc* HW_TO_BD(uint32_t x)
> +{
> +	if (x == 0)
> +		return 0;
> +
> +	return (struct 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)
> +{
> +	uint32_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 */
> +static int davinci_eth_phy_read(struct davinci_emac_priv *priv, uint8_t phy_addr, uint8_t reg_num, uint16_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. */
> +static int davinci_eth_phy_write(struct davinci_emac_priv *priv, uint8_t phy_addr, uint8_t reg_num, uint16_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;
> +}
> +
> +/*
> + * This function must be called before emac_open() if you want to override
> + * the default mac address.
> + */
> +static int davinci_emac_set_ethaddr(struct eth_device *edev, unsigned char *addr)
> +{
> +	struct davinci_emac_priv *priv = (struct davinci_emac_priv *)edev->priv;
> +	int i;
> +
> +	for (i = 0; i < sizeof(priv->mac_addr); i++)
> +		priv->mac_addr[i] = addr[i];
> +	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;
> +
> +	uint32_t	clkdiv, cnt;
> +	struct 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 = (priv->mac_addr[3] << 24) |
> +		 (priv->mac_addr[2] << 16) |
> +		 (priv->mac_addr[1] << 8)  |
> +		 (priv->mac_addr[0]);
> +	mac_lo = (priv->mac_addr[5] << 8) |
> +		 (priv->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 head and completion pointers to 0 */
> +	for(cnt = 0; cnt < 8; cnt++) {
> +		writel(0, (void *)&priv->adap_emac->TX0HDP + 4 * cnt);
> +		writel(0, (void *)&priv->adap_emac->RX0HDP + 4 * cnt);
> +		writel(0, (void *)&priv->adap_emac->TX0CP + 4 * cnt);
> +		writel(0, (void *)&priv->adap_emac->RX0CP + 4 * cnt);
> +	}
> +
> +	/* Clear Statistics (do this before setting MacControl register) */
> +	for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
> +		writel(0, (void *)&priv->adap_emac->RXGOODFRAMES + 4 * cnt);
> +
> +	/* 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)
> +{
> +	uint32_t dly = 0xff;
> +	uint32_t 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;
> +	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((uint8_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;
> +		}
> +		if (is_timeout(start, 100 * MSECOND)) {
> +			ret_status = -ETIMEDOUT;
> +			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;
> +	struct emac_desc *rx_curr_desc;
> +	struct emac_desc *curr_desc;
> +	struct 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 (status & EMAC_CPPI_OWNERSHIP_BIT) {
> +		ret = 0;
> +		goto out;
> +	}
> +
> +	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);
> +		}
> +	}
> +
> +out:
> +	dev_dbg(priv->dev, "- emac_recv\n");
> +
> +	return ret;
> +}
> +
> +static int davinci_emac_probe(struct device_d *dev)
> +{
> +	struct davinci_emac_priv *priv;
> +	uint64_t start;
> +
> +	dev_dbg(dev, "+ emac_probe\n");
> +
> +	priv = xzalloc(sizeof(*priv));
> +	dev->priv = priv;
> +
> +	priv->dev = dev;
> +
> +	priv->adap_emac = (struct emac_regs *)dev_request_mem_region(dev, 0);
> +	priv->adap_ewrap = (struct ewrap_regs *)dev_request_mem_region(dev, 1);
> +	priv->adap_mdio = (struct mdio_regs *)dev_request_mem_region(dev, 2);
> +
> +	/* EMAC descriptors */
> +	priv->emac_rx_desc = (struct emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
> +	priv->emac_tx_desc = (struct 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;
> +
> +	davinci_eth_mdio_enable(priv);
> +
> +	start = get_time_ns();
> +	while (1) {
> +		if (readl(&priv->adap_mdio->ALIVE))
> +			break;
> +		if (is_timeout(start, 256 * MSECOND)) {
> +			dev_err(dev, "No ETH PHY detected!\n");
> +			break;
> +		}
> +	}
> +
> +	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..b5d1dfa
> --- /dev/null
> +++ b/drivers/net/davinci_emac.h
> @@ -0,0 +1,318 @@
> +/*
> + * 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
> +
> +/***********************************************
> + ******** 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 */
> +struct emac_desc {
> +	uint32_t	next;		/* Pointer to next descriptor in chain */
> +	uint8_t		*buffer;	/* Pointer to data buffer */
> +	uint32_t	buff_off_len;	/* Buffer Offset(MSW) and Length(LSW) */
> +	uint32_t	pkt_flag_len;	/* Packet Flags(MSW) and Length(LSW) */
> +};
> +
> +/* 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 */
> +struct emac_regs {
> +	uint32_t	TXIDVER;
> +	uint32_t	TXCONTROL;
> +	uint32_t	TXTEARDOWN;
> +	uint8_t		RSVD0[4];
> +	uint32_t	RXIDVER;
> +	uint32_t	RXCONTROL;
> +	uint32_t	RXTEARDOWN;
> +	uint8_t		RSVD1[100];
> +	uint32_t	TXINTSTATRAW;
> +	uint32_t	TXINTSTATMASKED;
> +	uint32_t	TXINTMASKSET;
> +	uint32_t	TXINTMASKCLEAR;
> +	uint32_t	MACINVECTOR;
> +	uint8_t		RSVD2[12];
> +	uint32_t	RXINTSTATRAW;
> +	uint32_t	RXINTSTATMASKED;
> +	uint32_t	RXINTMASKSET;
> +	uint32_t	RXINTMASKCLEAR;
> +	uint32_t	MACINTSTATRAW;
> +	uint32_t	MACINTSTATMASKED;
> +	uint32_t	MACINTMASKSET;
> +	uint32_t	MACINTMASKCLEAR;
> +	uint8_t		RSVD3[64];
> +	uint32_t	RXMBPENABLE;
> +	uint32_t	RXUNICASTSET;
> +	uint32_t	RXUNICASTCLEAR;
> +	uint32_t	RXMAXLEN;
> +	uint32_t	RXBUFFEROFFSET;
> +	uint32_t	RXFILTERLOWTHRESH;
> +	uint8_t		RSVD4[8];
> +	uint32_t	RX0FLOWTHRESH;
> +	uint32_t	RX1FLOWTHRESH;
> +	uint32_t	RX2FLOWTHRESH;
> +	uint32_t	RX3FLOWTHRESH;
> +	uint32_t	RX4FLOWTHRESH;
> +	uint32_t	RX5FLOWTHRESH;
> +	uint32_t	RX6FLOWTHRESH;
> +	uint32_t	RX7FLOWTHRESH;
> +	uint32_t	RX0FREEBUFFER;
> +	uint32_t	RX1FREEBUFFER;
> +	uint32_t	RX2FREEBUFFER;
> +	uint32_t	RX3FREEBUFFER;
> +	uint32_t	RX4FREEBUFFER;
> +	uint32_t	RX5FREEBUFFER;
> +	uint32_t	RX6FREEBUFFER;
> +	uint32_t	RX7FREEBUFFER;
> +	uint32_t	MACCONTROL;
> +	uint32_t	MACSTATUS;
> +	uint32_t	EMCONTROL;
> +	uint32_t	FIFOCONTROL;
> +	uint32_t	MACCONFIG;
> +	uint32_t	SOFTRESET;
> +	uint8_t		RSVD5[88];
> +	uint32_t	MACSRCADDRLO;
> +	uint32_t	MACSRCADDRHI;
> +	uint32_t	MACHASH1;
> +	uint32_t	MACHASH2;
> +	uint32_t	BOFFTEST;
> +	uint32_t	TPACETEST;
> +	uint32_t	RXPAUSE;
> +	uint32_t	TXPAUSE;
> +	uint8_t		RSVD6[16];
> +	uint32_t	RXGOODFRAMES;
> +	uint32_t	RXBCASTFRAMES;
> +	uint32_t	RXMCASTFRAMES;
> +	uint32_t	RXPAUSEFRAMES;
> +	uint32_t	RXCRCERRORS;
> +	uint32_t	RXALIGNCODEERRORS;
> +	uint32_t	RXOVERSIZED;
> +	uint32_t	RXJABBER;
> +	uint32_t	RXUNDERSIZED;
> +	uint32_t	RXFRAGMENTS;
> +	uint32_t	RXFILTERED;
> +	uint32_t	RXQOSFILTERED;
> +	uint32_t	RXOCTETS;
> +	uint32_t	TXGOODFRAMES;
> +	uint32_t	TXBCASTFRAMES;
> +	uint32_t	TXMCASTFRAMES;
> +	uint32_t	TXPAUSEFRAMES;
> +	uint32_t	TXDEFERRED;
> +	uint32_t	TXCOLLISION;
> +	uint32_t	TXSINGLECOLL;
> +	uint32_t	TXMULTICOLL;
> +	uint32_t	TXEXCESSIVECOLL;
> +	uint32_t	TXLATECOLL;
> +	uint32_t	TXUNDERRUN;
> +	uint32_t	TXCARRIERSENSE;
> +	uint32_t	TXOCTETS;
> +	uint32_t	FRAME64;
> +	uint32_t	FRAME65T127;
> +	uint32_t	FRAME128T255;
> +	uint32_t	FRAME256T511;
> +	uint32_t	FRAME512T1023;
> +	uint32_t	FRAME1024TUP;
> +	uint32_t	NETOCTETS;
> +	uint32_t	RXSOFOVERRUNS;
> +	uint32_t	RXMOFOVERRUNS;
> +	uint32_t	RXDMAOVERRUNS;
> +	uint8_t		RSVD7[624];
> +	uint32_t	MACADDRLO;
> +	uint32_t	MACADDRHI;
> +	uint32_t	MACINDEX;
> +	uint8_t		RSVD8[244];
> +	uint32_t	TX0HDP;
> +	uint32_t	TX1HDP;
> +	uint32_t	TX2HDP;
> +	uint32_t	TX3HDP;
> +	uint32_t	TX4HDP;
> +	uint32_t	TX5HDP;
> +	uint32_t	TX6HDP;
> +	uint32_t	TX7HDP;
> +	uint32_t	RX0HDP;
> +	uint32_t	RX1HDP;
> +	uint32_t	RX2HDP;
> +	uint32_t	RX3HDP;
> +	uint32_t	RX4HDP;
> +	uint32_t	RX5HDP;
> +	uint32_t	RX6HDP;
> +	uint32_t	RX7HDP;
> +	uint32_t	TX0CP;
> +	uint32_t	TX1CP;
> +	uint32_t	TX2CP;
> +	uint32_t	TX3CP;
> +	uint32_t	TX4CP;
> +	uint32_t	TX5CP;
> +	uint32_t	TX6CP;
> +	uint32_t	TX7CP;
> +	uint32_t	RX0CP;
> +	uint32_t	RX1CP;
> +	uint32_t	RX2CP;
> +	uint32_t	RX3CP;
> +	uint32_t	RX4CP;
> +	uint32_t	RX5CP;
> +	uint32_t	RX6CP;
> +	uint32_t	RX7CP;
> +};
> +
> +/* EMAC Wrapper Registers Structure */
> +struct ewrap_regs {
> +#ifdef DAVINCI_EMAC_VERSION2
> +	uint32_t	idver;
> +	uint32_t	softrst;
> +	uint32_t	emctrl;
> +	uint32_t	c0rxthreshen;
> +	uint32_t	c0rxen;
> +	uint32_t	c0txen;
> +	uint32_t	c0miscen;
> +	uint32_t	c1rxthreshen;
> +	uint32_t	c1rxen;
> +	uint32_t	c1txen;
> +	uint32_t	c1miscen;
> +	uint32_t	c2rxthreshen;
> +	uint32_t	c2rxen;
> +	uint32_t	c2txen;
> +	uint32_t	c2miscen;
> +	uint32_t	c0rxthreshstat;
> +	uint32_t	c0rxstat;
> +	uint32_t	c0txstat;
> +	uint32_t	c0miscstat;
> +	uint32_t	c1rxthreshstat;
> +	uint32_t	c1rxstat;
> +	uint32_t	c1txstat;
> +	uint32_t	c1miscstat;
> +	uint32_t	c2rxthreshstat;
> +	uint32_t	c2rxstat;
> +	uint32_t	c2txstat;
> +	uint32_t	c2miscstat;
> +	uint32_t	c0rximax;
> +	uint32_t	c0tximax;
> +	uint32_t	c1rximax;
> +	uint32_t	c1tximax;
> +	uint32_t	c2rximax;
> +	uint32_t	c2tximax;
> +#else
> +	uint8_t		RSVD0[4100];
> +	uint32_t	EWCTL;
> +	uint32_t	EWINTTCNT;
> +#endif
> +};
> +
> +/* EMAC MDIO Registers Structure */
> +struct mdio_regs {
> +	uint32_t	VERSION;
> +	uint32_t	CONTROL;
> +	uint32_t	ALIVE;
> +	uint32_t	LINK;
> +	uint32_t	LINKINTRAW;
> +	uint32_t	LINKINTMASKED;
> +	uint8_t	RSVD0[8];
> +	uint32_t	USERINTRAW;
> +	uint32_t	USERINTMASKED;
> +	uint32_t	USERINTMASKSET;
> +	uint32_t	USERINTMASKCLEAR;
> +	uint8_t	RSVD1[80];
> +	uint32_t	USERACCESS0;
> +	uint32_t	USERPHYSEL0;
> +	uint32_t	USERACCESS1;
> +	uint32_t	USERPHYSEL1;
> +};
> +
> +#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] 16+ messages in thread

* Re: [PATCH 8/8] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs
  2012-09-05 15:52 ` [PATCH 8/8] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
@ 2012-09-05 18:04   ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 16+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-05 18:04 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On 17:52 Wed 05 Sep     , Jan Luebbe wrote:
> Also create devices for OMAP3.
> 
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
Again NACK

Drop the struct XXXX on the reg

Best Regards,
J.
> ---
>  arch/arm/mach-omap/include/mach/mcspi.h         |   11 +
>  arch/arm/mach-omap/include/mach/omap3-devices.h |   32 ++
>  drivers/spi/Kconfig                             |    6 +
>  drivers/spi/Makefile                            |    1 +
>  drivers/spi/omap3_spi.c                         |  399 +++++++++++++++++++++++
>  drivers/spi/omap3_spi.h                         |  100 ++++++
>  6 files changed, 549 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..8a6b324
> --- /dev/null
> +++ b/arch/arm/mach-omap/include/mach/omap3-devices.h
> @@ -0,0 +1,32 @@
> +#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_spi(int id, resource_size_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);
> +}
> +
> +static inline struct device_d *omap3_add_spi3(void)
> +{
> +	return omap3_add_spi(3, OMAP3_MCSPI3_BASE);
> +}
> +
> +static inline struct device_d *omap3_add_spi4(void)
> +{
> +	return omap3_add_spi(4, OMAP3_MCSPI4_BASE);
> +}
> diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
> index b5c55a4..dc17ead 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..c789bba
> --- /dev/null
> +++ b/drivers/spi/omap3_spi.c
> @@ -0,0 +1,399 @@
> +/*
> + * 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 <clock.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 MSECOND
> +
> +#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;
> +	uint64_t timer_start;
> +	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) */
> +		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 -ETIMEDOUT;
> +			}
> +		}
> +		/* 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;
> +	uint64_t timer_start;
> +	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) */
> +		timer_start = get_time_ns();
> +		while (!(readl(&regs->channel[spi->chip_select].chstat) &
> +			 OMAP3_MCSPI_CHSTAT_RXS)) {
> +			if (is_timeout(timer_start, SPI_WAIT_TIMEOUT)) {
> +				printf("SPI RXS timed out, status=0x%08x\n",
> +				       readl(&regs->channel[spi->chip_select].chstat));
> +				return -ETIMEDOUT;
> +			}
> +		}
> +		/* 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;
> +	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) && (t->rx_buf != NULL)) {
> +		printf("SPI error: full duplex unsupported\n");
> +		ret = -EINVAL;
> +	} else if (t->tx_buf != NULL) {
> +		ret = omap3_spi_write(spi, len, txp, flags);
> +	} else if (t->rx_buf != NULL) {
> +		ret = omap3_spi_read(spi, len, rxp, flags);
> +	} else {
> +		printf("SPI error: neither tx_buf nor rx_buf set\n");
> +		ret = -EINVAL;
> +	}
> +	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;
> +		ret = spi_xfer(spi, t, flags);
> +		if (ret < 0)
> +			return ret;
> +		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 -EINVAL;
> +	}
> +
> +	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 -EINVAL;
> +	}
> +
> +	if (spi->mode > SPI_MODE_3) {
> +		printf("SPI error: unsupported SPI mode %i\n", spi->mode);
> +		return -EINVAL;
> +	}
> +
> +	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)
> +	 *
> +	 * The board code has to make sure that it does not use
> +	 * invalid buses or chip selects.
> +	 */
> +
> +	master->bus_num = dev->id;
> +	master->num_chipselect = 4;
> +	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] 16+ messages in thread

* Re: [PATCH 2/8] Makefile: add target to produce a SPL compatible uimage
  2012-09-05 15:52 ` [PATCH 2/8] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
@ 2012-09-05 18:05   ` Jean-Christophe PLAGNIOL-VILLARD
  2012-09-05 19:10     ` Jan Luebbe
  0 siblings, 1 reply; 16+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-05 18:05 UTC (permalink / raw)
  To: Jan Luebbe; +Cc: barebox

On 17:52 Wed 05 Sep     , Jan Luebbe wrote:
> Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> ---
>  Makefile |   10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/Makefile b/Makefile
> index c6264d3..69e28e3 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -680,6 +680,16 @@ ifndef CONFIG_PBL_IMAGE
>  	$(call cmd,check_file_size,$(CONFIG_BAREBOX_MAX_IMAGE_SIZE))
>  endif
>  
> +# For development provide a target which makes barebox loadable by an
> +# unmodified u-boot
> +quiet_cmd_barebox_mkimage = MKIMAGE $@
> +      cmd_barebox_mkimage = $(srctree)/scripts/mkimage -A $(ARCH) -T firmware -C none \
> +	-O barebox -a $(CONFIG_TEXT_BASE) -e $(CONFIG_TEXT_BASE) \
> +	-n "barebox $(KERNELRELEASE)" -d $< $@
> +
> +barebox.img: barebox.bin FORCE
> +	$(call if_changed,barebox_mkimage)
this will not work whit the PBL

please fix it

Best Regards,
J.

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

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

* Re: [PATCH 2/8] Makefile: add target to produce a SPL compatible uimage
  2012-09-05 18:05   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-05 19:10     ` Jan Luebbe
  2012-09-05 20:19       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 16+ messages in thread
From: Jan Luebbe @ 2012-09-05 19:10 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

On Wed, Sep 05, 2012 at 08:05:16PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 17:52 Wed 05 Sep     , Jan Luebbe wrote:
> > +barebox.img: barebox.bin FORCE
> > +	$(call if_changed,barebox_mkimage)
> this will not work whit the PBL
> 
> please fix it

PBL is the preloader for the compressed barebox image?

While using that in an uImage doesn't seem very useful, how
would I fix it?

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] 16+ messages in thread

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

On 21:10 Wed 05 Sep     , Jan Luebbe wrote:
> On Wed, Sep 05, 2012 at 08:05:16PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > On 17:52 Wed 05 Sep     , Jan Luebbe wrote:
> > > +barebox.img: barebox.bin FORCE
> > > +	$(call if_changed,barebox_mkimage)
> > this will not work whit the PBL
> > 
> > please fix it
> 
> PBL is the preloader for the compressed barebox image?
> 
> While using that in an uImage doesn't seem very useful, how
> would I fix it?

so why do we do it to for the kernel?

As I already said check $(KBUILD_IMAGE)

Best Regards,
J.

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

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

* Re: [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs
  2012-09-05 18:03   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2012-09-06  7:20     ` Sascha Hauer
  2012-09-06  8:58       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 1 reply; 16+ messages in thread
From: Sascha Hauer @ 2012-09-06  7:20 UTC (permalink / raw)
  To: Jean-Christophe PLAGNIOL-VILLARD; +Cc: barebox

On Wed, Sep 05, 2012 at 08:03:20PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 17:52 Wed 05 Sep     , Jan Luebbe wrote:
> > Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> Again NACK
> 
> drop the struct XXXX on hte reg

I also don't like it, but let's not be religious about it.
Wolfgang currently forces all people to use structs for registers.
Forcing exactly the opposite is counterproductive I think. The original
drivers uses the structs and at some point it can be useful to compare
to this driver.

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] 16+ messages in thread

* Re: [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs
  2012-09-06  7:20     ` Sascha Hauer
@ 2012-09-06  8:58       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 16+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2012-09-06  8:58 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On 09:20 Thu 06 Sep     , Sascha Hauer wrote:
> On Wed, Sep 05, 2012 at 08:03:20PM +0200, Jean-Christophe PLAGNIOL-VILLARD wrote:
> > On 17:52 Wed 05 Sep     , Jan Luebbe wrote:
> > > Signed-off-by: Jan Luebbe <jlu@pengutronix.de>
> > Again NACK
> > 
> > drop the struct XXXX on hte reg
> 
> I also don't like it, but let's not be religious about it.
> Wolfgang currently forces all people to use structs for registers.
> Forcing exactly the opposite is counterproductive I think. The original
> drivers uses the structs and at some point it can be useful to compare
> to this driver.
this is really a shit to read the code is horible

So at the point we need to sync with the kernel

I'm working on the amba pl180 driver currently if I use the u-boot one my
board boot in 11s (just U-Boot), I re-write basing on linux I'm booting in arround
2s.

So I do not see the point to share the driver with u-boot, I prefer to have a
well writted one and optimised

Best Regards,
J.
> 
> 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] 16+ messages in thread

end of thread, other threads:[~2012-09-06  8:58 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-05 15:52 Prepare support for TI AM35xx Jan Luebbe
2012-09-05 15:52 ` [PATCH 1/8] drivers/nor/m25p80: add JEDEC ID for Micron/Numonyx SPI NOR flash Jan Luebbe
2012-09-05 15:52 ` [PATCH 2/8] Makefile: add target to produce a SPL compatible uimage Jan Luebbe
2012-09-05 18:05   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-05 19:10     ` Jan Luebbe
2012-09-05 20:19       ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-05 15:52 ` [PATCH 3/8] scripts: add tool to create image for SPI boot on AM35xx Jan Luebbe
2012-09-05 15:52 ` [PATCH 4/8] common: split out meminfo output and make it optional Jan Luebbe
2012-09-05 15:52 ` [PATCH 5/8] drivers/net/ksz8864rmn: add driver for Micrel KSZ8864RMN Ethernet Switch Jan Luebbe
2012-09-05 15:52 ` [PATCH 6/8] drivers/net: add driver for the EMAC device found in some TI SoCs Jan Luebbe
2012-09-05 18:03   ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-06  7:20     ` Sascha Hauer
2012-09-06  8:58       ` Jean-Christophe PLAGNIOL-VILLARD
2012-09-05 15:52 ` [PATCH 7/8] omap3: remove unused coded for clock configuration Jan Luebbe
2012-09-05 15:52 ` [PATCH 8/8] drivers/spi: add driver for the Multichannel SPI controller found in TI SoCs Jan Luebbe
2012-09-05 18:04   ` Jean-Christophe PLAGNIOL-VILLARD

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