summaryrefslogtreecommitdiff
path: root/cpu
diff options
context:
space:
mode:
authorGerald Van Baren <vanbaren@cideas.com>2007-08-10 19:19:50 -0400
committerGerald Van Baren <vanbaren@cideas.com>2007-08-10 19:19:50 -0400
commit29eaae953476f2bba4d5c7ac097b96cd827c1dff (patch)
tree537faa4c04db58ee7b070b56bd7de7bd116092d3 /cpu
parented8e5f362a2fc572eb9c1854f6c76c291b0f9a0f (diff)
parentfb56579ffe7ef3275b7036bb7b924e5a0d32bd70 (diff)
downloadu-boot-imx-29eaae953476f2bba4d5c7ac097b96cd827c1dff.zip
u-boot-imx-29eaae953476f2bba4d5c7ac097b96cd827c1dff.tar.gz
u-boot-imx-29eaae953476f2bba4d5c7ac097b96cd827c1dff.tar.bz2
Merge git://www.denx.de/git/u-boot
Diffstat (limited to 'cpu')
-rw-r--r--cpu/arm920t/at91rm9200/Makefile2
-rw-r--r--cpu/arm920t/at91rm9200/usb.c53
-rw-r--r--cpu/arm920t/at91rm9200/usb_ohci.c1635
-rw-r--r--cpu/arm920t/at91rm9200/usb_ohci.h419
-rw-r--r--cpu/arm920t/s3c24x0/Makefile2
-rw-r--r--cpu/arm920t/s3c24x0/usb.c72
-rw-r--r--cpu/arm926ejs/davinci/Makefile49
-rw-r--r--cpu/arm926ejs/davinci/dp83848.c156
-rw-r--r--cpu/arm926ejs/davinci/ether.c650
-rw-r--r--cpu/arm926ejs/davinci/i2c.c351
-rw-r--r--cpu/arm926ejs/davinci/lowlevel_init.S707
-rw-r--r--cpu/arm926ejs/davinci/lxt972.c142
-rw-r--r--cpu/arm926ejs/davinci/nand.c389
-rw-r--r--cpu/arm926ejs/davinci/reset.S77
-rw-r--r--cpu/arm926ejs/davinci/timer.c165
-rw-r--r--cpu/mpc5xxx/Makefile2
-rw-r--r--cpu/mpc5xxx/usb.c54
-rw-r--r--cpu/mpc83xx/Makefile2
-rw-r--r--cpu/mpc83xx/cpu.c118
-rw-r--r--cpu/mpc83xx/cpu_init.c50
-rw-r--r--cpu/mpc83xx/ecc.c390
-rw-r--r--cpu/mpc83xx/pci.c36
-rw-r--r--cpu/mpc83xx/spd_sdram.c13
-rw-r--r--cpu/ppc4xx/Makefile4
-rw-r--r--cpu/ppc4xx/usb.c50
-rw-r--r--cpu/pxa/Makefile2
-rw-r--r--cpu/pxa/usb.c79
27 files changed, 3552 insertions, 2117 deletions
diff --git a/cpu/arm920t/at91rm9200/Makefile b/cpu/arm920t/at91rm9200/Makefile
index 8d4e478..eaabad2 100644
--- a/cpu/arm920t/at91rm9200/Makefile
+++ b/cpu/arm920t/at91rm9200/Makefile
@@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).a
COBJS = bcm5221.o dm9161.o ether.o i2c.o interrupts.o \
- lxt972.o serial.o usb_ohci.o
+ lxt972.o serial.o usb.o
SOBJS = lowlevel_init.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/cpu/arm920t/at91rm9200/usb.c b/cpu/arm920t/at91rm9200/usb.c
new file mode 100644
index 0000000..366262e
--- /dev/null
+++ b/cpu/arm920t/at91rm9200/usb.c
@@ -0,0 +1,53 @@
+/*
+ * (C) Copyright 2006
+ * DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT)
+# ifdef CONFIG_AT91RM9200
+
+#include <asm/arch/hardware.h>
+
+int usb_cpu_init()
+{
+ /* Enable USB host clock. */
+ *AT91C_PMC_SCER = AT91C_PMC_UHP; /* 48MHz clock enabled for UHP */
+ *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; /* Peripheral Clock Enable Register */
+ return 0;
+}
+
+int usb_cpu_stop()
+{
+ /* Initialization failed */
+ *AT91C_PMC_PCDR = 1 << AT91C_ID_UHP; /* Peripheral Clock Disable Register */
+ *AT91C_PMC_SCDR = AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */
+ return 0;
+}
+
+int usb_cpu_init_fail()
+{
+ usb_cpu_stop();
+}
+
+# endif /* CONFIG_AT91RM9200 */
+#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */
diff --git a/cpu/arm920t/at91rm9200/usb_ohci.c b/cpu/arm920t/at91rm9200/usb_ohci.c
deleted file mode 100644
index 5b2c56c..0000000
--- a/cpu/arm920t/at91rm9200/usb_ohci.c
+++ /dev/null
@@ -1,1635 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB on the AT91RM9200.
- *
- * (C) Copyright 2003
- * Gary Jennejohn, DENX Software Engineering <gj@denx.de>
- *
- * Note: Much of this code has been derived from Linux 2.4
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2002 David Brownell
- *
- * Modified for the MP2USB by (C) Copyright 2005 Eric Benard
- * ebenard@eukrea.com - based on s3c24x0's driver
- *
- * 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
- *
- */
-/*
- * IMPORTANT NOTES
- * 1 - you MUST define LITTLEENDIAN in the configuration file for the
- * board or this driver will NOT work!
- * 2 - this driver is intended for use with USB Mass Storage Devices
- * (BBB) ONLY. There is NO support for Interrupt or Isochronous pipes!
- * 3 - when running on a PQFP208 AT91RM9200, define CONFIG_AT91C_PQFP_UHPBUG
- * to activate workaround for bug #41 or this driver will NOT work!
- */
-
-#include <common.h>
-/* #include <pci.h> no PCI on the S3C24X0 */
-
-#ifdef CONFIG_USB_OHCI
-
-#include <asm/arch/hardware.h>
-
-#include <malloc.h>
-#include <usb.h>
-#include "usb_ohci.h"
-
-#define OHCI_USE_NPS /* force NoPowerSwitching mode */
-#undef OHCI_VERBOSE_DEBUG /* not always helpful */
-
-/* For initializing controller (mask in an HCFS mode too) */
-#define OHCI_CONTROL_INIT \
- (OHCI_CTRL_CBSR & 0x3) | OHCI_CTRL_IE | OHCI_CTRL_PLE
-
-#define readl(a) (*((vu_long *)(a)))
-#define writel(a, b) (*((vu_long *)(b)) = ((vu_long)a))
-
-#define min_t(type,x,y) ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-
-#undef DEBUG
-#ifdef DEBUG
-#define dbg(format, arg...) printf("DEBUG: " format "\n", ## arg)
-#else
-#define dbg(format, arg...) do {} while(0)
-#endif /* DEBUG */
-#define err(format, arg...) printf("ERROR: " format "\n", ## arg)
-#undef SHOW_INFO
-#ifdef SHOW_INFO
-#define info(format, arg...) printf("INFO: " format "\n", ## arg)
-#else
-#define info(format, arg...) do {} while(0)
-#endif
-
-#define m16_swap(x) swap_16(x)
-#define m32_swap(x) swap_32(x)
-
-/* global ohci_t */
-static ohci_t gohci;
-/* this must be aligned to a 256 byte boundary */
-struct ohci_hcca ghcca[1];
-/* a pointer to the aligned storage */
-struct ohci_hcca *phcca;
-/* this allocates EDs for all possible endpoints */
-struct ohci_device ohci_dev;
-/* urb_priv */
-urb_priv_t urb_priv;
-/* RHSC flag */
-int got_rhsc;
-/* device which was disconnected */
-struct usb_device *devgone;
-
-/*-------------------------------------------------------------------------*/
-
-/* AMD-756 (D2 rev) reports corrupt register contents in some cases.
- * The erratum (#4) description is incorrect. AMD's workaround waits
- * till some bits (mostly reserved) are clear; ok for all revs.
- */
-#define OHCI_QUIRK_AMD756 0xabcd
-#define read_roothub(hc, register, mask) ({ \
- u32 temp = readl (&hc->regs->roothub.register); \
- if (hc->flags & OHCI_QUIRK_AMD756) \
- while (temp & mask) \
- temp = readl (&hc->regs->roothub.register); \
- temp; })
-
-static u32 roothub_a (struct ohci *hc)
- { return read_roothub (hc, a, 0xfc0fe000); }
-static inline u32 roothub_b (struct ohci *hc)
- { return readl (&hc->regs->roothub.b); }
-static inline u32 roothub_status (struct ohci *hc)
- { return readl (&hc->regs->roothub.status); }
-static u32 roothub_portstatus (struct ohci *hc, int i)
- { return read_roothub (hc, portstatus [i], 0xffe0fce0); }
-
-
-/* forward declaration */
-static int hc_interrupt (void);
-static void
-td_submit_job (struct usb_device * dev, unsigned long pipe, void * buffer,
- int transfer_len, struct devrequest * setup, urb_priv_t * urb, int interval);
-
-/*-------------------------------------------------------------------------*
- * URB support functions
- *-------------------------------------------------------------------------*/
-
-/* free HCD-private data associated with this URB */
-
-static void urb_free_priv (urb_priv_t * urb)
-{
- int i;
- int last;
- struct td * td;
-
- last = urb->length - 1;
- if (last >= 0) {
- for (i = 0; i <= last; i++) {
- td = urb->td[i];
- if (td) {
- td->usb_dev = NULL;
- urb->td[i] = NULL;
- }
- }
- }
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-static int sohci_get_current_frame_number (struct usb_device * dev);
-
-/* debug| print the main components of an URB
- * small: 0) header + data packets 1) just header */
-
-static void pkt_print (struct usb_device * dev, unsigned long pipe, void * buffer,
- int transfer_len, struct devrequest * setup, char * str, int small)
-{
- urb_priv_t * purb = &urb_priv;
-
- dbg("%s URB:[%4x] dev:%2d,ep:%2d-%c,type:%s,len:%d/%d stat:%#lx",
- str,
- sohci_get_current_frame_number (dev),
- usb_pipedevice (pipe),
- usb_pipeendpoint (pipe),
- usb_pipeout (pipe)? 'O': 'I',
- usb_pipetype (pipe) < 2? (usb_pipeint (pipe)? "INTR": "ISOC"):
- (usb_pipecontrol (pipe)? "CTRL": "BULK"),
- purb->actual_length,
- transfer_len, dev->status);
-#ifdef OHCI_VERBOSE_DEBUG
- if (!small) {
- int i, len;
-
- if (usb_pipecontrol (pipe)) {
- printf (__FILE__ ": cmd(8):");
- for (i = 0; i < 8 ; i++)
- printf (" %02x", ((__u8 *) setup) [i]);
- printf ("\n");
- }
- if (transfer_len > 0 && buffer) {
- printf (__FILE__ ": data(%d/%d):",
- purb->actual_length,
- transfer_len);
- len = usb_pipeout (pipe)?
- transfer_len: purb->actual_length;
- for (i = 0; i < 16 && i < len; i++)
- printf (" %02x", ((__u8 *) buffer) [i]);
- printf ("%s\n", i < len? "...": "");
- }
- }
-#endif
-}
-
-/* just for debugging; prints non-empty branches of the int ed tree inclusive iso eds*/
-void ep_print_int_eds (ohci_t *ohci, char * str) {
- int i, j;
- __u32 * ed_p;
- for (i= 0; i < 32; i++) {
- j = 5;
- ed_p = &(ohci->hcca->int_table [i]);
- if (*ed_p == 0)
- continue;
- printf (__FILE__ ": %s branch int %2d(%2x):", str, i, i);
- while (*ed_p != 0 && j--) {
- ed_t *ed = (ed_t *)m32_swap(ed_p);
- printf (" ed: %4x;", ed->hwINFO);
- ed_p = &ed->hwNextED;
- }
- printf ("\n");
- }
-}
-
-static void ohci_dump_intr_mask (char *label, __u32 mask)
-{
- dbg ("%s: 0x%08x%s%s%s%s%s%s%s%s%s",
- label,
- mask,
- (mask & OHCI_INTR_MIE) ? " MIE" : "",
- (mask & OHCI_INTR_OC) ? " OC" : "",
- (mask & OHCI_INTR_RHSC) ? " RHSC" : "",
- (mask & OHCI_INTR_FNO) ? " FNO" : "",
- (mask & OHCI_INTR_UE) ? " UE" : "",
- (mask & OHCI_INTR_RD) ? " RD" : "",
- (mask & OHCI_INTR_SF) ? " SF" : "",
- (mask & OHCI_INTR_WDH) ? " WDH" : "",
- (mask & OHCI_INTR_SO) ? " SO" : ""
- );
-}
-
-static void maybe_print_eds (char *label, __u32 value)
-{
- ed_t *edp = (ed_t *)value;
-
- if (value) {
- dbg ("%s %08x", label, value);
- dbg ("%08x", edp->hwINFO);
- dbg ("%08x", edp->hwTailP);
- dbg ("%08x", edp->hwHeadP);
- dbg ("%08x", edp->hwNextED);
- }
-}
-
-static char * hcfs2string (int state)
-{
- switch (state) {
- case OHCI_USB_RESET: return "reset";
- case OHCI_USB_RESUME: return "resume";
- case OHCI_USB_OPER: return "operational";
- case OHCI_USB_SUSPEND: return "suspend";
- }
- return "?";
-}
-
-/* dump control and status registers */
-static void ohci_dump_status (ohci_t *controller)
-{
- struct ohci_regs *regs = controller->regs;
- __u32 temp;
-
- temp = readl (&regs->revision) & 0xff;
- if (temp != 0x10)
- dbg ("spec %d.%d", (temp >> 4), (temp & 0x0f));
-
- temp = readl (&regs->control);
- dbg ("control: 0x%08x%s%s%s HCFS=%s%s%s%s%s CBSR=%d", temp,
- (temp & OHCI_CTRL_RWE) ? " RWE" : "",
- (temp & OHCI_CTRL_RWC) ? " RWC" : "",
- (temp & OHCI_CTRL_IR) ? " IR" : "",
- hcfs2string (temp & OHCI_CTRL_HCFS),
- (temp & OHCI_CTRL_BLE) ? " BLE" : "",
- (temp & OHCI_CTRL_CLE) ? " CLE" : "",
- (temp & OHCI_CTRL_IE) ? " IE" : "",
- (temp & OHCI_CTRL_PLE) ? " PLE" : "",
- temp & OHCI_CTRL_CBSR
- );
-
- temp = readl (&regs->cmdstatus);
- dbg ("cmdstatus: 0x%08x SOC=%d%s%s%s%s", temp,
- (temp & OHCI_SOC) >> 16,
- (temp & OHCI_OCR) ? " OCR" : "",
- (temp & OHCI_BLF) ? " BLF" : "",
- (temp & OHCI_CLF) ? " CLF" : "",
- (temp & OHCI_HCR) ? " HCR" : ""
- );
-
- ohci_dump_intr_mask ("intrstatus", readl (&regs->intrstatus));
- ohci_dump_intr_mask ("intrenable", readl (&regs->intrenable));
-
- maybe_print_eds ("ed_periodcurrent", readl (&regs->ed_periodcurrent));
-
- maybe_print_eds ("ed_controlhead", readl (&regs->ed_controlhead));
- maybe_print_eds ("ed_controlcurrent", readl (&regs->ed_controlcurrent));
-
- maybe_print_eds ("ed_bulkhead", readl (&regs->ed_bulkhead));
- maybe_print_eds ("ed_bulkcurrent", readl (&regs->ed_bulkcurrent));
-
- maybe_print_eds ("donehead", readl (&regs->donehead));
-}
-
-static void ohci_dump_roothub (ohci_t *controller, int verbose)
-{
- __u32 temp, ndp, i;
-
- temp = roothub_a (controller);
- ndp = (temp & RH_A_NDP);
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
- ndp = (ndp == 2) ? 1:0;
-#endif
- if (verbose) {
- dbg ("roothub.a: %08x POTPGT=%d%s%s%s%s%s NDP=%d", temp,
- ((temp & RH_A_POTPGT) >> 24) & 0xff,
- (temp & RH_A_NOCP) ? " NOCP" : "",
- (temp & RH_A_OCPM) ? " OCPM" : "",
- (temp & RH_A_DT) ? " DT" : "",
- (temp & RH_A_NPS) ? " NPS" : "",
- (temp & RH_A_PSM) ? " PSM" : "",
- ndp
- );
- temp = roothub_b (controller);
- dbg ("roothub.b: %08x PPCM=%04x DR=%04x",
- temp,
- (temp & RH_B_PPCM) >> 16,
- (temp & RH_B_DR)
- );
- temp = roothub_status (controller);
- dbg ("roothub.status: %08x%s%s%s%s%s%s",
- temp,
- (temp & RH_HS_CRWE) ? " CRWE" : "",
- (temp & RH_HS_OCIC) ? " OCIC" : "",
- (temp & RH_HS_LPSC) ? " LPSC" : "",
- (temp & RH_HS_DRWE) ? " DRWE" : "",
- (temp & RH_HS_OCI) ? " OCI" : "",
- (temp & RH_HS_LPS) ? " LPS" : ""
- );
- }
-
- for (i = 0; i < ndp; i++) {
- temp = roothub_portstatus (controller, i);
- dbg ("roothub.portstatus [%d] = 0x%08x%s%s%s%s%s%s%s%s%s%s%s%s",
- i,
- temp,
- (temp & RH_PS_PRSC) ? " PRSC" : "",
- (temp & RH_PS_OCIC) ? " OCIC" : "",
- (temp & RH_PS_PSSC) ? " PSSC" : "",
- (temp & RH_PS_PESC) ? " PESC" : "",
- (temp & RH_PS_CSC) ? " CSC" : "",
-
- (temp & RH_PS_LSDA) ? " LSDA" : "",
- (temp & RH_PS_PPS) ? " PPS" : "",
- (temp & RH_PS_PRS) ? " PRS" : "",
- (temp & RH_PS_POCI) ? " POCI" : "",
- (temp & RH_PS_PSS) ? " PSS" : "",
-
- (temp & RH_PS_PES) ? " PES" : "",
- (temp & RH_PS_CCS) ? " CCS" : ""
- );
- }
-}
-
-static void ohci_dump (ohci_t *controller, int verbose)
-{
- dbg ("OHCI controller usb-%s state", controller->slot_name);
-
- /* dumps some of the state we know about */
- ohci_dump_status (controller);
- if (verbose)
- ep_print_int_eds (controller, "hcca");
- dbg ("hcca frame #%04x", controller->hcca->frame_no);
- ohci_dump_roothub (controller, 1);
-}
-
-
-#endif /* DEBUG */
-
-/*-------------------------------------------------------------------------*
- * Interface functions (URB)
- *-------------------------------------------------------------------------*/
-
-/* get a transfer request */
-
-int sohci_submit_job(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, struct devrequest *setup, int interval)
-{
- ohci_t *ohci;
- ed_t * ed;
- urb_priv_t *purb_priv;
- int i, size = 0;
-
- ohci = &gohci;
-
- /* when controller's hung, permit only roothub cleanup attempts
- * such as powering down ports */
- if (ohci->disabled) {
- err("sohci_submit_job: EPIPE");
- return -1;
- }
-
- /* every endpoint has a ed, locate and fill it */
- if (!(ed = ep_add_ed (dev, pipe))) {
- err("sohci_submit_job: ENOMEM");
- return -1;
- }
-
- /* for the private part of the URB we need the number of TDs (size) */
- switch (usb_pipetype (pipe)) {
- case PIPE_BULK: /* one TD for every 4096 Byte */
- size = (transfer_len - 1) / 4096 + 1;
- break;
- case PIPE_CONTROL: /* 1 TD for setup, 1 for ACK and 1 for every 4096 B */
- size = (transfer_len == 0)? 2:
- (transfer_len - 1) / 4096 + 3;
- break;
- }
-
- if (size >= (N_URB_TD - 1)) {
- err("need %d TDs, only have %d", size, N_URB_TD);
- return -1;
- }
- purb_priv = &urb_priv;
- purb_priv->pipe = pipe;
-
- /* fill the private part of the URB */
- purb_priv->length = size;
- purb_priv->ed = ed;
- purb_priv->actual_length = 0;
-
- /* allocate the TDs */
- /* note that td[0] was allocated in ep_add_ed */
- for (i = 0; i < size; i++) {
- purb_priv->td[i] = td_alloc (dev);
- if (!purb_priv->td[i]) {
- purb_priv->length = i;
- urb_free_priv (purb_priv);
- err("sohci_submit_job: ENOMEM");
- return -1;
- }
- }
-
- if (ed->state == ED_NEW || (ed->state & ED_DEL)) {
- urb_free_priv (purb_priv);
- err("sohci_submit_job: EINVAL");
- return -1;
- }
-
- /* link the ed into a chain if is not already */
- if (ed->state != ED_OPER)
- ep_link (ohci, ed);
-
- /* fill the TDs and link it to the ed */
- td_submit_job(dev, pipe, buffer, transfer_len, setup, purb_priv, interval);
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef DEBUG
-/* tell us the current USB frame number */
-
-static int sohci_get_current_frame_number (struct usb_device *usb_dev)
-{
- ohci_t *ohci = &gohci;
-
- return m16_swap (ohci->hcca->frame_no);
-}
-#endif
-
-/*-------------------------------------------------------------------------*
- * ED handling functions
- *-------------------------------------------------------------------------*/
-
-/* link an ed into one of the HC chains */
-
-static int ep_link (ohci_t *ohci, ed_t *edi)
-{
- volatile ed_t *ed = edi;
-
- ed->state = ED_OPER;
-
- switch (ed->type) {
- case PIPE_CONTROL:
- ed->hwNextED = 0;
- if (ohci->ed_controltail == NULL) {
- writel (ed, &ohci->regs->ed_controlhead);
- } else {
- ohci->ed_controltail->hwNextED = m32_swap (ed);
- }
- ed->ed_prev = ohci->ed_controltail;
- if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1] && !ohci->sleeping) {
- ohci->hc_control |= OHCI_CTRL_CLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- ohci->ed_controltail = edi;
- break;
-
- case PIPE_BULK:
- ed->hwNextED = 0;
- if (ohci->ed_bulktail == NULL) {
- writel (ed, &ohci->regs->ed_bulkhead);
- } else {
- ohci->ed_bulktail->hwNextED = m32_swap (ed);
- }
- ed->ed_prev = ohci->ed_bulktail;
- if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1] && !ohci->sleeping) {
- ohci->hc_control |= OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- ohci->ed_bulktail = edi;
- break;
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* unlink an ed from one of the HC chains.
- * just the link to the ed is unlinked.
- * the link from the ed still points to another operational ed or 0
- * so the HC can eventually finish the processing of the unlinked ed */
-
-static int ep_unlink (ohci_t *ohci, ed_t *ed)
-{
- ed->hwINFO |= m32_swap (OHCI_ED_SKIP);
-
- switch (ed->type) {
- case PIPE_CONTROL:
- if (ed->ed_prev == NULL) {
- if (!ed->hwNextED) {
- ohci->hc_control &= ~OHCI_CTRL_CLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_controlhead);
- } else {
- ed->ed_prev->hwNextED = ed->hwNextED;
- }
- if (ohci->ed_controltail == ed) {
- ohci->ed_controltail = ed->ed_prev;
- } else {
- ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
- }
- break;
-
- case PIPE_BULK:
- if (ed->ed_prev == NULL) {
- if (!ed->hwNextED) {
- ohci->hc_control &= ~OHCI_CTRL_BLE;
- writel (ohci->hc_control, &ohci->regs->control);
- }
- writel (m32_swap (*((__u32 *)&ed->hwNextED)), &ohci->regs->ed_bulkhead);
- } else {
- ed->ed_prev->hwNextED = ed->hwNextED;
- }
- if (ohci->ed_bulktail == ed) {
- ohci->ed_bulktail = ed->ed_prev;
- } else {
- ((ed_t *)m32_swap (*((__u32 *)&ed->hwNextED)))->ed_prev = ed->ed_prev;
- }
- break;
- }
- ed->state = ED_UNLINK;
- return 0;
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-/* add/reinit an endpoint; this should be done once at the usb_set_configuration command,
- * but the USB stack is a little bit stateless so we do it at every transaction
- * if the state of the ed is ED_NEW then a dummy td is added and the state is changed to ED_UNLINK
- * in all other cases the state is left unchanged
- * the ed info fields are setted anyway even though most of them should not change */
-
-static ed_t * ep_add_ed (struct usb_device *usb_dev, unsigned long pipe)
-{
- td_t *td;
- ed_t *ed_ret;
- volatile ed_t *ed;
-
- ed = ed_ret = &ohci_dev.ed[(usb_pipeendpoint (pipe) << 1) |
- (usb_pipecontrol (pipe)? 0: usb_pipeout (pipe))];
-
- if ((ed->state & ED_DEL) || (ed->state & ED_URB_DEL)) {
- err("ep_add_ed: pending delete");
- /* pending delete request */
- return NULL;
- }
-
- if (ed->state == ED_NEW) {
- ed->hwINFO = m32_swap (OHCI_ED_SKIP); /* skip ed */
- /* dummy td; end of td list for ed */
- td = td_alloc (usb_dev);
- ed->hwTailP = m32_swap (td);
- ed->hwHeadP = ed->hwTailP;
- ed->state = ED_UNLINK;
- ed->type = usb_pipetype (pipe);
- ohci_dev.ed_cnt++;
- }
-
- ed->hwINFO = m32_swap (usb_pipedevice (pipe)
- | usb_pipeendpoint (pipe) << 7
- | (usb_pipeisoc (pipe)? 0x8000: 0)
- | (usb_pipecontrol (pipe)? 0: (usb_pipeout (pipe)? 0x800: 0x1000))
- | usb_pipeslow (pipe) << 13
- | usb_maxpacket (usb_dev, pipe) << 16);
-
- return ed_ret;
-}
-
-/*-------------------------------------------------------------------------*
- * TD handling functions
- *-------------------------------------------------------------------------*/
-
-/* enqueue next TD for this URB (OHCI spec 5.2.8.2) */
-
-static void td_fill (ohci_t *ohci, unsigned int info,
- void *data, int len,
- struct usb_device *dev, int index, urb_priv_t *urb_priv)
-{
- volatile td_t *td, *td_pt;
-#ifdef OHCI_FILL_TRACE
- int i;
-#endif
-
- if (index > urb_priv->length) {
- err("index > length");
- return;
- }
- /* use this td as the next dummy */
- td_pt = urb_priv->td [index];
- td_pt->hwNextTD = 0;
-
- /* fill the old dummy TD */
- td = urb_priv->td [index] = (td_t *)(m32_swap (urb_priv->ed->hwTailP) & ~0xf);
-
- td->ed = urb_priv->ed;
- td->next_dl_td = NULL;
- td->index = index;
- td->data = (__u32)data;
-#ifdef OHCI_FILL_TRACE
- if ((usb_pipetype(urb_priv->pipe) == PIPE_BULK) && usb_pipeout(urb_priv->pipe)) {
- for (i = 0; i < len; i++)
- printf("td->data[%d] %#2x ",i, ((unsigned char *)td->data)[i]);
- printf("\n");
- }
-#endif
- if (!len)
- data = 0;
-
- td->hwINFO = m32_swap (info);
- td->hwCBP = m32_swap (data);
- if (data)
- td->hwBE = m32_swap (data + len - 1);
- else
- td->hwBE = 0;
- td->hwNextTD = m32_swap (td_pt);
- td->hwPSW [0] = m16_swap (((__u32)data & 0x0FFF) | 0xE000);
-
- /* append to queue */
- td->ed->hwTailP = td->hwNextTD;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* prepare all TDs of a transfer */
-
-static void td_submit_job (struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, struct devrequest *setup, urb_priv_t *urb, int interval)
-{
- ohci_t *ohci = &gohci;
- int data_len = transfer_len;
- void *data;
- int cnt = 0;
- __u32 info = 0;
- unsigned int toggle = 0;
-
- /* OHCI handles the DATA-toggles itself, we just use the USB-toggle bits for reseting */
- if(usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
- toggle = TD_T_TOGGLE;
- } else {
- toggle = TD_T_DATA0;
- usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 1);
- }
- urb->td_cnt = 0;
- if (data_len)
- data = buffer;
- else
- data = 0;
-
- switch (usb_pipetype (pipe)) {
- case PIPE_BULK:
- info = usb_pipeout (pipe)?
- TD_CC | TD_DP_OUT : TD_CC | TD_DP_IN ;
- while(data_len > 4096) {
- td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, 4096, dev, cnt, urb);
- data += 4096; data_len -= 4096; cnt++;
- }
- info = usb_pipeout (pipe)?
- TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
- td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, dev, cnt, urb);
- cnt++;
-
- if (!ohci->sleeping)
- writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
- break;
-
- case PIPE_CONTROL:
- info = TD_CC | TD_DP_SETUP | TD_T_DATA0;
- td_fill (ohci, info, setup, 8, dev, cnt++, urb);
- if (data_len > 0) {
- info = usb_pipeout (pipe)?
- TD_CC | TD_R | TD_DP_OUT | TD_T_DATA1 : TD_CC | TD_R | TD_DP_IN | TD_T_DATA1;
- /* NOTE: mishandles transfers >8K, some >4K */
- td_fill (ohci, info, data, data_len, dev, cnt++, urb);
- }
- info = usb_pipeout (pipe)?
- TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
- td_fill (ohci, info, data, 0, dev, cnt++, urb);
- if (!ohci->sleeping)
- writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
- break;
- }
- if (urb->length != cnt)
- dbg("TD LENGTH %d != CNT %d", urb->length, cnt);
-}
-
-/*-------------------------------------------------------------------------*
- * Done List handling functions
- *-------------------------------------------------------------------------*/
-
-
-/* calculate the transfer length and update the urb */
-
-static void dl_transfer_length(td_t * td)
-{
- __u32 tdINFO, tdBE, tdCBP;
- urb_priv_t *lurb_priv = &urb_priv;
-
- tdINFO = m32_swap (td->hwINFO);
- tdBE = m32_swap (td->hwBE);
- tdCBP = m32_swap (td->hwCBP);
-
-
- if (!(usb_pipetype (lurb_priv->pipe) == PIPE_CONTROL &&
- ((td->index == 0) || (td->index == lurb_priv->length - 1)))) {
- if (tdBE != 0) {
- if (td->hwCBP == 0)
- lurb_priv->actual_length += tdBE - td->data + 1;
- else
- lurb_priv->actual_length += tdCBP - td->data;
- }
- }
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* replies to the request have to be on a FIFO basis so
- * we reverse the reversed done-list */
-
-static td_t * dl_reverse_done_list (ohci_t *ohci)
-{
- __u32 td_list_hc;
- td_t *td_rev = NULL;
- td_t *td_list = NULL;
- urb_priv_t *lurb_priv = NULL;
-
- td_list_hc = m32_swap (ohci->hcca->done_head) & 0xfffffff0;
- ohci->hcca->done_head = 0;
-
- while (td_list_hc) {
- td_list = (td_t *)td_list_hc;
-
- if (TD_CC_GET (m32_swap (td_list->hwINFO))) {
- lurb_priv = &urb_priv;
- dbg(" USB-error/status: %x : %p",
- TD_CC_GET (m32_swap (td_list->hwINFO)), td_list);
- if (td_list->ed->hwHeadP & m32_swap (0x1)) {
- if (lurb_priv && ((td_list->index + 1) < lurb_priv->length)) {
- td_list->ed->hwHeadP =
- (lurb_priv->td[lurb_priv->length - 1]->hwNextTD & m32_swap (0xfffffff0)) |
- (td_list->ed->hwHeadP & m32_swap (0x2));
- lurb_priv->td_cnt += lurb_priv->length - td_list->index - 1;
- } else
- td_list->ed->hwHeadP &= m32_swap (0xfffffff2);
- }
- }
-
- td_list->next_dl_td = td_rev;
- td_rev = td_list;
- td_list_hc = m32_swap (td_list->hwNextTD) & 0xfffffff0;
- }
- return td_list;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* td done list */
-static int dl_done_list (ohci_t *ohci, td_t *td_list)
-{
- td_t *td_list_next = NULL;
- ed_t *ed;
- int cc = 0;
- int stat = 0;
- /* urb_t *urb; */
- urb_priv_t *lurb_priv;
- __u32 tdINFO, edHeadP, edTailP;
-
- while (td_list) {
- td_list_next = td_list->next_dl_td;
-
- lurb_priv = &urb_priv;
- tdINFO = m32_swap (td_list->hwINFO);
-
- ed = td_list->ed;
-
- dl_transfer_length(td_list);
-
- /* error code of transfer */
- cc = TD_CC_GET (tdINFO);
- if (cc != 0) {
- dbg("ConditionCode %#x", cc);
- stat = cc_to_error[cc];
- }
-
- if (ed->state != ED_NEW) {
- edHeadP = m32_swap (ed->hwHeadP) & 0xfffffff0;
- edTailP = m32_swap (ed->hwTailP);
-
- /* unlink eds if they are not busy */
- if ((edHeadP == edTailP) && (ed->state == ED_OPER))
- ep_unlink (ohci, ed);
- }
-
- td_list = td_list_next;
- }
- return stat;
-}
-
-/*-------------------------------------------------------------------------*
- * Virtual Root Hub
- *-------------------------------------------------------------------------*/
-
-/* Device descriptor */
-static __u8 root_hub_dev_des[] =
-{
- 0x12, /* __u8 bLength; */
- 0x01, /* __u8 bDescriptorType; Device */
- 0x10, /* __u16 bcdUSB; v1.1 */
- 0x01,
- 0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
- 0x00, /* __u8 bDeviceSubClass; */
- 0x00, /* __u8 bDeviceProtocol; */
- 0x08, /* __u8 bMaxPacketSize0; 8 Bytes */
- 0x00, /* __u16 idVendor; */
- 0x00,
- 0x00, /* __u16 idProduct; */
- 0x00,
- 0x00, /* __u16 bcdDevice; */
- 0x00,
- 0x00, /* __u8 iManufacturer; */
- 0x01, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
- 0x01 /* __u8 bNumConfigurations; */
-};
-
-
-/* Configuration descriptor */
-static __u8 root_hub_config_des[] =
-{
- 0x09, /* __u8 bLength; */
- 0x02, /* __u8 bDescriptorType; Configuration */
- 0x19, /* __u16 wTotalLength; */
- 0x00,
- 0x01, /* __u8 bNumInterfaces; */
- 0x01, /* __u8 bConfigurationValue; */
- 0x00, /* __u8 iConfiguration; */
- 0x40, /* __u8 bmAttributes;
- Bit 7: Bus-powered, 6: Self-powered, 5 Remote-wakwup, 4..0: resvd */
- 0x00, /* __u8 MaxPower; */
-
- /* interface */
- 0x09, /* __u8 if_bLength; */
- 0x04, /* __u8 if_bDescriptorType; Interface */
- 0x00, /* __u8 if_bInterfaceNumber; */
- 0x00, /* __u8 if_bAlternateSetting; */
- 0x01, /* __u8 if_bNumEndpoints; */
- 0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
- 0x00, /* __u8 if_bInterfaceSubClass; */
- 0x00, /* __u8 if_bInterfaceProtocol; */
- 0x00, /* __u8 if_iInterface; */
-
- /* endpoint */
- 0x07, /* __u8 ep_bLength; */
- 0x05, /* __u8 ep_bDescriptorType; Endpoint */
- 0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
- 0x03, /* __u8 ep_bmAttributes; Interrupt */
- 0x02, /* __u16 ep_wMaxPacketSize; ((MAX_ROOT_PORTS + 1) / 8 */
- 0x00,
- 0xff /* __u8 ep_bInterval; 255 ms */
-};
-
-static unsigned char root_hub_str_index0[] =
-{
- 0x04, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 0x09, /* __u8 lang ID */
- 0x04, /* __u8 lang ID */
-};
-
-static unsigned char root_hub_str_index1[] =
-{
- 28, /* __u8 bLength; */
- 0x03, /* __u8 bDescriptorType; String-descriptor */
- 'O', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'H', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'C', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'I', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- ' ', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'R', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'o', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 't', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- ' ', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'H', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'u', /* __u8 Unicode */
- 0, /* __u8 Unicode */
- 'b', /* __u8 Unicode */
- 0, /* __u8 Unicode */
-};
-
-/* Hub class-specific descriptor is constructed dynamically */
-
-
-/*-------------------------------------------------------------------------*/
-
-#define OK(x) len = (x); break
-#ifdef DEBUG
-#define WR_RH_STAT(x) {info("WR:status %#8x", (x));writel((x), &gohci.regs->roothub.status);}
-#define WR_RH_PORTSTAT(x) {info("WR:portstatus[%d] %#8x", wIndex-1, (x));writel((x), &gohci.regs->roothub.portstatus[wIndex-1]);}
-#else
-#define WR_RH_STAT(x) writel((x), &gohci.regs->roothub.status)
-#define WR_RH_PORTSTAT(x) writel((x), &gohci.regs->roothub.portstatus[wIndex-1])
-#endif
-#define RD_RH_STAT roothub_status(&gohci)
-#define RD_RH_PORTSTAT roothub_portstatus(&gohci,wIndex-1)
-
-/* request to virtual root hub */
-
-int rh_check_port_status(ohci_t *controller)
-{
- __u32 temp, ndp, i;
- int res;
-
- res = -1;
- temp = roothub_a (controller);
- ndp = (temp & RH_A_NDP);
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
- ndp = (ndp == 2) ? 1:0;
-#endif
-
- for (i = 0; i < ndp; i++) {
- temp = roothub_portstatus (controller, i);
- /* check for a device disconnect */
- if (((temp & (RH_PS_PESC | RH_PS_CSC)) ==
- (RH_PS_PESC | RH_PS_CSC)) &&
- ((temp & RH_PS_CCS) == 0)) {
- res = i;
- break;
- }
- }
- return res;
-}
-
-static int ohci_submit_rh_msg(struct usb_device *dev, unsigned long pipe,
- void *buffer, int transfer_len, struct devrequest *cmd)
-{
- void * data = buffer;
- int leni = transfer_len;
- int len = 0;
- int stat = 0;
- __u32 datab[4];
- __u8 *data_buf = (__u8 *)datab;
- __u16 bmRType_bReq;
- __u16 wValue;
- __u16 wIndex;
- __u16 wLength;
-
-#ifdef DEBUG
-urb_priv.actual_length = 0;
-pkt_print(dev, pipe, buffer, transfer_len, cmd, "SUB(rh)", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
- if ((pipe & PIPE_INTERRUPT) == PIPE_INTERRUPT) {
- info("Root-Hub submit IRQ: NOT implemented");
- return 0;
- }
-
- bmRType_bReq = cmd->requesttype | (cmd->request << 8);
- wValue = m16_swap (cmd->value);
- wIndex = m16_swap (cmd->index);
- wLength = m16_swap (cmd->length);
-
- info("Root-Hub: adr: %2x cmd(%1x): %08x %04x %04x %04x",
- dev->devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
-
- switch (bmRType_bReq) {
- /* Request Destination:
- without flags: Device,
- RH_INTERFACE: interface,
- RH_ENDPOINT: endpoint,
- RH_CLASS means HUB here,
- RH_OTHER | RH_CLASS almost ever means HUB_PORT here
- */
-
- case RH_GET_STATUS:
- *(__u16 *) data_buf = m16_swap (1); OK (2);
- case RH_GET_STATUS | RH_INTERFACE:
- *(__u16 *) data_buf = m16_swap (0); OK (2);
- case RH_GET_STATUS | RH_ENDPOINT:
- *(__u16 *) data_buf = m16_swap (0); OK (2);
- case RH_GET_STATUS | RH_CLASS:
- *(__u32 *) data_buf = m32_swap (
- RD_RH_STAT & ~(RH_HS_CRWE | RH_HS_DRWE));
- OK (4);
- case RH_GET_STATUS | RH_OTHER | RH_CLASS:
- *(__u32 *) data_buf = m32_swap (RD_RH_PORTSTAT); OK (4);
-
- case RH_CLEAR_FEATURE | RH_ENDPOINT:
- switch (wValue) {
- case (RH_ENDPOINT_STALL): OK (0);
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_CLASS:
- switch (wValue) {
- case RH_C_HUB_LOCAL_POWER:
- OK(0);
- case (RH_C_HUB_OVER_CURRENT):
- WR_RH_STAT(RH_HS_OCIC); OK (0);
- }
- break;
-
- case RH_CLEAR_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_ENABLE):
- WR_RH_PORTSTAT (RH_PS_CCS ); OK (0);
- case (RH_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_POCI); OK (0);
- case (RH_PORT_POWER):
- WR_RH_PORTSTAT (RH_PS_LSDA); OK (0);
- case (RH_C_PORT_CONNECTION):
- WR_RH_PORTSTAT (RH_PS_CSC ); OK (0);
- case (RH_C_PORT_ENABLE):
- WR_RH_PORTSTAT (RH_PS_PESC); OK (0);
- case (RH_C_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_PSSC); OK (0);
- case (RH_C_PORT_OVER_CURRENT):
- WR_RH_PORTSTAT (RH_PS_OCIC); OK (0);
- case (RH_C_PORT_RESET):
- WR_RH_PORTSTAT (RH_PS_PRSC); OK (0);
- }
- break;
-
- case RH_SET_FEATURE | RH_OTHER | RH_CLASS:
- switch (wValue) {
- case (RH_PORT_SUSPEND):
- WR_RH_PORTSTAT (RH_PS_PSS ); OK (0);
- case (RH_PORT_RESET): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT (RH_PS_PRS);
- OK (0);
- case (RH_PORT_POWER):
- WR_RH_PORTSTAT (RH_PS_PPS ); OK (0);
- case (RH_PORT_ENABLE): /* BUG IN HUP CODE *********/
- if (RD_RH_PORTSTAT & RH_PS_CCS)
- WR_RH_PORTSTAT (RH_PS_PES );
- OK (0);
- }
- break;
-
- case RH_SET_ADDRESS: gohci.rh.devnum = wValue; OK(0);
-
- case RH_GET_DESCRIPTOR:
- switch ((wValue & 0xff00) >> 8) {
- case (0x01): /* device descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_dev_des),
- wLength));
- data_buf = root_hub_dev_des; OK(len);
- case (0x02): /* configuration descriptor */
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_config_des),
- wLength));
- data_buf = root_hub_config_des; OK(len);
- case (0x03): /* string descriptors */
- if(wValue==0x0300) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_str_index0),
- wLength));
- data_buf = root_hub_str_index0;
- OK(len);
- }
- if(wValue==0x0301) {
- len = min_t(unsigned int,
- leni,
- min_t(unsigned int,
- sizeof (root_hub_str_index1),
- wLength));
- data_buf = root_hub_str_index1;
- OK(len);
- }
- default:
- stat = USB_ST_STALLED;
- }
- break;
-
- case RH_GET_DESCRIPTOR | RH_CLASS:
- {
- __u32 temp = roothub_a (&gohci);
-
- data_buf [0] = 9; /* min length; */
- data_buf [1] = 0x29;
- data_buf [2] = temp & RH_A_NDP;
-#ifdef CONFIG_AT91C_PQFP_UHPBUG
- data_buf [2] = (data_buf [2] == 2) ? 1:0;
-#endif
- data_buf [3] = 0;
- if (temp & RH_A_PSM) /* per-port power switching? */
- data_buf [3] |= 0x1;
- if (temp & RH_A_NOCP) /* no overcurrent reporting? */
- data_buf [3] |= 0x10;
- else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
- data_buf [3] |= 0x8;
-
- /* corresponds to data_buf[4-7] */
- datab [1] = 0;
- data_buf [5] = (temp & RH_A_POTPGT) >> 24;
- temp = roothub_b (&gohci);
- data_buf [7] = temp & RH_B_DR;
- if (data_buf [2] < 7) {
- data_buf [8] = 0xff;
- } else {
- data_buf [0] += 2;
- data_buf [8] = (temp & RH_B_DR) >> 8;
- data_buf [10] = data_buf [9] = 0xff;
- }
-
- len = min_t(unsigned int, leni,
- min_t(unsigned int, data_buf [0], wLength));
- OK (len);
- }
-
- case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
-
- case RH_SET_CONFIGURATION: WR_RH_STAT (0x10000); OK (0);
-
- default:
- dbg ("unsupported root hub command");
- stat = USB_ST_STALLED;
- }
-
-#ifdef DEBUG
- ohci_dump_roothub (&gohci, 1);
-#else
- wait_ms(1);
-#endif
-
- len = min_t(int, len, leni);
- if (data != data_buf)
- memcpy (data, data_buf, len);
- dev->act_len = len;
- dev->status = stat;
-
-#ifdef DEBUG
- if (transfer_len)
- urb_priv.actual_length = transfer_len;
- pkt_print(dev, pipe, buffer, transfer_len, cmd, "RET(rh)", 0/*usb_pipein(pipe)*/);
-#else
- wait_ms(1);
-#endif
-
- return stat;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* common code for handling submit messages - used for all but root hub */
-/* accesses. */
-int submit_common_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, struct devrequest *setup, int interval)
-{
- int stat = 0;
- int maxsize = usb_maxpacket(dev, pipe);
- int timeout;
-
- /* device pulled? Shortcut the action. */
- if (devgone == dev) {
- dev->status = USB_ST_CRC_ERR;
- return 0;
- }
-
-#ifdef DEBUG
- urb_priv.actual_length = 0;
- pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
- if (!maxsize) {
- err("submit_common_message: pipesize for pipe %lx is zero",
- pipe);
- return -1;
- }
-
- if (sohci_submit_job(dev, pipe, buffer, transfer_len, setup, interval) < 0) {
- err("sohci_submit_job failed");
- return -1;
- }
-
- wait_ms(10);
- /* ohci_dump_status(&gohci); */
-
- /* allow more time for a BULK device to react - some are slow */
-#define BULK_TO 5000 /* timeout in milliseconds */
- if (usb_pipetype (pipe) == PIPE_BULK)
- timeout = BULK_TO;
- else
- timeout = 100;
-
- /* wait for it to complete */
- for (;;) {
- /* check whether the controller is done */
- stat = hc_interrupt();
- if (stat < 0) {
- stat = USB_ST_CRC_ERR;
- break;
- }
- if (stat >= 0 && stat != 0xff) {
- /* 0xff is returned for an SF-interrupt */
- break;
- }
- if (--timeout) {
- wait_ms(1);
- } else {
- err("CTL:TIMEOUT ");
- stat = USB_ST_CRC_ERR;
- break;
- }
- }
- /* we got an Root Hub Status Change interrupt */
- if (got_rhsc) {
-#ifdef DEBUG
- ohci_dump_roothub (&gohci, 1);
-#endif
- got_rhsc = 0;
- /* abuse timeout */
- timeout = rh_check_port_status(&gohci);
- if (timeout >= 0) {
-#if 0 /* this does nothing useful, but leave it here in case that changes */
- /* the called routine adds 1 to the passed value */
- usb_hub_port_connect_change(gohci.rh.dev, timeout - 1);
-#endif
- /*
- * XXX
- * This is potentially dangerous because it assumes
- * that only one device is ever plugged in!
- */
- devgone = dev;
- }
- }
-
- dev->status = stat;
- dev->act_len = transfer_len;
-
-#ifdef DEBUG
- pkt_print(dev, pipe, buffer, transfer_len, setup, "RET(ctlr)", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
-
- /* free TDs in urb_priv */
- urb_free_priv (&urb_priv);
- return 0;
-}
-
-/* submit routines called from usb.c */
-int submit_bulk_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len)
-{
- info("submit_bulk_msg");
- return submit_common_msg(dev, pipe, buffer, transfer_len, NULL, 0);
-}
-
-int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, struct devrequest *setup)
-{
- int maxsize = usb_maxpacket(dev, pipe);
-
- info("submit_control_msg");
-#ifdef DEBUG
- urb_priv.actual_length = 0;
- pkt_print(dev, pipe, buffer, transfer_len, setup, "SUB", usb_pipein(pipe));
-#else
- wait_ms(1);
-#endif
- if (!maxsize) {
- err("submit_control_message: pipesize for pipe %lx is zero",
- pipe);
- return -1;
- }
- if (((pipe >> 8) & 0x7f) == gohci.rh.devnum) {
- gohci.rh.dev = dev;
- /* root hub - redirect */
- return ohci_submit_rh_msg(dev, pipe, buffer, transfer_len,
- setup);
- }
-
- return submit_common_msg(dev, pipe, buffer, transfer_len, setup, 0);
-}
-
-int submit_int_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
- int transfer_len, int interval)
-{
- info("submit_int_msg");
- return -1;
-}
-
-/*-------------------------------------------------------------------------*
- * HC functions
- *-------------------------------------------------------------------------*/
-
-/* reset the HC and BUS */
-
-static int hc_reset (ohci_t *ohci)
-{
- int timeout = 30;
- int smm_timeout = 50; /* 0,5 sec */
-
- dbg("%s\n", __FUNCTION__);
-
- if (readl (&ohci->regs->control) & OHCI_CTRL_IR) { /* SMM owns the HC */
- writel (OHCI_OCR, &ohci->regs->cmdstatus); /* request ownership */
- info("USB HC TakeOver from SMM");
- while (readl (&ohci->regs->control) & OHCI_CTRL_IR) {
- wait_ms (10);
- if (--smm_timeout == 0) {
- err("USB HC TakeOver failed!");
- return -1;
- }
- }
- }
-
- /* Disable HC interrupts */
- writel (OHCI_INTR_MIE, &ohci->regs->intrdisable);
-
- dbg("USB HC reset_hc usb-%s: ctrl = 0x%X ;\n",
- ohci->slot_name,
- readl(&ohci->regs->control));
-
- /* Reset USB (needed by some controllers) */
- writel (0, &ohci->regs->control);
-
- /* HC Reset requires max 10 us delay */
- writel (OHCI_HCR, &ohci->regs->cmdstatus);
- while ((readl (&ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
- if (--timeout == 0) {
- err("USB HC reset timed out!");
- return -1;
- }
- udelay (1);
- }
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* Start an OHCI controller, set the BUS operational
- * enable interrupts
- * connect the virtual root hub */
-
-static int hc_start (ohci_t * ohci)
-{
- __u32 mask;
- unsigned int fminterval;
-
- ohci->disabled = 1;
-
- /* Tell the controller where the control and bulk lists are
- * The lists are empty now. */
-
- writel (0, &ohci->regs->ed_controlhead);
- writel (0, &ohci->regs->ed_bulkhead);
-
- writel ((__u32)ohci->hcca, &ohci->regs->hcca); /* a reset clears this */
-
- fminterval = 0x2edf;
- writel ((fminterval * 9) / 10, &ohci->regs->periodicstart);
- fminterval |= ((((fminterval - 210) * 6) / 7) << 16);
- writel (fminterval, &ohci->regs->fminterval);
- writel (0x628, &ohci->regs->lsthresh);
-
- /* start controller operations */
- ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
- ohci->disabled = 0;
- writel (ohci->hc_control, &ohci->regs->control);
-
- /* disable all interrupts */
- mask = (OHCI_INTR_SO | OHCI_INTR_WDH | OHCI_INTR_SF | OHCI_INTR_RD |
- OHCI_INTR_UE | OHCI_INTR_FNO | OHCI_INTR_RHSC |
- OHCI_INTR_OC | OHCI_INTR_MIE);
- writel (mask, &ohci->regs->intrdisable);
- /* clear all interrupts */
- mask &= ~OHCI_INTR_MIE;
- writel (mask, &ohci->regs->intrstatus);
- /* Choose the interrupts we care about now - but w/o MIE */
- mask = OHCI_INTR_RHSC | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
- writel (mask, &ohci->regs->intrenable);
-
-#ifdef OHCI_USE_NPS
- /* required for AMD-756 and some Mac platforms */
- writel ((roothub_a (ohci) | RH_A_NPS) & ~RH_A_PSM,
- &ohci->regs->roothub.a);
- writel (RH_HS_LPSC, &ohci->regs->roothub.status);
-#endif /* OHCI_USE_NPS */
-
-#define mdelay(n) ({unsigned long msec=(n); while (msec--) udelay(1000);})
- /* POTPGT delay is bits 24-31, in 2 ms units. */
- mdelay ((roothub_a (ohci) >> 23) & 0x1fe);
-
- /* connect the virtual root hub */
- ohci->rh.devnum = 0;
-
- return 0;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/* an interrupt happens */
-
-static int
-hc_interrupt (void)
-{
- ohci_t *ohci = &gohci;
- struct ohci_regs *regs = ohci->regs;
- int ints;
- int stat = -1;
-
- if ((ohci->hcca->done_head != 0) && !(m32_swap (ohci->hcca->done_head) & 0x01)) {
- ints = OHCI_INTR_WDH;
- } else {
- ints = readl (&regs->intrstatus);
- }
-
- /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
-
- if (ints & OHCI_INTR_RHSC) {
- got_rhsc = 1;
- }
-
- if (ints & OHCI_INTR_UE) {
- ohci->disabled++;
- err ("OHCI Unrecoverable Error, controller usb-%s disabled",
- ohci->slot_name);
- /* e.g. due to PCI Master/Target Abort */
-
-#ifdef DEBUG
- ohci_dump (ohci, 1);
-#else
- wait_ms(1);
-#endif
- /* FIXME: be optimistic, hope that bug won't repeat often. */
- /* Make some non-interrupt context restart the controller. */
- /* Count and limit the retries though; either hardware or */
- /* software errors can go forever... */
- hc_reset (ohci);
- return -1;
- }
-
- if (ints & OHCI_INTR_WDH) {
- wait_ms(1);
- writel (OHCI_INTR_WDH, &regs->intrdisable);
- stat = dl_done_list (&gohci, dl_reverse_done_list (&gohci));
- writel (OHCI_INTR_WDH, &regs->intrenable);
- }
-
- if (ints & OHCI_INTR_SO) {
- dbg("USB Schedule overrun\n");
- writel (OHCI_INTR_SO, &regs->intrenable);
- stat = -1;
- }
-
- /* FIXME: this assumes SOF (1/ms) interrupts don't get lost... */
- if (ints & OHCI_INTR_SF) {
- unsigned int frame = m16_swap (ohci->hcca->frame_no) & 1;
- wait_ms(1);
- writel (OHCI_INTR_SF, &regs->intrdisable);
- if (ohci->ed_rm_list[frame] != NULL)
- writel (OHCI_INTR_SF, &regs->intrenable);
- stat = 0xff;
- }
-
- writel (ints, &regs->intrstatus);
- return stat;
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*-------------------------------------------------------------------------*/
-
-/* De-allocate all resources.. */
-
-static void hc_release_ohci (ohci_t *ohci)
-{
- dbg ("USB HC release ohci usb-%s", ohci->slot_name);
-
- if (!ohci->disabled)
- hc_reset (ohci);
-}
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * low level initalisation routine, called from usb.c
- */
-static char ohci_inited = 0;
-
-int usb_lowlevel_init(void)
-{
- /*
- * Enable USB host clock.
- */
- *AT91C_PMC_SCER = AT91C_PMC_UHP; /* 48MHz clock enabled for UHP */
- *AT91C_PMC_PCER = 1 << AT91C_ID_UHP; /* Peripheral Clock Enable Register */
-
- memset (&gohci, 0, sizeof (ohci_t));
- memset (&urb_priv, 0, sizeof (urb_priv_t));
-
- /* align the storage */
- if ((__u32)&ghcca[0] & 0xff) {
- err("HCCA not aligned!!");
- return -1;
- }
- phcca = &ghcca[0];
- info("aligned ghcca %p", phcca);
- memset(&ohci_dev, 0, sizeof(struct ohci_device));
- if ((__u32)&ohci_dev.ed[0] & 0x7) {
- err("EDs not aligned!!");
- return -1;
- }
- memset(gtd, 0, sizeof(td_t) * (NUM_TD + 1));
- if ((__u32)gtd & 0x7) {
- err("TDs not aligned!!");
- return -1;
- }
- ptd = gtd;
- gohci.hcca = phcca;
- memset (phcca, 0, sizeof (struct ohci_hcca));
-
- gohci.disabled = 1;
- gohci.sleeping = 0;
- gohci.irq = -1;
- gohci.regs = (struct ohci_regs *)AT91_USB_HOST_BASE;
-
- gohci.flags = 0;
- gohci.slot_name = "at91rm9200";
-
- if (hc_reset (&gohci) < 0) {
- hc_release_ohci (&gohci);
- /* Initialization failed */
- *AT91C_PMC_PCER = AT91C_ID_UHP;
- *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */
- return -1;
- }
-
- /* FIXME this is a second HC reset; why?? */
-/* writel (gohci.hc_control = OHCI_USB_RESET, &gohci.regs->control);
- wait_ms (10);*/
-
- if (hc_start (&gohci) < 0) {
- err ("can't start usb-%s", gohci.slot_name);
- hc_release_ohci (&gohci);
- /* Initialization failed */
- *AT91C_PMC_PCER = AT91C_ID_UHP;
- *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */
- return -1;
- }
-
-#ifdef DEBUG
- ohci_dump (&gohci, 1);
-#else
- wait_ms(1);
-#endif
- ohci_inited = 1;
- return 0;
-}
-
-int usb_lowlevel_stop(void)
-{
- /* this gets called really early - before the controller has */
- /* even been initialized! */
- if (!ohci_inited)
- return 0;
- /* TODO release any interrupts, etc. */
- /* call hc_release_ohci() here ? */
- hc_reset (&gohci);
- /* may not want to do this */
- *AT91C_PMC_PCER = 1 << AT91C_ID_UHP;
- *AT91C_PMC_SCDR = 1 << AT91C_PMC_UHP; /* 48MHz clock disabled for UHP */
- return 0;
-}
-
-#endif /* CONFIG_USB_OHCI */
diff --git a/cpu/arm920t/at91rm9200/usb_ohci.h b/cpu/arm920t/at91rm9200/usb_ohci.h
deleted file mode 100644
index ecb4e93..0000000
--- a/cpu/arm920t/at91rm9200/usb_ohci.h
+++ /dev/null
@@ -1,419 +0,0 @@
-/*
- * URB OHCI HCD (Host Controller Driver) for USB.
- *
- * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
- *
- * usb-ohci.h
- */
-
-
-static int cc_to_error[16] = {
-
-/* mapping of the OHCI CC status to error codes */
- /* No Error */ 0,
- /* CRC Error */ USB_ST_CRC_ERR,
- /* Bit Stuff */ USB_ST_BIT_ERR,
- /* Data Togg */ USB_ST_CRC_ERR,
- /* Stall */ USB_ST_STALLED,
- /* DevNotResp */ -1,
- /* PIDCheck */ USB_ST_BIT_ERR,
- /* UnExpPID */ USB_ST_BIT_ERR,
- /* DataOver */ USB_ST_BUF_ERR,
- /* DataUnder */ USB_ST_BUF_ERR,
- /* reservd */ -1,
- /* reservd */ -1,
- /* BufferOver */ USB_ST_BUF_ERR,
- /* BuffUnder */ USB_ST_BUF_ERR,
- /* Not Access */ -1,
- /* Not Access */ -1
-};
-
-/* ED States */
-
-#define ED_NEW 0x00
-#define ED_UNLINK 0x01
-#define ED_OPER 0x02
-#define ED_DEL 0x04
-#define ED_URB_DEL 0x08
-
-/* usb_ohci_ed */
-struct ed {
- __u32 hwINFO;
- __u32 hwTailP;
- __u32 hwHeadP;
- __u32 hwNextED;
-
- struct ed *ed_prev;
- __u8 int_period;
- __u8 int_branch;
- __u8 int_load;
- __u8 int_interval;
- __u8 state;
- __u8 type;
- __u16 last_iso;
- struct ed *ed_rm_list;
-
- struct usb_device *usb_dev;
- __u32 unused[3];
-} __attribute((aligned(16)));
-typedef struct ed ed_t;
-
-
-/* TD info field */
-#define TD_CC 0xf0000000
-#define TD_CC_GET(td_p) ((td_p >>28) & 0x0f)
-#define TD_CC_SET(td_p, cc) (td_p) = ((td_p) & 0x0fffffff) | (((cc) & 0x0f) << 28)
-#define TD_EC 0x0C000000
-#define TD_T 0x03000000
-#define TD_T_DATA0 0x02000000
-#define TD_T_DATA1 0x03000000
-#define TD_T_TOGGLE 0x00000000
-#define TD_R 0x00040000
-#define TD_DI 0x00E00000
-#define TD_DI_SET(X) (((X) & 0x07)<< 21)
-#define TD_DP 0x00180000
-#define TD_DP_SETUP 0x00000000
-#define TD_DP_IN 0x00100000
-#define TD_DP_OUT 0x00080000
-
-#define TD_ISO 0x00010000
-#define TD_DEL 0x00020000
-
-/* CC Codes */
-#define TD_CC_NOERROR 0x00
-#define TD_CC_CRC 0x01
-#define TD_CC_BITSTUFFING 0x02
-#define TD_CC_DATATOGGLEM 0x03
-#define TD_CC_STALL 0x04
-#define TD_DEVNOTRESP 0x05
-#define TD_PIDCHECKFAIL 0x06
-#define TD_UNEXPECTEDPID 0x07
-#define TD_DATAOVERRUN 0x08
-#define TD_DATAUNDERRUN 0x09
-#define TD_BUFFEROVERRUN 0x0C
-#define TD_BUFFERUNDERRUN 0x0D
-#define TD_NOTACCESSED 0x0F
-
-
-#define MAXPSW 1
-
-struct td {
- __u32 hwINFO;
- __u32 hwCBP; /* Current Buffer Pointer */
- __u32 hwNextTD; /* Next TD Pointer */
- __u32 hwBE; /* Memory Buffer End Pointer */
-
- __u16 hwPSW[MAXPSW];
- __u8 unused;
- __u8 index;
- struct ed *ed;
- struct td *next_dl_td;
- struct usb_device *usb_dev;
- int transfer_len;
- __u32 data;
-
- __u32 unused2[2];
-} __attribute((aligned(32)));
-typedef struct td td_t;
-
-#define OHCI_ED_SKIP (1 << 14)
-
-/*
- * The HCCA (Host Controller Communications Area) is a 256 byte
- * structure defined in the OHCI spec. that the host controller is
- * told the base address of. It must be 256-byte aligned.
- */
-
-#define NUM_INTS 32 /* part of the OHCI standard */
-struct ohci_hcca {
- __u32 int_table[NUM_INTS]; /* Interrupt ED table */
- __u16 frame_no; /* current frame number */
- __u16 pad1; /* set to 0 on each frame_no change */
- __u32 done_head; /* info returned for an interrupt */
- u8 reserved_for_hc[116];
-} __attribute((aligned(256)));
-
-
-/*
- * Maximum number of root hub ports.
- */
-#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */
-
-/*
- * This is the structure of the OHCI controller's memory mapped I/O
- * region. This is Memory Mapped I/O. You must use the readl() and
- * writel() macros defined in asm/io.h to access these!!
- */
-struct ohci_regs {
- /* control and status registers */
- __u32 revision;
- __u32 control;
- __u32 cmdstatus;
- __u32 intrstatus;
- __u32 intrenable;
- __u32 intrdisable;
- /* memory pointers */
- __u32 hcca;
- __u32 ed_periodcurrent;
- __u32 ed_controlhead;
- __u32 ed_controlcurrent;
- __u32 ed_bulkhead;
- __u32 ed_bulkcurrent;
- __u32 donehead;
- /* frame counters */
- __u32 fminterval;
- __u32 fmremaining;
- __u32 fmnumber;
- __u32 periodicstart;
- __u32 lsthresh;
- /* Root hub ports */
- struct ohci_roothub_regs {
- __u32 a;
- __u32 b;
- __u32 status;
- __u32 portstatus[MAX_ROOT_PORTS];
- } roothub;
-} __attribute((aligned(32)));
-
-
-/* OHCI CONTROL AND STATUS REGISTER MASKS */
-
-/*
- * HcControl (control) register masks
- */
-#define OHCI_CTRL_CBSR (3 << 0) /* control/bulk service ratio */
-#define OHCI_CTRL_PLE (1 << 2) /* periodic list enable */
-#define OHCI_CTRL_IE (1 << 3) /* isochronous enable */
-#define OHCI_CTRL_CLE (1 << 4) /* control list enable */
-#define OHCI_CTRL_BLE (1 << 5) /* bulk list enable */
-#define OHCI_CTRL_HCFS (3 << 6) /* host controller functional state */
-#define OHCI_CTRL_IR (1 << 8) /* interrupt routing */
-#define OHCI_CTRL_RWC (1 << 9) /* remote wakeup connected */
-#define OHCI_CTRL_RWE (1 << 10) /* remote wakeup enable */
-
-/* pre-shifted values for HCFS */
-# define OHCI_USB_RESET (0 << 6)
-# define OHCI_USB_RESUME (1 << 6)
-# define OHCI_USB_OPER (2 << 6)
-# define OHCI_USB_SUSPEND (3 << 6)
-
-/*
- * HcCommandStatus (cmdstatus) register masks
- */
-#define OHCI_HCR (1 << 0) /* host controller reset */
-#define OHCI_CLF (1 << 1) /* control list filled */
-#define OHCI_BLF (1 << 2) /* bulk list filled */
-#define OHCI_OCR (1 << 3) /* ownership change request */
-#define OHCI_SOC (3 << 16) /* scheduling overrun count */
-
-/*
- * masks used with interrupt registers:
- * HcInterruptStatus (intrstatus)
- * HcInterruptEnable (intrenable)
- * HcInterruptDisable (intrdisable)
- */
-#define OHCI_INTR_SO (1 << 0) /* scheduling overrun */
-#define OHCI_INTR_WDH (1 << 1) /* writeback of done_head */
-#define OHCI_INTR_SF (1 << 2) /* start frame */
-#define OHCI_INTR_RD (1 << 3) /* resume detect */
-#define OHCI_INTR_UE (1 << 4) /* unrecoverable error */
-#define OHCI_INTR_FNO (1 << 5) /* frame number overflow */
-#define OHCI_INTR_RHSC (1 << 6) /* root hub status change */
-#define OHCI_INTR_OC (1 << 30) /* ownership change */
-#define OHCI_INTR_MIE (1 << 31) /* master interrupt enable */
-
-
-/* Virtual Root HUB */
-struct virt_root_hub {
- int devnum; /* Address of Root Hub endpoint */
- void *dev; /* was urb */
- void *int_addr;
- int send;
- int interval;
-};
-
-/* USB HUB CONSTANTS (not OHCI-specific; see hub.h) */
-
-/* destination of request */
-#define RH_INTERFACE 0x01
-#define RH_ENDPOINT 0x02
-#define RH_OTHER 0x03
-
-#define RH_CLASS 0x20
-#define RH_VENDOR 0x40
-
-/* Requests: bRequest << 8 | bmRequestType */
-#define RH_GET_STATUS 0x0080
-#define RH_CLEAR_FEATURE 0x0100
-#define RH_SET_FEATURE 0x0300
-#define RH_SET_ADDRESS 0x0500
-#define RH_GET_DESCRIPTOR 0x0680
-#define RH_SET_DESCRIPTOR 0x0700
-#define RH_GET_CONFIGURATION 0x0880
-#define RH_SET_CONFIGURATION 0x0900
-#define RH_GET_STATE 0x0280
-#define RH_GET_INTERFACE 0x0A80
-#define RH_SET_INTERFACE 0x0B00
-#define RH_SYNC_FRAME 0x0C80
-/* Our Vendor Specific Request */
-#define RH_SET_EP 0x2000
-
-
-/* Hub port features */
-#define RH_PORT_CONNECTION 0x00
-#define RH_PORT_ENABLE 0x01
-#define RH_PORT_SUSPEND 0x02
-#define RH_PORT_OVER_CURRENT 0x03
-#define RH_PORT_RESET 0x04
-#define RH_PORT_POWER 0x08
-#define RH_PORT_LOW_SPEED 0x09
-
-#define RH_C_PORT_CONNECTION 0x10
-#define RH_C_PORT_ENABLE 0x11
-#define RH_C_PORT_SUSPEND 0x12
-#define RH_C_PORT_OVER_CURRENT 0x13
-#define RH_C_PORT_RESET 0x14
-
-/* Hub features */
-#define RH_C_HUB_LOCAL_POWER 0x00
-#define RH_C_HUB_OVER_CURRENT 0x01
-
-#define RH_DEVICE_REMOTE_WAKEUP 0x00
-#define RH_ENDPOINT_STALL 0x01
-
-#define RH_ACK 0x01
-#define RH_REQ_ERR -1
-#define RH_NACK 0x00
-
-
-/* OHCI ROOT HUB REGISTER MASKS */
-
-/* roothub.portstatus [i] bits */
-#define RH_PS_CCS 0x00000001 /* current connect status */
-#define RH_PS_PES 0x00000002 /* port enable status*/
-#define RH_PS_PSS 0x00000004 /* port suspend status */
-#define RH_PS_POCI 0x00000008 /* port over current indicator */
-#define RH_PS_PRS 0x00000010 /* port reset status */
-#define RH_PS_PPS 0x00000100 /* port power status */
-#define RH_PS_LSDA 0x00000200 /* low speed device attached */
-#define RH_PS_CSC 0x00010000 /* connect status change */
-#define RH_PS_PESC 0x00020000 /* port enable status change */
-#define RH_PS_PSSC 0x00040000 /* port suspend status change */
-#define RH_PS_OCIC 0x00080000 /* over current indicator change */
-#define RH_PS_PRSC 0x00100000 /* port reset status change */
-
-/* roothub.status bits */
-#define RH_HS_LPS 0x00000001 /* local power status */
-#define RH_HS_OCI 0x00000002 /* over current indicator */
-#define RH_HS_DRWE 0x00008000 /* device remote wakeup enable */
-#define RH_HS_LPSC 0x00010000 /* local power status change */
-#define RH_HS_OCIC 0x00020000 /* over current indicator change */
-#define RH_HS_CRWE 0x80000000 /* clear remote wakeup enable */
-
-/* roothub.b masks */
-#define RH_B_DR 0x0000ffff /* device removable flags */
-#define RH_B_PPCM 0xffff0000 /* port power control mask */
-
-/* roothub.a masks */
-#define RH_A_NDP (0xff << 0) /* number of downstream ports */
-#define RH_A_PSM (1 << 8) /* power switching mode */
-#define RH_A_NPS (1 << 9) /* no power switching */
-#define RH_A_DT (1 << 10) /* device type (mbz) */
-#define RH_A_OCPM (1 << 11) /* over current protection mode */
-#define RH_A_NOCP (1 << 12) /* no over current protection */
-#define RH_A_POTPGT (0xff << 24) /* power on to power good time */
-
-/* urb */
-#define N_URB_TD 48
-typedef struct
-{
- ed_t *ed;
- __u16 length; /* number of tds associated with this request */
- __u16 td_cnt; /* number of tds already serviced */
- int state;
- unsigned long pipe;
- int actual_length;
- td_t *td[N_URB_TD]; /* list pointer to all corresponding TDs associated with this request */
-} urb_priv_t;
-#define URB_DEL 1
-
-/*
- * This is the full ohci controller description
- *
- * Note how the "proper" USB information is just
- * a subset of what the full implementation needs. (Linus)
- */
-
-
-typedef struct ohci {
- struct ohci_hcca *hcca; /* hcca */
- /*dma_addr_t hcca_dma;*/
-
- int irq;
- int disabled; /* e.g. got a UE, we're hung */
- int sleeping;
- unsigned long flags; /* for HC bugs */
-
- struct ohci_regs *regs; /* OHCI controller's memory */
-
- ed_t *ed_rm_list[2]; /* lists of all endpoints to be removed */
- ed_t *ed_bulktail; /* last endpoint of bulk list */
- ed_t *ed_controltail; /* last endpoint of control list */
- int intrstatus;
- __u32 hc_control; /* copy of the hc control reg */
- struct usb_device *dev[32];
- struct virt_root_hub rh;
-
- const char *slot_name;
-} ohci_t;
-
-#define NUM_EDS 8 /* num of preallocated endpoint descriptors */
-
-struct ohci_device {
- ed_t ed[NUM_EDS];
- int ed_cnt;
-};
-
-/* hcd */
-/* endpoint */
-static int ep_link(ohci_t * ohci, ed_t * ed);
-static int ep_unlink(ohci_t * ohci, ed_t * ed);
-static ed_t * ep_add_ed(struct usb_device * usb_dev, unsigned long pipe);
-
-/*-------------------------------------------------------------------------*/
-
-/* we need more TDs than EDs */
-#define NUM_TD 64
-
-/* +1 so we can align the storage */
-td_t gtd[NUM_TD+1];
-/* pointers to aligned storage */
-td_t *ptd;
-
-/* TDs ... */
-static inline struct td *
-td_alloc (struct usb_device *usb_dev)
-{
- int i;
- struct td *td;
-
- td = NULL;
- for (i = 0; i < NUM_TD; i++)
- {
- if (ptd[i].usb_dev == NULL)
- {
- td = &ptd[i];
- td->usb_dev = usb_dev;
- break;
- }
- }
-
- return td;
-}
-
-static inline void
-ed_free (struct ed *ed)
-{
- ed->usb_dev = NULL;
-}
diff --git a/cpu/arm920t/s3c24x0/Makefile b/cpu/arm920t/s3c24x0/Makefile
index 3a7c4b3..0ff36c5 100644
--- a/cpu/arm920t/s3c24x0/Makefile
+++ b/cpu/arm920t/s3c24x0/Makefile
@@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(SOC).a
COBJS = i2c.o interrupts.o serial.o speed.o \
- usb_ohci.o
+ usb.o
SRCS := $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/arm920t/s3c24x0/usb.c b/cpu/arm920t/s3c24x0/usb.c
new file mode 100644
index 0000000..ef5d5bf
--- /dev/null
+++ b/cpu/arm920t/s3c24x0/usb.c
@@ -0,0 +1,72 @@
+/*
+ * (C) Copyright 2006
+ * DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT)
+# if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
+
+#if defined(CONFIG_S3C2400)
+# include <s3c2400.h>
+#elif defined(CONFIG_S3C2410)
+# include <s3c2410.h>
+#endif
+
+int usb_cpu_init (void)
+{
+
+ S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
+ S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();
+
+ /*
+ * Set the 48 MHz UPLL clocking. Values are taken from
+ * "PLL value selection guide", 6-23, s3c2400_UM.pdf.
+ */
+ clk_power->UPLLCON = ((40 << 12) + (1 << 4) + 2);
+ gpio->MISCCR |= 0x8; /* 1 = use pads related USB for USB host */
+
+ /*
+ * Enable USB host clock.
+ */
+ clk_power->CLKCON |= (1 << 4);
+
+ return 0;
+}
+
+int usb_cpu_stop (void)
+{
+ S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
+ /* may not want to do this */
+ clk_power->CLKCON &= ~(1 << 4);
+ return 0;
+}
+
+int usb_cpu_init_fail (void)
+{
+ S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();
+ clk_power->CLKCON &= ~(1 << 4);
+ return 0;
+}
+
+# endif /* defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410) */
+#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */
diff --git a/cpu/arm926ejs/davinci/Makefile b/cpu/arm926ejs/davinci/Makefile
new file mode 100644
index 0000000..0f77f40
--- /dev/null
+++ b/cpu/arm926ejs/davinci/Makefile
@@ -0,0 +1,49 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = $(obj)lib$(SOC).a
+
+COBJS = timer.o ether.o lxt972.o dp83848.o i2c.o nand.o
+SOBJS = lowlevel_init.o reset.o
+
+SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
+OBJS := $(addprefix $(obj),$(COBJS) $(SOBJS))
+START := $(addprefix $(obj),$(START))
+
+all: $(obj).depend $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+
+#########################################################################
+
+# defines $(obj).depend target
+include $(SRCTREE)/rules.mk
+
+sinclude $(obj).depend
+
+#########################################################################
diff --git a/cpu/arm926ejs/davinci/dp83848.c b/cpu/arm926ejs/davinci/dp83848.c
new file mode 100644
index 0000000..5719845
--- /dev/null
+++ b/cpu/arm926ejs/davinci/dp83848.c
@@ -0,0 +1,156 @@
+/*
+ * National Semiconductor DP83848 PHY Driver for TI DaVinci
+ * (TMS320DM644x) based boards.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * --------------------------------------------------------
+ *
+ * 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 <net.h>
+#include <dp83848.h>
+#include <asm/arch/emac_defs.h>
+
+#ifdef CONFIG_DRIVER_TI_EMAC
+
+#ifdef CONFIG_CMD_NET
+
+int dp83848_is_phy_connected(int phy_addr)
+{
+ u_int16_t id1, id2;
+
+ if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID1_REG, &id1))
+ return(0);
+ if (!dm644x_eth_phy_read(phy_addr, DP83848_PHYID2_REG, &id2))
+ return(0);
+
+ if ((id1 == DP83848_PHYID1_OUI) && (id2 == DP83848_PHYID2_OUI))
+ return(1);
+
+ return(0);
+}
+
+int dp83848_get_link_speed(int phy_addr)
+{
+ u_int16_t tmp;
+ volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR;
+
+ if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp))
+ return(0);
+
+ if (!(tmp & DP83848_LINK_STATUS)) /* link up? */
+ return(0);
+
+ if (!dm644x_eth_phy_read(phy_addr, DP83848_PHY_STAT_REG, &tmp))
+ return(0);
+
+ /* Speed doesn't matter, there is no setting for it in EMAC... */
+ if (tmp & DP83848_SPEED) {
+ if (tmp & DP83848_DUPLEX) {
+ /* set DM644x EMAC for Full Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
+ } else {
+ /*set DM644x EMAC for Half Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
+ }
+
+ return(1);
+ } else {
+ if (tmp & DP83848_DUPLEX) {
+ /* set DM644x EMAC for Full Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
+ } else {
+ /*set DM644x EMAC for Half Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
+ }
+
+ return(1);
+ }
+
+ return(0);
+}
+
+
+int dp83848_init_phy(int phy_addr)
+{
+ int ret = 1;
+
+ if (!dp83848_get_link_speed(phy_addr)) {
+ /* Try another time */
+ udelay(100000);
+ ret = dp83848_get_link_speed(phy_addr);
+ }
+
+ /* Disable PHY Interrupts */
+ dm644x_eth_phy_write(phy_addr, DP83848_PHY_INTR_CTRL_REG, 0);
+
+ return(ret);
+}
+
+
+int dp83848_auto_negotiate(int phy_addr)
+{
+ u_int16_t tmp;
+
+
+ if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp))
+ return(0);
+
+ /* Restart Auto_negotiation */
+ tmp &= ~DP83848_AUTONEG; /* remove autonegotiation enable */
+ tmp |= DP83848_ISOLATE; /* Electrically isolate PHY */
+ dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
+
+ /* Set the Auto_negotiation Advertisement Register
+ * MII advertising for Next page, 100BaseTxFD and HD,
+ * 10BaseTFD and HD, IEEE 802.3
+ */
+ tmp = DP83848_NP | DP83848_TX_FDX | DP83848_TX_HDX |
+ DP83848_10_FDX | DP83848_10_HDX | DP83848_AN_IEEE_802_3;
+ dm644x_eth_phy_write(phy_addr, DP83848_ANA_REG, tmp);
+
+
+ /* Read Control Register */
+ if (!dm644x_eth_phy_read(phy_addr, DP83848_CTL_REG, &tmp))
+ return(0);
+
+ tmp |= DP83848_SPEED_SELECT | DP83848_AUTONEG | DP83848_DUPLEX_MODE;
+ dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
+
+ /* Restart Auto_negotiation */
+ tmp |= DP83848_RESTART_AUTONEG;
+ dm644x_eth_phy_write(phy_addr, DP83848_CTL_REG, tmp);
+
+ /*check AutoNegotiate complete */
+ udelay(10000);
+ if (!dm644x_eth_phy_read(phy_addr, DP83848_STAT_REG, &tmp))
+ return(0);
+
+ if (!(tmp & DP83848_AUTONEG_COMP))
+ return(0);
+
+ return (dp83848_get_link_speed(phy_addr));
+}
+
+#endif /* CONFIG_CMD_NET */
+
+#endif /* CONFIG_DRIVER_ETHER */
diff --git a/cpu/arm926ejs/davinci/ether.c b/cpu/arm926ejs/davinci/ether.c
new file mode 100644
index 0000000..32e81d1
--- /dev/null
+++ b/cpu/arm926ejs/davinci/ether.c
@@ -0,0 +1,650 @@
+/*
+ * 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 <command.h>
+#include <net.h>
+#include <miiphy.h>
+#include <asm/arch/emac_defs.h>
+
+#ifdef CONFIG_DRIVER_TI_EMAC
+
+#ifdef CONFIG_CMD_NET
+
+unsigned int emac_dbg = 0;
+#define debug_emac(fmt,args...) if (emac_dbg) printf(fmt,##args)
+
+/* Internal static functions */
+static int dm644x_eth_hw_init (void);
+static int dm644x_eth_open (void);
+static int dm644x_eth_close (void);
+static int dm644x_eth_send_packet (volatile void *packet, int length);
+static int dm644x_eth_rcv_packet (void);
+static void dm644x_eth_mdio_enable(void);
+
+static int gen_init_phy(int phy_addr);
+static int gen_is_phy_connected(int phy_addr);
+static int gen_get_link_speed(int phy_addr);
+static int gen_auto_negotiate(int phy_addr);
+
+/* Wrappers exported to the U-Boot proper */
+int eth_hw_init(void)
+{
+ return(dm644x_eth_hw_init());
+}
+
+int eth_init(bd_t * bd)
+{
+ return(dm644x_eth_open());
+}
+
+void eth_halt(void)
+{
+ dm644x_eth_close();
+}
+
+int eth_send(volatile void *packet, int length)
+{
+ return(dm644x_eth_send_packet(packet, length));
+}
+
+int eth_rx(void)
+{
+ return(dm644x_eth_rcv_packet());
+}
+
+void eth_mdio_enable(void)
+{
+ dm644x_eth_mdio_enable();
+}
+/* End of wrappers */
+
+
+static u_int8_t dm644x_eth_mac_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+/*
+ * This function must be called before emac_open() if you want to override
+ * the default mac address.
+ */
+void dm644x_eth_set_mac_addr(const u_int8_t *addr)
+{
+ int i;
+
+ for (i = 0; i < sizeof (dm644x_eth_mac_addr); i++) {
+ dm644x_eth_mac_addr[i] = addr[i];
+ }
+}
+
+/* EMAC Addresses */
+static volatile emac_regs *adap_emac = (emac_regs *)EMAC_BASE_ADDR;
+static volatile ewrap_regs *adap_ewrap = (ewrap_regs *)EMAC_WRAPPER_BASE_ADDR;
+static volatile mdio_regs *adap_mdio = (mdio_regs *)EMAC_MDIO_BASE_ADDR;
+
+/* EMAC descriptors */
+static volatile emac_desc *emac_rx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_RX_DESC_BASE);
+static volatile emac_desc *emac_tx_desc = (emac_desc *)(EMAC_WRAPPER_RAM_ADDR + EMAC_TX_DESC_BASE);
+static volatile emac_desc *emac_rx_active_head = 0;
+static volatile emac_desc *emac_rx_active_tail = 0;
+static int emac_rx_queue_active = 0;
+
+/* Receive packet buffers */
+static 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) */
+static volatile u_int8_t active_phy_addr = 0xff;
+
+phy_t phy;
+
+static void dm644x_eth_mdio_enable(void)
+{
+ u_int32_t clkdiv;
+
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+
+ adap_mdio->CONTROL = (clkdiv & 0xff) |
+ MDIO_CONTROL_ENABLE |
+ MDIO_CONTROL_FAULT |
+ MDIO_CONTROL_FAULT_ENABLE;
+
+ while (adap_mdio->CONTROL & MDIO_CONTROL_IDLE) {;}
+}
+
+/*
+ * Tries to find an active connected PHY. Returns 1 if address if found.
+ * If no active PHY (or more than one PHY) found returns 0.
+ * Sets active_phy_addr variable.
+ */
+static int dm644x_eth_phy_detect(void)
+{
+ u_int32_t phy_act_state;
+ int i;
+
+ active_phy_addr = 0xff;
+
+ if ((phy_act_state = adap_mdio->ALIVE) == 0)
+ return(0); /* No active PHYs */
+
+ debug_emac("dm644x_eth_phy_detect(), ALIVE = 0x%08x\n", phy_act_state);
+
+ for (i = 0; i < 32; i++) {
+ if (phy_act_state & (1 << i)) {
+ if (phy_act_state & ~(1 << i))
+ return(0); /* More than one PHY */
+ else {
+ active_phy_addr = i;
+ return(1);
+ }
+ }
+ }
+
+ return(0); /* Just to make GCC happy */
+}
+
+
+/* Read a PHY register via MDIO inteface. Returns 1 on success, 0 otherwise */
+int dm644x_eth_phy_read(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t *data)
+{
+ int tmp;
+
+ while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
+
+ adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_READ |
+ ((reg_num & 0x1f) << 21) |
+ ((phy_addr & 0x1f) << 16);
+
+ /* Wait for command to complete */
+ while ((tmp = adap_mdio->USERACCESS0) & MDIO_USERACCESS0_GO) {;}
+
+ if (tmp & MDIO_USERACCESS0_ACK) {
+ *data = tmp & 0xffff;
+ return(1);
+ }
+
+ *data = -1;
+ return(0);
+}
+
+/* Write to a PHY register via MDIO inteface. Blocks until operation is complete. */
+int dm644x_eth_phy_write(u_int8_t phy_addr, u_int8_t reg_num, u_int16_t data)
+{
+
+ while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
+
+ adap_mdio->USERACCESS0 = MDIO_USERACCESS0_GO |
+ MDIO_USERACCESS0_WRITE_WRITE |
+ ((reg_num & 0x1f) << 21) |
+ ((phy_addr & 0x1f) << 16) |
+ (data & 0xffff);
+
+ /* Wait for command to complete */
+ while (adap_mdio->USERACCESS0 & MDIO_USERACCESS0_GO) {;}
+
+ return(1);
+}
+
+/* PHY functions for a generic PHY */
+static int gen_init_phy(int phy_addr)
+{
+ int ret = 1;
+
+ if (gen_get_link_speed(phy_addr)) {
+ /* Try another time */
+ ret = gen_get_link_speed(phy_addr);
+ }
+
+ return(ret);
+}
+
+static int gen_is_phy_connected(int phy_addr)
+{
+ u_int16_t dummy;
+
+ return(dm644x_eth_phy_read(phy_addr, PHY_PHYIDR1, &dummy));
+}
+
+static int gen_get_link_speed(int phy_addr)
+{
+ u_int16_t tmp;
+
+ if (dm644x_eth_phy_read(phy_addr, MII_STATUS_REG, &tmp) && (tmp & 0x04))
+ return(1);
+
+ return(0);
+}
+
+static int gen_auto_negotiate(int phy_addr)
+{
+ u_int16_t tmp;
+
+ if (!dm644x_eth_phy_read(phy_addr, PHY_BMCR, &tmp))
+ return(0);
+
+ /* Restart Auto_negotiation */
+ tmp |= PHY_BMCR_AUTON;
+ dm644x_eth_phy_write(phy_addr, PHY_BMCR, tmp);
+
+ /*check AutoNegotiate complete */
+ udelay (10000);
+ if (!dm644x_eth_phy_read(phy_addr, PHY_BMSR, &tmp))
+ return(0);
+
+ if (!(tmp & PHY_BMSR_AUTN_COMP))
+ return(0);
+
+ return(gen_get_link_speed(phy_addr));
+}
+/* End of generic PHY functions */
+
+
+#if defined(CONFIG_MII) || (CONFIG_COMMANDS & CFG_CMD_MII)
+static int dm644x_mii_phy_read(char *devname, unsigned char addr, unsigned char reg, unsigned short *value)
+{
+ return(dm644x_eth_phy_read(addr, reg, value) ? 0 : 1);
+}
+
+static int dm644x_mii_phy_write(char *devname, unsigned char addr, unsigned char reg, unsigned short value)
+{
+ return(dm644x_eth_phy_write(addr, reg, value) ? 0 : 1);
+}
+
+int dm644x_eth_miiphy_initialize(bd_t *bis)
+{
+ miiphy_register(phy.name, dm644x_mii_phy_read, dm644x_mii_phy_write);
+
+ return(1);
+}
+#endif
+
+/*
+ * This function initializes the emac hardware. It does NOT initialize
+ * EMAC modules power or pin multiplexors, that is done by board_init()
+ * much earlier in bootup process. Returns 1 on success, 0 otherwise.
+ */
+static int dm644x_eth_hw_init(void)
+{
+ u_int32_t phy_id;
+ u_int16_t tmp;
+ int i;
+
+ dm644x_eth_mdio_enable();
+
+ for (i = 0; i < 256; i++) {
+ if (adap_mdio->ALIVE)
+ break;
+ udelay(10);
+ }
+
+ if (i >= 256) {
+ printf("No ETH PHY detected!!!\n");
+ return(0);
+ }
+
+ /* Find if a PHY is connected and get it's address */
+ if (!dm644x_eth_phy_detect())
+ return(0);
+
+ /* Get PHY ID and initialize phy_ops for a detected PHY */
+ if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR1, &tmp)) {
+ active_phy_addr = 0xff;
+ return(0);
+ }
+
+ phy_id = (tmp << 16) & 0xffff0000;
+
+ if (!dm644x_eth_phy_read(active_phy_addr, PHY_PHYIDR2, &tmp)) {
+ active_phy_addr = 0xff;
+ return(0);
+ }
+
+ phy_id |= tmp & 0x0000ffff;
+
+ switch (phy_id) {
+ case PHY_LXT972:
+ sprintf(phy.name, "LXT972 @ 0x%02x", active_phy_addr);
+ phy.init = lxt972_init_phy;
+ phy.is_phy_connected = lxt972_is_phy_connected;
+ phy.get_link_speed = lxt972_get_link_speed;
+ phy.auto_negotiate = lxt972_auto_negotiate;
+ break;
+ case PHY_DP83848:
+ sprintf(phy.name, "DP83848 @ 0x%02x", active_phy_addr);
+ phy.init = dp83848_init_phy;
+ phy.is_phy_connected = dp83848_is_phy_connected;
+ phy.get_link_speed = dp83848_get_link_speed;
+ phy.auto_negotiate = dp83848_auto_negotiate;
+ break;
+ default:
+ sprintf(phy.name, "GENERIC @ 0x%02x", active_phy_addr);
+ phy.init = gen_init_phy;
+ phy.is_phy_connected = gen_is_phy_connected;
+ phy.get_link_speed = gen_get_link_speed;
+ phy.auto_negotiate = gen_auto_negotiate;
+ }
+
+ return(1);
+}
+
+
+/* Eth device open */
+static int dm644x_eth_open(void)
+{
+ dv_reg_p addr;
+ u_int32_t clkdiv, cnt;
+ volatile emac_desc *rx_desc;
+
+ debug_emac("+ emac_open\n");
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ adap_emac->SOFTRESET = 1;
+ while (adap_emac->SOFTRESET != 0) {;}
+ adap_ewrap->EWCTL = 0;
+ for (cnt = 0; cnt < 5; cnt++) {
+ clkdiv = adap_ewrap->EWCTL;
+ }
+
+ rx_desc = emac_rx_desc;
+
+ adap_emac->TXCONTROL = 0x01;
+ adap_emac->RXCONTROL = 0x01;
+
+ /* Set MAC Addresses & Init multicast Hash to 0 (disable any multicast receive) */
+ /* Using channel 0 only - other channels are disabled */
+ adap_emac->MACINDEX = 0;
+ adap_emac->MACADDRHI =
+ (dm644x_eth_mac_addr[3] << 24) |
+ (dm644x_eth_mac_addr[2] << 16) |
+ (dm644x_eth_mac_addr[1] << 8) |
+ (dm644x_eth_mac_addr[0]);
+ adap_emac->MACADDRLO =
+ (dm644x_eth_mac_addr[5] << 8) |
+ (dm644x_eth_mac_addr[4]);
+
+ adap_emac->MACHASH1 = 0;
+ adap_emac->MACHASH2 = 0;
+
+ /* Set source MAC address - REQUIRED */
+ adap_emac->MACSRCADDRHI =
+ (dm644x_eth_mac_addr[3] << 24) |
+ (dm644x_eth_mac_addr[2] << 16) |
+ (dm644x_eth_mac_addr[1] << 8) |
+ (dm644x_eth_mac_addr[0]);
+ adap_emac->MACSRCADDRLO =
+ (dm644x_eth_mac_addr[4] << 8) |
+ (dm644x_eth_mac_addr[5]);
+
+ /* Set DMA 8 TX / 8 RX Head pointers to 0 */
+ addr = &adap_emac->TX0HDP;
+ for(cnt = 0; cnt < 16; cnt++)
+ *addr++ = 0;
+
+ addr = &adap_emac->RX0HDP;
+ for(cnt = 0; cnt < 16; cnt++)
+ *addr++ = 0;
+
+ /* Clear Statistics (do this before setting MacControl register) */
+ addr = &adap_emac->RXGOODFRAMES;
+ for(cnt = 0; cnt < EMAC_NUM_STATS; cnt++)
+ *addr++ = 0;
+
+ /* No multicast addressing */
+ adap_emac->MACHASH1 = 0;
+ adap_emac->MACHASH2 = 0;
+
+ /* Create RX queue and set receive process in place */
+ emac_rx_active_head = emac_rx_desc;
+ for (cnt = 0; cnt < EMAC_MAX_RX_BUFFERS; cnt++) {
+ rx_desc->next = (u_int32_t)(rx_desc + 1);
+ rx_desc->buffer = &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;
+ emac_rx_active_tail = rx_desc;
+ emac_rx_queue_active = 1;
+
+ /* Enable TX/RX */
+ adap_emac->RXMAXLEN = EMAC_MAX_ETHERNET_PKT_SIZE;
+ adap_emac->RXBUFFEROFFSET = 0;
+
+ /* No fancy configs - Use this for promiscous for debug - EMAC_RXMBPENABLE_RXCAFEN_ENABLE */
+ adap_emac->RXMBPENABLE = EMAC_RXMBPENABLE_RXBROADEN;
+
+ /* Enable ch 0 only */
+ adap_emac->RXUNICASTSET = 0x01;
+
+ /* Enable MII interface and Full duplex mode */
+ adap_emac->MACCONTROL = (EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE);
+
+ /* Init MDIO & get link state */
+ clkdiv = (EMAC_MDIO_BUS_FREQ / EMAC_MDIO_CLOCK_FREQ) - 1;
+ adap_mdio->CONTROL = ((clkdiv & 0xff) | MDIO_CONTROL_ENABLE | MDIO_CONTROL_FAULT);
+
+ if (!phy.get_link_speed(active_phy_addr))
+ return(0);
+
+ /* Start receive process */
+ adap_emac->RX0HDP = (u_int32_t)emac_rx_desc;
+
+ debug_emac("- emac_open\n");
+
+ return(1);
+}
+
+/* EMAC Channel Teardown */
+static void dm644x_eth_ch_teardown(int ch)
+{
+ dv_reg dly = 0xff;
+ dv_reg cnt;
+
+ debug_emac("+ emac_ch_teardown\n");
+
+ if (ch == EMAC_CH_TX) {
+ /* Init TX channel teardown */
+ adap_emac->TXTEARDOWN = 1;
+ for(cnt = 0; cnt != 0xfffffffc; cnt = 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;
+ }
+ adap_emac->TX0CP = cnt;
+ adap_emac->TX0HDP = 0;
+ } else {
+ /* Init RX channel teardown */
+ adap_emac->RXTEARDOWN = 1;
+ for(cnt = 0; cnt != 0xfffffffc; cnt = 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;
+ }
+ adap_emac->RX0CP = cnt;
+ adap_emac->RX0HDP = 0;
+ }
+
+ debug_emac("- emac_ch_teardown\n");
+}
+
+/* Eth device close */
+static int dm644x_eth_close(void)
+{
+ debug_emac("+ emac_close\n");
+
+ dm644x_eth_ch_teardown(EMAC_CH_TX); /* TX Channel teardown */
+ dm644x_eth_ch_teardown(EMAC_CH_RX); /* RX Channel teardown */
+
+ /* Reset EMAC module and disable interrupts in wrapper */
+ adap_emac->SOFTRESET = 1;
+ adap_ewrap->EWCTL = 0;
+
+ debug_emac("- emac_close\n");
+ return(1);
+}
+
+static int tx_send_loop = 0;
+
+/*
+ * This function sends a single packet on the network and returns
+ * positive number (number of bytes transmitted) or negative for error
+ */
+static int dm644x_eth_send_packet(volatile void *packet, int length)
+{
+ int ret_status = -1;
+ tx_send_loop = 0;
+
+ /* Return error if no link */
+ if (!phy.get_link_speed(active_phy_addr))
+ {
+ printf("WARN: emac_send_packet: No link\n");
+ return (ret_status);
+ }
+
+ /* 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 */
+ emac_tx_desc->next = 0;
+ emac_tx_desc->buffer = (u_int8_t *)packet;
+ emac_tx_desc->buff_off_len = (length & 0xffff);
+ emac_tx_desc->pkt_flag_len = ((length & 0xffff) |
+ EMAC_CPPI_SOP_BIT |
+ EMAC_CPPI_OWNERSHIP_BIT |
+ EMAC_CPPI_EOP_BIT);
+ /* Send the packet */
+ adap_emac->TX0HDP = (unsigned int)emac_tx_desc;
+
+ /* Wait for packet to complete or link down */
+ while (1) {
+ if (!phy.get_link_speed(active_phy_addr)) {
+ dm644x_eth_ch_teardown(EMAC_CH_TX);
+ return (ret_status);
+ }
+ if (adap_emac->TXINTSTATRAW & 0x01) {
+ ret_status = length;
+ break;
+ }
+ tx_send_loop++;
+ }
+
+ return(ret_status);
+}
+
+/*
+ * This function handles receipt of a packet from the network
+ */
+static int dm644x_eth_rcv_packet(void)
+{
+ volatile emac_desc *rx_curr_desc;
+ volatile emac_desc *curr_desc;
+ volatile emac_desc *tail_desc;
+ int status, ret = -1;
+
+ rx_curr_desc = emac_rx_active_head;
+ status = rx_curr_desc->pkt_flag_len;
+ if ((rx_curr_desc) && ((status & EMAC_CPPI_OWNERSHIP_BIT) == 0)) {
+ if (status & EMAC_CPPI_RX_ERROR_FRAME) {
+ /* Error in packet - discard it and requeue desc */
+ printf("WARN: emac_rcv_pkt: Error in packet\n");
+ } else {
+ NetReceive(rx_curr_desc->buffer, (rx_curr_desc->buff_off_len & 0xffff));
+ ret = rx_curr_desc->buff_off_len & 0xffff;
+ }
+
+ /* Ack received packet descriptor */
+ adap_emac->RX0CP = (unsigned int)rx_curr_desc;
+ curr_desc = rx_curr_desc;
+ emac_rx_active_head = (volatile emac_desc *)rx_curr_desc->next;
+
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ if (emac_rx_active_head) {
+ adap_emac->RX0HDP = (unsigned int)emac_rx_active_head;
+ } else {
+ emac_rx_queue_active = 0;
+ printf("INFO:emac_rcv_packet: RX Queue not active\n");
+ }
+ }
+
+ /* Recycle RX descriptor */
+ rx_curr_desc->buff_off_len = EMAC_MAX_ETHERNET_PKT_SIZE;
+ rx_curr_desc->pkt_flag_len = EMAC_CPPI_OWNERSHIP_BIT;
+ rx_curr_desc->next = 0;
+
+ if (emac_rx_active_head == 0) {
+ printf("INFO: emac_rcv_pkt: active queue head = 0\n");
+ emac_rx_active_head = curr_desc;
+ emac_rx_active_tail = curr_desc;
+ if (emac_rx_queue_active != 0) {
+ adap_emac->RX0HDP = (unsigned int)emac_rx_active_head;
+ printf("INFO: emac_rcv_pkt: active queue head = 0, HDP fired\n");
+ emac_rx_queue_active = 1;
+ }
+ } else {
+ tail_desc = emac_rx_active_tail;
+ emac_rx_active_tail = curr_desc;
+ tail_desc->next = (unsigned int)curr_desc;
+ status = tail_desc->pkt_flag_len;
+ if (status & EMAC_CPPI_EOQ_BIT) {
+ adap_emac->RX0HDP = (unsigned int)curr_desc;
+ status &= ~EMAC_CPPI_EOQ_BIT;
+ tail_desc->pkt_flag_len = status;
+ }
+ }
+ return(ret);
+ }
+ return(0);
+}
+
+#endif /* CONFIG_CMD_NET */
+
+#endif /* CONFIG_DRIVER_TI_EMAC */
diff --git a/cpu/arm926ejs/davinci/i2c.c b/cpu/arm926ejs/davinci/i2c.c
new file mode 100644
index 0000000..af9dc03
--- /dev/null
+++ b/cpu/arm926ejs/davinci/i2c.c
@@ -0,0 +1,351 @@
+/*
+ * TI DaVinci (TMS320DM644x) I2C driver.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * --------------------------------------------------------
+ *
+ * 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>
+
+#ifdef CONFIG_DRIVER_DAVINCI_I2C
+
+#include <i2c.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/i2c_defs.h>
+
+#define CHECK_NACK() \
+ do {\
+ if (tmp & (I2C_TIMEOUT | I2C_STAT_NACK)) {\
+ REG(I2C_CON) = 0;\
+ return(1);\
+ }\
+ } while (0)
+
+
+static int wait_for_bus(void)
+{
+ int stat, timeout;
+
+ REG(I2C_STAT) = 0xffff;
+
+ for (timeout = 0; timeout < 10; timeout++) {
+ if (!((stat = REG(I2C_STAT)) & I2C_STAT_BB)) {
+ REG(I2C_STAT) = 0xffff;
+ return(0);
+ }
+
+ REG(I2C_STAT) = stat;
+ udelay(50000);
+ }
+
+ REG(I2C_STAT) = 0xffff;
+ return(1);
+}
+
+
+static int poll_i2c_irq(int mask)
+{
+ int stat, timeout;
+
+ for (timeout = 0; timeout < 10; timeout++) {
+ udelay(1000);
+ stat = REG(I2C_STAT);
+ if (stat & mask) {
+ return(stat);
+ }
+ }
+
+ REG(I2C_STAT) = 0xffff;
+ return(stat | I2C_TIMEOUT);
+}
+
+
+void flush_rx(void)
+{
+ int dummy;
+
+ while (1) {
+ if (!(REG(I2C_STAT) & I2C_STAT_RRDY))
+ break;
+
+ dummy = REG(I2C_DRR);
+ REG(I2C_STAT) = I2C_STAT_RRDY;
+ udelay(1000);
+ }
+}
+
+
+void i2c_init(int speed, int slaveadd)
+{
+ u_int32_t div, psc;
+
+ if (REG(I2C_CON) & I2C_CON_EN) {
+ REG(I2C_CON) = 0;
+ udelay (50000);
+ }
+
+ psc = 2;
+ div = (CFG_HZ_CLOCK / ((psc + 1) * speed)) - 10; /* SCLL + SCLH */
+ REG(I2C_PSC) = psc; /* 27MHz / (2 + 1) = 9MHz */
+ REG(I2C_SCLL) = (div * 50) / 100; /* 50% Duty */
+ REG(I2C_SCLH) = div - REG(I2C_SCLL);
+
+ REG(I2C_OA) = slaveadd;
+ REG(I2C_CNT) = 0;
+
+ /* Interrupts must be enabled or I2C module won't work */
+ REG(I2C_IE) = I2C_IE_SCD_IE | I2C_IE_XRDY_IE |
+ I2C_IE_RRDY_IE | I2C_IE_ARDY_IE | I2C_IE_NACK_IE;
+
+ /* Now enable I2C controller (get it out of reset) */
+ REG(I2C_CON) = I2C_CON_EN;
+
+ udelay(1000);
+}
+
+
+int i2c_probe(u_int8_t chip)
+{
+ int rc = 1;
+
+ if (chip == REG(I2C_OA)) {
+ return(rc);
+ }
+
+ REG(I2C_CON) = 0;
+ if (wait_for_bus()) {return(1);}
+
+ /* try to read one byte from current (or only) address */
+ REG(I2C_CNT) = 1;
+ REG(I2C_SA) = chip;
+ REG(I2C_CON) = (I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP);
+ udelay (50000);
+
+ if (!(REG(I2C_STAT) & I2C_STAT_NACK)) {
+ rc = 0;
+ flush_rx();
+ REG(I2C_STAT) = 0xffff;
+ } else {
+ REG(I2C_STAT) = 0xffff;
+ REG(I2C_CON) |= I2C_CON_STP;
+ udelay(20000);
+ if (wait_for_bus()) {return(1);}
+ }
+
+ flush_rx();
+ REG(I2C_STAT) = 0xffff;
+ REG(I2C_CNT) = 0;
+ return(rc);
+}
+
+
+int i2c_read(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
+{
+ u_int32_t tmp;
+ int i;
+
+ if ((alen < 0) || (alen > 2)) {
+ printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
+ return(1);
+ }
+
+ if (wait_for_bus()) {return(1);}
+
+ if (alen != 0) {
+ /* Start address phase */
+ tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX;
+ REG(I2C_CNT) = alen;
+ REG(I2C_SA) = chip;
+ REG(I2C_CON) = tmp;
+
+ tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ switch (alen) {
+ case 2:
+ /* Send address MSByte */
+ if (tmp & I2C_STAT_XRDY) {
+ REG(I2C_DXR) = (addr >> 8) & 0xff;
+ } else {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+
+ tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+ /* No break, fall through */
+ case 1:
+ /* Send address LSByte */
+ if (tmp & I2C_STAT_XRDY) {
+ REG(I2C_DXR) = addr & 0xff;
+ } else {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+
+ tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK | I2C_STAT_ARDY);
+
+ CHECK_NACK();
+
+ if (!(tmp & I2C_STAT_ARDY)) {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+ }
+ }
+
+ /* Address phase is over, now read 'len' bytes and stop */
+ tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_STP;
+ REG(I2C_CNT) = len & 0xffff;
+ REG(I2C_SA) = chip;
+ REG(I2C_CON) = tmp;
+
+ for (i = 0; i < len; i++) {
+ tmp = poll_i2c_irq(I2C_STAT_RRDY | I2C_STAT_NACK | I2C_STAT_ROVR);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_RRDY) {
+ buf[i] = REG(I2C_DRR);
+ } else {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+ }
+
+ tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (!(tmp & I2C_STAT_SCD)) {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+
+ flush_rx();
+ REG(I2C_STAT) = 0xffff;
+ REG(I2C_CNT) = 0;
+ REG(I2C_CON) = 0;
+
+ return(0);
+}
+
+
+int i2c_write(u_int8_t chip, u_int32_t addr, int alen, u_int8_t *buf, int len)
+{
+ u_int32_t tmp;
+ int i;
+
+ if ((alen < 0) || (alen > 2)) {
+ printf("%s(): bogus address length %x\n", __FUNCTION__, alen);
+ return(1);
+ }
+ if (len < 0) {
+ printf("%s(): bogus length %x\n", __FUNCTION__, len);
+ return(1);
+ }
+
+ if (wait_for_bus()) {return(1);}
+
+ /* Start address phase */
+ tmp = I2C_CON_EN | I2C_CON_MST | I2C_CON_STT | I2C_CON_TRX | I2C_CON_STP;
+ REG(I2C_CNT) = (alen == 0) ? len & 0xffff : (len & 0xffff) + alen;
+ REG(I2C_SA) = chip;
+ REG(I2C_CON) = tmp;
+
+ switch (alen) {
+ case 2:
+ /* Send address MSByte */
+ tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_XRDY) {
+ REG(I2C_DXR) = (addr >> 8) & 0xff;
+ } else {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+ /* No break, fall through */
+ case 1:
+ /* Send address LSByte */
+ tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_XRDY) {
+ REG(I2C_DXR) = addr & 0xff;
+ } else {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+ }
+
+ for (i = 0; i < len; i++) {
+ tmp = poll_i2c_irq(I2C_STAT_XRDY | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (tmp & I2C_STAT_XRDY) {
+ REG(I2C_DXR) = buf[i];
+ } else {
+ return(1);
+ }
+ }
+
+ tmp = poll_i2c_irq(I2C_STAT_SCD | I2C_STAT_NACK);
+
+ CHECK_NACK();
+
+ if (!(tmp & I2C_STAT_SCD)) {
+ REG(I2C_CON) = 0;
+ return(1);
+ }
+
+ flush_rx();
+ REG(I2C_STAT) = 0xffff;
+ REG(I2C_CNT) = 0;
+ REG(I2C_CON) = 0;
+
+ return(0);
+}
+
+
+u_int8_t i2c_reg_read(u_int8_t chip, u_int8_t reg)
+{
+ u_int8_t tmp;
+
+ i2c_read(chip, reg, 1, &tmp, 1);
+ return(tmp);
+}
+
+
+void i2c_reg_write(u_int8_t chip, u_int8_t reg, u_int8_t val)
+{
+ u_int8_t tmp;
+
+ i2c_write(chip, reg, 1, &tmp, 1);
+}
+
+#endif /* CONFIG_DRIVER_DAVINCI_I2C */
diff --git a/cpu/arm926ejs/davinci/lowlevel_init.S b/cpu/arm926ejs/davinci/lowlevel_init.S
new file mode 100644
index 0000000..a87c112
--- /dev/null
+++ b/cpu/arm926ejs/davinci/lowlevel_init.S
@@ -0,0 +1,707 @@
+/*
+ * Low-level board setup code for TI DaVinci SoC based boards.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Partially based on TI sources, original copyrights follow:
+ */
+
+/*
+ * Board specific setup info
+ *
+ * (C) Copyright 2003
+ * Texas Instruments, <www.ti.com>
+ * Kshitij Gupta <Kshitij@ti.com>
+ *
+ * Modified for OMAP 1610 H2 board by Nishant Kamat, Jan 2004
+ *
+ * Modified for OMAP 5912 OSK board by Rishi Bhattacharya, Apr 2004
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * Modified for DV-EVM board by Rishi Bhattacharya, Apr 2005
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * Modified for DV-EVM board by Swaminathan S, Nov 2005
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <config.h>
+
+.globl lowlevel_init
+lowlevel_init:
+
+ /*-------------------------------------------------------*
+ * Mask all IRQs by setting all bits in the EINT default *
+ *-------------------------------------------------------*/
+ mov r1, $0
+ ldr r0, =EINT_ENABLE0
+ str r1, [r0]
+ ldr r0, =EINT_ENABLE1
+ str r1, [r0]
+
+ /*------------------------------------------------------*
+ * Put the GEM in reset *
+ *------------------------------------------------------*/
+
+ /* Put the GEM in reset */
+ ldr r8, PSC_GEM_FLAG_CLEAR
+ ldr r6, MDCTL_GEM
+ ldr r7, [r6]
+ and r7, r7, r8
+ str r7, [r6]
+
+ /* Enable the Power Domain Transition Command */
+ ldr r6, PTCMD
+ ldr r7, [r6]
+ orr r7, r7, $0x02
+ str r7, [r6]
+
+ /* Check for Transition Complete(PTSTAT) */
+checkStatClkStopGem:
+ ldr r6, PTSTAT
+ ldr r7, [r6]
+ ands r7, r7, $0x02
+ bne checkStatClkStopGem
+
+ /* Check for GEM Reset Completion */
+checkGemStatClkStop:
+ ldr r6, MDSTAT_GEM
+ ldr r7, [r6]
+ ands r7, r7, $0x100
+ bne checkGemStatClkStop
+
+ /* Do this for enabling a WDT initiated reset this is a workaround
+ for a chip bug. Not required under normal situations */
+ ldr r6, P1394
+ mov r10, $0
+ str r10, [r6]
+
+ /*------------------------------------------------------*
+ * Enable L1 & L2 Memories in Fast mode *
+ *------------------------------------------------------*/
+ ldr r6, DFT_ENABLE
+ mov r10, $0x01
+ str r10, [r6]
+
+ ldr r6, MMARG_BRF0
+ ldr r10, MMARG_BRF0_VAL
+ str r10, [r6]
+
+ ldr r6, DFT_ENABLE
+ mov r10, $0
+ str r10, [r6]
+
+ /*------------------------------------------------------*
+ * DDR2 PLL Initialization *
+ *------------------------------------------------------*/
+
+ /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */
+ mov r10, $0
+ ldr r6, PLL2_CTL
+ ldr r7, PLL_CLKSRC_MASK
+ ldr r8, [r6]
+ and r8, r8, r7
+ mov r9, r10, lsl $8
+ orr r8, r8, r9
+ str r8, [r6]
+
+ /* Select the PLLEN source */
+ ldr r7, PLL_ENSRC_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Bypass the PLL */
+ ldr r7, PLL_BYPASS_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */
+ mov r10, $0x20
+WaitPPL2Loop:
+ subs r10, r10, $1
+ bne WaitPPL2Loop
+
+ /* Reset the PLL */
+ ldr r7, PLL_RESET_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Power up the PLL */
+ ldr r7, PLL_PWRUP_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Enable the PLL from Disable Mode */
+ ldr r7, PLL_DISABLE_ENABLE_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Program the PLL Multiplier */
+ ldr r6, PLL2_PLLM
+ mov r2, $0x17 /* 162 MHz */
+ str r2, [r6]
+
+ /* Program the PLL2 Divisor Value */
+ ldr r6, PLL2_DIV2
+ mov r3, $0x01
+ str r3, [r6]
+
+ /* Program the PLL2 Divisor Value */
+ ldr r6, PLL2_DIV1
+ mov r4, $0x0b /* 54 MHz */
+ str r4, [r6]
+
+ /* PLL2 DIV2 MMR */
+ ldr r8, PLL2_DIV_MASK
+ ldr r6, PLL2_DIV2
+ ldr r9, [r6]
+ and r8, r8, r9
+ mov r9, $0x01
+ mov r9, r9, lsl $15
+ orr r8, r8, r9
+ str r8, [r6]
+
+ /* Program the GOSET bit to take new divider values */
+ ldr r6, PLL2_PLLCMD
+ ldr r7, [r6]
+ orr r7, r7, $0x01
+ str r7, [r6]
+
+ /* Wait for Done */
+ ldr r6, PLL2_PLLSTAT
+doneLoop_0:
+ ldr r7, [r6]
+ ands r7, r7, $0x01
+ bne doneLoop_0
+
+ /* PLL2 DIV1 MMR */
+ ldr r8, PLL2_DIV_MASK
+ ldr r6, PLL2_DIV1
+ ldr r9, [r6]
+ and r8, r8, r9
+ mov r9, $0x01
+ mov r9, r9, lsl $15
+ orr r8, r8, r9
+ str r8, [r6]
+
+ /* Program the GOSET bit to take new divider values */
+ ldr r6, PLL2_PLLCMD
+ ldr r7, [r6]
+ orr r7, r7, $0x01
+ str r7, [r6]
+
+ /* Wait for Done */
+ ldr r6, PLL2_PLLSTAT
+doneLoop:
+ ldr r7, [r6]
+ ands r7, r7, $0x01
+ bne doneLoop
+
+ /* Wait for PLL to Reset Properly */
+ mov r10, $0x218
+ResetPPL2Loop:
+ subs r10, r10, $1
+ bne ResetPPL2Loop
+
+ /* Bring PLL out of Reset */
+ ldr r6, PLL2_CTL
+ ldr r8, [r6]
+ orr r8, r8, $0x08
+ str r8, [r6]
+
+ /* Wait for PLL to Lock */
+ ldr r10, PLL_LOCK_COUNT
+PLL2Lock:
+ subs r10, r10, $1
+ bne PLL2Lock
+
+ /* Enable the PLL */
+ ldr r6, PLL2_CTL
+ ldr r8, [r6]
+ orr r8, r8, $0x01
+ str r8, [r6]
+
+ /*------------------------------------------------------*
+ * Issue Soft Reset to DDR Module *
+ *------------------------------------------------------*/
+
+ /* Shut down the DDR2 LPSC Module */
+ ldr r8, PSC_FLAG_CLEAR
+ ldr r6, MDCTL_DDR2
+ ldr r7, [r6]
+ and r7, r7, r8
+ orr r7, r7, $0x03
+ str r7, [r6]
+
+ /* Enable the Power Domain Transition Command */
+ ldr r6, PTCMD
+ ldr r7, [r6]
+ orr r7, r7, $0x01
+ str r7, [r6]
+
+ /* Check for Transition Complete(PTSTAT) */
+checkStatClkStop:
+ ldr r6, PTSTAT
+ ldr r7, [r6]
+ ands r7, r7, $0x01
+ bne checkStatClkStop
+
+ /* Check for DDR2 Controller Enable Completion */
+checkDDRStatClkStop:
+ ldr r6, MDSTAT_DDR2
+ ldr r7, [r6]
+ and r7, r7, $0x1f
+ cmp r7, $0x03
+ bne checkDDRStatClkStop
+
+ /*------------------------------------------------------*
+ * Program DDR2 MMRs for 162MHz Setting *
+ *------------------------------------------------------*/
+
+ /* Program PHY Control Register */
+ ldr r6, DDRCTL
+ ldr r7, DDRCTL_VAL
+ str r7, [r6]
+
+ /* Program SDRAM Bank Config Register */
+ ldr r6, SDCFG
+ ldr r7, SDCFG_VAL
+ str r7, [r6]
+
+ /* Program SDRAM TIM-0 Config Register */
+ ldr r6, SDTIM0
+ ldr r7, SDTIM0_VAL_162MHz
+ str r7, [r6]
+
+ /* Program SDRAM TIM-1 Config Register */
+ ldr r6, SDTIM1
+ ldr r7, SDTIM1_VAL_162MHz
+ str r7, [r6]
+
+ /* Program the SDRAM Bank Config Control Register */
+ ldr r10, MASK_VAL
+ ldr r8, SDCFG
+ ldr r9, SDCFG_VAL
+ and r9, r9, r10
+ str r9, [r8]
+
+ /* Program SDRAM SDREF Config Register */
+ ldr r6, SDREF
+ ldr r7, SDREF_VAL
+ str r7, [r6]
+
+ /*------------------------------------------------------*
+ * Issue Soft Reset to DDR Module *
+ *------------------------------------------------------*/
+
+ /* Issue a Dummy DDR2 read/write */
+ ldr r8, DDR2_START_ADDR
+ ldr r7, DUMMY_VAL
+ str r7, [r8]
+ ldr r7, [r8]
+
+ /* Shut down the DDR2 LPSC Module */
+ ldr r8, PSC_FLAG_CLEAR
+ ldr r6, MDCTL_DDR2
+ ldr r7, [r6]
+ and r7, r7, r8
+ orr r7, r7, $0x01
+ str r7, [r6]
+
+ /* Enable the Power Domain Transition Command */
+ ldr r6, PTCMD
+ ldr r7, [r6]
+ orr r7, r7, $0x01
+ str r7, [r6]
+
+ /* Check for Transition Complete(PTSTAT) */
+checkStatClkStop2:
+ ldr r6, PTSTAT
+ ldr r7, [r6]
+ ands r7, r7, $0x01
+ bne checkStatClkStop2
+
+ /* Check for DDR2 Controller Enable Completion */
+checkDDRStatClkStop2:
+ ldr r6, MDSTAT_DDR2
+ ldr r7, [r6]
+ and r7, r7, $0x1f
+ cmp r7, $0x01
+ bne checkDDRStatClkStop2
+
+ /*------------------------------------------------------*
+ * Turn DDR2 Controller Clocks On *
+ *------------------------------------------------------*/
+
+ /* Enable the DDR2 LPSC Module */
+ ldr r6, MDCTL_DDR2
+ ldr r7, [r6]
+ orr r7, r7, $0x03
+ str r7, [r6]
+
+ /* Enable the Power Domain Transition Command */
+ ldr r6, PTCMD
+ ldr r7, [r6]
+ orr r7, r7, $0x01
+ str r7, [r6]
+
+ /* Check for Transition Complete(PTSTAT) */
+checkStatClkEn2:
+ ldr r6, PTSTAT
+ ldr r7, [r6]
+ ands r7, r7, $0x01
+ bne checkStatClkEn2
+
+ /* Check for DDR2 Controller Enable Completion */
+checkDDRStatClkEn2:
+ ldr r6, MDSTAT_DDR2
+ ldr r7, [r6]
+ and r7, r7, $0x1f
+ cmp r7, $0x03
+ bne checkDDRStatClkEn2
+
+ /* DDR Writes and Reads */
+ ldr r6, CFGTEST
+ mov r3, $0x01
+ str r3, [r6]
+
+ /*------------------------------------------------------*
+ * System PLL Initialization *
+ *------------------------------------------------------*/
+
+ /* Select the Clock Mode Depending on the Value written in the Boot Table by the run script */
+ mov r2, $0
+ ldr r6, PLL1_CTL
+ ldr r7, PLL_CLKSRC_MASK
+ ldr r8, [r6]
+ and r8, r8, r7
+ mov r9, r2, lsl $8
+ orr r8, r8, r9
+ str r8, [r6]
+
+ /* Select the PLLEN source */
+ ldr r7, PLL_ENSRC_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Bypass the PLL */
+ ldr r7, PLL_BYPASS_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Wait for few cycles to allow PLLEN Mux switch properly to bypass Clock */
+ mov r10, $0x20
+
+WaitLoop:
+ subs r10, r10, $1
+ bne WaitLoop
+
+ /* Reset the PLL */
+ ldr r7, PLL_RESET_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Disable the PLL */
+ orr r8, r8, $0x10
+ str r8, [r6]
+
+ /* Power up the PLL */
+ ldr r7, PLL_PWRUP_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Enable the PLL from Disable Mode */
+ ldr r7, PLL_DISABLE_ENABLE_MASK
+ and r8, r8, r7
+ str r8, [r6]
+
+ /* Program the PLL Multiplier */
+ ldr r6, PLL1_PLLM
+ mov r3, $0x15 /* For 594MHz */
+ str r3, [r6]
+
+ /* Wait for PLL to Reset Properly */
+ mov r10, $0xff
+
+ResetLoop:
+ subs r10, r10, $1
+ bne ResetLoop
+
+ /* Bring PLL out of Reset */
+ ldr r6, PLL1_CTL
+ orr r8, r8, $0x08
+ str r8, [r6]
+
+ /* Wait for PLL to Lock */
+ ldr r10, PLL_LOCK_COUNT
+
+PLL1Lock:
+ subs r10, r10, $1
+ bne PLL1Lock
+
+ /* Enable the PLL */
+ orr r8, r8, $0x01
+ str r8, [r6]
+
+ nop
+ nop
+ nop
+ nop
+
+ /*------------------------------------------------------*
+ * AEMIF configuration for NOR Flash (double check) *
+ *------------------------------------------------------*/
+ ldr r0, _PINMUX0
+ ldr r1, _DEV_SETTING
+ str r1, [r0]
+
+ ldr r0, WAITCFG
+ ldr r1, WAITCFG_VAL
+ ldr r2, [r0]
+ orr r2, r2, r1
+ str r2, [r0]
+
+ ldr r0, ACFG3
+ ldr r1, ACFG3_VAL
+ ldr r2, [r0]
+ and r1, r2, r1
+ str r1, [r0]
+
+ ldr r0, ACFG4
+ ldr r1, ACFG4_VAL
+ ldr r2, [r0]
+ and r1, r2, r1
+ str r1, [r0]
+
+ ldr r0, ACFG5
+ ldr r1, ACFG5_VAL
+ ldr r2, [r0]
+ and r1, r2, r1
+ str r1, [r0]
+
+ /*--------------------------------------*
+ * VTP manual Calibration *
+ *--------------------------------------*/
+ ldr r0, VTPIOCR
+ ldr r1, VTP_MMR0
+ str r1, [r0]
+
+ ldr r0, VTPIOCR
+ ldr r1, VTP_MMR1
+ str r1, [r0]
+
+ /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */
+ ldr r10, VTP_LOCK_COUNT
+VTPLock:
+ subs r10, r10, $1
+ bne VTPLock
+
+ ldr r6, DFT_ENABLE
+ mov r10, $0x01
+ str r10, [r6]
+
+ ldr r6, DDRVTPR
+ ldr r7, [r6]
+ and r7, r7, $0x1f
+ and r8, r7, $0x3e0
+ orr r8, r7, r8
+ ldr r7, VTP_RECAL
+ orr r8, r7, r8
+ ldr r7, VTP_EN
+ orr r8, r7, r8
+ str r8, [r0]
+
+
+ /* Wait for 33 VTP CLK cycles. VRP operates at 27 MHz */
+ ldr r10, VTP_LOCK_COUNT
+VTP1Lock:
+ subs r10, r10, $1
+ bne VTP1Lock
+
+ ldr r1, [r0]
+ ldr r2, VTP_MASK
+ and r2, r1, r2
+ str r2, [r0]
+
+ ldr r6, DFT_ENABLE
+ mov r10, $0
+ str r10, [r6]
+
+ /*
+ * Call board-specific lowlevel init.
+ * That MUST be present and THAT returns
+ * back to arch calling code with "mov pc, lr."
+ */
+ b dv_board_init
+
+.ltorg
+
+_PINMUX0:
+ .word 0x01c40000 /* Device Configuration Registers */
+_PINMUX1:
+ .word 0x01c40004 /* Device Configuration Registers */
+
+_DEV_SETTING:
+ .word 0x00000c1f
+
+WAITCFG:
+ .word 0x01e00004
+WAITCFG_VAL:
+ .word 0
+ACFG3:
+ .word 0x01e00014
+ACFG3_VAL:
+ .word 0x3ffffffd
+ACFG4:
+ .word 0x01e00018
+ACFG4_VAL:
+ .word 0x3ffffffd
+ACFG5:
+ .word 0x01e0001c
+ACFG5_VAL:
+ .word 0x3ffffffd
+
+MDCTL_DDR2:
+ .word 0x01c41a34
+MDSTAT_DDR2:
+ .word 0x01c41834
+
+PTCMD:
+ .word 0x01c41120
+PTSTAT:
+ .word 0x01c41128
+
+EINT_ENABLE0:
+ .word 0x01c48018
+EINT_ENABLE1:
+ .word 0x01c4801c
+
+PSC_FLAG_CLEAR:
+ .word 0xffffffe0
+PSC_GEM_FLAG_CLEAR:
+ .word 0xfffffeff
+
+/* DDR2 MMR & CONFIGURATION VALUES, 162 MHZ clock */
+DDRCTL:
+ .word 0x200000e4
+DDRCTL_VAL:
+ .word 0x50006405
+SDREF:
+ .word 0x2000000c
+SDREF_VAL:
+ .word 0x000005c3
+SDCFG:
+ .word 0x20000008
+SDCFG_VAL:
+#ifdef DDR_4BANKS
+ .word 0x00178622
+#elif defined DDR_8BANKS
+ .word 0x00178632
+#else
+#error "Unknown DDR configuration!!!"
+#endif
+SDTIM0:
+ .word 0x20000010
+SDTIM0_VAL_162MHz:
+ .word 0x28923211
+SDTIM1:
+ .word 0x20000014
+SDTIM1_VAL_162MHz:
+ .word 0x0016c722
+VTPIOCR:
+ .word 0x200000f0 /* VTP IO Control register */
+DDRVTPR:
+ .word 0x01c42030 /* DDR VPTR MMR */
+VTP_MMR0:
+ .word 0x201f
+VTP_MMR1:
+ .word 0xa01f
+DFT_ENABLE:
+ .word 0x01c4004c
+VTP_LOCK_COUNT:
+ .word 0x5b0
+VTP_MASK:
+ .word 0xffffdfff
+VTP_RECAL:
+ .word 0x40000
+VTP_EN:
+ .word 0x02000
+CFGTEST:
+ .word 0x80010000
+MASK_VAL:
+ .word 0x00000fff
+
+/* GEM Power Up & LPSC Control Register */
+MDCTL_GEM:
+ .word 0x01c41a9c
+MDSTAT_GEM:
+ .word 0x01c4189c
+
+/* For WDT reset chip bug */
+P1394:
+ .word 0x01c41a20
+
+PLL_CLKSRC_MASK:
+ .word 0xfffffeff /* Mask the Clock Mode bit */
+PLL_ENSRC_MASK:
+ .word 0xffffffdf /* Select the PLLEN source */
+PLL_BYPASS_MASK:
+ .word 0xfffffffe /* Put the PLL in BYPASS */
+PLL_RESET_MASK:
+ .word 0xfffffff7 /* Put the PLL in Reset Mode */
+PLL_PWRUP_MASK:
+ .word 0xfffffffd /* PLL Power up Mask Bit */
+PLL_DISABLE_ENABLE_MASK:
+ .word 0xffffffef /* Enable the PLL from Disable */
+PLL_LOCK_COUNT:
+ .word 0x2000
+
+/* PLL1-SYSTEM PLL MMRs */
+PLL1_CTL:
+ .word 0x01c40900
+PLL1_PLLM:
+ .word 0x01c40910
+
+/* PLL2-SYSTEM PLL MMRs */
+PLL2_CTL:
+ .word 0x01c40d00
+PLL2_PLLM:
+ .word 0x01c40d10
+PLL2_DIV1:
+ .word 0x01c40d18
+PLL2_DIV2:
+ .word 0x01c40d1c
+PLL2_PLLCMD:
+ .word 0x01c40d38
+PLL2_PLLSTAT:
+ .word 0x01c40d3c
+PLL2_DIV_MASK:
+ .word 0xffff7fff
+
+MMARG_BRF0:
+ .word 0x01c42010 /* BRF margin mode 0 (R/W)*/
+MMARG_BRF0_VAL:
+ .word 0x00444400
+
+DDR2_START_ADDR:
+ .word 0x80000000
+DUMMY_VAL:
+ .word 0xa55aa55a
diff --git a/cpu/arm926ejs/davinci/lxt972.c b/cpu/arm926ejs/davinci/lxt972.c
new file mode 100644
index 0000000..6eeb6e5
--- /dev/null
+++ b/cpu/arm926ejs/davinci/lxt972.c
@@ -0,0 +1,142 @@
+/*
+ * Intel LXT971/LXT972 PHY Driver for TI DaVinci
+ * (TMS320DM644x) based boards.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * --------------------------------------------------------
+ *
+ * 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 <net.h>
+#include <lxt971a.h>
+#include <asm/arch/emac_defs.h>
+
+#ifdef CONFIG_DRIVER_TI_EMAC
+
+#ifdef CONFIG_CMD_NET
+
+int lxt972_is_phy_connected(int phy_addr)
+{
+ u_int16_t id1, id2;
+
+ if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID1, &id1))
+ return(0);
+ if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_ID2, &id2))
+ return(0);
+
+ if ((id1 == (0x0013)) && ((id2 & 0xfff0) == 0x78e0))
+ return(1);
+
+ return(0);
+}
+
+int lxt972_get_link_speed(int phy_addr)
+{
+ u_int16_t stat1, tmp;
+ volatile emac_regs* emac = (emac_regs *)EMAC_BASE_ADDR;
+
+ if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_STAT2, &stat1))
+ return(0);
+
+ if (!(stat1 & PHY_LXT971_STAT2_LINK)) /* link up? */
+ return(0);
+
+ if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp))
+ return(0);
+
+ tmp |= PHY_LXT971_DIG_CFG_MII_DRIVE;
+
+ dm644x_eth_phy_write(phy_addr, PHY_LXT971_DIG_CFG, tmp);
+ /* Read back */
+ if (!dm644x_eth_phy_read(phy_addr, PHY_LXT971_DIG_CFG, &tmp))
+ return(0);
+
+
+ /* Speed doesn't matter, there is no setting for it in EMAC... */
+ if (stat1 & PHY_LXT971_STAT2_100BTX) {
+ if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) {
+ /* set DM644x EMAC for Full Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
+ } else {
+ /*set DM644x EMAC for Half Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
+ }
+
+ return(1);
+ } else {
+ if (stat1 & PHY_LXT971_STAT2_DUPLEX_MODE) {
+ /* set DM644x EMAC for Full Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE | EMAC_MACCONTROL_FULLDUPLEX_ENABLE;
+ } else {
+ /*set DM644x EMAC for Half Duplex */
+ emac->MACCONTROL = EMAC_MACCONTROL_MIIEN_ENABLE;
+ }
+
+ return(1);
+ }
+
+ return(0);
+}
+
+
+int lxt972_init_phy(int phy_addr)
+{
+ int ret = 1;
+
+ if (!lxt972_get_link_speed(phy_addr)) {
+ /* Try another time */
+ ret = lxt972_get_link_speed(phy_addr);
+ }
+
+ /* Disable PHY Interrupts */
+ dm644x_eth_phy_write(phy_addr, PHY_LXT971_INT_ENABLE, 0);
+
+ return(ret);
+}
+
+
+int lxt972_auto_negotiate(int phy_addr)
+{
+ u_int16_t tmp;
+
+
+ if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_CTRL, &tmp))
+ return(0);
+
+ /* Restart Auto_negotiation */
+ tmp |= PHY_COMMON_CTRL_RES_AUTO;
+ dm644x_eth_phy_write(phy_addr, PHY_COMMON_CTRL, tmp);
+
+ /*check AutoNegotiate complete */
+ udelay (10000);
+ if (!dm644x_eth_phy_read(phy_addr, PHY_COMMON_STAT, &tmp))
+ return(0);
+
+ if (!(tmp & PHY_COMMON_STAT_AN_COMP))
+ return(0);
+
+ return (lxt972_get_link_speed(phy_addr));
+}
+
+#endif /* CONFIG_CMD_NET */
+
+#endif /* CONFIG_DRIVER_ETHER */
diff --git a/cpu/arm926ejs/davinci/nand.c b/cpu/arm926ejs/davinci/nand.c
new file mode 100644
index 0000000..127be9f
--- /dev/null
+++ b/cpu/arm926ejs/davinci/nand.c
@@ -0,0 +1,389 @@
+/*
+ * NAND driver for TI DaVinci based boards.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * Based on Linux DaVinci NAND driver by TI. Original copyright follows:
+ */
+
+/*
+ *
+ * linux/drivers/mtd/nand/nand_davinci.c
+ *
+ * NAND Flash Driver
+ *
+ * Copyright (C) 2006 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.
+ * ----------------------------------------------------------------------------
+ *
+ * Overview:
+ * This is a device driver for the NAND flash device found on the
+ * DaVinci board which utilizes the Samsung k9k2g08 part.
+ *
+ Modifications:
+ ver. 1.0: Feb 2005, Vinod/Sudhakar
+ -
+ *
+ */
+
+#include <common.h>
+
+#ifdef CFG_USE_NAND
+#if !defined(CFG_NAND_LEGACY)
+
+#include <nand.h>
+#include <asm/arch/nand_defs.h>
+#include <asm/arch/emif_defs.h>
+
+extern struct nand_chip nand_dev_desc[CFG_MAX_NAND_DEVICE];
+
+static void nand_davinci_hwcontrol(struct mtd_info *mtd, int cmd)
+{
+ struct nand_chip *this = mtd->priv;
+ u_int32_t IO_ADDR_W = (u_int32_t)this->IO_ADDR_W;
+
+ IO_ADDR_W &= ~(MASK_ALE|MASK_CLE);
+
+ switch (cmd) {
+ case NAND_CTL_SETCLE:
+ IO_ADDR_W |= MASK_CLE;
+ break;
+ case NAND_CTL_SETALE:
+ IO_ADDR_W |= MASK_ALE;
+ break;
+ }
+
+ this->IO_ADDR_W = (void *)IO_ADDR_W;
+}
+
+/* Set WP on deselect, write enable on select */
+static void nand_davinci_select_chip(struct mtd_info *mtd, int chip)
+{
+#define GPIO_SET_DATA01 0x01c67018
+#define GPIO_CLR_DATA01 0x01c6701c
+#define GPIO_NAND_WP (1 << 4)
+#ifdef SONATA_BOARD_GPIOWP
+ if (chip < 0) {
+ REG(GPIO_CLR_DATA01) |= GPIO_NAND_WP;
+ } else {
+ REG(GPIO_SET_DATA01) |= GPIO_NAND_WP;
+ }
+#endif
+}
+
+#ifdef CFG_NAND_HW_ECC
+#ifdef CFG_NAND_LARGEPAGE
+static struct nand_oobinfo davinci_nand_oobinfo = {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 12,
+ .eccpos = {8, 9, 10, 24, 25, 26, 40, 41, 42, 56, 57, 58},
+ .oobfree = { {2, 6}, {12, 12}, {28, 12}, {44, 12}, {60, 4} }
+};
+#elif defined(CFG_NAND_SMALLPAGE)
+static struct nand_oobinfo davinci_nand_oobinfo = {
+ .useecc = MTD_NANDECC_AUTOPLACE,
+ .eccbytes = 3,
+ .eccpos = {0, 1, 2},
+ .oobfree = { {6, 2}, {8, 8} }
+};
+#else
+#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!"
+#endif
+
+static void nand_davinci_enable_hwecc(struct mtd_info *mtd, int mode)
+{
+ emifregs emif_addr;
+ int dummy;
+
+ emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
+
+ dummy = emif_addr->NANDF1ECC;
+ dummy = emif_addr->NANDF2ECC;
+ dummy = emif_addr->NANDF3ECC;
+ dummy = emif_addr->NANDF4ECC;
+
+ emif_addr->NANDFCR |= (1 << 8);
+}
+
+static u_int32_t nand_davinci_readecc(struct mtd_info *mtd, u_int32_t region)
+{
+ u_int32_t ecc = 0;
+ emifregs emif_base_addr;
+
+ emif_base_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
+
+ if (region == 1)
+ ecc = emif_base_addr->NANDF1ECC;
+ else if (region == 2)
+ ecc = emif_base_addr->NANDF2ECC;
+ else if (region == 3)
+ ecc = emif_base_addr->NANDF3ECC;
+ else if (region == 4)
+ ecc = emif_base_addr->NANDF4ECC;
+
+ return(ecc);
+}
+
+static int nand_davinci_calculate_ecc(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code)
+{
+ u_int32_t tmp;
+ int region, n;
+ struct nand_chip *this = mtd->priv;
+
+ n = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1;
+
+ region = 1;
+ while (n--) {
+ tmp = nand_davinci_readecc(mtd, region);
+ *ecc_code++ = tmp;
+ *ecc_code++ = tmp >> 16;
+ *ecc_code++ = ((tmp >> 8) & 0x0f) | ((tmp >> 20) & 0xf0);
+ region++;
+ }
+ return(0);
+}
+
+static void nand_davinci_gen_true_ecc(u_int8_t *ecc_buf)
+{
+ u_int32_t tmp = ecc_buf[0] | (ecc_buf[1] << 16) | ((ecc_buf[2] & 0xf0) << 20) | ((ecc_buf[2] & 0x0f) << 8);
+
+ ecc_buf[0] = ~(P64o(tmp) | P64e(tmp) | P32o(tmp) | P32e(tmp) | P16o(tmp) | P16e(tmp) | P8o(tmp) | P8e(tmp));
+ ecc_buf[1] = ~(P1024o(tmp) | P1024e(tmp) | P512o(tmp) | P512e(tmp) | P256o(tmp) | P256e(tmp) | P128o(tmp) | P128e(tmp));
+ ecc_buf[2] = ~( P4o(tmp) | P4e(tmp) | P2o(tmp) | P2e(tmp) | P1o(tmp) | P1e(tmp) | P2048o(tmp) | P2048e(tmp));
+}
+
+static int nand_davinci_compare_ecc(u_int8_t *ecc_nand, u_int8_t *ecc_calc, u_int8_t *page_data)
+{
+ u_int32_t i;
+ u_int8_t tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+ u_int8_t comp0_bit[8], comp1_bit[8], comp2_bit[8];
+ u_int8_t ecc_bit[24];
+ u_int8_t ecc_sum = 0;
+ u_int8_t find_bit = 0;
+ u_int32_t find_byte = 0;
+ int is_ecc_ff;
+
+ is_ecc_ff = ((*ecc_nand == 0xff) && (*(ecc_nand + 1) == 0xff) && (*(ecc_nand + 2) == 0xff));
+
+ nand_davinci_gen_true_ecc(ecc_nand);
+ nand_davinci_gen_true_ecc(ecc_calc);
+
+ for (i = 0; i <= 2; i++) {
+ *(ecc_nand + i) = ~(*(ecc_nand + i));
+ *(ecc_calc + i) = ~(*(ecc_calc + i));
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp0_bit[i] = *ecc_nand % 2;
+ *ecc_nand = *ecc_nand / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp1_bit[i] = *(ecc_nand + 1) % 2;
+ *(ecc_nand + 1) = *(ecc_nand + 1) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ tmp2_bit[i] = *(ecc_nand + 2) % 2;
+ *(ecc_nand + 2) = *(ecc_nand + 2) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp0_bit[i] = *ecc_calc % 2;
+ *ecc_calc = *ecc_calc / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp1_bit[i] = *(ecc_calc + 1) % 2;
+ *(ecc_calc + 1) = *(ecc_calc + 1) / 2;
+ }
+
+ for (i = 0; i < 8; i++) {
+ comp2_bit[i] = *(ecc_calc + 2) % 2;
+ *(ecc_calc + 2) = *(ecc_calc + 2) / 2;
+ }
+
+ for (i = 0; i< 6; i++)
+ ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+ for (i = 0; i < 8; i++)
+ ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+ for (i = 0; i < 8; i++)
+ ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+ ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+ ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+ for (i = 0; i < 24; i++)
+ ecc_sum += ecc_bit[i];
+
+ switch (ecc_sum) {
+ case 0:
+ /* Not reached because this function is not called if
+ ECC values are equal */
+ return 0;
+ case 1:
+ /* Uncorrectable error */
+ DEBUG (MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+ return(-1);
+ case 12:
+ /* Correctable error */
+ find_byte = (ecc_bit[23] << 8) +
+ (ecc_bit[21] << 7) +
+ (ecc_bit[19] << 6) +
+ (ecc_bit[17] << 5) +
+ (ecc_bit[15] << 4) +
+ (ecc_bit[13] << 3) +
+ (ecc_bit[11] << 2) +
+ (ecc_bit[9] << 1) +
+ ecc_bit[7];
+
+ find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+ DEBUG (MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at offset: %d, bit: %d\n", find_byte, find_bit);
+
+ page_data[find_byte] ^= (1 << find_bit);
+
+ return(0);
+ default:
+ if (is_ecc_ff) {
+ if (ecc_calc[0] == 0 && ecc_calc[1] == 0 && ecc_calc[2] == 0)
+ return(0);
+ }
+ DEBUG (MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+ return(-1);
+ }
+}
+
+static int nand_davinci_correct_data(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc)
+{
+ struct nand_chip *this;
+ int block_count = 0, i, rc;
+
+ this = mtd->priv;
+ block_count = (this->eccmode == NAND_ECC_HW12_2048) ? 4 : 1;
+ for (i = 0; i < block_count; i++) {
+ if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+ rc = nand_davinci_compare_ecc(read_ecc, calc_ecc, dat);
+ if (rc < 0) {
+ return(rc);
+ }
+ }
+ read_ecc += 3;
+ calc_ecc += 3;
+ dat += 512;
+ }
+ return(0);
+}
+#endif
+
+static int nand_davinci_dev_ready(struct mtd_info *mtd)
+{
+ emifregs emif_addr;
+
+ emif_addr = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
+
+ return(emif_addr->NANDFSR & 0x1);
+}
+
+static int nand_davinci_waitfunc(struct mtd_info *mtd, struct nand_chip *this, int state)
+{
+ while(!nand_davinci_dev_ready(mtd)) {;}
+ *NAND_CE0CLE = NAND_STATUS;
+ return(*NAND_CE0DATA);
+}
+
+static void nand_flash_init(void)
+{
+ u_int32_t acfg1 = 0x3ffffffc;
+ u_int32_t acfg2 = 0x3ffffffc;
+ u_int32_t acfg3 = 0x3ffffffc;
+ u_int32_t acfg4 = 0x3ffffffc;
+ emifregs emif_regs;
+
+ /*------------------------------------------------------------------*
+ * NAND FLASH CHIP TIMEOUT @ 459 MHz *
+ * *
+ * AEMIF.CLK freq = PLL1/6 = 459/6 = 76.5 MHz *
+ * AEMIF.CLK period = 1/76.5 MHz = 13.1 ns *
+ * *
+ *------------------------------------------------------------------*/
+ acfg1 = 0
+ | (0 << 31 ) /* selectStrobe */
+ | (0 << 30 ) /* extWait */
+ | (1 << 26 ) /* writeSetup 10 ns */
+ | (3 << 20 ) /* writeStrobe 40 ns */
+ | (1 << 17 ) /* writeHold 10 ns */
+ | (1 << 13 ) /* readSetup 10 ns */
+ | (5 << 7 ) /* readStrobe 60 ns */
+ | (1 << 4 ) /* readHold 10 ns */
+ | (3 << 2 ) /* turnAround ?? ns */
+ | (0 << 0 ) /* asyncSize 8-bit bus */
+ ;
+
+ emif_regs = (emifregs)DAVINCI_ASYNC_EMIF_CNTRL_BASE;
+
+ emif_regs->AWCCR |= 0x10000000;
+ emif_regs->AB1CR = acfg1; /* 0x08244128 */;
+ emif_regs->AB2CR = acfg2;
+ emif_regs->AB3CR = acfg3;
+ emif_regs->AB4CR = acfg4;
+ emif_regs->NANDFCR = 0x00000101;
+}
+
+int board_nand_init(struct nand_chip *nand)
+{
+ nand->IO_ADDR_R = (void __iomem *)NAND_CE0DATA;
+ nand->IO_ADDR_W = (void __iomem *)NAND_CE0DATA;
+ nand->chip_delay = 0;
+ nand->select_chip = nand_davinci_select_chip;
+#ifdef CFG_NAND_USE_FLASH_BBT
+ nand->options = NAND_USE_FLASH_BBT;
+#endif
+#ifdef CFG_NAND_HW_ECC
+#ifdef CFG_NAND_LARGEPAGE
+ nand->eccmode = NAND_ECC_HW12_2048;
+#elif defined(CFG_NAND_SMALLPAGE)
+ nand->eccmode = NAND_ECC_HW3_512;
+#else
+#error "Either CFG_NAND_LARGEPAGE or CFG_NAND_SMALLPAGE must be defined!"
+#endif
+ nand->autooob = &davinci_nand_oobinfo;
+ nand->calculate_ecc = nand_davinci_calculate_ecc;
+ nand->correct_data = nand_davinci_correct_data;
+ nand->enable_hwecc = nand_davinci_enable_hwecc;
+#else
+ nand->eccmode = NAND_ECC_SOFT;
+#endif
+
+ /* Set address of hardware control function */
+ nand->hwcontrol = nand_davinci_hwcontrol;
+
+ nand->dev_ready = nand_davinci_dev_ready;
+ nand->waitfunc = nand_davinci_waitfunc;
+
+ nand_flash_init();
+
+ return(0);
+}
+
+#else
+#error "U-Boot legacy NAND support not available for DaVinci chips"
+#endif
+#endif /* CFG_USE_NAND */
diff --git a/cpu/arm926ejs/davinci/reset.S b/cpu/arm926ejs/davinci/reset.S
new file mode 100644
index 0000000..a687d44
--- /dev/null
+++ b/cpu/arm926ejs/davinci/reset.S
@@ -0,0 +1,77 @@
+/*
+ * Processor reset using WDT for TI TMS320DM644x SoC.
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * -----------------------------------------------------
+ *
+ * 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
+ */
+
+.globl reset_cpu
+reset_cpu:
+ ldr r0, WDT_TGCR
+ mov r1, $0x08
+ str r1, [r0]
+ ldr r1, [r0]
+ orr r1, r1, $0x03
+ str r1, [r0]
+ mov r1, $0
+ ldr r0, WDT_TIM12
+ str r1, [r0]
+ ldr r0, WDT_TIM34
+ str r1, [r0]
+ ldr r0, WDT_PRD12
+ str r1, [r0]
+ ldr r0, WDT_PRD34
+ str r1, [r0]
+ ldr r0, WDT_TCR
+ ldr r1, [r0]
+ orr r1, r1, $0x40
+ str r1, [r0]
+ ldr r0, WDT_WDTCR
+ ldr r1, [r0]
+ orr r1, r1, $0x4000
+ str r1, [r0]
+ ldr r1, WDTCR_VAL1
+ str r1, [r0]
+ ldr r1, WDTCR_VAL2
+ str r1, [r0]
+ nop
+ nop
+ nop
+ nop
+reset_cpu_loop:
+ b reset_cpu_loop
+
+WDT_TGCR:
+ .word 0x01c21c24
+WDT_TIM12:
+ .word 0x01c21c10
+WDT_TIM34:
+ .word 0x01c21c14
+WDT_PRD12:
+ .word 0x01c21c18
+WDT_PRD34:
+ .word 0x01c21c1c
+WDT_TCR:
+ .word 0x01c21c20
+WDT_WDTCR:
+ .word 0x01c21c28
+WDTCR_VAL1:
+ .word 0xa5c64000
+WDTCR_VAL2:
+ .word 0xda7e4000
diff --git a/cpu/arm926ejs/davinci/timer.c b/cpu/arm926ejs/davinci/timer.c
new file mode 100644
index 0000000..c6b1dda
--- /dev/null
+++ b/cpu/arm926ejs/davinci/timer.c
@@ -0,0 +1,165 @@
+/*
+ * (C) Copyright 2003
+ * Texas Instruments <www.ti.com>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002-2004
+ * Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+ *
+ * (C) Copyright 2004
+ * Philippe Robin, ARM Ltd. <philippe.robin@arm.com>
+ *
+ * Copyright (C) 2007 Sergey Kubushyn <ksi@koi8.net>
+ *
+ * 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 <arm926ejs.h>
+
+typedef volatile struct {
+ u_int32_t pid12;
+ u_int32_t emumgt_clksped;
+ u_int32_t gpint_en;
+ u_int32_t gpdir_dat;
+ u_int32_t tim12;
+ u_int32_t tim34;
+ u_int32_t prd12;
+ u_int32_t prd34;
+ u_int32_t tcr;
+ u_int32_t tgcr;
+ u_int32_t wdtcr;
+ u_int32_t tlgc;
+ u_int32_t tlmr;
+} davinci_timer;
+
+davinci_timer *timer = (davinci_timer *)CFG_TIMERBASE;
+
+#define TIMER_LOAD_VAL (CFG_HZ_CLOCK / CFG_HZ)
+#define READ_TIMER timer->tim34
+
+static ulong timestamp;
+static ulong lastinc;
+
+int timer_init(void)
+{
+ /* We are using timer34 in unchained 32-bit mode, full speed */
+ timer->tcr = 0x0;
+ timer->tgcr = 0x0;
+ timer->tgcr = 0x06;
+ timer->tim34 = 0x0;
+ timer->prd34 = TIMER_LOAD_VAL;
+ lastinc = 0;
+ timer->tcr = 0x80 << 16;
+ timestamp = 0;
+
+ return(0);
+}
+
+void reset_timer(void)
+{
+ reset_timer_masked();
+}
+
+ulong get_timer(ulong base)
+{
+ return(get_timer_masked() - base);
+}
+
+void set_timer(ulong t)
+{
+ timestamp = t;
+}
+
+void udelay(unsigned long usec)
+{
+ udelay_masked(usec);
+}
+
+void reset_timer_masked(void)
+{
+ lastinc = READ_TIMER;
+ timestamp = 0;
+}
+
+ulong get_timer_raw(void)
+{
+ ulong now = READ_TIMER;
+
+ if (now >= lastinc) {
+ /* normal mode */
+ timestamp += now - lastinc;
+ } else {
+ /* overflow ... */
+ timestamp += now + TIMER_LOAD_VAL - lastinc;
+ }
+ lastinc = now;
+ return timestamp;
+}
+
+ulong get_timer_masked(void)
+{
+ return(get_timer_raw() / TIMER_LOAD_VAL);
+}
+
+void udelay_masked(unsigned long usec)
+{
+ ulong tmo;
+ ulong endtime;
+ signed long diff;
+
+ tmo = CFG_HZ_CLOCK / 1000;
+ tmo *= usec;
+ tmo /= 1000;
+
+ endtime = get_timer_raw() + tmo;
+
+ do {
+ ulong now = get_timer_raw();
+ diff = endtime - now;
+ } while (diff >= 0);
+}
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+ return(get_timer(0));
+}
+
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk(void)
+{
+ ulong tbclk;
+
+ tbclk = CFG_HZ;
+ return(tbclk);
+}
diff --git a/cpu/mpc5xxx/Makefile b/cpu/mpc5xxx/Makefile
index 235adb7..312b0bf 100644
--- a/cpu/mpc5xxx/Makefile
+++ b/cpu/mpc5xxx/Makefile
@@ -28,7 +28,7 @@ LIB = $(obj)lib$(CPU).a
START = start.o
SOBJS = io.o firmware_sc_task_bestcomm.impl.o firmware_sc_task.impl.o
COBJS = i2c.o traps.o cpu.o cpu_init.o fec.o ide.o interrupts.o \
- loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o
+ loadtask.o pci_mpc5200.o serial.o speed.o usb_ohci.o usb.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/mpc5xxx/usb.c b/cpu/mpc5xxx/usb.c
new file mode 100644
index 0000000..ce709fc
--- /dev/null
+++ b/cpu/mpc5xxx/usb.c
@@ -0,0 +1,54 @@
+/*
+ * (C) Copyright 2007
+ * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT)
+
+#include <mpc5xxx.h>
+
+int usb_cpu_init()
+{
+ /* Set the USB Clock */
+ *(vu_long *)MPC5XXX_CDM_48_FDC = CONFIG_USB_CLOCK;
+
+ /* remove all USB bits first before ORing in ours */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG &= ~0x00807000;
+
+ /* Activate USB port */
+ *(vu_long *)MPC5XXX_GPS_PORT_CONFIG |= CONFIG_USB_CONFIG;
+
+ return 0;
+}
+
+int usb_cpu_stop()
+{
+ return 0;
+}
+
+int usb_cpu_init_fail()
+{
+ return 0;
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */
diff --git a/cpu/mpc83xx/Makefile b/cpu/mpc83xx/Makefile
index bb96f77..2329970 100644
--- a/cpu/mpc83xx/Makefile
+++ b/cpu/mpc83xx/Makefile
@@ -29,7 +29,7 @@ LIB = $(obj)lib$(CPU).a
START = start.o
COBJS = traps.o cpu.o cpu_init.o speed.o interrupts.o \
- spd_sdram.o qe_io.o pci.o
+ spd_sdram.o ecc.o qe_io.o pci.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/mpc83xx/cpu.c b/cpu/mpc83xx/cpu.c
index 841fe82..adf8083 100644
--- a/cpu/mpc83xx/cpu.c
+++ b/cpu/mpc83xx/cpu.c
@@ -33,8 +33,7 @@
#include <asm/processor.h>
#if defined(CONFIG_OF_FLAT_TREE)
#include <ft_build.h>
-#endif
-#if defined(CONFIG_OF_LIBFDT)
+#elif defined(CONFIG_OF_LIBFDT)
#include <libfdt.h>
#include <libfdt_env.h>
#endif
@@ -113,12 +112,14 @@ int checkcpu(void)
case SPR_8360E_REV11:
case SPR_8360E_REV12:
case SPR_8360E_REV20:
+ case SPR_8360E_REV21:
puts("MPC8360E, ");
break;
case SPR_8360_REV10:
case SPR_8360_REV11:
case SPR_8360_REV12:
case SPR_8360_REV20:
+ case SPR_8360_REV21:
puts("MPC8360, ");
break;
case SPR_8323E_REV10:
@@ -150,7 +151,8 @@ int checkcpu(void)
puts("MPC8313E, ");
break;
default:
- puts("Rev: Unknown revision number.\nWarning: Unsupported cpu revision!\n");
+ printf("Rev: Unknown revision number:%08x\n"
+ "Warning: Unsupported cpu revision!\n",spridr);
return 0;
}
@@ -329,154 +331,167 @@ void watchdog_reset (void)
/*
* "Setter" functions used to add/modify FDT entries.
*/
-static int fdt_set_eth0(void *fdt, int nodeoffset, const char *name, bd_t *bd)
+static int fdt_set_eth0(void *blob, int nodeoffset, const char *name, bd_t *bd)
{
/*
* Fix it up if it exists, don't create it if it doesn't exist.
*/
- if (fdt_get_property(fdt, nodeoffset, name, 0)) {
- return fdt_setprop(fdt, nodeoffset, name, bd->bi_enetaddr, 6);
+ if (fdt_get_property(blob, nodeoffset, name, 0)) {
+ return fdt_setprop(blob, nodeoffset, name, bd->bi_enetaddr, 6);
}
- return -FDT_ERR_NOTFOUND;
+ return 0;
}
#ifdef CONFIG_HAS_ETH1
/* second onboard ethernet port */
-static int fdt_set_eth1(void *fdt, int nodeoffset, const char *name, bd_t *bd)
+static int fdt_set_eth1(void *blob, int nodeoffset, const char *name, bd_t *bd)
{
/*
* Fix it up if it exists, don't create it if it doesn't exist.
*/
- if (fdt_get_property(fdt, nodeoffset, name, 0)) {
- return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet1addr, 6);
+ if (fdt_get_property(blob, nodeoffset, name, 0)) {
+ return fdt_setprop(blob, nodeoffset, name, bd->bi_enet1addr, 6);
}
- return -FDT_ERR_NOTFOUND;
+ return 0;
}
#endif
#ifdef CONFIG_HAS_ETH2
/* third onboard ethernet port */
-static int fdt_set_eth2(void *fdt, int nodeoffset, const char *name, bd_t *bd)
+static int fdt_set_eth2(void *blob, int nodeoffset, const char *name, bd_t *bd)
{
/*
* Fix it up if it exists, don't create it if it doesn't exist.
*/
- if (fdt_get_property(fdt, nodeoffset, name, 0)) {
- return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet2addr, 6);
+ if (fdt_get_property(blob, nodeoffset, name, 0)) {
+ return fdt_setprop(blob, nodeoffset, name, bd->bi_enet2addr, 6);
}
- return -FDT_ERR_NOTFOUND;
+ return 0;
}
#endif
#ifdef CONFIG_HAS_ETH3
/* fourth onboard ethernet port */
-static int fdt_set_eth3(void *fdt, int nodeoffset, const char *name, bd_t *bd)
+static int fdt_set_eth3(void *blob, int nodeoffset, const char *name, bd_t *bd)
{
/*
* Fix it up if it exists, don't create it if it doesn't exist.
*/
- if (fdt_get_property(fdt, nodeoffset, name, 0)) {
- return fdt_setprop(fdt, nodeoffset, name, bd->bi_enet3addr, 6);
+ if (fdt_get_property(blob, nodeoffset, name, 0)) {
+ return fdt_setprop(blob, nodeoffset, name, bd->bi_enet3addr, 6);
}
- return -FDT_ERR_NOTFOUND;
+ return 0;
}
#endif
-static int fdt_set_busfreq(void *fdt, int nodeoffset, const char *name, bd_t *bd)
+static int fdt_set_busfreq(void *blob, int nodeoffset, const char *name, bd_t *bd)
{
u32 tmp;
/*
* Create or update the property.
*/
tmp = cpu_to_be32(bd->bi_busfreq);
- return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+ return fdt_setprop(blob, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+static int fdt_set_tbfreq(void *blob, int nodeoffset, const char *name, bd_t *bd)
+{
+ u32 tmp;
+ /*
+ * Create or update the property.
+ */
+ tmp = cpu_to_be32(OF_TBCLK);
+ return fdt_setprop(blob, nodeoffset, name, &tmp, sizeof(tmp));
}
+
/*
- * Fixups to the fdt. If "create" is TRUE, the node is created
- * unconditionally. If "create" is FALSE, the node is updated
- * only if it already exists.
+ * Fixups to the fdt.
*/
static const struct {
char *node;
char *prop;
- int (*set_fn)(void *fdt, int nodeoffset, const char *name, bd_t *bd);
+ int (*set_fn)(void *blob, int nodeoffset, const char *name, bd_t *bd);
} fixup_props[] = {
{ "/cpus/" OF_CPU,
- "bus-frequency",
- fdt_set_busfreq
+ "timebase-frequency",
+ fdt_set_tbfreq
},
- { "/cpus/" OF_SOC,
+ { "/cpus/" OF_CPU,
"bus-frequency",
fdt_set_busfreq
},
- { "/" OF_SOC "/serial@4500/",
+ { "/cpus/" OF_CPU,
+ "clock-frequency",
+ fdt_set_busfreq
+ },
+ { "/" OF_SOC "/serial@4500",
"clock-frequency",
fdt_set_busfreq
},
- { "/" OF_SOC "/serial@4600/",
+ { "/" OF_SOC "/serial@4600",
"clock-frequency",
fdt_set_busfreq
},
#ifdef CONFIG_TSEC1
- { "/" OF_SOC "/ethernet@24000,
+ { "/" OF_SOC "/ethernet@24000",
"mac-address",
fdt_set_eth0
},
- { "/" OF_SOC "/ethernet@24000,
+ { "/" OF_SOC "/ethernet@24000",
"local-mac-address",
fdt_set_eth0
},
#endif
#ifdef CONFIG_TSEC2
- { "/" OF_SOC "/ethernet@25000,
+ { "/" OF_SOC "/ethernet@25000",
"mac-address",
fdt_set_eth1
},
- { "/" OF_SOC "/ethernet@25000,
+ { "/" OF_SOC "/ethernet@25000",
"local-mac-address",
fdt_set_eth1
},
#endif
#ifdef CONFIG_UEC_ETH1
#if CFG_UEC1_UCC_NUM == 0 /* UCC1 */
- { "/" OF_QE "/ucc@2000/mac-address",
+ { "/" OF_QE "/ucc@2000",
"mac-address",
fdt_set_eth0
},
- { "/" OF_QE "/ucc@2000/mac-address",
+ { "/" OF_QE "/ucc@2000",
"local-mac-address",
fdt_set_eth0
},
#elif CFG_UEC1_UCC_NUM == 2 /* UCC3 */
- { "/" OF_QE "/ucc@2200/mac-address",
+ { "/" OF_QE "/ucc@2200",
"mac-address",
fdt_set_eth0
},
- { "/" OF_QE "/ucc@2200/mac-address",
+ { "/" OF_QE "/ucc@2200",
"local-mac-address",
fdt_set_eth0
},
#endif
-#endif
+#endif /* CONFIG_UEC_ETH1 */
#ifdef CONFIG_UEC_ETH2
#if CFG_UEC2_UCC_NUM == 1 /* UCC2 */
- { "/" OF_QE "/ucc@3000/mac-address",
+ { "/" OF_QE "/ucc@3000",
"mac-address",
fdt_set_eth1
},
- { "/" OF_QE "/ucc@3000/mac-address",
+ { "/" OF_QE "/ucc@3000",
"local-mac-address",
fdt_set_eth1
},
#elif CFG_UEC1_UCC_NUM == 3 /* UCC4 */
- { "/" OF_QE "/ucc@3200/mac-address",
+ { "/" OF_QE "/ucc@3200",
"mac-address",
fdt_set_eth1
},
- { "/" OF_QE "/ucc@3200/mac-address",
+ { "/" OF_QE "/ucc@3200",
"local-mac-address",
fdt_set_eth1
},
#endif
-#endif
+#endif /* CONFIG_UEC_ETH2 */
};
void
@@ -487,20 +502,23 @@ ft_cpu_setup(void *blob, bd_t *bd)
int j;
for (j = 0; j < (sizeof(fixup_props) / sizeof(fixup_props[0])); j++) {
- nodeoffset = fdt_path_offset(fdt, fixup_props[j].node);
+ nodeoffset = fdt_find_node_by_path(blob, fixup_props[j].node);
if (nodeoffset >= 0) {
- err = (*fixup_props[j].set_fn)(blob, nodeoffset, fixup_props[j].prop, bd);
+ err = fixup_props[j].set_fn(blob, nodeoffset,
+ fixup_props[j].prop, bd);
if (err < 0)
- printf("set_fn/libfdt: %s %s returned %s\n",
+ debug("Problem setting %s = %s: %s\n",
fixup_props[j].node,
fixup_props[j].prop,
fdt_strerror(err));
+ } else {
+ debug("Couldn't find %s: %s\n",
+ fixup_props[j].node,
+ fdt_strerror(nodeoffset));
}
}
}
-#endif
-
-#if defined(CONFIG_OF_FLAT_TREE)
+#elif defined(CONFIG_OF_FLAT_TREE)
void
ft_cpu_setup(void *blob, bd_t *bd)
{
diff --git a/cpu/mpc83xx/cpu_init.c b/cpu/mpc83xx/cpu_init.c
index 3ac9161..7224979 100644
--- a/cpu/mpc83xx/cpu_init.c
+++ b/cpu/mpc83xx/cpu_init.c
@@ -83,20 +83,30 @@ void cpu_init_f (volatile immap_t * im)
im->sysconf.spcr = (im->sysconf.spcr & ~SPCR_TSEC2EP) | (CFG_SPCR_TSEC2EP << SPCR_TSEC2EP_SHIFT);
#endif
-#ifdef CONFIG_MPC834X
#ifdef CFG_SCCR_TSEC1CM
/* TSEC1 clock mode */
im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC1CM) | (CFG_SCCR_TSEC1CM << SCCR_TSEC1CM_SHIFT);
#endif
+
#ifdef CFG_SCCR_TSEC2CM
/* TSEC2 & I2C1 clock mode */
im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC2CM) | (CFG_SCCR_TSEC2CM << SCCR_TSEC2CM_SHIFT);
#endif
+
+#ifdef CFG_SCCR_TSEC1ON
+ /* TSEC1 clock switch */
+ im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC1ON) | (CFG_SCCR_TSEC1ON << SCCR_TSEC1ON_SHIFT);
+#endif
+
+#ifdef CFG_SCCR_TSEC2ON
+ /* TSEC2 clock switch */
+ im->clk.sccr = (im->clk.sccr & ~SCCR_TSEC2ON) | (CFG_SCCR_TSEC2ON << SCCR_TSEC2ON_SHIFT);
+#endif
+
#ifdef CFG_SCCR_USBMPHCM
/* USB MPH clock mode */
im->clk.sccr = (im->clk.sccr & ~SCCR_USBMPHCM) | (CFG_SCCR_USBMPHCM << SCCR_USBMPHCM_SHIFT);
#endif
-#endif /* CONFIG_MPC834X */
#ifdef CFG_SCCR_PCICM
/* PCI & DMA clock mode */
@@ -247,3 +257,39 @@ int cpu_init_r (void)
#endif
return 0;
}
+
+/*
+ * Figure out the cause of the reset
+ */
+int prt_83xx_rsr(void)
+{
+ static struct {
+ ulong mask;
+ char *desc;
+ } bits[] = {
+ {
+ RSR_SWSR, "Software Soft"}, {
+ RSR_SWHR, "Software Hard"}, {
+ RSR_JSRS, "JTAG Soft"}, {
+ RSR_CSHR, "Check Stop"}, {
+ RSR_SWRS, "Software Watchdog"}, {
+ RSR_BMRS, "Bus Monitor"}, {
+ RSR_SRS, "External/Internal Soft"}, {
+ RSR_HRS, "External/Internal Hard"}
+ };
+ static int n = sizeof bits / sizeof bits[0];
+ ulong rsr = gd->reset_status;
+ int i;
+ char *sep;
+
+ puts("Reset Status:");
+
+ sep = " ";
+ for (i = 0; i < n; i++)
+ if (rsr & bits[i].mask) {
+ printf("%s%s", sep, bits[i].desc);
+ sep = ", ";
+ }
+ puts("\n\n");
+ return 0;
+}
diff --git a/cpu/mpc83xx/ecc.c b/cpu/mpc83xx/ecc.c
new file mode 100644
index 0000000..6f13094
--- /dev/null
+++ b/cpu/mpc83xx/ecc.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2007 Freescale Semiconductor, Inc.
+ *
+ * Dave Liu <daveliu@freescale.com>
+ * based on the contribution of Marian Balakowicz <m8@semihalf.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.
+ */
+
+#include <common.h>
+#include <mpc83xx.h>
+#include <command.h>
+
+#if defined(CONFIG_DDR_ECC) && defined(CONFIG_DDR_ECC_CMD)
+void ecc_print_status(void)
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+
+ printf("\nECC mode: %s\n\n",
+ (ddr->sdram_cfg & SDRAM_CFG_ECC_EN) ? "ON" : "OFF");
+
+ /* Interrupts */
+ printf("Memory Error Interrupt Enable:\n");
+ printf(" Multiple-Bit Error Interrupt Enable: %d\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_MBEE) ? 1 : 0);
+ printf(" Single-Bit Error Interrupt Enable: %d\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_SBEE) ? 1 : 0);
+ printf(" Memory Select Error Interrupt Enable: %d\n\n",
+ (ddr->err_int_en & ECC_ERR_INT_EN_MSEE) ? 1 : 0);
+
+ /* Error disable */
+ printf("Memory Error Disable:\n");
+ printf(" Multiple-Bit Error Disable: %d\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_MBED) ? 1 : 0);
+ printf(" Sinle-Bit Error Disable: %d\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_SBED) ? 1 : 0);
+ printf(" Memory Select Error Disable: %d\n\n",
+ (ddr->err_disable & ECC_ERROR_DISABLE_MSED) ? 1 : 0);
+
+ /* Error injection */
+ printf("Memory Data Path Error Injection Mask High/Low: %08lx %08lx\n",
+ ddr->data_err_inject_hi, ddr->data_err_inject_lo);
+
+ printf("Memory Data Path Error Injection Mask ECC:\n");
+ printf(" ECC Mirror Byte: %d\n",
+ (ddr->ecc_err_inject & ECC_ERR_INJECT_EMB) ? 1 : 0);
+ printf(" ECC Injection Enable: %d\n",
+ (ddr->ecc_err_inject & ECC_ERR_INJECT_EIEN) ? 1 : 0);
+ printf(" ECC Error Injection Mask: 0x%02x\n\n",
+ ddr->ecc_err_inject & ECC_ERR_INJECT_EEIM);
+
+ /* SBE counter/threshold */
+ printf("Memory Single-Bit Error Management (0..255):\n");
+ printf(" Single-Bit Error Threshold: %d\n",
+ (ddr->err_sbe & ECC_ERROR_MAN_SBET) >> ECC_ERROR_MAN_SBET_SHIFT);
+ printf(" Single-Bit Error Counter: %d\n\n",
+ (ddr->err_sbe & ECC_ERROR_MAN_SBEC) >> ECC_ERROR_MAN_SBEC_SHIFT);
+
+ /* Error detect */
+ printf("Memory Error Detect:\n");
+ printf(" Multiple Memory Errors: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MME) ? 1 : 0);
+ printf(" Multiple-Bit Error: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MBE) ? 1 : 0);
+ printf(" Single-Bit Error: %d\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_SBE) ? 1 : 0);
+ printf(" Memory Select Error: %d\n\n",
+ (ddr->err_detect & ECC_ERROR_DETECT_MSE) ? 1 : 0);
+
+ /* Capture data */
+ printf("Memory Error Address Capture: 0x%08lx\n", ddr->capture_address);
+ printf("Memory Data Path Read Capture High/Low: %08lx %08lx\n",
+ ddr->capture_data_hi, ddr->capture_data_lo);
+ printf("Memory Data Path Read Capture ECC: 0x%02x\n\n",
+ ddr->capture_ecc & CAPTURE_ECC_ECE);
+
+ printf("Memory Error Attributes Capture:\n");
+ printf(" Data Beat Number: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_BNUM) >>
+ ECC_CAPT_ATTR_BNUM_SHIFT);
+ printf(" Transaction Size: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TSIZ) >>
+ ECC_CAPT_ATTR_TSIZ_SHIFT);
+ printf(" Transaction Source: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TSRC) >>
+ ECC_CAPT_ATTR_TSRC_SHIFT);
+ printf(" Transaction Type: %d\n",
+ (ddr->capture_attributes & ECC_CAPT_ATTR_TTYP) >>
+ ECC_CAPT_ATTR_TTYP_SHIFT);
+ printf(" Error Information Valid: %d\n\n",
+ ddr->capture_attributes & ECC_CAPT_ATTR_VLD);
+}
+
+int do_ecc(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
+{
+ volatile immap_t *immap = (immap_t *) CFG_IMMR;
+ volatile ddr83xx_t *ddr = &immap->ddr;
+ volatile u32 val;
+ u64 *addr;
+ u32 count;
+ register u64 *i;
+ u32 ret[2];
+ u32 pattern[2];
+ u32 writeback[2];
+
+ /* The pattern is written into memory to generate error */
+ pattern[0] = 0xfedcba98UL;
+ pattern[1] = 0x76543210UL;
+
+ /* After injecting error, re-initialize the memory with the value */
+ writeback[0] = 0x01234567UL;
+ writeback[1] = 0x89abcdefUL;
+
+ if (argc > 4) {
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+ }
+
+ if (argc == 2) {
+ if (strcmp(argv[1], "status") == 0) {
+ ecc_print_status();
+ return 0;
+ } else if (strcmp(argv[1], "captureclear") == 0) {
+ ddr->capture_address = 0;
+ ddr->capture_data_hi = 0;
+ ddr->capture_data_lo = 0;
+ ddr->capture_ecc = 0;
+ ddr->capture_attributes = 0;
+ return 0;
+ }
+ }
+ if (argc == 3) {
+ if (strcmp(argv[1], "sbecnt") == 0) {
+ val = simple_strtoul(argv[2], NULL, 10);
+ if (val > 255) {
+ printf("Incorrect Counter value, "
+ "should be 0..255\n");
+ return 1;
+ }
+
+ val = (val << ECC_ERROR_MAN_SBEC_SHIFT);
+ val |= (ddr->err_sbe & ECC_ERROR_MAN_SBET);
+
+ ddr->err_sbe = val;
+ return 0;
+ } else if (strcmp(argv[1], "sbethr") == 0) {
+ val = simple_strtoul(argv[2], NULL, 10);
+ if (val > 255) {
+ printf("Incorrect Counter value, "
+ "should be 0..255\n");
+ return 1;
+ }
+
+ val = (val << ECC_ERROR_MAN_SBET_SHIFT);
+ val |= (ddr->err_sbe & ECC_ERROR_MAN_SBEC);
+
+ ddr->err_sbe = val;
+ return 0;
+ } else if (strcmp(argv[1], "errdisable") == 0) {
+ val = ddr->err_disable;
+
+ if (strcmp(argv[2], "+sbe") == 0) {
+ val |= ECC_ERROR_DISABLE_SBED;
+ } else if (strcmp(argv[2], "+mbe") == 0) {
+ val |= ECC_ERROR_DISABLE_MBED;
+ } else if (strcmp(argv[2], "+mse") == 0) {
+ val |= ECC_ERROR_DISABLE_MSED;
+ } else if (strcmp(argv[2], "+all") == 0) {
+ val |= (ECC_ERROR_DISABLE_SBED |
+ ECC_ERROR_DISABLE_MBED |
+ ECC_ERROR_DISABLE_MSED);
+ } else if (strcmp(argv[2], "-sbe") == 0) {
+ val &= ~ECC_ERROR_DISABLE_SBED;
+ } else if (strcmp(argv[2], "-mbe") == 0) {
+ val &= ~ECC_ERROR_DISABLE_MBED;
+ } else if (strcmp(argv[2], "-mse") == 0) {
+ val &= ~ECC_ERROR_DISABLE_MSED;
+ } else if (strcmp(argv[2], "-all") == 0) {
+ val &= ~(ECC_ERROR_DISABLE_SBED |
+ ECC_ERROR_DISABLE_MBED |
+ ECC_ERROR_DISABLE_MSED);
+ } else {
+ printf("Incorrect err_disable field\n");
+ return 1;
+ }
+
+ ddr->err_disable = val;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+ return 0;
+ } else if (strcmp(argv[1], "errdetectclr") == 0) {
+ val = ddr->err_detect;
+
+ if (strcmp(argv[2], "mme") == 0) {
+ val |= ECC_ERROR_DETECT_MME;
+ } else if (strcmp(argv[2], "sbe") == 0) {
+ val |= ECC_ERROR_DETECT_SBE;
+ } else if (strcmp(argv[2], "mbe") == 0) {
+ val |= ECC_ERROR_DETECT_MBE;
+ } else if (strcmp(argv[2], "mse") == 0) {
+ val |= ECC_ERROR_DETECT_MSE;
+ } else if (strcmp(argv[2], "all") == 0) {
+ val |= (ECC_ERROR_DETECT_MME |
+ ECC_ERROR_DETECT_MBE |
+ ECC_ERROR_DETECT_SBE |
+ ECC_ERROR_DETECT_MSE);
+ } else {
+ printf("Incorrect err_detect field\n");
+ return 1;
+ }
+
+ ddr->err_detect = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectdatahi") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+
+ ddr->data_err_inject_hi = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectdatalo") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+
+ ddr->data_err_inject_lo = val;
+ return 0;
+ } else if (strcmp(argv[1], "injectecc") == 0) {
+ val = simple_strtoul(argv[2], NULL, 16);
+ if (val > 0xff) {
+ printf("Incorrect ECC inject mask, "
+ "should be 0x00..0xff\n");
+ return 1;
+ }
+ val |= (ddr->ecc_err_inject & ~ECC_ERR_INJECT_EEIM);
+
+ ddr->ecc_err_inject = val;
+ return 0;
+ } else if (strcmp(argv[1], "inject") == 0) {
+ val = ddr->ecc_err_inject;
+
+ if (strcmp(argv[2], "en") == 0)
+ val |= ECC_ERR_INJECT_EIEN;
+ else if (strcmp(argv[2], "dis") == 0)
+ val &= ~ECC_ERR_INJECT_EIEN;
+ else
+ printf("Incorrect command\n");
+
+ ddr->ecc_err_inject = val;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+ return 0;
+ } else if (strcmp(argv[1], "mirror") == 0) {
+ val = ddr->ecc_err_inject;
+
+ if (strcmp(argv[2], "en") == 0)
+ val |= ECC_ERR_INJECT_EMB;
+ else if (strcmp(argv[2], "dis") == 0)
+ val &= ~ECC_ERR_INJECT_EMB;
+ else
+ printf("Incorrect command\n");
+
+ ddr->ecc_err_inject = val;
+ return 0;
+ }
+ }
+ if (argc == 4) {
+ if (strcmp(argv[1], "testdw") == 0) {
+ addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if ((u32) addr % 8) {
+ printf("Address not alligned on "
+ "double word boundary\n");
+ return 1;
+ }
+ disable_interrupts();
+
+ for (i = addr; i < addr + count; i++) {
+
+ /* enable injects */
+ ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* write memory location injecting errors */
+ ppcDWstore((u32 *) i, pattern);
+ __asm__ __volatile__("sync");
+
+ /* disable injects */
+ ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* read data, this generates ECC error */
+ ppcDWload((u32 *) i, ret);
+ __asm__ __volatile__("sync");
+
+ /* re-initialize memory, double word write the location again,
+ * generates new ECC code this time */
+ ppcDWstore((u32 *) i, writeback);
+ __asm__ __volatile__("sync");
+ }
+ enable_interrupts();
+ return 0;
+ }
+ if (strcmp(argv[1], "testword") == 0) {
+ addr = (u64 *) simple_strtoul(argv[2], NULL, 16);
+ count = simple_strtoul(argv[3], NULL, 16);
+
+ if ((u32) addr % 8) {
+ printf("Address not alligned on "
+ "double word boundary\n");
+ return 1;
+ }
+ disable_interrupts();
+
+ for (i = addr; i < addr + count; i++) {
+
+ /* enable injects */
+ ddr->ecc_err_inject |= ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* write memory location injecting errors */
+ *(u32 *) i = 0xfedcba98UL;
+ __asm__ __volatile__("sync");
+
+ /* sub double word write,
+ * bus will read-modify-write,
+ * generates ECC error */
+ *((u32 *) i + 1) = 0x76543210UL;
+ __asm__ __volatile__("sync");
+
+ /* disable injects */
+ ddr->ecc_err_inject &= ~ECC_ERR_INJECT_EIEN;
+ __asm__ __volatile__("sync");
+ __asm__ __volatile__("isync");
+
+ /* re-initialize memory,
+ * double word write the location again,
+ * generates new ECC code this time */
+ ppcDWstore((u32 *) i, writeback);
+ __asm__ __volatile__("sync");
+ }
+ enable_interrupts();
+ return 0;
+ }
+ }
+ printf("Usage:\n%s\n", cmdtp->usage);
+ return 1;
+}
+
+U_BOOT_CMD(ecc, 4, 0, do_ecc,
+ "ecc - support for DDR ECC features\n",
+ "status - print out status info\n"
+ "ecc captureclear - clear capture regs data\n"
+ "ecc sbecnt <val> - set Single-Bit Error counter\n"
+ "ecc sbethr <val> - set Single-Bit Threshold\n"
+ "ecc errdisable <flag> - clear/set disable Memory Error Disable, flag:\n"
+ " [-|+]sbe - Single-Bit Error\n"
+ " [-|+]mbe - Multiple-Bit Error\n"
+ " [-|+]mse - Memory Select Error\n"
+ " [-|+]all - all errors\n"
+ "ecc errdetectclr <flag> - clear Memory Error Detect, flag:\n"
+ " mme - Multiple Memory Errors\n"
+ " sbe - Single-Bit Error\n"
+ " mbe - Multiple-Bit Error\n"
+ " mse - Memory Select Error\n"
+ " all - all errors\n"
+ "ecc injectdatahi <hi> - set Memory Data Path Error Injection Mask High\n"
+ "ecc injectdatalo <lo> - set Memory Data Path Error Injection Mask Low\n"
+ "ecc injectecc <ecc> - set ECC Error Injection Mask\n"
+ "ecc inject <en|dis> - enable/disable error injection\n"
+ "ecc mirror <en|dis> - enable/disable mirror byte\n"
+ "ecc testdw <addr> <cnt> - test mem region with double word access:\n"
+ " - enables injects\n"
+ " - writes pattern injecting errors with double word access\n"
+ " - disables injects\n"
+ " - reads pattern back with double word access, generates error\n"
+ " - re-inits memory\n"
+ "ecc testword <addr> <cnt> - test mem region with word access:\n"
+ " - enables injects\n"
+ " - writes pattern injecting errors with word access\n"
+ " - writes pattern with word access, generates error\n"
+ " - disables injects\n" " - re-inits memory");
+#endif
diff --git a/cpu/mpc83xx/pci.c b/cpu/mpc83xx/pci.c
index 785d612..2298218 100644
--- a/cpu/mpc83xx/pci.c
+++ b/cpu/mpc83xx/pci.c
@@ -25,7 +25,14 @@
#include <common.h>
#include <pci.h>
+
+#if defined(CONFIG_OF_LIBFDT)
+#include <libfdt.h>
+#include <libfdt_env.h>
+#elif defined(CONFIG_OF_FLAT_TREE)
#include <ft_build.h>
+#endif
+
#include <asm/mpc8349_pci.h>
#ifdef CONFIG_83XX_GENERIC_PCI
@@ -163,7 +170,34 @@ void mpc83xx_pci_init(int num_buses, struct pci_region **reg, int warmboot)
pci_init_bus(i, reg[i]);
}
-#ifdef CONFIG_OF_FLAT_TREE
+#if defined(CONFIG_OF_LIBFDT)
+void ft_pci_setup(void *blob, bd_t *bd)
+{
+ int nodeoffset;
+ int err;
+ int tmp[2];
+
+ if (pci_num_buses < 1)
+ return;
+
+ nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8500");
+ if (nodeoffset >= 0) {
+ tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
+ tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+ err = fdt_setprop(blob, nodeoffset, "bus-range", tmp, sizeof(tmp));
+ }
+
+ if (pci_num_buses < 2)
+ return;
+
+ nodeoffset = fdt_find_node_by_path(blob, "/" OF_SOC "/pci@8600");
+ if (nodeoffset >= 0) {
+ tmp[0] = cpu_to_be32(pci_hose[0].first_busno);
+ tmp[1] = cpu_to_be32(pci_hose[0].last_busno);
+ err = fdt_setprop(blob, nodeoffset, "bus-range", tmp, sizeof(tmp));
+ }
+}
+#elif CONFIG_OF_FLAT_TREE
void ft_pci_setup(void *blob, bd_t *bd)
{
u32 *p;
diff --git a/cpu/mpc83xx/spd_sdram.c b/cpu/mpc83xx/spd_sdram.c
index 647813f..54f0c83 100644
--- a/cpu/mpc83xx/spd_sdram.c
+++ b/cpu/mpc83xx/spd_sdram.c
@@ -574,7 +574,10 @@ long int spd_sdram()
/* Check DIMM data bus width */
if (spd.dataw_lsb == 0x20) {
- burstlen = 0x03; /* 32 bit data bus, burst len is 8 */
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ burstlen = 0x03; /* 32 bit data bus, burst len is 8 */
+ else
+ burstlen = 0x02; /* 32 bit data bus, burst len is 4 */
printf("\n DDR DIMM: data bus width is 32 bit");
} else {
burstlen = 0x02; /* Others act as 64 bit bus, burst len is 4 */
@@ -730,8 +733,12 @@ long int spd_sdram()
sdram_cfg |= 0x10000000;
/* The DIMM is 32bit width */
- if (spd.dataw_lsb == 0x20)
- sdram_cfg |= 0x000C0000;
+ if (spd.dataw_lsb == 0x20) {
+ if (spd.mem_type == SPD_MEMTYPE_DDR)
+ sdram_cfg |= 0x000C0000;
+ if (spd.mem_type == SPD_MEMTYPE_DDR2)
+ sdram_cfg |= 0x00080000;
+ }
ddrc_ecc_enable = 0;
diff --git a/cpu/ppc4xx/Makefile b/cpu/ppc4xx/Makefile
index 4068b53..af9da5b 100644
--- a/cpu/ppc4xx/Makefile
+++ b/cpu/ppc4xx/Makefile
@@ -27,12 +27,12 @@ LIB = $(obj)lib$(CPU).a
START = start.o resetvec.o kgdb.o
SOBJS = dcr.o
-COBJS = 405gp_pci.o 4xx_enet.o \
+COBJS = 405gp_pci.o 440spe_pcie.o 4xx_enet.o \
bedbug_405.o commproc.o \
cpu.o cpu_init.o gpio.o i2c.o interrupts.o \
miiphy.o ndfc.o sdram.o serial.o \
40x_spd_sdram.o 44x_spd_ddr.o 44x_spd_ddr2.o speed.o \
- tlb.o traps.o usb_ohci.o usbdev.o \
+ tlb.o traps.o usb_ohci.o usb.o usbdev.o \
440spe_pcie.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
diff --git a/cpu/ppc4xx/usb.c b/cpu/ppc4xx/usb.c
new file mode 100644
index 0000000..2837b37
--- /dev/null
+++ b/cpu/ppc4xx/usb.c
@@ -0,0 +1,50 @@
+/*
+ * (C) Copyright 2007
+ * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT)
+
+#include "usbdev.h"
+
+int usb_cpu_init()
+{
+
+#if defined(CONFIG_440EP) || defined(CONFIG_440EPX)
+ usb_dev_init();
+#endif
+
+ return 0;
+}
+
+int usb_cpu_stop()
+{
+ return 0;
+}
+
+int usb_cpu_init_fail()
+{
+ return 0;
+}
+
+#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */
diff --git a/cpu/pxa/Makefile b/cpu/pxa/Makefile
index cded7ff..8b4367e 100644
--- a/cpu/pxa/Makefile
+++ b/cpu/pxa/Makefile
@@ -26,7 +26,7 @@ include $(TOPDIR)/config.mk
LIB = $(obj)lib$(CPU).a
START = start.o
-COBJS = serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o
+COBJS = serial.o interrupts.o cpu.o i2c.o pxafb.o mmc.o usb.o
SRCS := $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
OBJS := $(addprefix $(obj),$(SOBJS) $(COBJS))
diff --git a/cpu/pxa/usb.c b/cpu/pxa/usb.c
new file mode 100644
index 0000000..65f457f
--- /dev/null
+++ b/cpu/pxa/usb.c
@@ -0,0 +1,79 @@
+/*
+ * (C) Copyright 2006
+ * Markus Klotzbuecher, DENX Software Engineering <mk@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+
+#if defined(CONFIG_USB_OHCI_NEW) && defined(CFG_USB_OHCI_CPU_INIT)
+# if defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X)
+
+#include <asm/arch/pxa-regs.h>
+
+int usb_cpu_init()
+{
+#if defined(CONFIG_CPU_MONAHANS)
+ /* Enable USB host clock. */
+ CKENA |= (CKENA_2_USBHOST | CKENA_20_UDC);
+ udelay(100);
+#endif
+#if defined(CONFIG_PXA27X)
+ /* Enable USB host clock. */
+ CKEN |= CKEN10_USBHOST;
+#endif
+
+#if defined(CONFIG_CPU_MONAHANS)
+ /* Configure Port 2 for Host (USB Client Registers) */
+ UP2OCR = 0x3000c;
+#endif
+
+ UHCHR |= UHCHR_FHR;
+ wait_ms(11);
+ UHCHR &= ~UHCHR_FHR;
+
+ UHCHR |= UHCHR_FSBIR;
+ while (UHCHR & UHCHR_FSBIR)
+ udelay(1);
+
+#if defined(CONFIG_CPU_MONAHANS)
+ UHCHR &= ~UHCHR_SSEP0;
+#endif
+#if defined(CONFIG_PXA27X)
+ UHCHR &= ~UHCHR_SSEP2;
+#endif
+ UHCHR &= ~UHCHR_SSEP1;
+ UHCHR &= ~UHCHR_SSE;
+
+ return 0;
+}
+
+int usb_cpu_stop()
+{
+ return 0;
+}
+
+int usb_cpu_init_fail()
+{
+ return 0;
+}
+
+# endif /* defined(CONFIG_CPU_MONAHANS) || defined(CONFIG_PXA27X) */
+#endif /* defined(CONFIG_USB_OHCI) && defined(CFG_USB_OHCI_CPU_INIT) */