summaryrefslogtreecommitdiff
path: root/cpu
diff options
context:
space:
mode:
authorJustin Waters <justin@justin-linux.(none)>2008-01-21 13:46:21 -0500
committerJustin Waters <justin@justin-linux.(none)>2008-01-21 13:46:21 -0500
commit037af3481edfb2b7a3fbed1dffd277df25f677b9 (patch)
tree2c39b8891b4494298b7ee447c480645d96e13bdb /cpu
parentba999c531ed16ec749b2b6f4b0133cee38842b91 (diff)
Add Atmel AT91 patch version 1.5
This patch adds support for the following boards: AT91RM9200-EK AT91SAM9260-EK AT91SAM9261-EK AT91SAM9263-EK AT91SAM9RL-EK It was downloaded from http://www.linux4sam.org/twiki/pub/Linux4SAM/U-Boot/u-boot-1.1.5_atmel_1.5.diff.bz2 Signed-off-by: Justin Waters <justin.waters@timesys.com>
Diffstat (limited to 'cpu')
-rw-r--r--cpu/arm920t/at91rm9200/interrupts.c4
-rw-r--r--cpu/arm926ejs/at91sam926x/Makefile44
-rw-r--r--cpu/arm926ejs/at91sam926x/config.mk29
-rw-r--r--cpu/arm926ejs/at91sam926x/ether.c454
-rw-r--r--cpu/arm926ejs/at91sam926x/interrupts.c207
-rw-r--r--cpu/arm926ejs/at91sam926x/lcd.c279
-rw-r--r--cpu/arm926ejs/at91sam926x/lcd_lut.h271
-rw-r--r--cpu/arm926ejs/at91sam926x/serial.c116
-rw-r--r--cpu/arm926ejs/at91sam926x/spi.c243
-rw-r--r--cpu/arm926ejs/at91sam926x/usb_ohci.c1709
-rw-r--r--cpu/arm926ejs/at91sam926x/usb_ohci.h417
-rw-r--r--cpu/arm926ejs/interrupts.c4
-rw-r--r--cpu/arm926ejs/start.S8
13 files changed, 3779 insertions, 6 deletions
diff --git a/cpu/arm920t/at91rm9200/interrupts.c b/cpu/arm920t/at91rm9200/interrupts.c
index 10546027f8d..f0f8e8ec46c 100644
--- a/cpu/arm920t/at91rm9200/interrupts.c
+++ b/cpu/arm920t/at91rm9200/interrupts.c
@@ -175,14 +175,14 @@ void reset_cpu (ulong ignored)
#ifdef CONFIG_USART1
AT91PS_USART us = AT91C_BASE_US1;
#endif
-#ifdef CONFIG_AT91RM9200DK
+#if defined CONFIG_AT91RM9200DK || defined CONFIG_AT91RM9200EK
AT91PS_PIO pio = AT91C_BASE_PIOA;
#endif
/*shutdown the console to avoid strange chars during reset */
us->US_CR = (AT91C_US_RSTRX | AT91C_US_RSTTX);
-#ifdef CONFIG_AT91RM9200DK
+#if defined CONFIG_AT91RM9200DK || defined CONFIG_AT91RM9200EK
/* Clear PA19 to trigger the hard reset */
pio->PIO_CODR = 0x00080000;
pio->PIO_OER = 0x00080000;
diff --git a/cpu/arm926ejs/at91sam926x/Makefile b/cpu/arm926ejs/at91sam926x/Makefile
new file mode 100644
index 00000000000..83a82c42fe5
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/Makefile
@@ -0,0 +1,44 @@
+#
+# (C) Copyright 2000-2003
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+include $(TOPDIR)/config.mk
+
+LIB = lib$(SOC).a
+
+
+OBJS = serial.o interrupts.o usb_ohci.o lcd.o ether.o spi.o
+SOBJS =
+
+all: .depend $(LIB)
+
+$(LIB): $(OBJS) $(SOBJS)
+ $(AR) crv $@ $(OBJS) $(SOBJS)
+
+#########################################################################
+
+.depend: Makefile $(OBJS:.o=.c)
+ $(CC) -M $(CFLAGS) $(OBJS:.o=.c) > $@
+
+sinclude .depend
+
+#########################################################################
diff --git a/cpu/arm926ejs/at91sam926x/config.mk b/cpu/arm926ejs/at91sam926x/config.mk
new file mode 100644
index 00000000000..8866690cd29
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/config.mk
@@ -0,0 +1,29 @@
+#
+# (C) Copyright 2002
+# Gary Jennejohn, DENX Software Engineering, <gj@denx.de>
+#
+# See file CREDITS for list of people who contributed to this
+# project.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+# MA 02111-1307 USA
+#
+
+PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8
+PLATFORM_RELFLAGS += $(call cc-option,-msoft-float,)
+
+PLATFORM_CPPFLAGS += -march=armv5te
+PLATFORM_CPPFLAGS += $(call cc-option,-mtune=arm926ejs,)
+PLATFORM_CPPFLAGS += $(call cc-option,-mapcs-32,)
diff --git a/cpu/arm926ejs/at91sam926x/ether.c b/cpu/arm926ejs/at91sam926x/ether.c
new file mode 100644
index 00000000000..46b9b985282
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/ether.c
@@ -0,0 +1,454 @@
+/*
+ * (C) Copyright 2006
+ * Author : Lacressonniere Nicolas (Atmel)
+ *
+ * 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>
+#ifndef CONFIG_DRIVER_DM9000 /* SAM9261EK uses DM9000 Phy */
+
+#ifdef CONFIG_DRIVER_ETHER
+#if (CONFIG_COMMANDS & CFG_CMD_NET)
+
+#include <net.h>
+#include <at91_net.h>
+#include <miiphy.h>
+#include <dm9161.h>
+
+
+/* ----- Ethernet Buffer definitions ----- */
+
+/* Receive Transfer descriptor structure */
+typedef struct _AT91S_RxTdDescriptor {
+ unsigned int addr;
+ union
+ {
+ unsigned int status;
+ struct {
+ unsigned int Length:12;
+ unsigned int Rxbuf_off:2;
+ unsigned int StartOfFrame:1;
+ unsigned int EndOfFrame:1;
+ unsigned int Cfi:1;
+ unsigned int VlanPriority:3;
+ unsigned int PriorityTag:1;
+ unsigned int VlanTag:1;
+ unsigned int TypeID:1;
+ unsigned int Sa4Match:1;
+ unsigned int Sa3Match:1;
+ unsigned int Sa2Match:1;
+ unsigned int Sa1Match:1;
+ unsigned int Res0:1;
+ unsigned int ExternalAdd:1;
+ unsigned int UniCast:1;
+ unsigned int MultiCast:1;
+ unsigned int BroadCast:1;
+ } S_Status;
+ } U_Status;
+} AT91S_RxTdDescriptor, *AT91PS_RxTdDescriptor;
+
+
+/* Transmit Transfer descriptor structure */
+typedef struct _AT91S_TxTdDescriptor {
+ unsigned int addr;
+ union
+ {
+ unsigned int status;
+ struct {
+ unsigned int Length:11;
+ unsigned int Res0:4;
+ unsigned int LastBuff:1;
+ unsigned int NoCrc:1;
+ unsigned int Res1:10;
+ unsigned int BufExhausted:1;
+ unsigned int TransmitUnderrun:1;
+ unsigned int TransmitError:1;
+ unsigned int Wrap:1;
+ unsigned int BuffUsed:1;
+ } S_Status;
+ } U_Status;
+} AT91S_TxTdDescriptor, *AT91PS_TxTdDescriptor;
+
+
+#define RBF_ADDR 0xfffffffc
+#define RBF_OWNER (1<<0)
+#define RBF_WRAP (1<<1)
+#define RBF_BROADCAST (1<<31)
+#define RBF_MULTICAST (1<<30)
+#define RBF_UNICAST (1<<29)
+#define RBF_EXTERNAL (1<<28)
+#define RBF_UNKOWN (1<<27)
+#define RBF_SIZE 0x07ff
+#define RBF_LOCAL4 (1<<26)
+#define RBF_LOCAL3 (1<<25)
+#define RBF_LOCAL2 (1<<24)
+#define RBF_LOCAL1 (1<<23)
+#define RBF_EOF (1<<15)
+#define RBF_SOF (1<<14)
+
+#define MAX_ETH_FRAME_LEN 0x600 /* 1536 bytes. Max ethernet frame size */
+
+#define RBF_FRAMEMAX 64
+#define RBF_FRAMELEN 128
+
+#define TBF_FRAMEMAX 64
+#define TBF_FRAMELEN 0x600
+
+/* alignment as per Errata #11 (64 bytes) is insufficient! */
+AT91S_RxTdDescriptor RxtdList[RBF_FRAMEMAX] __attribute((aligned(512)));
+AT91S_TxTdDescriptor TxtdList[TBF_FRAMEMAX] __attribute((aligned(512)));
+
+unsigned char rbf_framebuf[RBF_FRAMEMAX][RBF_FRAMELEN] __attribute((aligned(4)));
+unsigned char tbf_framebuf[TBF_FRAMEMAX][TBF_FRAMELEN] __attribute((aligned(4)));
+
+unsigned int RxBuffIndex = 0;
+unsigned int TxBuffIndex = 0;
+
+static unsigned char stage_rx_buffer[MAX_ETH_FRAME_LEN];
+volatile unsigned char *rx_pkt_tmp = stage_rx_buffer;
+
+/* structure to interface the PHY */
+AT91S_PhyOps PhyOps;
+
+AT91PS_EMAC p_mac;
+
+extern int AT91F_EMAC_Hardware_Init(void);
+
+/*********** EMAC Phy layer Management functions *************************/
+/*
+ * Name:
+ * at91_EmacEnableMDIO
+ * Description:
+ * Enables the MDIO bit in MAC control register
+ * Arguments:
+ * p_mac - pointer to struct AT91S_EMAC
+ * Return value:
+ * none
+ */
+void at91_EmacEnableMDIO (AT91PS_EMAC p_mac)
+{
+ /* Mac CTRL reg set for MDIO enable */
+ p_mac->EMAC_NCR |= AT91C_EMAC_MPE; /* Management port enable */
+}
+
+/*
+ * Name:
+ * at91_EmacDisableMDIO
+ * Description:
+ * Disables the MDIO bit in MAC control register
+ * Arguments:
+ * p_mac - pointer to struct AT91S_EMAC
+ * Return value:
+ * none
+ */
+void at91_EmacDisableMDIO (AT91PS_EMAC p_mac)
+{
+ /* Mac CTRL reg set for MDIO disable */
+ p_mac->EMAC_NCR &= ~AT91C_EMAC_MPE; /* Management port disable */
+}
+
+
+/*
+ * Name:
+ * at91_EmacReadPhy
+ * Description:
+ * Reads data from the PHY register
+ * Arguments:
+ * dev - pointer to struct net_device
+ * RegisterAddress - unsigned char
+ * pInput - pointer to value read from register
+ * Return value:
+ * TRUE - if data read successfully
+ */
+uchar at91_EmacReadPhy (AT91PS_EMAC p_mac,
+ unsigned char PhyAddress,
+ unsigned char RegisterAddress,
+ unsigned short *pInput)
+{
+ p_mac->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30)) |
+ (AT91C_EMAC_RW & (0x2 << 28)) |
+ ((PhyAddress & 0x1F) << 23) |
+ (RegisterAddress << 18) |
+ (AT91C_EMAC_CODE & (0x2 << 16));
+
+ /* Wait until IDLE bit in Network Status register is cleared */
+ while (!(p_mac->EMAC_NSR & AT91C_EMAC_IDLE));
+
+ *pInput = (unsigned short) (p_mac->EMAC_MAN & 0x0000FFFF);
+
+ return TRUE;
+}
+
+
+/*
+ * Name:
+ * at91_EmacWritePhy
+ * Description:
+ * Writes data to the PHY register
+ * Arguments:
+ * dev - pointer to struct net_device
+ * RegisterAddress - unsigned char
+ * pOutput - pointer to value to be written in the register
+ * Return value:
+ * TRUE - if data read successfully
+ */
+uchar at91_EmacWritePhy (AT91PS_EMAC p_mac,
+ unsigned char PhyAddress,
+ unsigned char RegisterAddress,
+ unsigned short *pOutput)
+{
+ p_mac->EMAC_MAN = (AT91C_EMAC_SOF & (0x01 << 30)) |
+ (AT91C_EMAC_RW & (0x1 << 28)) |
+ ((PhyAddress & 0x1F) << 23) |
+ (RegisterAddress << 18) |
+ (AT91C_EMAC_CODE & (0x2 << 16)) |
+ *pOutput;
+
+ /* Wait until IDLE bit in Network Status register is cleared */
+ while (!(p_mac->EMAC_NSR & AT91C_EMAC_IDLE));
+
+ return TRUE;
+}
+
+/*---------------------------------------------------------------------------- */
+/* \fn AT91F_EMACInit */
+/* \brief This function initialise the ethernet */
+/* \return Status ( Success = 0) */
+/*---------------------------------------------------------------------------- */
+int AT91F_EMACInit(bd_t * bd,
+ unsigned int pRxTdList,
+ unsigned int pTxTdList)
+{
+ unsigned int tick = 0;
+ unsigned short status;
+
+ /* Wait for PHY auto negotiation completed */
+ at91_EmacEnableMDIO(p_mac);
+
+ do {
+ at91_EmacReadPhy(p_mac, AT91C_PHY_ADDR, DM9161_BMSR, &status);
+ at91_EmacReadPhy(p_mac, AT91C_PHY_ADDR, DM9161_BMSR, &status);
+
+ tick++;
+ }
+ while (!(status & DM9161_AUTONEG_COMP) && (tick < AT91C_ETH_TIMEOUT));
+
+ at91_EmacDisableMDIO(p_mac);
+
+ if (tick == AT91C_ETH_TIMEOUT)
+ {
+ printf ("-E- Autonegociation Timeout\n\r");
+ return 1;
+ } else
+ printf ("End of Autonegociation\n\r");
+
+ /* the sequence write EMAC_SA1L and write EMAC_SA1H must be respected */
+ p_mac->EMAC_SA1L = (bd->bi_enetaddr[3] << 24) | (bd->bi_enetaddr[2] << 16)
+ | (bd->bi_enetaddr[1] << 8) | (bd->bi_enetaddr[0]);
+ p_mac->EMAC_SA1H = (bd->bi_enetaddr[5] << 8) | (bd->bi_enetaddr[4]);
+
+ p_mac->EMAC_RBQP = pRxTdList;
+ p_mac->EMAC_TBQP = pTxTdList;
+
+
+ p_mac->EMAC_NCFGR |= (AT91C_EMAC_CAF | AT91C_EMAC_NBC );
+ p_mac->EMAC_NCFGR &= ~(AT91C_EMAC_CLK);
+
+ p_mac->EMAC_NCR |= (AT91C_EMAC_TE | AT91C_EMAC_RE);
+
+ return 0;
+}
+
+int eth_init (bd_t * bd)
+{
+ volatile unsigned int uStatus;
+ unsigned int val, i;
+ int ret;
+ static int first_time = 0;
+
+ if (!first_time)
+ {
+ /* Init PIOs in peripheral mode */
+ AT91F_EMAC_Hardware_Init();
+
+ *AT91C_PMC_PCER = 1 << AT91C_ID_EMAC; /* Peripheral Clock Enable Register */
+
+ /* Disable Tx and Rx */
+ p_mac->EMAC_NCR = 0;
+ /* Clear statistics */
+ p_mac->EMAC_NCR = AT91C_EMAC_CLRSTAT;
+
+ uStatus = p_mac->EMAC_ISR;
+ p_mac->EMAC_TSR = 0xFFFFFFFF;
+ p_mac->EMAC_RSR = 0xFFFFFFFF;
+
+ /* We don't use interrupts. disable them */
+ p_mac->EMAC_IDR = 0xFFFFFFFF;
+
+ /* Enable EMAC in MII mode and enable MII Clock (25MHz) */
+ p_mac->EMAC_USRIO = AT91C_EMAC_CLKEN;
+
+#ifdef CONFIG_AT91C_USE_RMII
+ p_mac->EMAC_USRIO |= AT91C_EMAC_RMII;
+#endif
+
+ /* Set MDIO clock */
+#if (AT91C_MASTER_CLOCK > 80000000)
+ p_mac->EMAC_NCFGR |= AT91C_EMAC_CLK_HCLK_64;
+#else
+ p_mac->EMAC_NCFGR |= AT91C_EMAC_CLK_HCLK_32;
+#endif
+
+ /* Init Ethernet buffers */
+ RxBuffIndex = 0;
+ TxBuffIndex = 0;
+
+ /* Initialise RxtdList descriptor */
+ for (i = 0; i < RBF_FRAMEMAX; ++i) {
+ val = (unsigned int)(&rbf_framebuf[i][0]);
+ RxtdList[i].addr = val & 0xFFFFFFF8;
+ RxtdList[i].U_Status.status = 0;
+ }
+ /* Set the WRAP bit at the end of the list descriptor */
+ RxtdList[RBF_FRAMEMAX-1].addr |= RBF_WRAP;
+
+ /* Initialise TxtdList descriptor */
+ for (i = 0; i < TBF_FRAMEMAX; ++i) {
+ val = (unsigned int)(&tbf_framebuf[i][0]);
+ TxtdList[i].addr = val & 0xFFFFFFF8;
+ TxtdList[i].U_Status.status = 0;
+ TxtdList[i].U_Status.S_Status.BuffUsed = 1;
+ }
+ TxtdList[0].U_Status.S_Status.BuffUsed = 0;
+ /* Set the WRAP bit at the end of the list descriptor */
+ TxtdList[TBF_FRAMEMAX-1].U_Status.S_Status.Wrap = 1;
+
+ at91_GetPhyInterface (&PhyOps);
+
+ /* Phy Software Reset */
+ if (!PhyOps.Reset(p_mac))
+ {
+ printf ("PHY not reset!!\n\r");
+ return 0;
+ }
+
+ if (!PhyOps.IsPhyConnected (p_mac))
+ {
+ printf ("PHY not connected!!\n\r");
+ return 0;
+ }
+
+ /* MII management start from here */
+ if (!(ret = PhyOps.Init (p_mac)))
+ {
+ printf ("MAC: error during RMII initialization\n");
+ return 0;
+ }
+
+ if (AT91F_EMACInit(bd, (unsigned int)RxtdList, (unsigned int)TxtdList))
+ return 0;
+
+ first_time = 1;
+ }
+
+ /* Initialize Receive Frame Pointer */
+ rx_pkt_tmp = stage_rx_buffer;
+
+ return 0;
+}
+
+int eth_send (volatile void *packet, int length)
+{
+
+ if ((TxtdList[TxBuffIndex].U_Status.S_Status.BuffUsed == 0))
+ {
+ TxtdList[TxBuffIndex].addr = (unsigned int)packet;
+ TxtdList[TxBuffIndex].U_Status.S_Status.Length = length;
+ TxtdList[TxBuffIndex].U_Status.S_Status.LastBuff = 1;
+ }
+ else
+ return 2;
+
+ p_mac->EMAC_NCR |= AT91C_EMAC_TSTART;
+
+ while (!(p_mac->EMAC_TSR & AT91C_EMAC_COMP));
+
+ p_mac->EMAC_TSR |= AT91C_EMAC_COMP;
+
+ TxtdList[TxBuffIndex].U_Status.S_Status.Length = 0;
+ TxtdList[TxBuffIndex].U_Status.S_Status.LastBuff = 0;
+
+ if (TxBuffIndex == (TBF_FRAMEMAX - 1))
+ TxBuffIndex = 0;
+ else
+ TxBuffIndex ++;
+
+ TxtdList[TxBuffIndex].U_Status.S_Status.BuffUsed = 0;
+
+ if (p_mac->EMAC_TSR & AT91C_EMAC_UBR)
+ p_mac->EMAC_TSR |= AT91C_EMAC_UBR;
+
+ return 0;
+}
+
+int eth_rx (void)
+{
+ int size = 0;
+
+ while (!size)
+ {
+ while (!(RxtdList[RxBuffIndex].addr & RBF_OWNER));
+
+ if (RxtdList[RxBuffIndex].U_Status.S_Status.StartOfFrame == 1)
+ rx_pkt_tmp = stage_rx_buffer;
+
+ memcpy((uchar *)rx_pkt_tmp, (uchar *)(RxtdList[RxBuffIndex].addr & RBF_ADDR), RBF_FRAMELEN);
+ rx_pkt_tmp += RBF_FRAMELEN;
+
+ if (RxtdList[RxBuffIndex].U_Status.S_Status.EndOfFrame == 1)
+ {
+ size = RxtdList[RxBuffIndex].U_Status.S_Status.Length;
+
+ NetReceive ((uchar *)stage_rx_buffer, size);
+ if (p_mac->EMAC_RSR & AT91C_EMAC_REC)
+ p_mac->EMAC_RSR |= AT91C_EMAC_REC;
+
+ rx_pkt_tmp = stage_rx_buffer;
+ }
+
+ RxtdList[RxBuffIndex].U_Status.status = 0;
+ RxtdList[RxBuffIndex].addr &= ~RBF_OWNER;
+
+ if (RxtdList[RxBuffIndex].addr & RBF_WRAP)
+ RxBuffIndex = 0;
+ else
+ RxBuffIndex++;
+ }
+
+ return size;
+}
+
+void eth_halt (void)
+{
+};
+
+#endif /* CONFIG_COMMANDS & CFG_CMD_NET */
+#endif /* CONFIG_DRIVER_DM9000 */
+#endif /* CONFIG_DRIVER_ETHER */
diff --git a/cpu/arm926ejs/at91sam926x/interrupts.c b/cpu/arm926ejs/at91sam926x/interrupts.c
new file mode 100644
index 00000000000..85b33f2846b
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/interrupts.c
@@ -0,0 +1,207 @@
+/*
+ * (C) Copyright 2005
+ * M. Amine SAYA ATMEL Rousset, France.
+ *
+ * (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>
+ *
+ * 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 <asm/arch/hardware.h>
+
+
+#define TIMER_LOAD_VAL (AT91C_MASTER_CLOCK / (16 * CFG_HZ))
+
+/* macro to read the 20-bit wide AT91SAM9263 PITC value*/
+#define READ_RESET_TIMER (p_pitc->PITC_PIVR)
+#define READ_TIMER (p_pitc->PITC_PIIR)
+
+#define HIGH_TIMER_VALUE(X) ((((X) & 0xfff00000) >> 20))
+#define TIMER_VALUE(X) ((((X) & 0xfff00000) >> 20) * TIMER_LOAD_VAL + ((X) & 0x000fffff))
+
+
+ulong get_timer_masked (void);
+
+AT91PS_PITC p_pitc;
+
+static ulong timestamp;
+static ulong lastinc;
+
+/* nothing really to do with interrupts, just starts up a counter. */
+int interrupt_init (void)
+{
+ p_pitc = AT91C_BASE_PITC;
+
+ /* Enable PITC Clock
+ The clock is already enabled for system controller in boot */
+ *AT91C_PMC_PCER = 1 << AT91C_ID_SYS;
+
+ /* Enable PITC */
+ p_pitc->PITC_PIMR = AT91C_PITC_PITEN;
+
+ /* Load PITC_PIMR with the right timer value */
+ p_pitc->PITC_PIMR |= TIMER_LOAD_VAL;
+
+ reset_timer_masked();
+
+ return 0;
+}
+
+
+/*
+ * timer without interrupts
+ */
+
+void reset_timer (void)
+{
+ reset_timer_masked ();
+}
+
+ulong get_timer (ulong base)
+{
+ return get_timer_masked () - base;
+}
+
+void set_timer (ulong t)
+{
+ timestamp = t;
+}
+
+ulong get_all_timer(void)
+{
+ ulong now;
+
+ now = READ_TIMER;
+ return TIMER_VALUE(now);
+}
+
+
+/* delay x useconds AND perserve advance timstamp value */
+void udelay (unsigned long usec)
+{
+ ulong tmo;
+
+ if(usec >= 1000){ /* if "big" number, spread normalization to seconds */
+ tmo = usec / 1000; /* start to normalize for usec to ticks per sec */
+ tmo *= (AT91C_MASTER_CLOCK/16); /* find number of "ticks" to wait to achieve target */
+ tmo /= 1000; /* finish normalize. */
+ }else{ /* else small number, don't kill it prior to HZ multiply */
+ tmo = usec * (AT91C_MASTER_CLOCK/16);
+ tmo /= (1000*1000);
+ }
+
+ reset_timer_masked();
+ tmo += get_all_timer(); /* get current timestamp */
+
+ while(get_all_timer() < tmo); /* loop till event */
+}
+
+void reset_timer_masked (void)
+{
+ /* reset time */
+ lastinc = READ_RESET_TIMER;
+
+ /* start "advancing" time stamp from 0 */
+ timestamp = 0;
+}
+
+ulong get_timer_masked (void)
+{
+ ulong now = READ_TIMER;
+
+ now = HIGH_TIMER_VALUE(now);
+
+ timestamp = now;
+
+ lastinc = now;
+
+ return timestamp * CFG_HZ;
+}
+
+/* waits specified delay value and resets timestamp */
+void udelay_masked (unsigned long usec)
+{
+ ulong tmo;
+
+ if(usec >= 1000){ /* if "big" number, spread normalization to seconds */
+ tmo = usec / 1000; /* start to normalize for usec to ticks per sec */
+ tmo *= (AT91C_MASTER_CLOCK/16); /* find number of "ticks" to wait to achieve target */
+ tmo /= 1000; /* finish normalize. */
+ }else{ /* else small number, don't kill it prior to HZ multiply */
+ tmo = usec * (AT91C_MASTER_CLOCK/16);
+ tmo /= (1000*1000);
+ }
+
+ reset_timer_masked(); /* set "advancing" timestamp to 0, set lastinc value */
+ tmo += get_all_timer();
+
+ while (get_all_timer() < tmo) /* wait for time stamp to overtake tick number.*/
+ /*NOP*/;
+}
+
+/*
+ * 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;
+}
+
+/*
+ * Reset the cpu by setting up the Reset Controller
+ * on the SAM9263EK board
+ */
+void reset_cpu (ulong ignored)
+{
+ /* Use Reset Controller */
+
+
+ while (1);
+ /* Never reached */
+}
+
diff --git a/cpu/arm926ejs/at91sam926x/lcd.c b/cpu/arm926ejs/at91sam926x/lcd.c
new file mode 100644
index 00000000000..affb6be01b0
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/lcd.c
@@ -0,0 +1,279 @@
+/*
+ * (C) Copyright 2005
+ * M. Amine SAYA, ATMEL Rousset, France.
+ * Added support to AT91SAM9261 LCD Controller
+ *
+ * (C) Copyright 2001-2002
+ * Wolfgang Denk, DENX Software Engineering -- wd@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
+ */
+
+/************************************************************************/
+/* ** HEADER FILES */
+/************************************************************************/
+
+#include <config.h>
+#include <common.h>
+#include <version.h>
+#include <stdarg.h>
+#include <linux/types.h>
+#include <devices.h>
+
+#undef CONFIG_LCD_LOGO
+#include <lcd.h>
+#include "lcd_lut.h"
+
+
+#ifdef CONFIG_LCD
+//#include <asm/arch/pio.h>
+
+#define LCD_BPP LCD_COLOR8
+
+/* #define DEBUG */
+#define FB_SYNC_HOR_HIGH_ACT 1 /* horizontal sync high active */
+#define FB_SYNC_VERT_HIGH_ACT 2 /* vertical sync high active */
+
+/* More or less configurable parameters for LCDC controller*/
+#define SIDSAFB_FIFO_SIZE 512
+#define SIDSAFB_DMA_BURST_LEN 16
+#define SIDSAFB_CRST_VAL 0xc8 /* 0xda */
+
+
+AT91PS_SYS AT91_SYS = (AT91PS_SYS)AT91C_BASE_SYS;
+
+/* 640x480x16 @ 61 Hz */
+vidinfo_t panel_info = {
+ vl_col: 240,
+ vl_row: 320,
+ vl_width: 64,
+ vl_height: 86,
+ vl_pixclock: 4965000,
+ vl_hsp: FB_SYNC_HOR_HIGH_ACT,
+ vl_vsp: FB_SYNC_VERT_HIGH_ACT,
+ vl_bpix: 3,
+ vl_tft: 1,
+ /* Horizontal control Timing */
+ vl_hpw: 5,
+ vl_blw: 1,
+ vl_elw: 33,
+ /* Vertical control Timing */
+ vl_vpw: 1,
+ vl_bfw: 1,
+ vl_efw: 0,
+};
+
+
+
+
+/*----------------------------------------------------------------------*/
+void lcd_setcolreg (ushort regno, ushort red, ushort green, ushort blue);
+void lcd_ctrl_init (void *lcdbase);
+void lcd_enable (void);
+void lcd_init_lut(void);
+
+
+int lcd_line_length;
+int lcd_color_fg;
+int lcd_color_bg;
+
+void *lcd_base; /* Start of framebuffer memory */
+void *lcd_console_address; /* Start of console buffer */
+
+short console_col;
+short console_row;
+
+
+
+/************************************************************************/
+void lcd_init_lut(void)
+{
+ unsigned int i;
+ for(i =0; i <256; i++) {
+#if defined(CONFIG_AT91SAM9261EK) || defined(CONFIG_AT91SAM9263EK)
+ panel_info.controller.lcdc->LCDC_LUT_ENTRY[i] =
+ ((rgbPalette[i].red) >> 3 |
+ ((rgbPalette[i].green & 0xf8) << 2) |
+ ((rgbPalette[i].blue & 0xf8) << 7));
+#else
+ panel_info.controller.lcdc->LCDC_LUT_ENTRY[i] =
+ ((rgbPalette[i].blue) >> 3 |
+ ((rgbPalette[i].green & 0xfc) << 3) |
+ ((rgbPalette[i].red & 0xf8) << 8));
+#endif
+ }
+}
+
+
+void lcd_setcolreg (ushort regno, ushort red,
+ ushort green, ushort blue)
+{
+#if defined(CONFIG_AT91SAM9261EK) || defined(CONFIG_AT91SAM9263EK)
+ panel_info.controller.lcdc->LCDC_LUT_ENTRY[regno] = ((red >> 3) |
+ ((green & 0xf8) << 2) |
+ ((blue & 0xf8) << 7));
+#else
+ panel_info.controller.lcdc->LCDC_LUT_ENTRY[regno] = ((blue >> 3) |
+ ((green & 0xfc) << 3) |
+ ((red & 0xf8) << 8));
+#endif
+}
+
+
+void lcd_ctrl_init (void *lcdbase)
+{
+ unsigned long value;
+
+ AT91F_LCDC_TFT_CfgPIO();
+
+#ifdef CONFIG_AT91SAM9261EK
+ /* Enable HCLOCK in PMC */
+ *AT91C_PMC_SCER = AT91C_PMC_HCK1;
+#endif
+
+#ifdef CONFIG_AT91SAM9263EK
+ /* Enable LCDC clock in PMC */
+ *AT91C_PMC_PCER = 1 << AT91C_ID_LCDC;
+#endif
+#ifdef CONFIG_AT91SAM9RLEK
+ /* Enable LCDC clock in PMC */
+ *AT91C_PMC_PCER = 1 << AT91C_ID_LCDC;
+#endif
+ /* Init controller field in panel_info */
+ panel_info.controller.lcdc = (AT91PS_LCDC) AT91C_BASE_LCDC;
+ panel_info.controller.frame_buffer = (unsigned long) lcdbase;
+
+ /* Turn off the LCD controller and the DMA controller */
+ panel_info.controller.lcdc->LCDC_PWRCON = 0x00;
+ panel_info.controller.lcdc->LCDC_DMACON = 0;
+
+ /* Reset LCDC DMA */
+ panel_info.controller.lcdc->LCDC_DMACON = AT91C_LCDC_DMARST;
+
+ /* ...set frame size and burst length = 8 words (?) */
+ value = ((unsigned int)panel_info.vl_row * (unsigned int)panel_info.vl_col * (unsigned int)NBITS(panel_info.vl_bpix)) / 32;
+ value |= ((512 - 1) << 24);
+ panel_info.controller.lcdc->LCDC_FRMCFG = value;
+
+ /* Set pixel clock */
+ value = AT91C_MASTER_CLOCK / panel_info.vl_pixclock;
+
+ if (AT91C_MASTER_CLOCK % panel_info.vl_pixclock)
+ value++;
+
+ value = (value / 2) - 1;
+
+ if (!value) {
+ panel_info.controller.lcdc->LCDC_LCDCON1 = AT91C_LCDC_BYPASS;
+ } else
+ panel_info.controller.lcdc->LCDC_LCDCON1 = value << 12;
+
+ /* Initialize control register 2 */
+ if (panel_info.vl_tft)
+ value = ( AT91C_LCDC_MEMOR_LITTLEIND | AT91C_LCDC_DISTYPE_TFT | AT91C_LCDC_CLKMOD);
+ else
+ value = ( AT91C_LCDC_MEMOR_LITTLEIND | AT91C_LCDC_CLKMOD);
+
+ if (!((unsigned int)panel_info.vl_hsp & FB_SYNC_HOR_HIGH_ACT))
+ value |= 1 << 10; /* INVLINE */
+ if (!((unsigned int)panel_info.vl_vsp & FB_SYNC_VERT_HIGH_ACT))
+ value |= 1 << 9; /* INVFRAME */
+
+ value |= (unsigned int)(panel_info.vl_bpix << 5);
+
+ panel_info.controller.lcdc->LCDC_LCDCON2 = value;
+
+ /* Vertical timing */
+ value = (unsigned int)((panel_info.vl_vpw - 1) << 16);
+ value |= (unsigned int)(panel_info.vl_bfw << 8);
+ value |= (unsigned int)panel_info.vl_efw;
+ panel_info.controller.lcdc->LCDC_TIM1 = value;
+
+ /* Horizontal timing */
+ value = (unsigned int)((panel_info.vl_elw - 1) << 21);
+ value |= (unsigned int)((panel_info.vl_hpw - 1) << 8);
+ value |= (unsigned int)(panel_info.vl_blw - 1);
+
+ panel_info.controller.lcdc->LCDC_TIM2 = value;
+
+ value = (unsigned int)((panel_info.vl_col - 1) << 21);
+ value |= (unsigned int)(panel_info.vl_row - 1);
+
+ panel_info.controller.lcdc->LCDC_LCDFRCFG = value;
+
+ /* FIFO Threshold: Use formula from data sheet */
+ value = SIDSAFB_FIFO_SIZE - (2 * SIDSAFB_DMA_BURST_LEN + 3);
+ panel_info.controller.lcdc->LCDC_FIFO = value;
+
+ /* Toggle LCD_MODE every frame */
+ value = 0;
+ panel_info.controller.lcdc->LCDC_MVAL = value;
+
+ /* Disable all interrupts */
+ panel_info.controller.lcdc->LCDC_IDR = ~0UL;
+ /* Set contrast */
+ value = AT91C_LCDC_PS_DIVIDEDBYEIGHT | AT91C_LCDC_POL_POSITIVEPULSE | AT91C_LCDC_ENA_PWMGEMENABLED;
+ panel_info.controller.lcdc->LCDC_CTRSTCON = value;
+ panel_info.controller.lcdc->LCDC_CTRSTVAL = 0xDA; /*SIDSAFB_CRST_VAL;*/
+
+ panel_info.controller.lcdc->LCDC_BA1 = (unsigned int)lcdbase;
+ panel_info.controller.lcdc->LCDC_FRMCFG = (15 << 24) + ((unsigned int)panel_info.vl_col * (unsigned int)panel_info.vl_row * (unsigned int)NBITS(panel_info.vl_bpix)) / 32;
+ panel_info.controller.lcdc->LCDC_DMACON = AT91C_LCDC_DMAEN;
+ panel_info.controller.lcdc->LCDC_PWRCON = AT91C_LCDC_PWR | 0x0C;
+}
+
+
+/*----------------------------------------------------------------------*/
+void lcd_enable (void)
+{
+#ifdef CONFIG_AT91SAM9261EK
+ *AT91C_PIOA_SODR = AT91C_PIO_PA12;
+#endif
+
+#ifdef CONFIG_AT91SAM9263EK
+ *AT91C_PIOD_SODR = AT91C_PIO_PD12;
+#endif
+}
+
+/*----------------------------------------------------------------------*/
+void lcd_disable (void)
+{
+#ifdef CONFIG_AT91SAM9261EK
+ *AT91C_PIOA_CODR = AT91C_PIO_PA12;
+#endif
+
+#ifdef CONFIG_AT91SAM9263EK
+ *AT91C_PIOD_CODR = AT91C_PIO_PD12;
+#endif
+}
+
+/*----------------------------------------------------------------------*/
+
+ulong calc_fbsize (void)
+{
+ ulong size;
+ int line_length = ((unsigned int)panel_info.vl_col * (unsigned int)NBITS(panel_info.vl_bpix)) / 8;
+
+ size = line_length * (unsigned int)panel_info.vl_row;
+ size += PAGE_SIZE;
+
+ return size;
+}
+
+#endif /* CONFIG_LCD */
diff --git a/cpu/arm926ejs/at91sam926x/lcd_lut.h b/cpu/arm926ejs/at91sam926x/lcd_lut.h
new file mode 100644
index 00000000000..5885075920c
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/lcd_lut.h
@@ -0,0 +1,271 @@
+#ifndef _LCDLUT_H
+#define _LCDLUT_H
+
+typedef struct _PALETTEENTRY {
+ unsigned char red;
+ unsigned char green;
+ unsigned char blue;
+ unsigned char peFlags;
+} PALETTEENTRY, *PPALETTEENTRY;
+
+const PALETTEENTRY rgbPalette[256] =
+{
+ { 0x00, 0x00, 0x00, 0 }, /* 0 Sys Black gray 0 */
+ { 0x80, 0x00, 0x00, 0 }, /* 1 Sys Dk Red */
+ { 0x00, 0x80, 0x00, 0 }, /* 2 Sys Dk Green */
+ { 0x80, 0x80, 0x00, 0 }, /* 3 Sys Dk Yellow */
+ { 0x00, 0x00, 0x80, 0 }, /* 4 Sys Dk Blue */
+ { 0x80, 0x00, 0x80, 0 }, /* 5 Sys Dk Violet */
+ { 0x00, 0x80, 0x80, 0 }, /* 6 Sys Dk Cyan */
+ { 0xc0, 0xc0, 0xc0, 0 }, /* 7 Sys Lt Grey gray 192 */
+ { 0xc0, 0xdc, 0xc0, 0 }, /* 8 Sys 8 */
+ { 0xa6, 0xca, 0xf0, 0 }, /* 9 Sys 9 (the first 10 are fixed by Windows) */
+ { 0x04, 0x04, 0x04, 0 }, /* 10 gray 4 */
+ { 0x08, 0x08, 0x08, 0 }, /* 11 gray 8 */
+ { 0x0c, 0x0c, 0x0c, 0 }, /* 12 gray 12 */
+ { 0x11, 0x11, 0x11, 0 }, /* 13 gray 17 */
+ { 0x16, 0x16, 0x16, 0 }, /* 14 gray 22 */
+ { 0x1c, 0x1c, 0x1c, 0 }, /* 15 gray 28 */
+ { 0x22, 0x22, 0x22, 0 }, /* 16 gray 34 */
+ { 0x29, 0x29, 0x29, 0 }, /* 17 gray 41 */
+ { 0x55, 0x55, 0x55, 0 }, /* 18 swapped so inversions look good gray 85 */
+ { 0x4d, 0x4d, 0x4d, 0 }, /* 19 swapped so inversions look good gray 77 */
+ { 0x42, 0x42, 0x42, 0 }, /* 20 swapped so inversions look good gray 66 */
+ { 0x39, 0x39, 0x39, 0 }, /* 21 swapped so inversions look good gray 57 */
+ { 0xFF, 0x7C, 0x80, 0 }, /* 22 R255 G124 B128 */
+ { 0xFF, 0x50, 0x50, 0 }, /* 23 R255 G80 B80 */
+ { 0xD6, 0x00, 0x93, 0 }, /* 24 R214 G0 B147 */
+ { 0xCC, 0xEC, 0xFF, 0 }, /* 25 R204 G236 B255 */
+ { 0xEF, 0xD6, 0xC6, 0 }, /* 26 R239 G214 B198 */
+ { 0xE7, 0xE7, 0xD6, 0 }, /* 27 R231 G231 B214 */
+ { 0xAD, 0xA9, 0x90, 0 }, /* 28 R173 G169 B144 */
+ { 0x33, 0x00, 0x00, 0 }, /* 29 */
+ { 0x66, 0x00, 0x00, 0 }, /* 30 */
+ { 0x99, 0x00, 0x00, 0 }, /* 31 */
+ { 0xcc, 0x00, 0x00, 0 }, /* 32 */
+ { 0x00, 0x33, 0x00, 0 }, /* 33 */
+ { 0x33, 0x33, 0x00, 0 }, /* 34 */
+ { 0x66, 0x33, 0x00, 0 }, /* 35 */
+ { 0x99, 0x33, 0x00, 0 }, /* 36 */
+ { 0xcc, 0x33, 0x00, 0 }, /* 37 */
+ { 0xff, 0x33, 0x00, 0 }, /* 38 */
+ { 0x00, 0x66, 0x00, 0 }, /* 39 */
+ { 0x33, 0x66, 0x00, 0 }, /* 40 */
+ { 0x66, 0x66, 0x00, 0 }, /* 41 */
+ { 0x99, 0x66, 0x00, 0 }, /* 42 */
+ { 0xcc, 0x66, 0x00, 0 }, /* 43 */
+ { 0xff, 0x66, 0x00, 0 }, /* 44 */
+ { 0x00, 0x99, 0x00, 0 }, /* 45 */
+ { 0x33, 0x99, 0x00, 0 }, /* 46 */
+ { 0x66, 0x99, 0x00, 0 }, /* 47 */
+ { 0x99, 0x99, 0x00, 0 }, /* 48 */
+ { 0xcc, 0x99, 0x00, 0 }, /* 49 */
+ { 0xff, 0x99, 0x00, 0 }, /* 50 */
+ { 0x00, 0xcc, 0x00, 0 }, /* 51 */
+ { 0x33, 0xcc, 0x00, 0 }, /* 52 */
+ { 0x66, 0xcc, 0x00, 0 }, /* 53 */
+ { 0x99, 0xcc, 0x00, 0 }, /* 54 */
+ { 0xcc, 0xcc, 0x00, 0 }, /* 55 */
+ { 0xff, 0xcc, 0x00, 0 }, /* 56 */
+ { 0x66, 0xff, 0x00, 0 }, /* 57 */
+ { 0x99, 0xff, 0x00, 0 }, /* 58 */
+ { 0xcc, 0xff, 0x00, 0 }, /* 59 */
+ { 0x00, 0x00, 0x33, 0 }, /* 60 */
+ { 0x33, 0x00, 0x33, 0 }, /* 61 */
+ { 0x66, 0x00, 0x33, 0 }, /* 62 */
+ { 0x99, 0x00, 0x33, 0 }, /* 63 */
+ { 0xcc, 0x00, 0x33, 0 }, /* 64 */
+ { 0xff, 0x00, 0x33, 0 }, /* 65 */
+ { 0x00, 0x33, 0x33, 0 }, /* 66 */
+ { 0x33, 0x33, 0x33, 0 }, /* 67 gray 51 */
+ { 0x66, 0x33, 0x33, 0 }, /* 68 */
+ { 0x99, 0x33, 0x33, 0 }, /* 69 */
+ { 0xcc, 0x33, 0x33, 0 }, /* 70 */
+ { 0xff, 0x33, 0x33, 0 }, /* 71 */
+ { 0x00, 0x66, 0x33, 0 }, /* 72 */
+ { 0x33, 0x66, 0x33, 0 }, /* 73 */
+ { 0x66, 0x66, 0x33, 0 }, /* 74 */
+ { 0x99, 0x66, 0x33, 0 }, /* 75 */
+ { 0xcc, 0x66, 0x33, 0 }, /* 76 */
+ { 0xff, 0x66, 0x33, 0 }, /* 77 */
+ { 0x00, 0x99, 0x33, 0 }, /* 78 */
+ { 0x33, 0x99, 0x33, 0 }, /* 79 */
+ { 0x66, 0x99, 0x33, 0 }, /* 80 */
+ { 0x99, 0x99, 0x33, 0 }, /* 81 */
+ { 0xcc, 0x99, 0x33, 0 }, /* 82 */
+ { 0xff, 0x99, 0x33, 0 }, /* 83 */
+ { 0x00, 0xcc, 0x33, 0 }, /* 84 */
+ { 0x33, 0xcc, 0x33, 0 }, /* 85 */
+ { 0x66, 0xcc, 0x33, 0 }, /* 86 */
+ { 0x99, 0xcc, 0x33, 0 }, /* 87 */
+ { 0xcc, 0xcc, 0x33, 0 }, /* 88 */
+ { 0xff, 0xcc, 0x33, 0 }, /* 89 */
+ { 0x33, 0xff, 0x33, 0 }, /* 90 */
+ { 0x66, 0xff, 0x33, 0 }, /* 91 */
+ { 0x99, 0xff, 0x33, 0 }, /* 92 */
+ { 0xcc, 0xff, 0x33, 0 }, /* 93 */
+ { 0xff, 0xff, 0x33, 0 }, /* 94 */
+ { 0x00, 0x00, 0x66, 0 }, /* 95 */
+ { 0x33, 0x00, 0x66, 0 }, /* 96 */
+ { 0x66, 0x00, 0x66, 0 }, /* 97 */
+ { 0x99, 0x00, 0x66, 0 }, /* 98 */
+ { 0xcc, 0x00, 0x66, 0 }, /* 99 */
+ { 0xff, 0x00, 0x66, 0 }, /* 100 */
+ { 0x00, 0x33, 0x66, 0 }, /* 101 */
+ { 0x33, 0x33, 0x66, 0 }, /* 102 */
+ { 0x66, 0x33, 0x66, 0 }, /* 103 */
+ { 0x99, 0x33, 0x66, 0 }, /* 104 */
+ { 0xcc, 0x33, 0x66, 0 }, /* 105 */
+ { 0xff, 0x33, 0x66, 0 }, /* 106 */
+ { 0x00, 0x66, 0x66, 0 }, /* 107 */
+ { 0x33, 0x66, 0x66, 0 }, /* 108 */
+ { 0x66, 0x66, 0x66, 0 }, /* 109 gray 102 */
+ { 0x99, 0x66, 0x66, 0 }, /* 110 */
+ { 0xcc, 0x66, 0x66, 0 }, /* 111 */
+ { 0x00, 0x99, 0x66, 0 }, /* 112 */
+ { 0x33, 0x99, 0x66, 0 }, /* 113 */
+ { 0x66, 0x99, 0x66, 0 }, /* 114 */
+ { 0x99, 0x99, 0x66, 0 }, /* 115 */
+ { 0xcc, 0x99, 0x66, 0 }, /* 116 */
+ { 0xff, 0x99, 0x66, 0 }, /* 117 */
+ { 0x00, 0xcc, 0x66, 0 }, /* 118 */
+ { 0x33, 0xcc, 0x66, 0 }, /* 119 */
+ { 0x99, 0xcc, 0x66, 0 }, /* 120 */
+ { 0xcc, 0xcc, 0x66, 0 }, /* 121 */
+ { 0xff, 0xcc, 0x66, 0 }, /* 122 */
+ { 0x00, 0xff, 0x66, 0 }, /* 123 */
+ { 0x33, 0xff, 0x66, 0 }, /* 124 */
+ { 0x99, 0xff, 0x66, 0 }, /* 125 */
+ { 0xcc, 0xff, 0x66, 0 }, /* 126 */
+ { 0xff, 0x00, 0xcc, 0 }, /* 127 */
+ { 0xcc, 0x00, 0xff, 0 }, /* 128 */
+ { 0x00, 0x99, 0x99, 0 }, /* 129 */
+ { 0x99, 0x33, 0x99, 0 }, /* 130 */
+ { 0x99, 0x00, 0x99, 0 }, /* 131 */
+ { 0xcc, 0x00, 0x99, 0 }, /* 132 */
+ { 0x00, 0x00, 0x99, 0 }, /* 133 */
+ { 0x33, 0x33, 0x99, 0 }, /* 134 */
+ { 0x66, 0x00, 0x99, 0 }, /* 135 */
+ { 0xcc, 0x33, 0x99, 0 }, /* 136 */
+ { 0xff, 0x00, 0x99, 0 }, /* 137 */
+ { 0x00, 0x66, 0x99, 0 }, /* 138 */
+ { 0x33, 0x66, 0x99, 0 }, /* 139 */
+ { 0x66, 0x33, 0x99, 0 }, /* 140 */
+ { 0x99, 0x66, 0x99, 0 }, /* 141 */
+ { 0xcc, 0x66, 0x99, 0 }, /* 142 */
+ { 0xff, 0x33, 0x99, 0 }, /* 143 */
+ { 0x33, 0x99, 0x99, 0 }, /* 144 */
+ { 0x66, 0x99, 0x99, 0 }, /* 145 */
+ { 0x99, 0x99, 0x99, 0 }, /* 146 gray 153 */
+ { 0xcc, 0x99, 0x99, 0 }, /* 147 */
+ { 0xff, 0x99, 0x99, 0 }, /* 148 */
+ { 0x00, 0xcc, 0x99, 0 }, /* 149 */
+ { 0x33, 0xcc, 0x99, 0 }, /* 150 */
+ { 0x66, 0xcc, 0x66, 0 }, /* 151 */
+ { 0x99, 0xcc, 0x99, 0 }, /* 152 */
+ { 0xcc, 0xcc, 0x99, 0 }, /* 153 */
+ { 0xff, 0xcc, 0x99, 0 }, /* 154 */
+ { 0x00, 0xff, 0x99, 0 }, /* 155 */
+ { 0x33, 0xff, 0x99, 0 }, /* 156 */
+ { 0x66, 0xcc, 0x99, 0 }, /* 157 */
+ { 0x99, 0xff, 0x99, 0 }, /* 158 */
+ { 0xcc, 0xff, 0x99, 0 }, /* 159 */
+ { 0xff, 0xff, 0x99, 0 }, /* 160 */
+ { 0x00, 0x00, 0xcc, 0 }, /* 161 */
+ { 0x33, 0x00, 0x99, 0 }, /* 162 */
+ { 0x66, 0x00, 0xcc, 0 }, /* 163 */
+ { 0x99, 0x00, 0xcc, 0 }, /* 164 */
+ { 0xcc, 0x00, 0xcc, 0 }, /* 165 */
+ { 0x00, 0x33, 0x99, 0 }, /* 166 */
+ { 0x33, 0x33, 0xcc, 0 }, /* 167 */
+ { 0x66, 0x33, 0xcc, 0 }, /* 168 */
+ { 0x99, 0x33, 0xcc, 0 }, /* 169 */
+ { 0xcc, 0x33, 0xcc, 0 }, /* 170 */
+ { 0xff, 0x33, 0xcc, 0 }, /* 171 */
+ { 0x00, 0x66, 0xcc, 0 }, /* 172 */
+ { 0x33, 0x66, 0xcc, 0 }, /* 173 */
+ { 0x66, 0x66, 0x99, 0 }, /* 174 */
+ { 0x99, 0x66, 0xcc, 0 }, /* 175 */
+ { 0xcc, 0x66, 0xcc, 0 }, /* 176 */
+ { 0xff, 0x66, 0x99, 0 }, /* 177 */
+ { 0x00, 0x99, 0xcc, 0 }, /* 178 */
+ { 0x33, 0x99, 0xcc, 0 }, /* 179 */
+ { 0x66, 0x99, 0xcc, 0 }, /* 180 */
+ { 0x99, 0x99, 0xcc, 0 }, /* 181 */
+ { 0xcc, 0x99, 0xcc, 0 }, /* 182 */
+ { 0xff, 0x99, 0xcc, 0 }, /* 183 */
+ { 0x00, 0xcc, 0xcc, 0 }, /* 184 */
+ { 0x33, 0xcc, 0xcc, 0 }, /* 185 */
+ { 0x66, 0xcc, 0xcc, 0 }, /* 186 */
+ { 0x99, 0xcc, 0xcc, 0 }, /* 187 */
+ { 0xcc, 0xcc, 0xcc, 0 }, /* 188 gray 204 */
+ { 0xff, 0xcc, 0xcc, 0 }, /* 189 */
+ { 0x00, 0xff, 0xcc, 0 }, /* 190 */
+ { 0x33, 0xff, 0xcc, 0 }, /* 191 */
+ { 0x66, 0xff, 0x99, 0 }, /* 192 */
+ { 0x99, 0xff, 0xcc, 0 }, /* 193 */
+ { 0xcc, 0xff, 0xcc, 0 }, /* 194 */
+ { 0xff, 0xff, 0xcc, 0 }, /* 195 */
+ { 0x33, 0x00, 0xcc, 0 }, /* 196 */
+ { 0x66, 0x00, 0xff, 0 }, /* 197 */
+ { 0x99, 0x00, 0xff, 0 }, /* 198 */
+ { 0x00, 0x33, 0xcc, 0 }, /* 199 */
+ { 0x33, 0x33, 0xff, 0 }, /* 200 */
+ { 0x66, 0x33, 0xff, 0 }, /* 201 */
+ { 0x99, 0x33, 0xff, 0 }, /* 202 */
+ { 0xcc, 0x33, 0xff, 0 }, /* 203 */
+ { 0xff, 0x33, 0xff, 0 }, /* 204 */
+ { 0x00, 0x66, 0xff, 0 }, /* 205 */
+ { 0x33, 0x66, 0xff, 0 }, /* 206 */
+ { 0x66, 0x66, 0xcc, 0 }, /* 207 */
+ { 0x99, 0x66, 0xff, 0 }, /* 208 */
+ { 0xcc, 0x66, 0xff, 0 }, /* 209 */
+ { 0xff, 0x66, 0xcc, 0 }, /* 210 */
+ { 0x00, 0x99, 0xff, 0 }, /* 211 */
+ { 0x33, 0x99, 0xff, 0 }, /* 212 */
+ { 0x66, 0x99, 0xff, 0 }, /* 213 */
+ { 0x99, 0x99, 0xff, 0 }, /* 214 */
+ { 0xcc, 0x99, 0xff, 0 }, /* 215 */
+ { 0xff, 0x99, 0xff, 0 }, /* 216 */
+ { 0x00, 0xcc, 0xff, 0 }, /* 217 */
+ { 0x33, 0xcc, 0xff, 0 }, /* 218 */
+ { 0x66, 0xcc, 0xff, 0 }, /* 219 */
+ { 0x99, 0xcc, 0xff, 0 }, /* 220 */
+ { 0xcc, 0xcc, 0xff, 0 }, /* 221 */
+ { 0xff, 0xcc, 0xff, 0 }, /* 222 */
+ { 0x33, 0xff, 0xff, 0 }, /* 223 */
+ { 0x66, 0xff, 0xcc, 0 }, /* 224 */
+ { 0x99, 0xff, 0xff, 0 }, /* 225 */
+ { 0xcc, 0xff, 0xff, 0 }, /* 226 */
+ { 0xff, 0x66, 0x66, 0 }, /* 227 */
+ { 0x66, 0xff, 0x66, 0 }, /* 228 */
+ { 0xff, 0xff, 0x66, 0 }, /* 229 */
+ { 0x66, 0x66, 0xff, 0 }, /* 230 */
+ { 0xff, 0x66, 0xff, 0 }, /* 231 */
+ { 0x66, 0xff, 0xff, 0 }, /* 232 */
+ { 0xA5, 0x00, 0x21, 0 }, /* 233 R165 G0 B33 */
+ { 0x5f, 0x5f, 0x5f, 0 }, /* 234 gray 95 */
+ { 0x77, 0x77, 0x77, 0 }, /* 235 gray 119 */
+ { 0x86, 0x86, 0x86, 0 }, /* 236 gray 134 */
+ { 0x96, 0x96, 0x96, 0 }, /* 237 gray 150 */
+ { 0xcb, 0xcb, 0xcb, 0 }, /* 238 gray 203 */
+ { 0xb2, 0xb2, 0xb2, 0 }, /* 239 gray 178 */
+ { 0xd7, 0xd7, 0xd7, 0 }, /* 240 gray 215 */
+ { 0xdd, 0xdd, 0xdd, 0 }, /* 241 gray 221 */
+ { 0xe3, 0xe3, 0xe3, 0 }, /* 242 gray 227 */
+ { 0xea, 0xea, 0xea, 0 }, /* 243 gray 234 */
+ { 0xf1, 0xf1, 0xf1, 0 }, /* 244 gray 241 */
+ { 0xf8, 0xf8, 0xf8, 0 }, /* 245 gray 248 */
+ { 0xff, 0xfb, 0xf0, 0 }, /* 246 Sys Reserved */
+ { 0xa0, 0xa0, 0xa4, 0 }, /* 247 Sys Reserved */
+ { 0x80, 0x80, 0x80, 0 }, /* 248 Sys Lt Gray gray 128 */
+ { 0xff, 0x00, 0x00, 0 }, /* 249 Sys Red */
+ { 0x00, 0xff, 0x00, 0 }, /* 250 Sys Green */
+ { 0xff, 0xff, 0x00, 0 }, /* 251 Sys Yellow */
+ { 0x00, 0x00, 0xff, 0 }, /* 252 Sys Blue */
+ { 0xff, 0x00, 0xff, 0 }, /* 253 Sys Violet */
+ { 0x00, 0xff, 0xff, 0 }, /* 254 Sys Cyan */
+ { 0xff, 0xff, 0xff, 0 } /* 255 Sys White gray 255 */
+};
+
+#endif
diff --git a/cpu/arm926ejs/at91sam926x/serial.c b/cpu/arm926ejs/at91sam926x/serial.c
new file mode 100644
index 00000000000..8ef91c2e41e
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/serial.c
@@ -0,0 +1,116 @@
+/*
+ * (C) Copyright 2005
+ * M. Amine SAYA ATMEL Rousset, France.
+ * Added AT91SAM9261's serial port support.
+ * Added NADIA2's serial port support.
+ *
+ * (C) Copyright 2002
+ * Lineo, Inc <www.lineo.com>
+ * Bernhard Kuhn <bkuhn@lineo.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>
+ *
+ * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+
+#if !defined(CONFIG_DBGU) && !defined(CONFIG_USART0) && !defined(CONFIG_USART1) && !defined(CONFIG_USART2)
+#error must define one of CONFIG_DBGU or CONFIG_USART0 or CONFIG_USART1 or CONFIG_USART2
+#endif
+
+/* Serial ports for SAM926x */
+#ifdef CONFIG_DBGU
+AT91PS_USART us = (AT91PS_USART) AT91C_BASE_DBGU;
+#endif
+
+#ifdef CONFIG_USART0
+AT91PS_USART us = (AT91PS_USART) AT91C_BASE_US0;
+#endif
+
+#ifdef CONFIG_USART1
+AT91PS_USART us = (AT91PS_USART) AT91C_BASE_US1;
+#endif
+
+#ifdef CONFIG_USART2
+AT91PS_USART us = (AT91PS_USART) AT91C_BASE_US2;
+#endif
+
+extern int AT91F_Serial_Hardware_Init(void);
+
+
+void serial_setbrg (void)
+{
+ DECLARE_GLOBAL_DATA_PTR;
+ int baudrate;
+
+ if ((baudrate = gd->baudrate) <= 0)
+ baudrate = CONFIG_BAUDRATE;
+ if (baudrate == 0 || baudrate == CONFIG_BAUDRATE)
+ us->US_BRGR = AT91C_MASTER_CLOCK/(baudrate * 16);
+}
+
+int serial_init (void)
+{
+ /* make any port initializations specific to this port */
+ AT91F_Serial_Hardware_Init();
+
+ serial_setbrg ();
+
+ us->US_CR = AT91C_US_RSTRX | AT91C_US_RSTTX;
+ us->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
+ us->US_MR =
+ (AT91C_US_CLKS_CLOCK | AT91C_US_CHRL_8_BITS |
+ AT91C_US_PAR_NONE | AT91C_US_NBSTOP_1_BIT);
+ us->US_IMR = ~0ul;
+ return (0);
+}
+
+void serial_putc (const char c)
+{
+ if (c == '\n')
+ serial_putc ('\r');
+ while ((us->US_CSR & AT91C_US_TXRDY) == 0);
+ us->US_THR = c;
+}
+
+void serial_puts (const char *s)
+{
+ while (*s) {
+ serial_putc (*s++);
+ }
+}
+
+int serial_getc (void)
+{
+ while ((us->US_CSR & AT91C_US_RXRDY) == 0);
+ return us->US_RHR;
+}
+
+int serial_tstc (void)
+{
+ return ((us->US_CSR & AT91C_US_RXRDY) == AT91C_US_RXRDY);
+}
diff --git a/cpu/arm926ejs/at91sam926x/spi.c b/cpu/arm926ejs/at91sam926x/spi.c
new file mode 100644
index 00000000000..bd855283b92
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/spi.c
@@ -0,0 +1,243 @@
+/*
+ * (c) Copyright 2005
+ * M. Amine SAYA, ATMEL Rousset, France.
+ * Driver for AT91SAM9261 SPI
+ * Based on at91rm9200 spi driver from H. Ikdoumi, ATMEL Rousset.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ *
+ */
+
+#include <config.h>
+#include <common.h>
+
+#ifdef CONFIG_HAS_DATAFLASH
+#include <dataflash.h>
+#include <asm/arch/pio.h>
+
+#ifdef CONFIG_AT91SAM9263EK
+#define AT91C_SPI_CS0_CLK 8000000 /* SPI Clock for Dataflash cards -> SAM9263EK */
+#else
+#define AT91C_SPI_CS0_CLK 33000000 /* SPI Clock for Dataflash devices */
+#endif
+
+#define AT91C_SPI_CS1_CLK 33000000 /* SPI Clock for Dataflash devices -> SAM9260EK */
+#define AT91C_SPI_CS3_CLK 8000000 /* SPI Clock for Dataflash cards -> SAM9261EK */
+
+#define AT91C_SPI_PCS0_DATAFLASH_CARD 0xE /* Chip Select 0 : NPCS0 %1110 */
+#define AT91C_SPI_PCS1_DATAFLASH_CARD 0xD /* Chip Select 1 : NPCS1 %1101 */
+#define AT91C_SPI_PCS3_DATAFLASH_CARD 0x7 /* Chip Select 3 : NPCS3 %0111 */
+
+
+/*----------------------------------------------------------------------------*/
+/* \fn AT91F_SpiInit */
+/* \brief SPI Init */
+/*----------------------------------------------------------------------------*/
+void AT91F_SpiInit(void) {
+
+ volatile unsigned int dummy;
+
+#ifdef CONFIG_AT91SAM9260EK
+ /* Configure PIO controllers to periph mode */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, // PIO controller base address
+ ((unsigned int) AT91C_PA1_SPI0_MOSI) |
+ ((unsigned int) AT91C_PA3_SPI0_NPCS0) |
+ ((unsigned int) AT91C_PA0_SPI0_MISO) |
+ ((unsigned int) AT91C_PA2_SPI0_SPCK), /* Peripheral A */
+ 0); /* Peripheral B */
+ /* Configure PIO controllers to periph mode */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOC, /* PIO controller base address */
+ 0, /* Peripheral A */
+ ((unsigned int) AT91C_PC11_SPI0_NPCS1)); /* Peripheral B */
+#endif
+
+#ifdef CONFIG_AT91SAM9261EK
+ /* Configure PIOs for SPI0 (internal DataFlash) */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,
+ (AT91C_PA0_MISO0 | AT91C_PA1_MOSI0 |
+ AT91C_PA2_SPCK0 | AT91C_PA3_NPCS00),
+ 0);
+#endif
+
+#ifdef CONFIG_AT91SAM9263EK
+ /* Configure PIO controllers to periph mode */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA, /* PIO controller base address */
+ 0, /* Peripheral A */
+ ((unsigned int) AT91C_PA2_SPI0_SPCK) |
+ ((unsigned int) AT91C_PA1_SPI0_MOSI) |
+ ((unsigned int) AT91C_PA5_SPI0_NPCS0) |
+ ((unsigned int) AT91C_PA0_SPI0_MISO)); /* Peripheral B */
+#endif
+
+#ifdef CONFIG_AT91SAM9RLEK
+ /* Configure PIOs for SPI0 (internal DataFlash) */
+ AT91F_PIO_CfgPeriph(AT91C_BASE_PIOA,
+ ((unsigned int) AT91C_PA25_MISO) |
+ ((unsigned int) AT91C_PA26_MOSI) |
+ ((unsigned int) AT91C_PA27_SPCK) |
+ ((unsigned int) AT91C_PA28_NPCS0), /* Peripheral A */
+ 0 /* Peripheral B */);
+#endif
+
+
+ /* Enable Clock */
+ AT91C_BASE_PMC->PMC_PCER = 1 << AT91C_ID_SPI0;
+
+ /* Reset the SPI */
+ AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SWRST;
+
+ /* Configure SPI in Master Mode with No CS selected !!! */
+ AT91C_BASE_SPI0->SPI_MR = AT91C_SPI_MSTR | AT91C_SPI_MODFDIS | AT91C_SPI_PCS;
+
+ /* Configure CS0 in Mode 0 */
+ /* to avoid pb with DataFlash AT45DB642D */
+ AT91C_BASE_SPI0->SPI_CSR[0] = (AT91C_SPI_NCPHA | (AT91C_SPI_DLYBS & DATAFLASH_TCSS) |
+ (AT91C_SPI_DLYBCT & DATAFLASH_TCHS) |
+ (AT91C_MASTER_CLOCK / AT91C_SPI_CS0_CLK) << 8);
+
+
+#ifdef CONFIG_AT91SAM9260EK
+ AT91C_BASE_SPI0->SPI_CSR[1] = (AT91C_SPI_NCPHA | (AT91C_SPI_DLYBS & DATAFLASH_TCSS) |
+ (AT91C_SPI_DLYBCT & DATAFLASH_TCHS) |
+ (AT91C_MASTER_CLOCK / AT91C_SPI_CS1_CLK) << 8);
+#endif
+#ifdef CONFIG_AT91SAM9261EK
+ AT91C_BASE_SPI0->SPI_CSR[3] = (AT91C_SPI_NCPHA | (AT91C_SPI_DLYBS & DATAFLASH_TCSS) |
+ (AT91C_SPI_DLYBCT & DATAFLASH_TCHS) |
+ (AT91C_MASTER_CLOCK / AT91C_SPI_CS3_CLK) << 8);
+#endif
+
+ /* SPI_Enable */
+ AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN;
+
+ while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_SPIENS));
+
+ /* Add tempo to get SPI in a safe state.
+ Should be removed for new silicon (Rev B)
+ */
+ udelay(500000);
+ dummy = AT91C_BASE_SPI0->SPI_SR;
+ dummy = AT91C_BASE_SPI0->SPI_RDR;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* \fn AT91F_SpiEnable */
+/* \brief SPI Enable */
+/*----------------------------------------------------------------------------*/
+void AT91F_SpiEnable(int cs) {
+ AT91C_BASE_SPI0->SPI_MR &= 0xFFF0FFFF;
+
+ switch(cs) {
+ case 0:
+ /* Configure SPI CS0 for DataFlash card AT45DBxx */
+ AT91C_BASE_SPI0->SPI_MR |= ((AT91C_SPI_PCS0_DATAFLASH_CARD<<16) & AT91C_SPI_PCS);
+ break;
+ case 1:
+ /* Configure SPI CS1 for dataflash card AT45DBxx */
+ AT91C_BASE_SPI0->SPI_MR |= ((AT91C_SPI_PCS1_DATAFLASH_CARD<<16) & AT91C_SPI_PCS);
+ break;
+ case 2:
+ case 3:
+ /* Configure SPI CS3 for dataflash card AT45DBxx */
+ AT91C_BASE_SPI0->SPI_MR |= ((AT91C_SPI_PCS3_DATAFLASH_CARD<<16) & AT91C_SPI_PCS);
+ break;
+ default:
+ /* Configure PCS */
+ AT91C_BASE_SPI0->SPI_MR |= ((AT91C_SPI_PCS0_DATAFLASH_CARD<<16) & AT91C_SPI_PCS);
+ break;
+ }
+
+ /* SPI_Enable */
+ AT91C_BASE_SPI0->SPI_CR = AT91C_SPI_SPIEN;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* \fn AT91F_SpiDisablePDC */
+/* \brief Disable PDC registers */
+/*----------------------------------------------------------------------------*/
+void __inline__ AT91F_SpiDisablePDC(AT91PS_SPI spi_ptr)
+{
+ spi_ptr->SPI_PTCR = AT91C_PDC_RXTDIS | AT91C_PDC_TXTDIS;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* \fn AT91F_SpiEnablePDC */
+/* \brief Enable PDC registers */
+/*----------------------------------------------------------------------------*/
+void __inline__ AT91F_SpiEnablePDC(AT91PS_SPI spi_ptr)
+{
+ spi_ptr->SPI_PTCR = AT91C_PDC_RXTEN | AT91C_PDC_TXTEN;
+}
+
+
+/*----------------------------------------------------------------------------*/
+/* \fn AT91F_SpiWrite */
+/* \brief Set the PDC registers for a transfert */
+/*----------------------------------------------------------------------------*/
+unsigned int AT91F_SpiWrite ( AT91PS_DataflashDesc pDesc )
+{
+ unsigned int timeout;
+
+ pDesc->state = BUSY;
+
+ /* Disable PDC TX and RX channels */
+ AT91C_BASE_SPI0->SPI_PTCR = AT91C_PDC_TXTDIS + AT91C_PDC_RXTDIS;
+
+ /* Initialize the Transmit and Receive Pointer */
+ AT91C_BASE_SPI0->SPI_RPR = (unsigned int)pDesc->rx_cmd_pt ;
+ AT91C_BASE_SPI0->SPI_TPR = (unsigned int)pDesc->tx_cmd_pt ;
+
+ /* Intialize the Transmit and Receive Counters */
+ AT91C_BASE_SPI0->SPI_RCR = pDesc->rx_cmd_size;
+ AT91C_BASE_SPI0->SPI_TCR = pDesc->tx_cmd_size;
+
+ /* If there is another transfer to perform */
+ if(pDesc->tx_data_size){
+ /* Initialize the Next Transmit and Next Receive Pointer */
+ AT91C_BASE_SPI0->SPI_RNPR = (unsigned int)pDesc->rx_data_pt ;
+ AT91C_BASE_SPI0->SPI_TNPR = (unsigned int)pDesc->tx_data_pt ;
+
+ /* Initialize the Next Transmit and Next Receive Counters */
+ AT91C_BASE_SPI0->SPI_RNCR = pDesc->rx_data_size ;
+ AT91C_BASE_SPI0->SPI_TNCR = pDesc->tx_data_size ;
+ }
+
+ /* arm simple, non interrupt dependent timer */
+ reset_timer_masked();
+ timeout = 0;
+
+ AT91F_SpiEnablePDC(AT91C_BASE_SPI0);
+
+ while(!(AT91C_BASE_SPI0->SPI_SR & AT91C_SPI_RXBUFF) && ((timeout = get_timer_masked() ) < CFG_SPI_WRITE_TOUT));
+
+ /* Disable PDC TX and RX channels */
+ AT91F_SpiDisablePDC(AT91C_BASE_SPI0);
+
+ pDesc->state = IDLE;
+
+
+ if (timeout >= CFG_SPI_WRITE_TOUT){
+ printf("AT91F_SpiWrite : Error Timeout\n\r");
+ return DATAFLASH_ERROR;
+ }
+
+ return DATAFLASH_OK;
+}
+
+#endif
diff --git a/cpu/arm926ejs/at91sam926x/usb_ohci.c b/cpu/arm926ejs/at91sam926x/usb_ohci.c
new file mode 100644
index 00000000000..79d0fc008ff
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/usb_ohci.c
@@ -0,0 +1,1709 @@
+/*
+ * URB OHCI HCD (Host Controller Driver) for USB on the S3C2400 and SAM9263 from ATMEL.
+ *
+ * (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
+ *
+ * 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!
+ */
+
+#include <common.h>
+
+#ifdef CONFIG_USB_OHCI
+
+#include <asm/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;
+/* flag guarding URB transation */
+int urb_finished = 0;
+
+/*-------------------------------------------------------------------------*/
+
+/* 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);
+
+ 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;
+ }
+
+ /* if we have an unfinished URB from previous transaction let's
+ * fail and scream as quickly as possible so as not to corrupt
+ * further communication */
+ if (!urb_finished) {
+ err("sohci_submit_job: URB NOT FINISHED");
+ return -1;
+ }
+ /* we're about to begin a new transaction here so mark the URB unfinished */
+ urb_finished = 0;
+
+ /* 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);
+
+ /* 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];
+ }
+
+ /* see if this done list makes for all TD's of current URB,
+ * and mark the URB finished if so */
+ if (++(lurb_priv->td_cnt) == lurb_priv->length) {
+ if ((ed->state & (ED_OPER | ED_UNLINK)))
+ urb_finished = 1;
+ else
+ dbg("dl_done_list: strange.., ED state %x, ed->state\n");
+ } else
+ dbg("dl_done_list: processing TD %x, len %x\n", lurb_priv->td_cnt,
+ lurb_priv->length);
+
+ 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);
+ 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;
+ 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;
+ }
+
+ /* NOTE: since we are not interrupt driven in U-Boot and always
+ * handle only one URB at a time, we cannot assume the
+ * transaction finished on the first successful return from
+ * hc_interrupt().. unless the flag for current URB is set,
+ * meaning that all TD's to/from device got actually
+ * transferred and processed. If the current URB is not
+ * finished we need to re-iterate this loop so as
+ * hc_interrupt() gets called again as there needs to be some
+ * more TD's to process still */
+ if ((stat >= 0) && (stat != 0xff) && (urb_finished)) {
+ /* 0xff is returned for an SF-interrupt */
+ break;
+ }
+
+ if (--timeout) {
+ wait_ms(1);
+ if (!urb_finished)
+ dbg("\%");
+
+ } else {
+ err("CTL:TIMEOUT ");
+ dbg("submit_common_msg: TO status %x\n", stat);
+ stat = USB_ST_CRC_ERR;
+ urb_finished = 1;
+ break;
+ }
+ }
+
+#if 0
+ /* 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;
+ }
+ }
+#endif
+
+ 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 */
+
+ 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 ;",
+ 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 if ((ints = readl (&regs->intrstatus)) == ~(u32)0) {
+ ohci->disabled++;
+ err ("%s device removed!", ohci->slot_name);
+ return -1;
+
+ } else if ((ints &= readl (&regs->intrenable)) == 0) {
+ dbg("hc_interrupt: returning..\n");
+ return 0xff;
+ }
+
+ /* dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca->frame_no)); */
+
+ if (ints & OHCI_INTR_RHSC) {
+ got_rhsc = 1;
+ stat = 0xff;
+ }
+
+ 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_PCER = 1 << AT91C_ID_UHP; /* Peripheral Clock Enable Register */
+#ifdef CONFIG_AT91SAM9261EK
+ *AT91C_PMC_SCER = AT91C_PMC_UHP | AT91C_PMC_HCK0; /* UHP System clock enable*/
+#else
+ *AT91C_PMC_SCER = AT91C_PMC_UHP; /* UHP System clock enable*/
+#endif
+
+#ifdef CONFIG_AT91SAM9263EK
+ /* ON SAM9263-EK ONLY !!! */
+
+ /* Configure PIOA21 & PIOA24 in output */
+ /* Used to enable VBus on UHP ports */
+ *AT91C_PIOA_PER = AT91C_PIO_PA21 | AT91C_PIO_PA24;
+ *AT91C_PIOA_OER = AT91C_PIO_PA21 | AT91C_PIO_PA24;
+ *AT91C_PIOA_CODR = AT91C_PIO_PA21 | AT91C_PIO_PA24;
+#endif
+
+ 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 *) AT91C_BASE_UHP;
+
+ gohci.flags = 0;
+#if defined CONFIG_AT91SAM9260EK
+ gohci.slot_name = "sam9260";
+#elif defined CONFIG_AT91SAM9261EK
+ gohci.slot_name = "sam9261";
+#elif defined CONFIG_AT91SAM9263EK
+ gohci.slot_name = "sam9263";
+#endif
+
+ if (hc_reset (&gohci) < 0) {
+ hc_release_ohci (&gohci);
+
+ /* Initialization failed */
+ *AT91C_PMC_PCDR = 1 << AT91C_ID_UHP; /* Peripheral Clock Disable Register */
+ *AT91C_PMC_SCDR = AT91C_PMC_UHP; /* UHP System clock disable*/
+
+ return -1;
+ }
+
+ /* FIXME this is a second HC reset; why?? */
+ gohci.hc_control = OHCI_USB_RESET;
+ writel (gohci.hc_control, &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_PCDR = 1 << AT91C_ID_UHP; /* Peripheral Clock Disable Register */
+#ifdef CONFIG_AT91SAM9261EK
+ *AT91C_PMC_SCDR = AT91C_PMC_UHP | AT91C_PMC_HCK0; /* UHP System clock disable*/
+#else
+ *AT91C_PMC_SCDR = AT91C_PMC_UHP; /* UHP System clock disable*/
+#endif
+ return -1;
+ }
+
+#ifdef DEBUG
+ ohci_dump (&gohci, 1);
+#else
+ wait_ms(1);
+#endif
+ ohci_inited = 1;
+ urb_finished = 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_PCDR = 1 << AT91C_ID_UHP; /* Peripheral Clock Disable Register */
+#ifdef CONFIG_AT91SAM9261EK
+ *AT91C_PMC_SCDR = AT91C_PMC_UHP | AT91C_PMC_HCK0; /* UHP System clock disable*/
+#else
+ *AT91C_PMC_SCDR = AT91C_PMC_UHP; /* UHP System clock disable*/
+#endif
+
+ return 0;
+}
+
+#endif /* CONFIG_USB_OHCI */
diff --git a/cpu/arm926ejs/at91sam926x/usb_ohci.h b/cpu/arm926ejs/at91sam926x/usb_ohci.h
new file mode 100644
index 00000000000..5e9a0fdfc4e
--- /dev/null
+++ b/cpu/arm926ejs/at91sam926x/usb_ohci.h
@@ -0,0 +1,417 @@
+/*
+ * 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 */
+
+ __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/arm926ejs/interrupts.c b/cpu/arm926ejs/interrupts.c
index 9cac969f64a..f4f22c0351c 100644
--- a/cpu/arm926ejs/interrupts.c
+++ b/cpu/arm926ejs/interrupts.c
@@ -172,7 +172,9 @@ void do_irq (struct pt_regs *pt_regs)
bad_mode ();
}
-#ifdef CONFIG_INTEGRATOR
+#if defined(CONFIG_INTEGRATOR) || defined(CONFIG_AT91SAM9261EK) \
+|| defined(CONFIG_AT91SAM9260EK)|| defined(CONFIG_AT91SAM9263EK) \
+|| defined(CONFIG_AT91SAM9RLEK)
/* Timer functionality supplied by Integrator board (AP or CP) */
diff --git a/cpu/arm926ejs/start.S b/cpu/arm926ejs/start.S
index 725c6639a1e..11b7c3cadfb 100644
--- a/cpu/arm926ejs/start.S
+++ b/cpu/arm926ejs/start.S
@@ -5,8 +5,8 @@
*
* ----- Adapted for OMAP1610 OMAP730 from ARM925t code ------
*
- * Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
- * Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
+ * Copyright (c) 2001 Marius Gröger <mag@sysgo.de>
+ * Copyright (c) 2002 Alex Züpke <azu@sysgo.de>
* Copyright (c) 2002 Gary Jennejohn <gj@denx.de>
* Copyright (c) 2003 Richard Woodruff <r-woodruff2@ti.com>
* Copyright (c) 2003 Kshitij <kshitij@ti.com>
@@ -199,7 +199,7 @@ _start_armboot:
*************************************************************************
*/
-
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
/*
* flush v4 I/D caches
@@ -225,6 +225,8 @@ cpu_init_crit:
bl lowlevel_init /* go setup pll,mux,memory */
mov lr, ip /* restore link */
mov pc, lr /* back to my caller */
+#endif
+
/*
*************************************************************************
*